Skip to content

Commit 2a30d93

Browse files
committed
pbio/sys/main: Expose how program was started.
This gives the user a way to optionally run certain code only when it is first downloaded to the robot. Examples include one-off motor initialization or one-off wiping of user data. Fixes pybricks/support#1496
1 parent 26f7701 commit 2a30d93

File tree

6 files changed

+69
-15
lines changed

6 files changed

+69
-15
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
coding ([support#1661]).
1212
- Added `observe_enable` to the hub `BLE` class to selectively turn observing
1313
on and off, just like you can with broadcasting ([support#1806]).
14-
- Added `hub.system.info()` method with hub status flags ([support#1496]).
14+
- Added `hub.system.info()` method with hub status flags ([support#1496]) and
15+
value representing how the program was started.
1516

1617
### Changed
1718

lib/pbio/include/pbsys/main.h

+34-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@
1616
#include <stdbool.h>
1717
#include <stdint.h>
1818

19+
/**
20+
* Whether and how the program was requested to start.
21+
*
22+
* Values are returned to the user, so the numeric values must not change.
23+
*/
24+
typedef enum {
25+
/**
26+
* The program was not requested to start.
27+
*/
28+
PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_NONE = 0,
29+
/**
30+
* The program was requested to start automatically on boot.
31+
*/
32+
PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_BOOT = 1,
33+
/**
34+
* The program was requested to start using the hub button/display UI.
35+
*/
36+
PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_HUB_UI = 2,
37+
/**
38+
* The program was requested to start remotely, such as with an IDE.
39+
*/
40+
PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_REMOTE = 3,
41+
} pbsys_main_program_start_request_type_t;
42+
1943
/**
2044
* Main application program data information.
2145
*/
@@ -41,14 +65,16 @@ typedef struct _pbsys_main_program_t {
4165
*/
4266
pbio_pybricks_user_program_id_t id;
4367
/**
44-
* Whether a request was made to start the program.
68+
* Whether a request was made to start the program, and how.
4569
*/
46-
bool start_requested;
70+
pbsys_main_program_start_request_type_t start_request_type;
4771
} pbsys_main_program_t;
4872

4973
#if PBSYS_CONFIG_MAIN
5074

51-
pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id);
75+
pbsys_main_program_start_request_type_t pbsys_main_program_get_start_request_type(void);
76+
77+
pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id, pbsys_main_program_start_request_type_t start_request_type);
5278

5379
/**
5480
* Validates the program that is being requested to start.
@@ -99,7 +125,11 @@ const char *pbsys_main_get_application_version_hash(void);
99125

100126
#else // PBSYS_CONFIG_MAIN
101127

102-
static inline pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id) {
128+
static inline pbsys_main_program_start_request_type_t pbsys_main_program_get_start_request_type(void) {
129+
return PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_NONE;
130+
}
131+
132+
static inline pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id, pbsys_main_program_start_request_type_t start_request_type) {
103133
return PBIO_ERROR_NOT_SUPPORTED;
104134
}
105135

lib/pbio/sys/command.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ pbio_pybricks_error_t pbsys_command(const uint8_t *data, uint32_t size) {
4949
}
5050
// Use payload as program ID, otherwise use active user slot.
5151
return pbio_pybricks_error_from_pbio_error(
52-
pbsys_main_program_request_start((size == 2 ? data[1] : pbsys_hmi_get_selected_program_slot())));
52+
pbsys_main_program_request_start((size == 2 ? data[1] : pbsys_hmi_get_selected_program_slot()), PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_REMOTE));
5353
}
5454
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
5555
case PBIO_PYBRICKS_COMMAND_START_REPL:
5656
// Deprecated. For backwards compatibility with Pybricks
5757
// Profile < v1.4.0, make it work anyway.
5858
return pbio_pybricks_error_from_pbio_error(
59-
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_REPL));
59+
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_REPL, PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_REMOTE));
6060
#endif // PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
6161

6262
case PBIO_PYBRICKS_COMMAND_WRITE_USER_PROGRAM_META:

lib/pbio/sys/hmi.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static PT_THREAD(update_program_run_button_wait_state(bool button_pressed)) {
5656

5757
// If we made it through a full press and release, without the user
5858
// program running, then start the currently selected user program.
59-
pbsys_main_program_request_start(selected_slot);
59+
pbsys_main_program_request_start(selected_slot, PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_HUB_UI);
6060
}
6161

6262
PT_END(pt);
@@ -152,7 +152,7 @@ static PT_THREAD(update_left_right_button_wait_state(bool left_button_pressed, b
152152
if (left_button_pressed && pbdrv_clock_get_ms() - first_press_time < 100) {
153153
selected_slot = previous_slot;
154154
pbsys_hub_light_matrix_update_program_slot();
155-
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW);
155+
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW, PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_HUB_UI);
156156
} else {
157157
// Successful switch. And UI was already updated.
158158
previous_slot = selected_slot;

lib/pbio/sys/main.c

+27-6
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,29 @@
2020
#include <pbsys/program_stop.h>
2121
#include <pbsys/bluetooth.h>
2222

23+
// Singleton with information about the currently (or soon) active program.
2324
static pbsys_main_program_t program;
2425

26+
/**
27+
* Checks if a start request has been made for the main program.
28+
*
29+
* @param [in] program A pointer to the main program structure.
30+
* @returns true if a start request has been made, false otherwise.
31+
*/
32+
static bool pbsys_main_program_start_requested() {
33+
return program.start_request_type != PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_NONE;
34+
}
35+
36+
/**
37+
* Gets the type of start request for the main program.
38+
*
39+
* @param [in] program A pointer to the main program structure.
40+
* @returns The type of start request.
41+
*/
42+
pbsys_main_program_start_request_type_t pbsys_main_program_get_start_request_type(void) {
43+
return program.start_request_type;
44+
}
45+
2546
/**
2647
* Requests to start the main user application program.
2748
*
@@ -31,10 +52,10 @@ static pbsys_main_program_t program;
3152
* ::PBIO_ERROR_NOT_SUPPORTED if the program is not available.
3253
* Otherwise ::PBIO_SUCCESS.
3354
*/
34-
pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id) {
55+
pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id, pbsys_main_program_start_request_type_t start_request_type) {
3556

3657
// Can't start new program if already running or new requested.
37-
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING) || program.start_requested) {
58+
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING) || pbsys_main_program_start_requested()) {
3859
return PBIO_ERROR_BUSY;
3960
}
4061

@@ -49,7 +70,7 @@ pbio_error_t pbsys_main_program_request_start(pbio_pybricks_user_program_id_t id
4970
return err;
5071
}
5172

52-
program.start_requested = true;
73+
program.start_request_type = start_request_type;
5374

5475
return PBIO_SUCCESS;
5576
}
@@ -68,15 +89,15 @@ int main(int argc, char **argv) {
6889
while (!pbsys_status_test(PBIO_PYBRICKS_STATUS_SHUTDOWN_REQUEST)) {
6990

7091
#if PBSYS_CONFIG_USER_PROGRAM_AUTO_START
71-
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_REPL);
92+
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_REPL, PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_BOOT);
7293
#endif
7394

7495
// REVISIT: this can be long waiting, so we could do a more efficient
7596
// wait (i.e. __WFI() on embedded system)
7697
while (pbio_do_one_event()) {
7798
}
7899

79-
if (!program.start_requested) {
100+
if (!pbsys_main_program_start_requested()) {
80101
continue;
81102
}
82103

@@ -98,7 +119,7 @@ int main(int argc, char **argv) {
98119
pbsys_bluetooth_rx_set_callback(NULL);
99120
pbsys_program_stop_set_buttons(PBIO_BUTTON_CENTER);
100121
pbio_stop_all(true);
101-
program.start_requested = false;
122+
program.start_request_type = PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_NONE;
102123
}
103124

104125
// Stop system processes and save user data before we shutdown.

pybricks/common/pb_type_system.c

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <pbdrv/bluetooth.h>
1111
#include <pbdrv/reset.h>
12+
#include <pbsys/main.h>
1213
#include <pbsys/program_stop.h>
1314
#include <pbsys/status.h>
1415
#include <pbsys/storage.h>
@@ -48,6 +49,7 @@ static mp_obj_t pb_type_System_info(void) {
4849
{MP_OBJ_NEW_QSTR(MP_QSTR_reset_reason), mp_obj_new_int(pbdrv_reset_get_reason())},
4950
#endif // PBDRV_CONFIG_RESET
5051
{MP_OBJ_NEW_QSTR(MP_QSTR_host_connected_ble), mp_obj_new_bool(pbsys_status_test(PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED))},
52+
{MP_OBJ_NEW_QSTR(MP_QSTR_program_start_type), mp_obj_new_int(pbsys_main_program_get_start_request_type())},
5153
};
5254
mp_obj_t info_dict = mp_obj_new_dict(MP_ARRAY_SIZE(info));
5355

0 commit comments

Comments
 (0)