Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 57 additions & 9 deletions bricks/_common/micropython.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdio.h>
#include <string.h>

#include <pbdrv/bluetooth.h>
#include <pbdrv/stack.h>

#include <pbio/button.h>
Expand All @@ -19,6 +20,7 @@
#include <pbsys/storage.h>

#include <pybricks/common.h>
#include <pybricks/stdio.h>
#include <pybricks/util_mp/pb_obj_helper.h>

#include "genhdr/mpversion.h"
Expand Down Expand Up @@ -105,16 +107,30 @@ static void mp_vfs_map_minimal_new_reader(mp_reader_t *reader, mp_vfs_map_minima

// Prints the exception that ended the program.
static void print_final_exception(mp_obj_t exc, int ret) {
// Handle graceful stop with button.
if ((ret & PYEXEC_FORCED_EXIT) &&
mp_obj_exception_match(exc, MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
mp_printf(&mp_plat_print, "The program was stopped (%q).\n",
((mp_obj_exception_t *)MP_OBJ_TO_PTR(exc))->base.type->name);
return;
}
nlr_buf_t nlr;
nlr.ret_val = NULL;

if (nlr_push(&nlr) == 0) {
// Handle graceful stop with button.
if ((ret & PYEXEC_FORCED_EXIT) &&
mp_obj_exception_match(exc, MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
mp_printf(&mp_plat_print, "The program was stopped (%q).\n",
((mp_obj_exception_t *)MP_OBJ_TO_PTR(exc))->base.type->name);
return;
}

// Print unhandled exception with traceback.
mp_obj_print_exception(&mp_plat_print, exc);
// REVISIT: flash the light red a few times to indicate an unhandled exception?

// Print unhandled exception with traceback.
mp_obj_print_exception(&mp_plat_print, exc);

nlr_pop();
} else {
// If we couldn't print the exception, just return. There is nothing
// else we can do.

// REVISIT: flash the light with a different pattern here?
}
}

#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
Expand Down Expand Up @@ -375,6 +391,38 @@ void pbsys_main_run_program(pbsys_main_program_t *program) {
// Initialize MicroPython.
mp_init();

#if MICROPY_PY_SYS_MUTABLE_STDIO

bool use_bluetooth;

// If the program was started remotely, use the same transport for stdio.
switch (program->start_request_type) {
case PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_BLUETOOTH:
use_bluetooth = true;
break;
case PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_USB:
use_bluetooth = false;
break;
default:
// Use Bluetooth if available, otherwise USB.
// REVISIT: might want to keep track of last used transport and use
// that instead.
use_bluetooth = pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PYBRICKS);
break;
}

if (use_bluetooth) {
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDIN]) = MP_OBJ_FROM_PTR(&pb_bluetooth_stdio_wrapper_obj);
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDOUT]) = MP_OBJ_FROM_PTR(&pb_bluetooth_stdio_wrapper_obj);
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDERR]) = MP_OBJ_FROM_PTR(&pb_bluetooth_stdio_wrapper_obj);
} else {
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDIN]) = MP_OBJ_FROM_PTR(&pb_usb_stdio_wrapper_obj);
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDOUT]) = MP_OBJ_FROM_PTR(&pb_usb_stdio_wrapper_obj);
MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDERR]) = MP_OBJ_FROM_PTR(&pb_usb_stdio_wrapper_obj);
}

#endif // MICROPY_PY_SYS_MUTABLE_STDIO

