Skip to content

Commit 1e22561

Browse files
committed
Add ability to disable BLE workflow
Call `supervisor.disable_ble_workflow()` and the BLE workflow will be disabled until the chip is reset. This also includes a couple fixes: 1. Terminals can now be deinit by setting the tilegrid to NULL. This prevents using the tilegrid before display is init. 2. Fix BLE serial send amount when sending more than a single packet. Fixes #5049
1 parent e9369d5 commit 1e22561

File tree

10 files changed

+259
-8
lines changed

10 files changed

+259
-8
lines changed

main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ int __attribute__((used)) main(void) {
830830
serial_init();
831831

832832
#if CIRCUITPY_BLEIO
833+
supervisor_bluetooth_enable_workflow();
833834
supervisor_start_bluetooth();
834835
#endif
835836

ports/nrf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ CFLAGS += \
120120
# TODO: check this
121121
CFLAGS += -D__START=main
122122

123-
LDFLAGS = $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-T,$(GENERATED_LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs
123+
LDFLAGS = $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-z,max-page-size=0x1000 -Wl,-T,$(GENERATED_LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs
124124
LIBS := -lgcc -lc
125125

126126
LDFLAGS += -mthumb -mcpu=cortex-m4

shared-bindings/supervisor/__init__.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "lib/utils/interrupt_char.h"
3434
#include "supervisor/shared/autoreload.h"
35+
#include "supervisor/shared/bluetooth/bluetooth.h"
3536
#include "supervisor/shared/status_leds.h"
3637
#include "supervisor/shared/stack.h"
3738
#include "supervisor/shared/traceback.h"
@@ -283,6 +284,17 @@ STATIC mp_obj_t supervisor_get_previous_traceback(void) {
283284
}
284285
MP_DEFINE_CONST_FUN_OBJ_0(supervisor_get_previous_traceback_obj, supervisor_get_previous_traceback);
285286

287+
//| def disable_ble_workflow() -> None:
288+
//| """Disable ble workflow until a reset. This prevents BLE advertising outside of the VM and
289+
//| the services used for it."""
290+
//| ...
291+
//|
292+
STATIC mp_obj_t supervisor_disable_ble_workflow(void) {
293+
supervisor_bluetooth_disable_workflow();
294+
return mp_const_none;
295+
}
296+
MP_DEFINE_CONST_FUN_OBJ_0(supervisor_disable_ble_workflow_obj, supervisor_disable_ble_workflow);
297+
286298
STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
287299
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
288300
{ MP_ROM_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) },
@@ -295,6 +307,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
295307
{ MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) },
296308
{ MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&supervisor_ticks_ms_obj) },
297309
{ MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },
310+
{ MP_ROM_QSTR(MP_QSTR_disable_ble_workflow), MP_ROM_PTR(&supervisor_disable_ble_workflow_obj) },
298311
};
299312

300313
STATIC MP_DEFINE_CONST_DICT(supervisor_module_globals, supervisor_module_globals_table);

shared-module/terminalio/Terminal.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d
4646
}
4747

