forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathsleep_memory_persist.py
More file actions
100 lines (78 loc) · 2.75 KB
/
sleep_memory_persist.py
File metadata and controls
100 lines (78 loc) · 2.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Reproducer for https://github.com/adafruit/circuitpython/issues/10896
Copy to code.py. Sequences through test steps using sleep_memory to
track state.
The test scoreboard is printed to the magtag e-ink display after every
run so the final display shows cumulative results.
"""
import alarm
import binascii
import microcontroller
import struct
import supervisor
import time
# Safe mode avoidance
# On boot CircuitPython writes a SAFE_MODE_USER guard to an RTC register,
# If a second boot occurs before 1000ms elapses then we enter safe mode.
# So, wait for 1000+1ms before calling microcontroller.reset().
_SAFE_MODE_WINDOW_MS = 1000
def _wait_for_safe_mode_window():
elapsed_ms = time.monotonic() * 1000
remaining = _SAFE_MODE_WINDOW_MS + 1 - elapsed_ms
if remaining > 0:
time.sleep(remaining / 1000)
# Test result enum
_UNTESTED = 0
_PASS = 1
_FAIL = 2
_LABEL = {_UNTESTED: "-", _PASS: "PASS", _FAIL: "FAIL"}
# CRC32-protected state in sleep_memory
# [magic:2][step:1][r_reset:1][r_reload:1][pad:1][crc32:4]
_MAGIC = 0xBE01
_FMT = "<HBBBx"
_DATA_SZ = struct.calcsize(_FMT) # 6
_TOTAL = _DATA_SZ + 4 # 10
def _write(step, r_reset=_UNTESTED, r_reload=_UNTESTED):
data = struct.pack(_FMT, _MAGIC, step, r_reset, r_reload)
crc = struct.pack("<I", binascii.crc32(data) & 0xFFFFFFFF)
alarm.sleep_memory[0:_TOTAL] = data + crc
def _read():
raw = bytes(alarm.sleep_memory[0:_TOTAL])
data = raw[:_DATA_SZ]
stored_crc = struct.unpack_from("<I", raw, _DATA_SZ)[0]
if (binascii.crc32(data) & 0xFFFFFFFF) != stored_crc:
return (0, _UNTESTED, _UNTESTED, False)
magic, step, r_reset, r_reload = struct.unpack(_FMT, data)
if magic != _MAGIC:
return (0, _UNTESTED, _UNTESTED, False)
return (step, r_reset, r_reload, True)
def _scoreboard(r_reset, r_reload):
print(f" reset: {_LABEL[r_reset]}")
print(f" reload: {_LABEL[r_reload]}")
# Main
reason = microcontroller.cpu.reset_reason
step, r_reset, r_reload, valid = _read()
if reason == microcontroller.ResetReason.POWER_ON:
_scoreboard(_UNTESTED, _UNTESTED)
print("writing marker, resetting...")
_write(0)
_wait_for_safe_mode_window()
microcontroller.reset()
elif valid and step == 0:
r_reset = _PASS
_scoreboard(r_reset, _UNTESTED)
print("testing supervisor.reload()...")
_write(1, r_reset)
_wait_for_safe_mode_window()
supervisor.reload()
elif not valid and step == 0:
r_reset = _FAIL
_scoreboard(r_reset, _UNTESTED)
print("Install patched FW, power cycle")
elif valid and step == 1:
r_reload = _PASS
_scoreboard(r_reset, r_reload)
_write(2, r_reset, r_reload)
else:
_scoreboard(r_reset, r_reload)
print(f"unexpected: step={step} valid={valid}")
print("Power cycle to restart tests")