Skip to content

Commit

Permalink
pbio/sys/protocol: Use single byte for program ID.
Browse files Browse the repository at this point in the history
This will let us include it in the hub status for
monitoring by Pybricks Code.

Use it for both downloaded and builtin user
programs.

Also restore the original START_REPL and START_PROGRAMS, and instead
introduce a new command for starting both builtin and downloaded user
programs. The previous modifications had not been released yet.
  • Loading branch information
laurensvalk committed Sep 2, 2024
1 parent 4df225e commit 42d64cb
Show file tree
Hide file tree
Showing 18 changed files with 223 additions and 149 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@
correction of the `hub.imu.heading()` value ([support#1678]).
- Added `update_heading_correction` to interactively set the heading
correction value ([support#1678]).
- Added command to start downloaded or builtin user program with a one byte
program identifier. The existing START_PROGRAM and START_REPL are special
cases of this new more generic command, but will remain available for
backwards compatibility. For now, this is added to start various builtin
programs, but it prepares for the ability to start different downloaded
programs too ([pybricks-micropython#254]).

### Changed

- Changed protocol to Pybricks Profile v1.4.0.
- When upgrading the firmware to a new version, the user program will now
be erased. This avoids issues with incompatible program files ([support#1622]).
- The `angular_velocity_threshold`, and `acceleration_threshold` settings
Expand All @@ -40,6 +47,7 @@

[pybricks-micropython#250]: https://github.com/pybricks/pybricks-micropython/pull/250
[pybricks-micropython#253]: https://github.com/pybricks/pybricks-micropython/pull/253
[pybricks-micropython#254]: https://github.com/pybricks/pybricks-micropython/pull/254
[support#1429]: https://github.com/pybricks/support/issues/1429
[support#1460]: https://github.com/pybricks/support/issues/1460
[support#1615]: https://github.com/pybricks/support/issues/1615
Expand Down
110 changes: 54 additions & 56 deletions bricks/_common/micropython.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static void print_final_exception(mp_obj_t exc) {
mp_obj_print_exception(&mp_plat_print, exc);
}

#if PYBRICKS_OPT_COMPILER
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
static void run_repl(void) {
readline_init0();
pyexec_system_exit = 0;
Expand Down Expand Up @@ -145,7 +145,7 @@ static void run_repl(void) {

nlr_set_abort(NULL);
}
#endif
#endif // PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL

// From micropython/py/builtinimport.c, but copied because it is static.
static void do_execute_raw_code(mp_module_context_t *context, const mp_raw_code_t *rc, const mp_module_context_t *mc) {
Expand Down Expand Up @@ -277,7 +277,7 @@ static void run_user_program(void) {

print_final_exception(MP_OBJ_FROM_PTR(nlr.ret_val));

#if PYBRICKS_OPT_COMPILER
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
// On KeyboardInterrupt, drop to REPL for debugging.
if (mp_obj_exception_match(MP_OBJ_FROM_PTR(nlr.ret_val), MP_OBJ_FROM_PTR(&mp_type_KeyboardInterrupt))) {

Expand All @@ -289,47 +289,39 @@ static void run_user_program(void) {
// Enter REPL.
run_repl();
}
#endif
#endif // PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
}

nlr_set_abort(NULL);
}

/**
* Builtin Pybricks MicroPython program identifiers.
*/
typedef enum {
/**
* The MicroPython REPL.
*/
PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_ID_REPL = 0,
/**
* Program that detects attached devices, displays sensor values, and
* relays sensor data to host if connected.
*/
PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_ID_PORT_VIEW = 1,
/**
* The number of builtin user programs.
*/
PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_NUMBER_OF_PROGRAMS,
} pybricks_micropython_builtin_user_program_id_t;

pbio_error_t pbsys_main_program_validate(pbsys_main_program_t *program) {

// Validate builtin user programs for existence.
if (program->type == PBSYS_MAIN_PROGRAM_TYPE_BUILTIN) {
#if PBSYS_CONFIG_APP_BUILTIN_USER_PROGRAMS
if (program->id < PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_NUMBER_OF_PROGRAMS) {
return PBIO_SUCCESS;
}
#endif
// For builtin programs, check requested ID against feature flags.
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_REPL) {
return PBIO_SUCCESS;
}
#endif
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_PORT_VIEW
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW) {
return PBIO_SUCCESS;
}
#endif
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_IMU_CALIBRATION
if (program->id == PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION) {
return PBIO_SUCCESS;
}
#endif

// Only user program 0 is supported for now.
if (program->id != PBIO_PYBRICKS_USER_PROGRAM_ID_FIRST_SLOT) {
return PBIO_ERROR_NOT_SUPPORTED;
}

// 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) {
if (program_size == 0 || program_size > PBSYS_STORAGE_MAX_PROGRAM_SIZE) {
return PBIO_ERROR_NOT_SUPPORTED;
}

Expand Down Expand Up @@ -361,31 +353,37 @@ void pbsys_main_run_program(pbsys_main_program_t *program) {
// Initialize MicroPython.
mp_init();

// Check for run type.
if (program->type == PBSYS_MAIN_PROGRAM_TYPE_USER) {
// Init Pybricks package without auto-import.
pb_package_pybricks_init(false);
// Run loaded user program.
run_user_program();
}
#if PBSYS_CONFIG_APP_BUILTIN_USER_PROGRAMS
else {
switch (program->id) {
case PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_ID_REPL:
// Run REPL with everything auto-imported.
pb_package_pybricks_init(true);
run_repl();
break;
case PYBRICKS_MICROPYTHON_BUILTIN_USER_PROGRAM_ID_PORT_VIEW:
pyexec_frozen_module("_builtin_port_view.py", false);
break;
default:
// Existence was already validated above, so just quietly exit
// since we can't get here.
break;
}
// Runs the requested downloaded or builtin user program.
switch (program->id) {

#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
case PBIO_PYBRICKS_USER_PROGRAM_ID_REPL:
// Run REPL with everything auto-imported.
pb_package_pybricks_init(true);
run_repl();
break;
#endif

#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_PORT_VIEW
case PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW:
pb_package_pybricks_init(false);
pyexec_frozen_module("_builtin_port_view.py", false);
break;
#endif

#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_IMU_CALIBRATION
case PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION:
// Todo
break;
#endif

default:
// Init Pybricks package without auto-import.
pb_package_pybricks_init(false);
// Run loaded user program (just slot 0 for now).
run_user_program();
break;
}
#endif // PYBRICKS_OPT_COMPILER

// De-init bluetooth resources (including flushing stdout) that may use
// memory allocated by MicroPython before we wipe it.
Expand Down
2 changes: 1 addition & 1 deletion bricks/ev3rt/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void main_task(intptr_t unused) {

while (true) {
pbsys_main_program_t program = {
.type = PBSYS_MAIN_PROGRAM_TYPE_BUILTIN,
.id = PBIO_PYBRICKS_USER_PROGRAM_ID_REPL,
.code_end = heap,
.data_end = heap + sizeof(heap),
};
Expand Down
99 changes: 74 additions & 25 deletions lib/pbio/include/pbio/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@
PBIO_XSTR(PBIO_PROTOCOL_VERSION_MINOR) "." \
PBIO_XSTR(PBIO_PROTOCOL_VERSION_PATCH)


/**
* User program identifiers.
*
* 0--127: Downloadabled user programs.
* 128--255: Builtin user programs.
*/
typedef enum {
/**
* First possible downloadable user program.
*/
PBIO_PYBRICKS_USER_PROGRAM_ID_FIRST_SLOT = 0,
/**
* Last possible downloadable user program.
*/
PBIO_PYBRICKS_USER_PROGRAM_ID_LAST_SLOT = 127,
/**
* Read-eval-print loop (REPL) interface.
*/
PBIO_PYBRICKS_USER_PROGRAM_ID_REPL = 128,
/**
* Program that detects attached devices, displays sensor values, and
* relays sensor data to host if connected.
*/
PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW = 129,
/**
* Program that calibrates the internal inertial measurement unit and saves
* data persistently on the hub.
*/
PBIO_PYBRICKS_USER_PROGRAM_ID_IMU_CALIBRATION = 130,
} pbio_pybricks_user_program_id_t;

/**
* Pybricks command types.
*
Expand All @@ -53,36 +85,28 @@ typedef enum {
PBIO_PYBRICKS_COMMAND_STOP_USER_PROGRAM = 0,

/**
* 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
* Requests that the user program should be started.
*
* Errors:
* - ::PBIO_PYBRICKS_ERROR_BUSY if a program is already running.
* - ::PBIO_PYBRICKS_ERROR_INVALID_COMMAND if the builtin user program is not available (Since Pybricks Profile v1.4.0).
* - ::PBIO_PYBRICKS_ERROR_BUSY if another program is already running.
*
* @since Pybricks Profile v1.2.0
* @deprecated in Pybricks Profile v1.4.0.
* Use ::PBIO_PYBRICKS_COMMAND_START_USER_OR_BUILTIN_PROGRAM instead.
*/
PBIO_PYBRICKS_COMMAND_START_USER_PROGRAM = 1,

/**
* Requests that a specified builtin user program should be started.
*
* Parameters:
* - id (optional): The identifier of the builtin 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
* Requests that the REPL should be started.
*
* Errors:
* - ::PBIO_PYBRICKS_ERROR_BUSY if a program is already running.
* - ::PBIO_PYBRICKS_ERROR_INVALID_COMMAND if the builtin user program is not available (Since Pybricks Profile v1.4.0).
* - ::PBIO_PYBRICKS_ERROR_BUSY if another program is already running.
*
* @since Pybricks Profile v1.2.0
* @deprecated in Pybricks Profile v1.4.0.
* Use ::PBIO_PYBRICKS_COMMAND_START_USER_OR_BUILTIN_PROGRAM instead.
*/
PBIO_PYBRICKS_COMMAND_START_BUILTIN_USER_PROGRAM = 2,
PBIO_PYBRICKS_COMMAND_START_REPL = 2,

/**
* Requests to write user program metadata.
Expand Down Expand Up @@ -159,8 +183,24 @@ typedef enum {
* @since Pybricks Profile v1.4.0
*/
PBIO_PYBRICKS_COMMAND_WRITE_APP_DATA = 7,
} pbio_pybricks_command_t;

/**
* Requests that a previously downloaded user program or builtin user
* program is started.
*
* Parameters:
* - payload: Program identifier (one byte). Slots 0--127 are reserved for
* downloaded user programs. Slots 128--255 are for builtin user
* programs.
*
* Errors:
* - ::PBIO_PYBRICKS_ERROR_BUSY if another program is already running.
* - ::PBIO_PYBRICKS_ERROR_INVALID_COMMAND if the requested program is not available.
*
* @since Pybricks Profile v1.4.0.
*/
PBIO_PYBRICKS_COMMAND_START_USER_OR_BUILTIN_PROGRAM = 8,
} pbio_pybricks_command_t;
/**
* Application-specific error codes that are used in ATT_ERROR_RSP.
*/
Expand Down Expand Up @@ -310,14 +350,11 @@ typedef enum {
// NB: the values are part of the protocol, so don't change the values!

/**
* Hub supports builtin user 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 user programs.
* Hub supports interactive REPL.
*
* @since Pybricks Profile v1.2.0.
*/
PBIO_PYBRICKS_FEATURE_BUILTIN_USER_PROGRAMS = 1 << 0,
PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_REPL = 1 << 0,
/**
* Hub supports user program with multiple MicroPython .mpy files ABI v6
*
Expand All @@ -326,14 +363,26 @@ typedef enum {
*
* @since Pybricks Profile v1.2.0.
*/
PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6 = 1 << 1,
PBIO_PYBRICKS_FEATURE_FLAG_USER_PROG_FORMAT_MULTI_MPY_V6 = 1 << 1,
/**
* Hub supports user program with multiple MicroPython .mpy files ABI v6.1
* including native module support.
*
* @since Pybricks Profile v1.3.0.
*/
PBIO_PYBRICKS_FEATURE_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE = 1 << 2,
PBIO_PYBRICKS_FEATURE_FLAG_USER_PROG_FORMAT_MULTI_MPY_V6_1_NATIVE = 1 << 2,
/**
* Hub supports builtin sensor port view monitoring program.
*
* @since Pybricks Profile v1.4.0.
*/
PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_PORT_VIEW = 1 << 3,
/**
* Hub supports builtin IMU calibration program.
*
* @since Pybricks Profile v1.4.0.
*/
PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_IMU_CALIBRATION = 1 << 4,
} pbio_pybricks_feature_flags_t;

void pbio_pybricks_hub_capabilities(uint8_t *buf,
Expand Down
8 changes: 5 additions & 3 deletions lib/pbio/include/pbsys/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
#include <pbio/protocol.h>

#define PBSYS_CONFIG_APP_FEATURE_FLAGS (0 \
+ PBSYS_CONFIG_APP_BUILTIN_USER_PROGRAMS * PBIO_PYBRICKS_FEATURE_BUILTIN_USER_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 \
+ PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL * PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_REPL \
+ PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_PORT_VIEW * PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_PORT_VIEW \
+ PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_IMU_CALIBRATION * PBIO_PYBRICKS_FEATURE_FLAG_BUILTIN_USER_PROGRAM_IMU_CALIBRATION \
+ PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6 * PBIO_PYBRICKS_FEATURE_FLAG_USER_PROG_FORMAT_MULTI_MPY_V6 \
+ PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE * PBIO_PYBRICKS_FEATURE_FLAG_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
Expand Down
Loading

0 comments on commit 42d64cb

Please sign in to comment.