From 7bda2230757ee82adee4d2dcc5a22632905470fb Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Thu, 25 Jul 2024 13:38:19 +0200 Subject: [PATCH] pbsys/main: Generalize and clean up program start commands. This brings the waiting process for the main program to start to the main.c loop, which makes it easier to follow. This also generalized the commands to start builtin and user programs with an optional identifier. For now, this will be used to start either the REPL or Port View. In the future, it can be used to start programs on different slots. This also adds a hook for verifying the program at the application level so we can verify MicroPython-specific validity and avoid hardcoding such checks at the pbio level. pbio/sys/config: Consolidate app config. The separate placement of these settings was a bit contrived. We can have it at the pbsys config level since the definitions exist at the pbio protocol level anyway. This lets us use them as defined feature guards. --- bricks/_common/micropython.c | 28 ++++- bricks/_common/sources.mk | 1 - bricks/cityhub/pbsys_app_config.h | 2 - bricks/essentialhub/pbsys_app_config.h | 2 - bricks/ev3/pbsys_app_config.h | 2 - bricks/ev3rt/app.c | 2 +- bricks/movehub/pbsys_app_config.h | 2 - bricks/primehub/pbsys_app_config.h | 2 - bricks/technichub/pbsys_app_config.h | 2 - .../drv/bluetooth/bluetooth_stm32_bluenrg.c | 4 +- .../drv/bluetooth/bluetooth_stm32_cc2640.c | 4 +- .../drv/bluetooth/pybricks_service_server.c | 4 +- lib/pbio/include/pbio/protocol.h | 29 +++-- lib/pbio/include/pbsys/app.h | 31 ----- lib/pbio/include/pbsys/config.h | 8 ++ lib/pbio/include/pbsys/main.h | 56 ++++++++- lib/pbio/platform/city_hub/pbsysconfig.h | 3 + lib/pbio/platform/essential_hub/pbsysconfig.h | 3 + lib/pbio/platform/ev3/pbsysconfig.h | 3 + lib/pbio/platform/ev3rt/pbsysconfig.h | 3 + lib/pbio/platform/move_hub/pbsysconfig.h | 3 + lib/pbio/platform/prime_hub/pbsysconfig.h | 3 + lib/pbio/platform/technic_hub/pbsysconfig.h | 3 + lib/pbio/platform/test/pbsysconfig.h | 3 + lib/pbio/sys/command.c | 25 +++- lib/pbio/sys/hmi.c | 4 +- lib/pbio/sys/main.c | 51 +++++++- lib/pbio/sys/storage.c | 15 --- lib/pbio/sys/storage.h | 4 - lib/pbio/sys/user_program.c | 111 ------------------ lib/pbio/sys/user_program.h | 33 ------ lib/pbio/test/pbsys_app_config.h | 1 - 32 files changed, 210 insertions(+), 237 deletions(-) delete mode 100644 bricks/cityhub/pbsys_app_config.h delete mode 100644 bricks/essentialhub/pbsys_app_config.h delete mode 100644 bricks/ev3/pbsys_app_config.h delete mode 100644 bricks/movehub/pbsys_app_config.h delete mode 100644 bricks/primehub/pbsys_app_config.h delete mode 100644 bricks/technichub/pbsys_app_config.h delete mode 100644 lib/pbio/include/pbsys/app.h delete mode 100644 lib/pbio/sys/user_program.c delete mode 100644 lib/pbio/sys/user_program.h delete mode 100644 lib/pbio/test/pbsys_app_config.h diff --git a/bricks/_common/micropython.c b/bricks/_common/micropython.c index 0aa5657c7..162ad49b4 100644 --- a/bricks/_common/micropython.c +++ b/bricks/_common/micropython.c @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -293,6 +295,30 @@ static void run_user_program(void) { nlr_set_abort(NULL); } +pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program) { + + #if !PYBRICKS_OPT_COMPILER + if (program->type == PBSYS_MAIN_PROGRAM_TYPE_BUILTIN) { + return PBIO_ERROR_NOT_SUPPORTED; + } + #endif + + if (program->type == PBSYS_MAIN_PROGRAM_TYPE_USER) { + + // If requesting a user program, ensure that it exists and is valid. + // Currently, only programs on slot 0 are supported. + uint32_t program_size = program->code_end - program->code_start; + if (program->id != 0 || program_size == 0 || program_size > PBSYS_STORAGE_MAX_PROGRAM_SIZE) { + return PBIO_ERROR_NOT_SUPPORTED; + } + + // TODO: Now that we have moved these checks to the MicroPython + // application code, we can check that a valid program is in fact + // present by checking the MicroPython format. + } + return PBIO_SUCCESS; +} + // Runs MicroPython with the given program data. void pbsys_main_run_program(pbsys_main_program_t *program) { @@ -316,7 +342,7 @@ void pbsys_main_run_program(pbsys_main_program_t *program) { mp_init(); // Check for run type. - if (!program->run_builtin) { + if (program->type == PBSYS_MAIN_PROGRAM_TYPE_USER) { // Init Pybricks package without auto-import. pb_package_pybricks_init(false); // Run loaded program. diff --git a/bricks/_common/sources.mk b/bricks/_common/sources.mk index 1bc0e7d7a..cdc3a044f 100644 --- a/bricks/_common/sources.mk +++ b/bricks/_common/sources.mk @@ -237,7 +237,6 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\ sys/storage.c \ sys/storage_settings.c \ sys/supervisor.c \ - sys/user_program.c \ ) # MicroPython math library diff --git a/bricks/cityhub/pbsys_app_config.h b/bricks/cityhub/pbsys_app_config.h deleted file mode 100644 index 6c1050f07..000000000 --- a/bricks/cityhub/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_REPL | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6) diff --git a/bricks/essentialhub/pbsys_app_config.h b/bricks/essentialhub/pbsys_app_config.h deleted file mode 100644 index 20965a168..000000000 --- a/bricks/essentialhub/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_REPL | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6 | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE) diff --git a/bricks/ev3/pbsys_app_config.h b/bricks/ev3/pbsys_app_config.h deleted file mode 100644 index 8272af3ec..000000000 --- a/bricks/ev3/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6) diff --git a/bricks/ev3rt/app.c b/bricks/ev3rt/app.c index 61dce8f5e..93b5ee486 100644 --- a/bricks/ev3rt/app.c +++ b/bricks/ev3rt/app.c @@ -26,7 +26,7 @@ void main_task(intptr_t unused) { while (true) { pbsys_main_program_t program = { - .run_builtin = true, + .type = PBSYS_MAIN_PROGRAM_TYPE_BUILTIN, .code_end = heap, .data_end = heap + sizeof(heap), }; diff --git a/bricks/movehub/pbsys_app_config.h b/bricks/movehub/pbsys_app_config.h deleted file mode 100644 index 8272af3ec..000000000 --- a/bricks/movehub/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6) diff --git a/bricks/primehub/pbsys_app_config.h b/bricks/primehub/pbsys_app_config.h deleted file mode 100644 index 20965a168..000000000 --- a/bricks/primehub/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_REPL | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6 | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE) diff --git a/bricks/technichub/pbsys_app_config.h b/bricks/technichub/pbsys_app_config.h deleted file mode 100644 index 6c1050f07..000000000 --- a/bricks/technichub/pbsys_app_config.h +++ /dev/null @@ -1,2 +0,0 @@ - -#define PBSYS_APP_HUB_FEATURE_FLAGS (PBIO_PYBRICKS_FEATURE_REPL | PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6) diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c index 9fdfa54a9..2d080ae6b 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include @@ -1078,7 +1078,7 @@ static PT_THREAD(init_pybricks_service(struct pt *pt)) { PT_WAIT_WHILE(pt, write_xfer_size); { uint8_t buf[PBIO_PYBRICKS_HUB_CAPABILITIES_VALUE_SIZE]; - pbio_pybricks_hub_capabilities(buf, ATT_MTU - 3, PBSYS_APP_HUB_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); + pbio_pybricks_hub_capabilities(buf, ATT_MTU - 3, PBSYS_CONFIG_APP_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); aci_gatt_update_char_value_begin(pybricks_service_handle, pybricks_hub_capabilities_char_handle, 0, PBIO_PYBRICKS_HUB_CAPABILITIES_VALUE_SIZE, buf); } diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c index 845e86f04..817f2cdd5 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -1480,7 +1480,7 @@ static void handle_event(uint8_t *packet) { uint8_t buf[PBIO_PYBRICKS_HUB_CAPABILITIES_VALUE_SIZE]; // REVISIT: this assumes connection_handle == conn_handle - pbio_pybricks_hub_capabilities(buf, conn_mtu - 3, PBSYS_APP_HUB_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); + pbio_pybricks_hub_capabilities(buf, conn_mtu - 3, PBSYS_CONFIG_APP_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); rsp.len = sizeof(buf); rsp.pValue = buf; ATT_ReadRsp(connection_handle, &rsp); diff --git a/lib/pbio/drv/bluetooth/pybricks_service_server.c b/lib/pbio/drv/bluetooth/pybricks_service_server.c index 40468753a..6121279ed 100644 --- a/lib/pbio/drv/bluetooth/pybricks_service_server.c +++ b/lib/pbio/drv/bluetooth/pybricks_service_server.c @@ -52,7 +52,7 @@ #include #include -#include +#include #include #include "btstack_defines.h" @@ -89,7 +89,7 @@ static uint16_t pybricks_service_read_callback(hci_con_handle_t con_handle, uint if (attribute_handle == pybricks_hub_capabilities_value_handle) { if (buffer && buffer_size >= PBIO_PYBRICKS_HUB_CAPABILITIES_VALUE_SIZE) { pbio_pybricks_hub_capabilities(buffer, pbio_int_math_min(att_server_get_mtu(con_handle) - 3, 512), - PBSYS_APP_HUB_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); + PBSYS_CONFIG_APP_FEATURE_FLAGS, PBSYS_STORAGE_MAX_PROGRAM_SIZE); } return PBIO_PYBRICKS_HUB_CAPABILITIES_VALUE_SIZE; } diff --git a/lib/pbio/include/pbio/protocol.h b/lib/pbio/include/pbio/protocol.h index 9ef0c587f..a2900ab5d 100644 --- a/lib/pbio/include/pbio/protocol.h +++ b/lib/pbio/include/pbio/protocol.h @@ -53,24 +53,36 @@ typedef enum { PBIO_PYBRICKS_COMMAND_STOP_USER_PROGRAM = 0, /** - * Requests that the user program should be started. + * Requests that a specified user program should be started. + * + * Parameters: + * - id (optional): The identifier of the user program (32-bit little-endian unsigned integer). + * Defaults to 0 if no identifier is provided. + * This optional parameter was introduced in Pybricks Profile v1.4.0 * * Errors: - * - ::PBIO_PYBRICKS_ERROR_BUSY if another program is already running. + * - ::PBIO_PYBRICKS_ERROR_BUSY if a program is already running. + * - ::PBIO_PYBRICKS_ERROR_INVALID_COMMAND if the builtin program is not available (Since Pybricks Profile v1.4.0). * * @since Pybricks Profile v1.2.0 */ PBIO_PYBRICKS_COMMAND_START_USER_PROGRAM = 1, /** - * Requests that the REPL should be started. + * Requests that a specified builtin program should be started. + * + * Parameters: + * - id (optional): The identifier of the builtin program (32-bit little-endian unsigned integer). + * Defaults to 0 if no identifier is provided. + * This optional parameter was introduced in Pybricks Profile v1.4.0 * * Errors: - * - ::PBIO_PYBRICKS_ERROR_BUSY if another program is already running. + * - ::PBIO_PYBRICKS_ERROR_BUSY if a program is already running. + * - ::PBIO_PYBRICKS_ERROR_INVALID_COMMAND if the builtin program is not available (Since Pybricks Profile v1.4.0). * * @since Pybricks Profile v1.2.0 */ - PBIO_PYBRICKS_COMMAND_START_REPL = 2, + PBIO_PYBRICKS_COMMAND_START_BUILTIN_PROGRAM = 2, /** * Requests to write user program metadata. @@ -298,11 +310,14 @@ typedef enum { // NB: the values are part of the protocol, so don't change the values! /** - * Hub support interactive REPL. + * Hub supports builtin programs, such as an interactive REPL or Port View. + * + * Prior to version 1.4.0 this flag was exclusively used to indicate REPL + * support since there were no other builtin programs. * * @since Pybricks Profile v1.2.0. */ - PBIO_PYBRICKS_FEATURE_REPL = 1 << 0, + PBIO_PYBRICKS_FEATURE_BUILTIN_PROGRAMS = 1 << 0, /** * Hub supports user program with multiple MicroPython .mpy files ABI v6 * diff --git a/lib/pbio/include/pbsys/app.h b/lib/pbio/include/pbsys/app.h deleted file mode 100644 index fb834072c..000000000 --- a/lib/pbio/include/pbsys/app.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022 The Pybricks Authors - -/** - * @addtogroup SystemApp System: Application-specific config - * - * The following macros must be defined in a "pbsys_app_config.h" file by the - * application that is using pbsys. - * - * @{ - */ - -#ifndef _PBSYS_APP_H_ -#define _PBSYS_APP_H_ - - -#include "pbsys_app_config.h" - -#if DOXYGEN -/** - * Specifies the hub features enabled by the application. See ::pbio_pybricks_feature_flags_t. - */ -#define PBSYS_APP_HUB_FEATURE_FLAGS -#endif -#ifndef PBSYS_APP_HUB_FEATURE_FLAGS -#error "Application must define PBSYS_APP_HUB_FEATURE_FLAGS" -#endif - -#endif // _PBSYS_APP_H_ - -/** @} */ diff --git a/lib/pbio/include/pbsys/config.h b/lib/pbio/include/pbsys/config.h index a47905846..6ad6af96a 100644 --- a/lib/pbio/include/pbsys/config.h +++ b/lib/pbio/include/pbsys/config.h @@ -8,6 +8,14 @@ #include "pbsysconfig.h" +#include + +#define PBSYS_CONFIG_APP_FEATURE_FLAGS (0 \ + + PBSYS_CONFIG_APP_BUILTIN_PROGRAMS * PBIO_PYBRICKS_FEATURE_BUILTIN_PROGRAMS \ + + PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 * PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6 \ + + PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE * PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE \ + ) + // When set to (1) PBSYS_CONFIG_STATUS_LIGHT indicates that a hub has a hub status light #ifndef PBSYS_CONFIG_STATUS_LIGHT #error "Must define PBSYS_CONFIG_STATUS_LIGHT in pbsysconfig.h" diff --git a/lib/pbio/include/pbsys/main.h b/lib/pbio/include/pbsys/main.h index f2b7173ab..d64938b2a 100644 --- a/lib/pbio/include/pbsys/main.h +++ b/lib/pbio/include/pbsys/main.h @@ -9,11 +9,21 @@ #ifndef _PBSYS_MAIN_H_ #define _PBSYS_MAIN_H_ +#include + #include #include #include +/** + * Main program types. + */ +typedef enum { + PBSYS_MAIN_PROGRAM_TYPE_USER, // User-defined program + PBSYS_MAIN_PROGRAM_TYPE_BUILTIN // Built-in program +} pbsys_main_program_type_t; + /** * Main application program data information. */ @@ -30,13 +40,34 @@ typedef struct _pbsys_main_program_t { * Ending address of user RAM. */ void *data_end; + /** + * Program identifier (selects one user program or one of the builtins). + */ + uint32_t id; /** * Whether to run an application-specific builtin program instead of the * program given by the data. The builtin program may still use the data. */ - bool run_builtin; + pbsys_main_program_type_t type; + /** + * Whether a request was made to start the program. + */ + bool start_requested; } pbsys_main_program_t; +#if PBSYS_CONFIG_MAIN + +pbio_error_t pbsys_main_program_request_start(pbsys_main_program_type_t type, uint32_t id); + +/** + * Validates the program that is being requested to start. + * + * @param [in] program The program that is about to start. + * @returns ::PBIO_ERROR_NOT_SUPPORTED if the program is not available. + * Otherwise ::PBIO_SUCCESS. + */ +pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program); + /** * Runs the main application program. * @@ -68,6 +99,29 @@ void pbsys_main_stop_program(bool force_stop); */ bool pbsys_main_stdin_event(uint8_t c); +#else // PBSYS_CONFIG_MAIN + +static inline pbio_error_t pbsys_main_program_request_start(pbsys_main_program_type_t type, uint32_t id) { + return PBIO_ERROR_NOT_SUPPORTED; +} + +static inline pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program) { + return PBIO_ERROR_NOT_SUPPORTED; +} + +static inline void pbsys_main_run_program(pbsys_main_program_t *program) { +} + +static inline void pbsys_main_stop_program(bool force_stop) { +} + +static inline bool pbsys_main_stdin_event(uint8_t c) { + return false; +} + +#endif // PBSYS_CONFIG_MAIN + + #endif // _PBSYS_MAIN_H_ /** @} */ diff --git a/lib/pbio/platform/city_hub/pbsysconfig.h b/lib/pbio/platform/city_hub/pbsysconfig.h index 7482995d5..08b0e89a1 100644 --- a/lib/pbio/platform/city_hub/pbsysconfig.h +++ b/lib/pbio/platform/city_hub/pbsysconfig.h @@ -3,6 +3,9 @@ #include "pbdrvconfig.h" +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_BATTERY_CHARGER (0) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0) diff --git a/lib/pbio/platform/essential_hub/pbsysconfig.h b/lib/pbio/platform/essential_hub/pbsysconfig.h index 3b7007ab8..d4ce15806 100644 --- a/lib/pbio/platform/essential_hub/pbsysconfig.h +++ b/lib/pbio/platform/essential_hub/pbsysconfig.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2021-2023 The Pybricks Authors +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (1) #define PBSYS_CONFIG_BATTERY_CHARGER (1) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0) diff --git a/lib/pbio/platform/ev3/pbsysconfig.h b/lib/pbio/platform/ev3/pbsysconfig.h index 0b4e6405f..0a7267033 100644 --- a/lib/pbio/platform/ev3/pbsysconfig.h +++ b/lib/pbio/platform/ev3/pbsysconfig.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2024 The Pybricks Authors +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (0) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_MAIN (1) #define PBSYS_CONFIG_STORAGE (1) #define PBSYS_CONFIG_STORAGE_RAM_SIZE (10 * 1024) diff --git a/lib/pbio/platform/ev3rt/pbsysconfig.h b/lib/pbio/platform/ev3rt/pbsysconfig.h index b5f8450fa..1085456d7 100644 --- a/lib/pbio/platform/ev3rt/pbsysconfig.h +++ b/lib/pbio/platform/ev3rt/pbsysconfig.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2023 The Pybricks Authors +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (0) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_BATTERY_CHARGER (0) #define PBSYS_CONFIG_BLUETOOTH (0) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0) diff --git a/lib/pbio/platform/move_hub/pbsysconfig.h b/lib/pbio/platform/move_hub/pbsysconfig.h index 8f47bd691..d50f1a36b 100644 --- a/lib/pbio/platform/move_hub/pbsysconfig.h +++ b/lib/pbio/platform/move_hub/pbsysconfig.h @@ -3,6 +3,9 @@ #include "pbdrvconfig.h" +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (0) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_BATTERY_CHARGER (0) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0) diff --git a/lib/pbio/platform/prime_hub/pbsysconfig.h b/lib/pbio/platform/prime_hub/pbsysconfig.h index 47fe8eec7..1864f9e86 100644 --- a/lib/pbio/platform/prime_hub/pbsysconfig.h +++ b/lib/pbio/platform/prime_hub/pbsysconfig.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2023 The Pybricks Authors +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (1) #define PBSYS_CONFIG_BATTERY_CHARGER (1) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_BLUETOOTH_TOGGLE (1) diff --git a/lib/pbio/platform/technic_hub/pbsysconfig.h b/lib/pbio/platform/technic_hub/pbsysconfig.h index dd1b7b0ff..d66a9b842 100644 --- a/lib/pbio/platform/technic_hub/pbsysconfig.h +++ b/lib/pbio/platform/technic_hub/pbsysconfig.h @@ -3,6 +3,9 @@ #include "pbdrvconfig.h" +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (1) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_BATTERY_CHARGER (0) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0) diff --git a/lib/pbio/platform/test/pbsysconfig.h b/lib/pbio/platform/test/pbsysconfig.h index 22fc4a4cc..f973ac807 100644 --- a/lib/pbio/platform/test/pbsysconfig.h +++ b/lib/pbio/platform/test/pbsysconfig.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2020-2023 The Pybricks Authors +#define PBSYS_CONFIG_APP_BUILTIN_PROGRAMS (0) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6 (0) +#define PBSYS_CONFIG_APP_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE (0) #define PBSYS_CONFIG_BLUETOOTH (1) #define PBSYS_CONFIG_HUB_LIGHT_MATRIX (1) #define PBSYS_CONFIG_MAIN (0) diff --git a/lib/pbio/sys/command.c b/lib/pbio/sys/command.c index 7a3912548..ffaa0455d 100644 --- a/lib/pbio/sys/command.c +++ b/lib/pbio/sys/command.c @@ -7,13 +7,12 @@ #include #include #include - +#include #include #include "./bluetooth.h" #include "./storage.h" #include "./program_stop.h" -#include "./user_program.h" static pbsys_command_write_app_data_callback_t write_app_data_callback = NULL; @@ -41,10 +40,24 @@ pbio_pybricks_error_t pbsys_command(const uint8_t *data, uint32_t size) { case PBIO_PYBRICKS_COMMAND_STOP_USER_PROGRAM: pbsys_program_stop(false); return PBIO_PYBRICKS_ERROR_OK; - case PBIO_PYBRICKS_COMMAND_START_USER_PROGRAM: - return pbio_pybricks_error_from_pbio_error(pbsys_user_program_start_program()); - case PBIO_PYBRICKS_COMMAND_START_REPL: - return pbio_pybricks_error_from_pbio_error(pbsys_user_program_start_repl()); + case PBIO_PYBRICKS_COMMAND_START_USER_PROGRAM: { + uint32_t id = 0; + if (size == (1 + sizeof(uint32_t))) { + id = pbio_get_uint32_le(&data[1]); + } + return pbio_pybricks_error_from_pbio_error( + pbsys_main_program_request_start(PBSYS_MAIN_PROGRAM_TYPE_USER, id)); + } + #if PBSYS_CONFIG_APP_BUILTIN_PROGRAMS + case PBIO_PYBRICKS_COMMAND_START_BUILTIN_PROGRAM: { + uint32_t id = 0; + if (size == (1 + sizeof(uint32_t))) { + id = pbio_get_uint32_le(&data[1]); + } + return pbio_pybricks_error_from_pbio_error( + pbsys_main_program_request_start(PBSYS_MAIN_PROGRAM_TYPE_BUILTIN, id)); + } + #endif // PBIO_PYBRICKS_FEATURE_TEST(PBIO_PYBRICKS_FEATURE_BUILTIN_PROGRAMS) case PBIO_PYBRICKS_COMMAND_WRITE_USER_PROGRAM_META: return pbio_pybricks_error_from_pbio_error(pbsys_storage_set_program_size( pbio_get_uint32_le(&data[1]))); diff --git a/lib/pbio/sys/hmi.c b/lib/pbio/sys/hmi.c index 55fb9a17c..9558e1d39 100644 --- a/lib/pbio/sys/hmi.c +++ b/lib/pbio/sys/hmi.c @@ -20,12 +20,12 @@ #include #include #include +#include #include #include #include "light_matrix.h" #include "light.h" -#include "user_program.h" static struct pt update_program_run_button_wait_state_pt; @@ -52,7 +52,7 @@ static PT_THREAD(update_program_run_button_wait_state(bool button_pressed)) { // if we made it through a full press and release, without the user // program running, then start the user program - pbsys_user_program_start_program(); + pbsys_main_program_request_start(PBSYS_MAIN_PROGRAM_TYPE_USER, 0); } PT_END(pt); diff --git a/lib/pbio/sys/main.c b/lib/pbio/sys/main.c index b3e4ba325..9dbca0514 100644 --- a/lib/pbio/sys/main.c +++ b/lib/pbio/sys/main.c @@ -10,15 +10,53 @@ #include #include #include +#include #include #include #include -#include "user_program.h" #include "program_stop.h" +#include "storage.h" #include #include +static pbsys_main_program_t program; + +#include + +/** + * Requests to start the main user application program. + * + * @param [in] type Chooses to start a builtin program or a user program. + * @param [in] id Selects which builtin or user program will run. + * @returns ::PBIO_ERROR_BUSY if a user program is already running. + * ::PBIO_ERROR_NOT_SUPPORTED if the program is not available. + * Otherwise ::PBIO_SUCCESS. + */ +pbio_error_t pbsys_main_program_request_start(pbsys_main_program_type_t type, uint32_t id) { + + // Can't start new program if already running or new requested. + if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING) || program.start_requested) { + return PBIO_ERROR_BUSY; + } + + program.type = type; + program.id = id; + + // Builtin programs are also allowed to access user program, + // so load data in all cases. + pbsys_storage_get_program_data(&program); + + pbio_error_t err = pbsys_main_program_validate(&program); + if (err != PBIO_SUCCESS) { + return err; + } + + program.start_requested = true; + + return PBIO_SUCCESS; +} + /** * Initializes the PBIO library, runs custom main program, and handles shutdown. * @@ -32,10 +70,12 @@ int main(int argc, char **argv) { // Keep loading and running user programs until shutdown is requested. while (!pbsys_status_test(PBIO_PYBRICKS_STATUS_SHUTDOWN_REQUEST)) { - // Receive a program. This cancels itself on shutdown. - static pbsys_main_program_t program; - pbio_error_t err = pbsys_user_program_wait_command(&program); - if (err != PBIO_SUCCESS) { + // REVISIT: this can be long waiting, so we could do a more efficient + // wait (i.e. __WFI() on embedded system) + while (pbio_do_one_event()) { + } + + if (!program.start_requested) { continue; } @@ -56,6 +96,7 @@ int main(int argc, char **argv) { pbsys_bluetooth_rx_set_callback(NULL); pbsys_program_stop_set_buttons(PBIO_BUTTON_CENTER); pbio_stop_all(true); + program.start_requested = false; } // Stop system processes and save user data before we shutdown. diff --git a/lib/pbio/sys/storage.c b/lib/pbio/sys/storage.c index 9d2dc56f1..d53154424 100644 --- a/lib/pbio/sys/storage.c +++ b/lib/pbio/sys/storage.c @@ -175,21 +175,6 @@ pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, u return PBIO_SUCCESS; } -/** - * Asserts that the loaded/stored user program is valid and ready to run. - * - * @returns ::PBIO_ERROR_INVALID_ARG if loaded program is not - * valid. Otherwise ::PBIO_SUCCESS. - */ -pbio_error_t pbsys_storage_assert_program_valid(void) { - // Don't run invalid programs. - if (map->program_size == 0 || map->program_size > PBSYS_STORAGE_MAX_PROGRAM_SIZE) { - // TODO: Validate the data beyond just size. - return PBIO_ERROR_INVALID_ARG; - } - return PBIO_SUCCESS; -} - /** * Populates the program data with references to the loaded program data. * diff --git a/lib/pbio/sys/storage.h b/lib/pbio/sys/storage.h index e9363ba8a..cd64d73ab 100644 --- a/lib/pbio/sys/storage.h +++ b/lib/pbio/sys/storage.h @@ -17,7 +17,6 @@ void pbsys_storage_init(void); void pbsys_storage_deinit(void); pbio_error_t pbsys_storage_set_program_size(uint32_t size); pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, uint32_t size); -pbio_error_t pbsys_storage_assert_program_valid(void); void pbsys_storage_get_program_data(pbsys_main_program_t *program); pbsys_storage_settings_t *pbsys_storage_settings_get_settings(void); void pbsys_storage_request_write(void); @@ -36,9 +35,6 @@ static inline pbio_error_t pbsys_storage_set_program_size(uint32_t size) { static inline pbio_error_t pbsys_storage_set_program_data(uint32_t offset, const void *data, uint32_t size) { return PBIO_ERROR_NOT_SUPPORTED; } -static inline pbio_error_t pbsys_storage_assert_program_valid(void) { - return PBIO_ERROR_NOT_SUPPORTED; -} static inline void pbsys_storage_get_program_data(pbsys_main_program_t *program) { } static inline void pbsys_storage_request_write(void) { diff --git a/lib/pbio/sys/user_program.c b/lib/pbio/sys/user_program.c deleted file mode 100644 index 8658218a0..000000000 --- a/lib/pbio/sys/user_program.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2018-2022 The Pybricks Authors - -#include - -#if PBSYS_CONFIG_USER_PROGRAM - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "core.h" -#include "storage.h" - -static bool pbsys_user_program_start_user_program_requested; -static bool pbsys_user_program_start_repl_requested; - -/** - * Requests to start the user program. - * - * @returns ::PBIO_ERROR_BUSY if a user program is already running. - * ::PBIO_ERROR_INVALID_ARG if the user program has an invalid size. - * ::PBIO_ERROR_NOT_SUPPORTED if the program load module is disabled. - * Otherwise ::PBIO_SUCCESS. - */ -pbio_error_t pbsys_user_program_start_program(void) { - if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) { - return PBIO_ERROR_BUSY; - } - - pbio_error_t err = pbsys_storage_assert_program_valid(); - if (err != PBIO_SUCCESS) { - return err; - } - - pbsys_user_program_start_user_program_requested = true; - - return PBIO_SUCCESS; -} - -/** - * Requests to start the REPL. - * - * @returns ::PBIO_ERROR_BUSY if a user program is already running. - * ::PBIO_ERROR_NOT_SUPPORTED if the program load module is disabled. - * Otherwise ::PBIO_SUCCESS. - */ -pbio_error_t pbsys_user_program_start_repl(void) { - if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) { - return PBIO_ERROR_BUSY; - } - - pbsys_user_program_start_repl_requested = true; - - return PBIO_SUCCESS; -} - -/** - * Waits for a command to start a user program or REPL. - * - * NOTE: this function runs the contiki event loop, so it should not be called - * from inside an contiki process. - * - * @param [out] program Program info structure to be populated. - * @return ::PBIO_SUCCESS on success. - * ::PBIO_ERROR_CANCELED when canceled due to shutdown request. - * ::PBIO_ERROR_NOT_SUPPORTED if the program load module is disabled. - */ -pbio_error_t pbsys_user_program_wait_command(pbsys_main_program_t *program) { - for (;;) { - // REVISIT: this can be long waiting, so we could do a more efficient - // wait (i.e. __WFI() on embedded system) - pbio_do_one_event(); - - if (pbsys_status_test(PBIO_PYBRICKS_STATUS_SHUTDOWN_REQUEST)) { - return PBIO_ERROR_CANCELED; - } - - #if PBSYS_CONFIG_USER_PROGRAM_AUTO_START - pbsys_user_program_start_user_program_requested = true; - #endif - - if (pbsys_user_program_start_user_program_requested) { - pbsys_user_program_start_user_program_requested = false; - program->run_builtin = false; - break; - } - - if (pbsys_user_program_start_repl_requested) { - pbsys_user_program_start_repl_requested = false; - program->run_builtin = true; - break; - } - } - - // Builtin program can also use user program (e.g. in MicroPython, REPL may - // import user modules), so load data in all cases. - pbsys_storage_get_program_data(program); - - return PBIO_SUCCESS; -} - -#endif // PBSYS_CONFIG_USER_PROGRAM diff --git a/lib/pbio/sys/user_program.h b/lib/pbio/sys/user_program.h deleted file mode 100644 index 563dd4272..000000000 --- a/lib/pbio/sys/user_program.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2022-2024 The Pybricks Authors - -#ifndef _PBSYS_SYS_USER_PROGRAM_H_ -#define _PBSYS_SYS_USER_PROGRAM_H_ - -#include - -#include -#include -#include - -#if PBSYS_CONFIG_USER_PROGRAM - -pbio_error_t pbsys_user_program_wait_command(pbsys_main_program_t *program); -pbio_error_t pbsys_user_program_start_program(void); -pbio_error_t pbsys_user_program_start_repl(void); - -#else - -static inline pbio_error_t pbsys_user_program_wait_command(pbsys_main_program_t *program) { - return PBIO_ERROR_NOT_SUPPORTED; -} -static inline pbio_error_t pbsys_user_program_start_program(void) { - return PBIO_ERROR_NOT_SUPPORTED; -} -static inline pbio_error_t pbsys_user_program_start_repl(void) { - return PBIO_ERROR_NOT_SUPPORTED; -} - -#endif // PBSYS_CONFIG_USER_PROGRAM - -#endif // _PBSYS_SYS_USER_PROGRAM_H_ diff --git a/lib/pbio/test/pbsys_app_config.h b/lib/pbio/test/pbsys_app_config.h deleted file mode 100644 index bf2e13898..000000000 --- a/lib/pbio/test/pbsys_app_config.h +++ /dev/null @@ -1 +0,0 @@ -#define PBSYS_APP_HUB_FEATURE_FLAGS 0