Skip to content

Commit 6e2c634

Browse files
committed
pbdrv/bluetooth: UART block fixes for EV3.
During debugging, found a bunch of errors with the EV3 UART block impl. - `block_received` and `block_sent` are written before open, therefore, we have to set them in init, not in open. - Read thread passed wrong state to pbdrv_uart_read. - Safer shutdown sequence.
1 parent 580f3de commit 6e2c634

File tree

1 file changed

+47
-16
lines changed

1 file changed

+47
-16
lines changed

lib/pbio/drv/bluetooth/bluetooth_btstack_uart_block_ev3.c

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818

1919
#include "bluetooth_btstack_uart_block_ev3.h"
2020

21+
#define DEBUG 1
22+
23+
#if DEBUG
24+
#include <pbdrv/../../drv/uart/uart_debug_first_port.h>
25+
#define DEBUG_PRINT pbdrv_uart_debug_printf
26+
#else
27+
#define DEBUG_PRINT(...)
28+
#endif
29+
2130
// If a read has been requested, a pointer to the buffer and its length, else
2231
// null and zero.
2332
static uint8_t *read_buf;
@@ -31,9 +40,6 @@ static int write_buf_len;
3140
// Should the reader and writer processes shut down?
3241
static bool start_shutdown;
3342

34-
// Count of threads that have finished since start_shutdown was set.
35-
static int8_t threads_shutdown_complete;
36-
3743
// Called when a block finishes sending.
3844
static void (*block_sent)(void);
3945
// Called when a block finishes being received.
@@ -54,6 +60,8 @@ static pbdrv_uart_dev_t *pbdrv_bluetooth_btstack_uart_block_ev3_uart_device() {
5460
}
5561

5662
static int pbdrv_bluetooth_btstack_uart_block_ev3_init(const btstack_uart_config_t *config) {
63+
block_received = NULL;
64+
block_sent = NULL;
5765
pbdrv_uart_set_baud_rate(pbdrv_bluetooth_btstack_uart_block_ev3_uart_device(), config->baudrate);
5866
// TODO: add parity, flow control APIs and obey them.
5967

@@ -63,7 +71,8 @@ static int pbdrv_bluetooth_btstack_uart_block_ev3_init(const btstack_uart_config
6371
static pbio_error_t pbdrv_bluetooth_btstack_uart_block_ev3_do_read_process(pbio_os_state_t *state, void *context) {
6472
pbdrv_uart_dev_t *const uart = pbdrv_bluetooth_btstack_uart_block_ev3_uart_device();
6573

66-
pbio_os_state_t read_state;
74+
static pbio_os_state_t read_state;
75+
static pbio_error_t err;
6776
PBIO_OS_ASYNC_BEGIN(state);
6877

6978
while (true) {
@@ -72,23 +81,42 @@ static pbio_error_t pbdrv_bluetooth_btstack_uart_block_ev3_do_read_process(pbio_
7281
break;
7382
}
7483

84+
// Come up for air every 500ms to check for shutdown. If we don't do this,
85+
// reads will hang permanently during a bluetooth module shutdown, which
86+
// deadlocks the shutdown process since this UART block then will not close.
87+
//
88+
// This is kinda unsatisfying though because *what if* a read is pending
89+
// and the message happens to come in just after 500ms and gets split up.
90+
// Things are going to get confusing! There should probably be a way
91+
// to cancel pending reads and writes in the UART interface.
92+
// That way we don't have to set a timeout and only interrupt a read
93+
// if we need to do so explicitly.
7594
PBIO_OS_AWAIT(state, &read_state,
76-
pbdrv_uart_read(state, uart, read_buf, read_buf_len, /*timeout=*/ 0));
95+
(err = pbdrv_uart_read(&read_state, uart, read_buf, read_buf_len, 500)));
96+
97+
if (err == PBIO_ERROR_TIMEDOUT) {
98+
// Just a timeout, go back to waiting.
99+
continue;
100+
}
101+
if (err != PBIO_SUCCESS) {
102+
DEBUG_PRINT("UART read error: %d\n", err);
103+
}
104+
77105
read_buf = NULL;
78106
read_buf_len = 0;
79107
if (block_received) {
80108
block_received();
81109
}
82110
}
83111

84-
++threads_shutdown_complete;
85112
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
86113
}
87114

88115
static pbio_error_t pbdrv_bluetooth_btstack_uart_block_ev3_do_write_process(pbio_os_state_t *state, void *context) {
89116
pbdrv_uart_dev_t *const uart = pbdrv_bluetooth_btstack_uart_block_ev3_uart_device();
90117

91-
pbio_os_state_t write_state;
118+
static pbio_os_state_t write_state;
119+
static pbio_error_t err;
92120

93121
PBIO_OS_ASYNC_BEGIN(state);
94122

@@ -99,15 +127,19 @@ static pbio_error_t pbdrv_bluetooth_btstack_uart_block_ev3_do_write_process(pbio
99127
}
100128

101129
PBIO_OS_AWAIT(state, &write_state,
102-
pbdrv_uart_write(&write_state, uart, (uint8_t *)write_buf, write_buf_len, /*timeout=*/ 0));
130+
(err = pbdrv_uart_write(&write_state, uart, (uint8_t *)write_buf, write_buf_len, /*timeout=*/ 0)));
131+
132+
if (err != PBIO_SUCCESS) {
133+
DEBUG_PRINT("UART write error: %d\n", err);
134+
}
135+
103136
write_buf = NULL;
104137
write_buf_len = 0;
105138
if (block_sent) {
106139
block_sent();
107140
}
108141
}
109142

110-
++threads_shutdown_complete;
111143
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
112144
}
113145

@@ -118,22 +150,21 @@ static int pbdrv_bluetooth_btstack_uart_block_ev3_open(void) {
118150
read_buf = NULL;
119151
read_buf_len = 0;
120152
start_shutdown = false;
121-
threads_shutdown_complete = 0;
122-
block_received = NULL;
123-
block_sent = NULL;
124153

125-
pbio_os_process_start(&reader_process, pbdrv_bluetooth_btstack_uart_block_ev3_do_read_process, NULL);
154+
DEBUG_PRINT("Starting UART read/write processes\n");
126155
pbio_os_process_start(&writer_process, pbdrv_bluetooth_btstack_uart_block_ev3_do_write_process, NULL);
156+
pbio_os_process_start(&reader_process, pbdrv_bluetooth_btstack_uart_block_ev3_do_read_process, NULL);
127157

128158
return 0;
129159
}
130160

131161
static int pbdrv_bluetooth_btstack_uart_block_ev3_close(void) {
132162
start_shutdown = true;
133-
while (threads_shutdown_complete < 2) {
134-
pbio_os_run_processes_and_wait_for_event();
163+
DEBUG_PRINT("Waiting for UART read/write processes to shut down...\n");
164+
while (reader_process.err != PBIO_SUCCESS || writer_process.err != PBIO_SUCCESS) {
165+
pbio_os_request_poll();
166+
pbio_os_run_processes_once();
135167
}
136-
137168
return 0;
138169
}
139170

0 commit comments

Comments
 (0)