// Runs the requested downloaded or builtin user program.
switch (program->id) {

Expand Down
7 changes: 4 additions & 3 deletions bricks/_common/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_EXIT (0)
#define MICROPY_PY_SYS_MODULES (0)
#define MICROPY_PY_SYS_STDFILES (PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_STDIO_BUFFER (PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_STDIO_FLUSH (PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_STDFILES (!PYBRICKS_PY_STDIO && PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_STDIO_BUFFER (!PYBRICKS_PY_STDIO && PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_STDIO_FLUSH (!PYBRICKS_PY_STDIO && PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_SYS_MUTABLE_STDIO (PYBRICKS_PY_STDIO)
#define MICROPY_PY_RANDOM_EXTRA_FUNCS (PYBRICKS_OPT_EXTRA_LEVEL1)
#define MICROPY_PY_RANDOM_SEED_INIT_FUNC ({ extern uint32_t pbdrv_clock_get_us(void); pbdrv_clock_get_us(); })
#define MICROPY_MODULE_BUILTIN_INIT (1)
Expand Down
5 changes: 4 additions & 1 deletion bricks/_common/sources.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CONTIKI_SRC_C = $(addprefix lib/contiki-core/,\
PYBRICKS_PYBRICKS_SRC_C = $(addprefix pybricks/,\
common/pb_type_ble.c \
common/pb_type_battery.c \
common/pb_type_bluetooth_stdio.c \
common/pb_type_charger.c \
common/pb_type_colorlight_external.c \
common/pb_type_colorlight_internal.c \
Expand All @@ -39,6 +40,8 @@ PYBRICKS_PYBRICKS_SRC_C = $(addprefix pybricks/,\
common/pb_type_motor.c \
common/pb_type_speaker.c \
common/pb_type_system.c \
common/pb_type_usb.c \
common/pb_type_usb_stdio.c \
ev3devices/pb_module_ev3devices.c \
ev3devices/pb_type_ev3devices_colorsensor.c \
ev3devices/pb_type_ev3devices_gyrosensor.c \
Expand Down Expand Up @@ -91,6 +94,7 @@ PYBRICKS_PYBRICKS_SRC_C = $(addprefix pybricks/,\
pupdevices/pb_type_pupdevices_tiltsensor.c \
pupdevices/pb_type_pupdevices_ultrasonicsensor.c \
pybricks.c \
stdio.c \
robotics/pb_module_robotics.c \
robotics/pb_type_car.c \
robotics/pb_type_drivebase.c \
Expand Down Expand Up @@ -227,7 +231,6 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
sys/command.c \
sys/core.c \
sys/hmi.c \
sys/host.c \
sys/light_matrix.c \
sys/light.c \
sys/main.c \
Expand Down
120 changes: 113 additions & 7 deletions bricks/_common_stm32/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <pbdrv/clock.h>
#include <pbdrv/config.h>
#include <pbio/main.h>
#include <pbsys/host.h>
#include <pbsys/bluetooth.h>

#include "py/runtime.h"
#include "py/mphal.h"
Expand Down Expand Up @@ -43,20 +43,109 @@ void mp_hal_delay_ms(mp_uint_t Delay) {
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;

if ((poll_flags & MP_STREAM_POLL_RD) && pbsys_host_rx_get_available()) {
if ((poll_flags & MP_STREAM_POLL_RD) && pbsys_bluetooth_rx_get_available()) {
ret |= MP_STREAM_POLL_RD;
}

return ret;
}

#if MICROPY_PY_SYS_MUTABLE_STDIO

// When MICROPY_PY_SYS_MUTABLE_STDIO is enabled, the relationship between
// sys.stdin/stdout/stderr and mp_hal_stdin/stdout is inverted. In this case,
// calls to mp_hal_stdin/stdout are implemented by calling the currently set
// sys.stdin/stdout objects.

#include <pybricks/stdio.h>
#include <pybricks/util_pb/pb_error.h>

// Receive single character
int mp_hal_stdin_rx_chr(void) {
mp_obj_t stdin_obj = MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDIN]);

const mp_stream_p_t *stream_p = mp_get_stream_raise(stdin_obj, MP_STREAM_OP_READ);

if (stream_p->is_text) {
mp_obj_t buffer_obj;
mp_load_method(stdin_obj, MP_QSTR_buffer, &buffer_obj);
stream_p = mp_get_stream_raise(buffer_obj, MP_STREAM_OP_READ);
}

if (!stream_p->read) {
pb_assert(PBIO_ERROR_NOT_IMPLEMENTED);
}

uint8_t c;
int errcode;
mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream_p), &c, sizeof(c), &errcode);

if (out_sz == MP_STREAM_ERROR) {
mp_raise_OSError(errcode);
}

return c;
}

// Send string of given length
mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
mp_obj_t stdout_obj = MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDOUT]);

const mp_stream_p_t *stream_p = mp_get_stream_raise(stdout_obj, MP_STREAM_OP_WRITE);

if (stream_p->is_text) {
mp_obj_t buffer_obj;
mp_load_method(stdout_obj, MP_QSTR_buffer, &buffer_obj);
stream_p = mp_get_stream_raise(buffer_obj, MP_STREAM_OP_WRITE);
}

if (!stream_p->write) {
pb_assert(PBIO_ERROR_NOT_IMPLEMENTED);
}

int errcode;
mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream_p), str, len, &errcode);
if (out_sz == MP_STREAM_ERROR) {
mp_raise_OSError(errcode);
}

return out_sz;
}

void mp_hal_stdout_tx_flush(void) {
mp_obj_t stdout_obj = MP_STATE_VM(sys_mutable[MP_SYS_MUTABLE_STDOUT]);

const mp_stream_p_t *stream_p = mp_get_stream_raise(stdout_obj, MP_STREAM_OP_IOCTL);

if (stream_p->is_text) {
mp_obj_t buffer_obj;
mp_load_method(stdout_obj, MP_QSTR_buffer, &buffer_obj);
stream_p = mp_get_stream_raise(buffer_obj, MP_STREAM_OP_IOCTL);
}

if (!stream_p->ioctl) {
pb_assert(PBIO_ERROR_NOT_IMPLEMENTED);
}

int errcode;
mp_uint_t ret = stream_p->ioctl(MP_OBJ_FROM_PTR(stream_p), MP_STREAM_FLUSH, 0, &errcode);
if (ret == MP_STREAM_ERROR) {
mp_raise_OSError(errcode);
}
}

#else // MICROPY_PY_SYS_MUTABLE_STDIO

// When there is only Bluetooth, we will use the mp_hal to directly connect
// stdin/stdout to Bluetooth to keep the code size small.