4848
size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, const byte *data, size_t len, int *errcode) {
49+
// Make sure the terminal is initialized before we do anything with it.
50+
if (self->tilegrid == NULL) {
51+
return len;
52+
}
4953
const byte *i = data;
5054
uint16_t start_y = self->cursor_y;
5155
while (i < data + len) {
@@ -169,5 +173,5 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
169173
}
170174

171175
bool common_hal_terminalio_terminal_ready_to_tx(terminalio_terminal_obj_t *self) {
172-
return true;
176+
return self->tilegrid != NULL;
173177
}

supervisor/shared/bluetooth/bluetooth.c

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,27 @@ uint8_t circuitpython_scan_response_data[] = {
8383
#endif
8484
};
8585

86-
bool boot_in_discovery_mode = false;
87-
bool advertising = false;
86+
87+
#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE
88+
STATIC bool boot_in_discovery_mode = false;
89+
STATIC bool advertising = false;
90+
STATIC bool ble_started = false;
91+
92+
#define WORKFLOW_UNSET 0
93+
#define WORKFLOW_ENABLED 1
94+
#define WORKFLOW_DISABLED 2
95+
96+
STATIC uint8_t workflow_state = WORKFLOW_UNSET;
97+
STATIC bool was_connected = false;
98+
#endif
8899

89100
STATIC void supervisor_bluetooth_start_advertising(void) {
90101
#if !CIRCUITPY_BLE_FILE_SERVICE && !CIRCUITPY_SERIAL_BLE
91102
return;
92103
#else
104+
if (workflow_state != WORKFLOW_ENABLED) {
105+
return;
106+
}
93107
bool is_connected = common_hal_bleio_adapter_get_connected(&common_hal_bleio_adapter_obj);
94108
if (is_connected) {
95109
return;
@@ -211,8 +225,10 @@ void supervisor_bluetooth_init(void) {
211225
port_set_saved_word(reset_state);
212226
}
213227

214-
STATIC bool was_connected;
215228
void supervisor_bluetooth_background(void) {
229+
if (!ble_started) {
230+
return;
231+
}
216232
bool is_connected = common_hal_bleio_adapter_get_connected(&common_hal_bleio_adapter_obj);
217233
if (was_connected && !is_connected) {
218234
#if CIRCUITPY_BLE_FILE_SERVICE
@@ -235,6 +251,10 @@ void supervisor_start_bluetooth(void) {
235251
return;
236252
#endif
237253

254+
if (workflow_state != WORKFLOW_ENABLED) {
255+
return;
256+
}
257+
238258
common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true);
239259

240260
#if CIRCUITPY_BLE_FILE_SERVICE
@@ -245,7 +265,10 @@ void supervisor_start_bluetooth(void) {
245265
supervisor_start_bluetooth_serial();
246266
#endif
247267

248-
// Kick off advertisments
268+
// Mark as started so that the background call does something.
269+
ble_started = true;
270+
271+
// Kick off advertisements
249272
supervisor_bluetooth_background();
250273
}
251274

@@ -254,7 +277,31 @@ void supervisor_stop_bluetooth(void) {
254277
return;
255278
#endif
256279

280+
if (!ble_started && workflow_state != WORKFLOW_ENABLED) {
281+
return;
282+
}
283+
257284
#if CIRCUITPY_SERIAL_BLE
258285
supervisor_stop_bluetooth_serial();
259286
#endif
260287
}
288+
289+
void supervisor_bluetooth_enable_workflow(void) {
290+
#if !CIRCUITPY_BLE_FILE_SERVICE && !CIRCUITPY_SERIAL_BLE
291+
return;
292+
#endif
293+
294+
if (workflow_state == WORKFLOW_DISABLED) {
295+
return;
296+
}
297+
298+
workflow_state = WORKFLOW_ENABLED;
299+
}
300+
301+
void supervisor_bluetooth_disable_workflow(void) {
302+
#if !CIRCUITPY_BLE_FILE_SERVICE && !CIRCUITPY_SERIAL_BLE
303+
mp_raise_NotImplementedError();
304+
#endif
305+
306+
workflow_state = WORKFLOW_DISABLED;
307+
}

supervisor/shared/bluetooth/bluetooth.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ void supervisor_bluetooth_init(void);
3434
void supervisor_start_bluetooth(void);
3535
void supervisor_stop_bluetooth(void);
3636

37+
// Enable only works if it hasn't been set yet.
38+
void supervisor_bluetooth_enable_workflow(void);
39+
void supervisor_bluetooth_disable_workflow(void);
40+
3741
#endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_H

supervisor/shared/bluetooth/serial.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ void ble_serial_write(const char *text, size_t len) {
166166
}
167167
size_t sent = 0;
168168
while (sent < len) {
169-
uint16_t packet_size = MIN(len, (size_t)common_hal_bleio_packet_buffer_get_outgoing_packet_length(&_tx_packet_buffer));
169+
uint16_t packet_size = MIN(len - sent, (size_t)common_hal_bleio_packet_buffer_get_outgoing_packet_length(&_tx_packet_buffer));
170170
mp_int_t written = common_hal_bleio_packet_buffer_write(&_tx_packet_buffer, (const uint8_t *)text + sent, packet_size, NULL, 0);
171171
// Error, so we drop characters to transmit.
172172
if (written < 0) {

supervisor/shared/display.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ void supervisor_stop_terminal(void) {
123123
free_memory(tilegrid_tiles);
124124
tilegrid_tiles = NULL;
125125
supervisor_terminal_text_grid.tiles = NULL;
126+
supervisor_terminal.tilegrid = NULL;
126127
}
127128
#endif
128129
}

tools/gen_display_resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def _load_row(self, y, row):
228228
.font = &supervisor_terminal_font,
229229
.cursor_x = 0,
230230
.cursor_y = 0,
231-
.tilegrid = &supervisor_terminal_text_grid
231+
.tilegrid = NULL
232232
};
233233
"""
234234
)

tools/safe_mode_finder.py

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# This uses pyocd to control a Cortex M core, set a breakpoint and dump the stack.
2+
# It is expected that you modify it for your particular case.
3+
4+
from pyocd.core.helpers import ConnectHelper
5+
from pyocd.core.target import Target
6+
from pyocd.debug.elf.symbols import ELFSymbolProvider
7+
from pyocd.flash.file_programmer import FileProgrammer
8+
9+
import logging
10+
11+
# logging.basicConfig(level=logging.DEBUG)
12+
13+
import sys
14+
import time
15+
16+
board = sys.argv[1]
17+
18+
# Connect to the target.
19+
with ConnectHelper.session_with_chosen_probe(target_override="nrf52840") as session:
20+
target = session.target
21+
22+
# Set ELF file on target.
23+
filename = f"build-{board}/firmware.elf"
24+
target.elf = filename
25+
26+
e = target.elf._elf
27+
28+
# Look up address of reset_into_safe_mode().
29+
provider = ELFSymbolProvider(target.elf)
30+
addr = provider.get_symbol_value("reset_into_safe_mode")
31+
print("reset_into_safe_mode() address: 0x%X" % addr)
32+
33+
for section in target.elf.sections:
34+
print(section)
35+
print()
36+
37+
print("loading", filename)
38+
# FileProgrammer(session).program(filename, file_format="elf")
39+
print("load done")
40+
41+
# Set breakpoint.
42+
target.set_breakpoint(addr)
43+
# target.set_watchpoint(0x20010558, 4, Target.WatchpointType.WRITE)
44+
45+
# Reset and run.
46+
target.reset_and_halt()
47+
for i in range(1):
48+
target.resume()
49+
50+
print("resuming")
51+
start = time.monotonic()
52+
# Wait 10s until breakpoint is hit.
53+
while target.get_state() != Target.State.HALTED and time.monotonic() - start < 10:
54+
pass
55+
56+
# value = target.read_memory(0x20010558)
57+
# print(f"{value:08x}")
58+
59+
# time.sleep(2)
60+
61+
target.halt()
62+
63+
# print("_sidata", hex(provider.get_symbol_value("_sidata")))
64+
65+
# flash_start = 0x000affe8
66+
# ram_start = 0x20010000
67+
# for i in range(0, 0x55c, 4):
68+
# flash_value = target.read_memory(flash_start + i)
69+
# value = target.read_memory(ram_start + i)
70+
# diff = ""
71+
# if flash_value != value:
72+
# diff = "*"
73+
# print(f"{ram_start + i:08x} {flash_value:08x} {value:08x} {diff}")
74+
75+
# Print PC.
76+
pc = target.read_core_register("pc")
77+
print("pc: 0x%X" % pc)
78+
print(target.elf.symbol_decoder.get_symbol_for_address(pc))
79+
sp = target.read_core_register("sp")
80+
print("sp: 0x%X" % sp)
81+
msp = target.read_core_register("msp")
82+
print("msp: 0x%X" % msp)
83+
psp = target.read_core_register("psp")
84+
print("psp: 0x%X" % psp)
85+
86+
print(e.has_dwarf_info())
87+
d = e.get_dwarf_info()
88+
# print(dir(d))
89+
aranges = d.get_aranges()
90+
cu_offset = aranges.cu_offset_at_addr(pc)
91+
if not cu_offset:
92+
cu_offset = 0
93+
main_cu = d.get_CU_at(cu_offset)
94+
lines = d.line_program_for_CU(main_cu).get_entries()
95+
96+
lines_by_address = {}
97+
for line in lines:
98+
if not line.state:
99+
# print(line)
100+
continue
101+
lines_by_address[line.state.address] = line.state
102+
call_frames = None
103+
# if d.has_CFI():
104+
# print("CFI")
105+
# call_frames = d.CFI_entries()
106+
# if d.has_EH_CFI():
107+
# print("EH CFI")
108+
# call_frames = d.EH_CFI_entries()
109+
all_frames = {}
110+
# for frame in call_frames:
111+
# decoded = frame.get_decoded()
112+
# for entry in decoded.table:
113+
# entry_pc = entry["pc"]
114+
# all_frames[entry_pc] = decoded
115+
# for r in d.range_lists().iter_range_lists():
116+
# print(r)
117+
if pc in all_frames:
118+
print(all_frames[pc])
119+
ad = target.elf.address_decoder
120+
function = ad.get_function_for_address(pc)
121+
if function:
122+
print(" ", function)
123+
line = ad.get_line_for_address(pc)
124+
if line:
125+
print(" ", line)
126+
127+
mm = target.get_memory_map()
128+
129+
ram = mm.get_region_for_address(sp)
130+
if not ram:
131+
sp_guess = 0x20013BCC
132+
print("stack pointer bad using 0x{%08x}")
133+
ram = mm.get_region_for_address(sp_guess)
134+
stack_address = sp
135+
offset = 0
136+
while ram and sp + offset <= ram.end:
137+
stack_address = sp + offset
138+
value = target.read_memory(stack_address)
139+
symbol = target.elf.symbol_decoder.get_symbol_for_address(value)
140+
print(f"{stack_address:08x} {offset:04x} {value:08x} {symbol}")
141+
function = ad.get_function_for_address(value)
142+
if function:
143+
print(" ", function)
144+
line = ad.get_line_for_address(value)
145+
if line:
146+
print(" ", line)
147+
# value -= 0x27000
148+
# if value in all_frames:
149+
# print(all_frames[value])
150+
# if value in lines_by_address:
151+
# print(lines_by_address[value])
152+
offset += 4
153+
154+
top_symbol = target.elf.symbol_decoder.get_symbol_for_address(target.read_memory(sp))
155+
if True or (top_symbol and top_symbol.name == "HardFault_Handler"):
156+
lr = target.read_core_register("lr")
157+
print("lr: 0x%08X" % lr)
158+
cfsr = target.read_memory(0xE000ED28)
159+
print("cfsr: 0x%08X" % cfsr)
160+
hfsr = target.read_memory(0xE000ED2C)
161+
print("hfsr: 0x%08X" % hfsr)
162+
if hfsr & 0x4000_0000:
163+
print("hard fault forced")
164+
bfsr = (cfsr >> 8) & 0xFF
165+
if bfsr & 0x80 != 0:
166+
bad_address = target.read_memory(0xE000ED38)
167+
print(f"bus fault with address 0x{bad_address:08x}")
168+
bits = ["IBUSERR", "PRECISERR", "IMPRECISERR", "UNSTKERR", "STKERR", "LSPERR"]
169+
for i, bit in enumerate(bits):
170+
if bfsr & (1 << i):
171+
print(bit)
172+
173+
for i in range(13):
174+
reg = f"r{i}"
175+
value = target.read_core_register(reg)
176+
print(f"{reg} 0x{value:08x}")
177+
178+
# print(hex(target.read_memory(provider.get_symbol_value("prescaler"))))
179+
180+
# Remove breakpoint.
181+
target.remove_breakpoint(addr)

0 commit comments

Comments
 (0)