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