// Receive single character
int mp_hal_stdin_rx_chr(void) {
uint32_t size;
uint8_t c;

// wait for rx interrupt
while (size = 1, pbsys_host_rx(&c, &size) != PBIO_SUCCESS) {
while (size = 1, pbsys_bluetooth_rx(&c, &size) != PBIO_SUCCESS) {
MICROPY_EVENT_POLL_HOOK
}

Expand All @@ -65,16 +154,33 @@ int mp_hal_stdin_rx_chr(void) {

// Send string of given length
mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
while (pbsys_host_tx((const uint8_t *)str, len) == PBIO_ERROR_AGAIN) {
uint32_t remaining = len;

while (remaining) {
uint32_t size = remaining;

pbio_error_t err = pbsys_bluetooth_tx((const uint8_t *)str, &size);
if (err == PBIO_SUCCESS) {
str += size;
remaining -= size;
}

MICROPY_EVENT_POLL_HOOK

if (err != PBIO_ERROR_AGAIN) {
// Ignoring error for now. This means stdout lost if Bluetooth is
// disconnected.
break;
}
}
// Not raising the error. This means stdout lost if host is not connected.

return len;
return len - remaining;
}

void mp_hal_stdout_tx_flush(void) {
while (!pbsys_host_tx_is_idle()) {
while (!pbsys_bluetooth_tx_is_idle()) {
MICROPY_EVENT_POLL_HOOK
}
}

#endif // MICROPY_PY_SYS_MUTABLE_STDIO
2 changes: 2 additions & 0 deletions bricks/cityhub/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SPEAKER (0)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (0)
#define PYBRICKS_PY_EV3DEVICES (0)
#define PYBRICKS_PY_EXPERIMENTAL (1)
#define PYBRICKS_PY_HUBS (1)
Expand All @@ -42,6 +43,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (0)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (0)
#define PYBRICKS_PY_STDIO (0)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (0)
#define PYBRICKS_PY_TOOLS_APP_DATA (1)
Expand Down
2 changes: 2 additions & 0 deletions bricks/essentialhub/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SPEAKER (0)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (1)
#define PYBRICKS_PY_EV3DEVICES (0)
#define PYBRICKS_PY_EXPERIMENTAL (1)
#define PYBRICKS_PY_HUBS (1)
Expand All @@ -43,6 +44,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (1)
#define PYBRICKS_PY_STDIO (1)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (0)
#define PYBRICKS_PY_TOOLS_APP_DATA (1)
Expand Down
2 changes: 2 additions & 0 deletions bricks/ev3/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SPEAKER (1)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (0)
#define PYBRICKS_PY_EV3DEVICES (1)
#define PYBRICKS_PY_EXPERIMENTAL (1)
#define PYBRICKS_PY_HUBS (1)
Expand All @@ -41,6 +42,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (0)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (0)
#define PYBRICKS_PY_STDIO (0)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (0)
#define PYBRICKS_PY_TOOLS_APP_DATA (1)
Expand Down
2 changes: 2 additions & 0 deletions bricks/movehub/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define PYBRICKS_PY_COMMON_MOTOR_MODEL (0)
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (0)
#define PYBRICKS_PY_EXPERIMENTAL (0)
#define PYBRICKS_PY_HUBS (1)
#define PYBRICKS_PY_IODEVICES (0)
Expand All @@ -39,6 +40,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (0)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (0)
#define PYBRICKS_PY_STDIO (0)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (0)
#define PYBRICKS_PY_TOOLS_APP_DATA (0)
Expand Down
2 changes: 2 additions & 0 deletions bricks/nxt/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SPEAKER (1)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (0)
#define PYBRICKS_PY_EV3DEVICES (0)
#define PYBRICKS_PY_EXPERIMENTAL (0)
#define PYBRICKS_PY_HUBS (1)
Expand All @@ -41,6 +42,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (0)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (0)
#define PYBRICKS_PY_STDIO (0)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (0)
#define PYBRICKS_PY_TOOLS_APP_DATA (0)
Expand Down
2 changes: 2 additions & 0 deletions bricks/primehub/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define PYBRICKS_PY_COMMON_MOTORS (1)
#define PYBRICKS_PY_COMMON_SPEAKER (1)
#define PYBRICKS_PY_COMMON_SYSTEM (1)
#define PYBRICKS_PY_COMMON_USB (1)
#define PYBRICKS_PY_EV3DEVICES (0)
#define PYBRICKS_PY_EXPERIMENTAL (1)
#define PYBRICKS_PY_HUBS (1)
Expand All @@ -44,6 +45,7 @@
#define PYBRICKS_PY_ROBOTICS (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_GYRO (1)
#define PYBRICKS_PY_ROBOTICS_DRIVEBASE_SPIKE (1)
#define PYBRICKS_PY_STDIO (1)
#define PYBRICKS_PY_TOOLS (1)
#define PYBRICKS_PY_TOOLS_HUB_MENU (1)
#define PYBRICKS_PY_TOOLS_APP_DATA (1)
Expand Down
Loading