Skip to content

Commit

Permalink
pbio/sys/hmi: Add slot selection UI.
Browse files Browse the repository at this point in the history
Also add ability to start port view program.
  • Loading branch information
laurensvalk committed Sep 17, 2024
1 parent 1081780 commit b6fe100
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 16 deletions.
16 changes: 15 additions & 1 deletion bricks/_common/modules/_builtin_port_view.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from pybricks.hubs import ThisHub
from pybricks.pupdevices import (
DCMotor,
Motor,
Expand All @@ -22,6 +21,21 @@
except AttributeError:
pass

try:
from pybricks.hubs import PrimeHub
from pybricks.parameters import Icon, Button

hub = PrimeHub()
hub.light.off()

# Create an animation of the heart icon with changing brightness.
brightness = list(range(0, 100, 4)) + list(range(100, 0, -4))
hub.display.animate([Icon.HEART * i / 100 for i in brightness], 30)
while hub.buttons.pressed():
wait(10)
hub.system.set_stop_button([Button.LEFT, Button.RIGHT])
except ImportError:
pass

# Allocates small buffer so the IDE can send us mode index
# values for each sensor.
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/city_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (1)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (20 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE)
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/debug/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (0)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (64 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (0)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (0)
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/essential_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (1)
#define PBSYS_CONFIG_BATTERY_CHARGER (1)
#define PBSYS_CONFIG_BLUETOOTH (1)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (258 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_W25QXX_STM32_SIZE)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (0)
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/ev3/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (10 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_TEST_SIZE)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (0)
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/ev3rt/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (0)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (0)
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/move_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (1)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (7 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE)
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/nxt/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (10 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_TEST_SIZE)
#define PBSYS_CONFIG_STORAGE_USER_DATA_SIZE (512)
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/prime_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define PBSYS_CONFIG_BLUETOOTH (1)
#define PBSYS_CONFIG_BLUETOOTH_TOGGLE (1)
#define PBSYS_CONFIG_BLUETOOTH_TOGGLE_BUTTON (512) // PBIO_BUTTON_RIGHT_UP, but enum value cannot be used here.
#define PBSYS_CONFIG_HMI_NUM_SLOTS (5)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (1)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (PBSYS_CONFIG_HMI_NUM_SLOTS)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (258 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_W25QXX_STM32_SIZE)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (0)
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/platform/technic_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#define PBSYS_CONFIG_FEATURE_PROGRAM_FORMAT_MULTI_MPY_V6_1_NATIVE (0)
#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (1)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (1)
#define PBSYS_CONFIG_STORAGE (1)
#define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1)
#define PBSYS_CONFIG_STORAGE_OVERLAPS_BOOTLOADER_CHECKSUM (1)
#define PBSYS_CONFIG_STORAGE_RAM_SIZE (32 * 1024)
#define PBSYS_CONFIG_STORAGE_ROM_SIZE (PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE)
Expand Down
1 change: 1 addition & 0 deletions lib/pbio/platform/virtual_hub/pbsysconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define PBSYS_CONFIG_BATTERY_CHARGER (0)
#define PBSYS_CONFIG_BLUETOOTH (0)
#define PBSYS_CONFIG_HMI_NUM_SLOTS (0)
#define PBSYS_CONFIG_HUB_LIGHT_MATRIX (0)
#define PBSYS_CONFIG_MAIN (0)
#define PBSYS_CONFIG_STORAGE (0)
Expand Down
88 changes: 83 additions & 5 deletions lib/pbio/sys/hmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@

static struct pt update_program_run_button_wait_state_pt;

static uint8_t selected_slot = 0;

/**
* Protothread to monitor the button state to trigger starting the user program.
* @param [in] button_pressed The current button state.
*/
static PT_THREAD(update_program_run_button_wait_state(bool button_pressed)) {
struct pt *pt = &update_program_run_button_wait_state_pt;
// HACK: Misuse of protothread to reduce code size. This is the same
// Creative use of protothread to reduce code size. This is the same
// as checking if the user program is running after each PT_WAIT.
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) {
goto start;
Expand All @@ -51,9 +53,8 @@ static PT_THREAD(update_program_run_button_wait_state(bool button_pressed)) {
PT_WAIT_UNTIL(pt, !button_pressed);

// If we made it through a full press and release, without the user
// program running, then start the user program. There is no UI for
// multiple programs yet, so start the one and only program.
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_FIRST_SLOT);
// program running, then start the currently selected user program.
pbsys_main_program_request_start(selected_slot);
}

PT_END(pt);
Expand All @@ -69,7 +70,7 @@ static struct pt update_bluetooth_button_wait_state_pt;
*/
static PT_THREAD(update_bluetooth_button_wait_state(bool button_pressed)) {
struct pt *pt = &update_bluetooth_button_wait_state_pt;
// HACK: Misuse of protothread to reduce code size. This is the same
// Creative use of protothread to reduce code size. This is the same
// as checking if the user program is running after each PT_WAIT.
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) {
goto start;
Expand All @@ -90,6 +91,79 @@ static PT_THREAD(update_bluetooth_button_wait_state(bool button_pressed)) {

#endif // PBSYS_CONFIG_BLUETOOTH_TOGGLE

#if PBSYS_CONFIG_HMI_NUM_SLOTS

static struct pt update_left_right_button_wait_state_pt;

/**
* Gets the currently selected program slot.
*
* @return The currently selected program slot (zero-indexed).
*/
uint8_t pbsys_hmi_get_selected_program_slot(void) {
return selected_slot;
}

/**
* Protothread to monitor the left and right button state to select a slot.
*
* @param [in] left_button_pressed The current left button state.
* @param [in] right_button_pressed The current right button state.
*/
static PT_THREAD(update_left_right_button_wait_state(bool left_button_pressed, bool right_button_pressed)) {
struct pt *pt = &update_left_right_button_wait_state_pt;
// Creative use of protothread to reduce code size. This is the same
// as checking if the user program is running after each PT_WAIT.
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) {
goto start;
}

static uint8_t previous_slot;
static uint32_t first_press_time;

PT_BEGIN(pt);

for (;;) {
start:
// Buttons may still be pressed during user program
PT_WAIT_UNTIL(pt, !left_button_pressed && !right_button_pressed);

// Wait for either button.
PT_WAIT_UNTIL(pt, left_button_pressed || right_button_pressed);

first_press_time = pbdrv_clock_get_ms();

// On right, increment slot when possible.
if (right_button_pressed && selected_slot < 4) {
selected_slot++;
pbsys_hub_light_matrix_update_program_slot();
}
// On left, decrement slot when possible.
if (left_button_pressed && selected_slot > 0) {
selected_slot--;
pbsys_hub_light_matrix_update_program_slot();
}

// Next state could be either both pressed or both released.
PT_WAIT_UNTIL(pt, left_button_pressed == right_button_pressed);

// If both were pressed soon after another, user wanted to start port view,
// not switch programs, so revert slot change.
if (left_button_pressed && pbdrv_clock_get_ms() - first_press_time < 100) {
selected_slot = previous_slot;
pbsys_hub_light_matrix_update_program_slot();
pbsys_main_program_request_start(PBIO_PYBRICKS_USER_PROGRAM_ID_PORT_VIEW);
} else {
// Successful switch. And UI was already updated.
previous_slot = selected_slot;
}
}

PT_END(pt);
}

#endif // PBSYS_CONFIG_HMI_NUM_SLOTS

void pbsys_hmi_init(void) {
pbsys_status_light_init();
pbsys_hub_light_matrix_init();
Expand Down Expand Up @@ -142,6 +216,10 @@ void pbsys_hmi_poll(void) {
#if PBSYS_CONFIG_BLUETOOTH_TOGGLE
update_bluetooth_button_wait_state(btn & PBSYS_CONFIG_BLUETOOTH_TOGGLE_BUTTON);
#endif // PBSYS_CONFIG_BLUETOOTH_TOGGLE

#if PBSYS_CONFIG_HMI_NUM_SLOTS
update_left_right_button_wait_state(btn & PBIO_BUTTON_LEFT, btn & PBIO_BUTTON_RIGHT);
#endif // PBSYS_CONFIG_HMI_NUM_SLOTS
}

pbsys_status_light_poll();
Expand Down
9 changes: 9 additions & 0 deletions lib/pbio/sys/hmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@
#define _PBSYS_SYS_HMI_H_

#include <contiki.h>
#include <pbsys/config.h>

void pbsys_hmi_init(void);
void pbsys_hmi_handle_event(process_event_t event, process_data_t data);
void pbsys_hmi_poll(void);

#if PBSYS_CONFIG_HMI_NUM_SLOTS
uint8_t pbsys_hmi_get_selected_program_slot(void);
#else
static inline uint8_t pbsys_hmi_get_selected_program_slot(void) {
return 0;
}
#endif

#endif // _PBSYS_SYS_HMI_H_
41 changes: 31 additions & 10 deletions lib/pbio/sys/light_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <pbsys/status.h>

#include "../src/light/light_matrix.h"
#include "hmi.h"

#if PBSYS_CONFIG_HUB_LIGHT_MATRIX

Expand Down Expand Up @@ -46,25 +47,45 @@ static const pbio_light_matrix_funcs_t pbsys_hub_light_matrix_funcs = {
.set_pixel = pbsys_hub_light_matrix_set_pixel,
};

static void pbsys_hub_light_matrix_clear(void) {
// turn of all pixels
/**
* Clears the idle UI, leaving the selected slot in place.
*/
static void pbsys_hub_light_matrix_clear_idle_ui(void) {

uint8_t slot = pbsys_hmi_get_selected_program_slot();

// turn of all pixels except program slot.
for (uint8_t r = 0; r < pbsys_hub_light_matrix->size; r++) {
for (uint8_t c = 0; c < pbsys_hub_light_matrix->size; c++) {
pbsys_hub_light_matrix_set_pixel(pbsys_hub_light_matrix, r, c, 0);
bool on = r == 4 && c == slot;
pbsys_hub_light_matrix_set_pixel(pbsys_hub_light_matrix, r, c, on ? 100 : 0);
}
}
}

static void pbsys_hub_light_matrix_show_stop_sign(uint8_t brightness) {
/**
* Displays the idle UI. Has a square stop sign and selected slot on bottom row.
*
* @param brightness Brightness (0--100%).
*/
static void pbsys_hub_light_matrix_show_idle_ui(uint8_t brightness) {

uint8_t slot = pbsys_hmi_get_selected_program_slot();

// 3x3 "stop sign" at top center of light matrix
for (uint8_t r = 0; r < pbsys_hub_light_matrix->size; r++) {
for (uint8_t c = 0; c < pbsys_hub_light_matrix->size; c++) {
uint8_t b = r < 3 && c > 0 && c < 4 ? brightness: 0;
pbsys_hub_light_matrix_set_pixel(pbsys_hub_light_matrix, r, c, b);
bool in_stop_sign = r < 3 && c > 0 && c < 4;
bool in_slot_indicator = r == 4 && c == slot;
pbsys_hub_light_matrix_set_pixel(pbsys_hub_light_matrix, r, c, in_stop_sign || in_slot_indicator ? brightness : 0);
}
}
}

void pbsys_hub_light_matrix_update_program_slot(void) {
pbsys_hub_light_matrix_show_idle_ui(100);
}

// Animation frame for on/off animation.
static uint32_t pbsys_hub_light_matrix_user_power_animation_next(pbio_light_animation_t *animation) {

Expand All @@ -74,7 +95,7 @@ static uint32_t pbsys_hub_light_matrix_user_power_animation_next(pbio_light_anim

// Show the stop sign fading in/out.
brightness += increment;
pbsys_hub_light_matrix_show_stop_sign(brightness);
pbsys_hub_light_matrix_show_idle_ui(brightness);

// Stop at 100% and re-initialize so we can use this again for shutdown.
if (brightness == 100 || brightness == 0) {
Expand Down Expand Up @@ -132,7 +153,7 @@ void pbsys_hub_light_matrix_handle_event(process_event_t event, process_data_t d
if (status == PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING) {
// The user animation updates only a subset of pixels to save time,
// so the rest must be cleared before it starts.
pbsys_hub_light_matrix_clear();
pbsys_hub_light_matrix_clear_idle_ui();
pbio_light_animation_init(&pbsys_hub_light_matrix->animation, pbsys_hub_light_matrix_user_program_animation_next);
pbio_light_animation_start(&pbsys_hub_light_matrix->animation);
} else if (status == PBIO_PYBRICKS_STATUS_SHUTDOWN_REQUEST && !pbsys_status_test(PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING)) {
Expand All @@ -151,8 +172,8 @@ void pbsys_hub_light_matrix_handle_event(process_event_t event, process_data_t d
// If it ended due to forced shutdown, show power-off animation.
pbsys_hub_light_matrix_start_power_animation();
} else {
// If it simply completed, show stop sign.
pbsys_hub_light_matrix_show_stop_sign(100);
// If it simply completed, show stop sign and selected slot.
pbsys_hub_light_matrix_show_idle_ui(100);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions lib/pbio/sys/light_matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
#if PBSYS_CONFIG_HUB_LIGHT_MATRIX
void pbsys_hub_light_matrix_init(void);
void pbsys_hub_light_matrix_handle_event(process_event_t event, process_data_t data);
void pbsys_hub_light_matrix_update_program_slot(void);
#else
#define pbsys_hub_light_matrix_init()
#define pbsys_hub_light_matrix_handle_event(event, data)
#define pbsys_hub_light_matrix_update_program_slot(void)
#endif

#endif // _PBSYS_SYS_LIGHT_MATRIX_H_

0 comments on commit b6fe100

Please sign in to comment.