Skip to content

Commit afd1170

Browse files
committed
pbio/sys/storage: Use status to block duplicate downloads.
This is technically the same as before, but implemented with a status flag. This lets us visually disable the download button in Pybricks Code. The status is immediately set on the first download, so this is safe against race conditions even if the visual update arrives a little bit later.
1 parent 9d3e904 commit afd1170

5 files changed

Lines changed: 40 additions & 34 deletions

File tree

lib/pbio/include/pbio/protocol.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ typedef enum {
363363
* @since Pybricks Profile v1.5.0
364364
*/
365365
PBIO_PYBRICKS_STATUS_USB_HOST_CONNECTED = 12,
366+
/**
367+
* Hub is receiving, transmitting, or moving a file.
368+
*
369+
* @since Pybricks Profile v1.5.0
370+
*/
371+
PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS = 13,
366372
/** Total number of indications. */
367373
NUM_PBIO_PYBRICKS_STATUS,
368374
} pbio_pybricks_status_flags_t;

lib/pbio/sys/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static pbio_error_t pbsys_system_poll_process_thread(pbio_os_state_t *state, voi
3939
pbsys_battery_poll();
4040
pbsys_program_stop_poll();
4141
pbsys_status_light_poll();
42+
pbsys_storage_poll();
4243

4344
// keep the hub from resetting itself
4445
pbdrv_watchdog_update();

lib/pbio/sys/status.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ uint32_t pbsys_status_get_status_report(uint8_t *buf) {
8484
*/
8585
void pbsys_status_increment_selected_slot(bool increment) {
8686
#if PBSYS_CONFIG_HMI_NUM_SLOTS
87-
if (!pbsys_storage_slot_change_is_allowed()) {
87+
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS)) {
8888
return;
8989
}
9090
if (increment && pbsys_status.slot + 1 < PBSYS_CONFIG_HMI_NUM_SLOTS) {

lib/pbio/sys/storage.c

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,32 @@
2222
#include <pbsys/status.h>
2323

2424
#include "hmi.h"
25-
#include "storage.h"
2625

2726
/**
2827
* State of incoming program data.
2928
*/
3029
static struct {
3130
/** Where incoming program data is placed. */
3231
uint8_t slot;
33-
/** Currently downloading. */
34-
bool busy;
35-
/** Latest incoming message time. Only relevant while busy. */
32+
/** Latest incoming message time. */
3633
pbio_os_timer_t timer;
3734
} download_state;
3835

36+
/**
37+
* Polls storage system for timeouts.
38+
*
39+
* This should be called periodically.
40+
*/
41+
void pbsys_storage_poll(void) {
42+
// If we are receiving a program, check for timeout and clear
43+
// busy state if timed out.
44+
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS)) {
45+
if (pbio_os_timer_is_expired(&download_state.timer)) {
46+
pbsys_status_clear(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS);
47+
}
48+
}
49+
}
50+
3951
/**
4052
* Map of loaded data. This is kept in memory between successive runs of the
4153
* end user application (like MicroPython).
@@ -252,19 +264,25 @@ pbio_error_t pbsys_storage_set_program_size(uint32_t new_size) {
252264
// Pybricks Code sends size 0 to clear the state before sending the new
253265
// program, then sends the size on completion.
254266
if (new_size == 0) {
255-
if (!pbsys_storage_slot_change_is_allowed()) {
267+
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS)) {
256268
// Cannot start a new download while another is in progress.
257269
return PBIO_ERROR_INVALID_OP;
258270
}
259271

260272
pbsys_storage_prepare_receive();
261273

262-
// Keep track of busy state to disallow some operations while busy.
263-
download_state.busy = true;
274+
// Set busy status to disallow some operations while busy.
275+
pbsys_status_set(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS);
264276
pbio_os_timer_set(&download_state.timer, 1000);
265277
return PBIO_SUCCESS;
266278
}
267279

280+
// This is also called on completion of the program download, in which
281+
// case we expect that a download is in progress.
282+
if (!pbsys_status_test(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS)) {
283+
return PBIO_ERROR_INVALID_OP;
284+
}
285+
268286
// Expecting that the slot has been cleared as per the above.
269287
if (download_state.slot >= PBSYS_CONFIG_STORAGE_NUM_SLOTS || map->slot_info[download_state.slot].size != 0) {
270288
return PBIO_ERROR_FAILED;
@@ -278,29 +296,11 @@ pbio_error_t pbsys_storage_set_program_size(uint32_t new_size) {
278296

279297
// Program download complete, so request saving on poweroff.
280298
pbsys_storage_request_write();
281-
download_state.busy = false;
282299

283-
return PBIO_SUCCESS;
284-
}
300+
// Clear busy status.
301+
pbsys_status_clear(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS);
285302

286-
/**
287-
* Tests whether a slot change is allowed.
288-
*
289-
* @return True when allowed, false if not, i.e. when new a new program is being downloaded.
290-
*/
291-
bool pbsys_storage_slot_change_is_allowed(void) {
292-
#if !PBSYS_CONFIG_HMI_NUM_SLOTS
293-
return false;
294-
#endif
295-
296-
if (download_state.busy && pbio_os_timer_is_expired(&download_state.timer)) {
297-
// Download must have been interrupted midway through. Give up
298-
// and unblock anything waiting on download to complete.
299-
download_state.busy = false;
300-
}
301-
302-
// Slot change is allowed when no longer busy.
303-
return !download_state.busy;
303+
return PBIO_SUCCESS;
304304
}
305305

306306
/**
@@ -328,7 +328,7 @@ pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, u
328328
}
329329

330330
// A program transfer should have been started.
331-
if (!download_state.busy) {
331+
if (!pbsys_status_test(PBIO_PYBRICKS_STATUS_FILE_IO_IN_PROGRESS)) {
332332
return PBIO_ERROR_INVALID_OP;
333333
}
334334

lib/pbio/sys/storage.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
void pbsys_storage_init(void);
1717
void pbsys_storage_deinit(void);
18+
void pbsys_storage_poll(void);
1819
pbio_error_t pbsys_storage_set_program_size(uint32_t size);
1920
pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, uint32_t size);
20-
bool pbsys_storage_slot_change_is_allowed(void);
2121
void pbsys_storage_get_program_data(pbsys_main_program_t *program);
2222
pbsys_storage_settings_t *pbsys_storage_settings_get_settings(void);
2323

@@ -26,6 +26,8 @@ static inline void pbsys_storage_init(void) {
2626
}
2727
static inline void pbsys_storage_deinit(void) {
2828
}
29+
static inline void pbsys_storage_poll(void) {
30+
}
2931
static inline pbsys_storage_settings_t *pbsys_storage_settings_get_settings(void) {
3032
return NULL;
3133
}
@@ -35,9 +37,6 @@ static inline pbio_error_t pbsys_storage_set_program_size(uint32_t size) {
3537
static inline pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, uint32_t size) {
3638
return PBIO_ERROR_NOT_SUPPORTED;
3739
}
38-
static inline bool pbsys_storage_slot_change_is_allowed(void) {
39-
return false;
40-
}
4140
static inline void pbsys_storage_get_program_data(pbsys_main_program_t *program) {
4241
program->code_start = NULL;
4342
program->code_end = NULL;

0 commit comments

Comments
 (0)