Skip to content
Merged
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
2 changes: 1 addition & 1 deletion lib/pbio/drv/usb/usb_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ PROCESS(pbdrv_usb_process, "USB");
// to/from FIFOs in 32-bit chunks.
static uint8_t usb_in_buf[USBD_PYBRICKS_MAX_PACKET_SIZE] __aligned(4);
static uint8_t usb_response_buf[PBIO_PYBRICKS_USB_MESSAGE_SIZE(sizeof(uint32_t))] __aligned(4);
static uint8_t usb_status_buf[PBIO_PYBRICKS_USB_MESSAGE_SIZE(PBSYS_STATUS_REPORT_SIZE)] __aligned(4);
static uint8_t usb_status_buf[PBIO_PYBRICKS_USB_MESSAGE_SIZE(PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE)] __aligned(4);
static uint8_t usb_stdout_buf[USBD_PYBRICKS_MAX_PACKET_SIZE] __aligned(4);
static volatile uint32_t usb_in_sz;
static volatile uint32_t usb_response_sz;
Expand Down
4 changes: 4 additions & 0 deletions lib/pbio/include/pbio/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pbio_error_t pbio_color_light_on_hsv(pbio_color_light_t *light, const pbio_color
pbio_error_t pbio_color_light_on(pbio_color_light_t *light, pbio_color_t color);
pbio_error_t pbio_color_light_off(pbio_color_light_t *light);
void pbio_color_light_start_blink_animation(pbio_color_light_t *light, const pbio_color_hsv_t *hsv, const uint16_t *cells);
void pbio_color_light_start_breathe_animation(pbio_color_light_t *light, uint16_t hue);
void pbio_color_light_start_animation(pbio_color_light_t *light, uint16_t interval, const pbio_color_compressed_hsv_t *cells);

#else // PBIO_CONFIG_LIGHT
Expand All @@ -57,6 +58,9 @@ static inline pbio_error_t pbio_color_light_off(pbio_color_light_t *light) {
static inline void pbio_color_light_start_blink_animation(pbio_color_light_t *light, const pbio_color_hsv_t *hsv, const uint16_t *cells) {
}

static inline void pbio_color_light_start_breathe_animation(pbio_color_light_t *light, uint16_t hue) {
}

static inline void pbio_color_light_start_animation(pbio_color_light_t *light, uint16_t interval, const pbio_color_compressed_hsv_t *cells) {
}

Expand Down
6 changes: 3 additions & 3 deletions lib/pbio/include/pbio/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ typedef enum {
* Status report event.
*
* The payload is one 32-bit little-endian unsigned integer containing
* ::pbio_pybricks_status_t flags and a one byte program identifier
* ::pbio_pybricks_status_flags_t flags and a one byte program identifier
* representing the currently active program if it is running.
*
* @since Pybricks Profile v1.0.0. Program identifier added in Pybricks Profile v1.4.0.
Expand Down Expand Up @@ -331,12 +331,12 @@ typedef enum {
PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED = 9,
/** Total number of indications. */
NUM_PBIO_PYBRICKS_STATUS,
} pbio_pybricks_status_t;
} pbio_pybricks_status_flags_t;

/**
* Converts a status value to a bit flag.
*
* @param [in] status A ::pbio_pybricks_status_t value.
* @param [in] status A ::pbio_pybricks_status_flags_t value.
* @return A bit flag corresponding to @p status.
*/
#define PBIO_PYBRICKS_STATUS_FLAG(status) (1 << status)
Expand Down
22 changes: 6 additions & 16 deletions lib/pbio/include/pbsys/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,15 @@

#include <pbio/protocol.h>

#define PBSYS_STATUS_REPORT_SIZE 7

/**
* Status flag change.
*/
typedef enum {
/** System status indicator was set. */
PBSYS_STATUS_CHANGE_SET,
/** System status indicator was cleared. */
PBSYS_STATUS_CHANGE_CLEARED,
} pbsys_status_change_t;

void pbsys_status_set_program_id(pbio_pybricks_user_program_id_t program_id);
void pbsys_status_set(pbio_pybricks_status_t status);
void pbsys_status_clear(pbio_pybricks_status_t status);
bool pbsys_status_test(pbio_pybricks_status_t status);
bool pbsys_status_test_debounce(pbio_pybricks_status_t status, bool state, uint32_t ms);
void pbsys_status_set(pbio_pybricks_status_flags_t status);
void pbsys_status_clear(pbio_pybricks_status_flags_t status);
bool pbsys_status_test(pbio_pybricks_status_flags_t status);
bool pbsys_status_test_debounce(pbio_pybricks_status_flags_t status, bool state, uint32_t ms);
uint32_t pbsys_status_get_flags(void);
uint32_t pbsys_status_get_status_report(uint8_t *buf);
void pbsys_status_increment_selected_slot(bool increment);
pbio_pybricks_user_program_id_t pbsys_status_get_selected_slot(void);

#endif // _PBSYS_STATUS_H_

Expand Down
35 changes: 35 additions & 0 deletions lib/pbio/src/light/color_light.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,41 @@ void pbio_color_light_start_blink_animation(pbio_color_light_t *light, const pbi
pbio_light_animation_start(&light->animation);
}

static uint8_t breathe_animation_progress;
static uint16_t breathe_animation_hue;

static uint32_t pbio_color_light_breathe_next(pbio_light_animation_t *animation) {

pbio_color_light_t *light = PBIO_CONTAINER_OF(animation, pbio_color_light_t, animation);

// The brightness pattern has the form /\ through which we cycle in N steps.
// It is reset back to the start when the user program starts.
const uint8_t animation_progress_max = 200;

pbio_color_hsv_t hsv = {
.h = breathe_animation_hue,
.s = 100,
.v = breathe_animation_progress < animation_progress_max / 2 ?
breathe_animation_progress :
animation_progress_max - breathe_animation_progress,
};

light->funcs->set_hsv(light, &hsv);

// This increment controls the speed of the pattern and wraps on completion
breathe_animation_progress = (breathe_animation_progress + 4) % animation_progress_max;

return 40;
}

void pbio_color_light_start_breathe_animation(pbio_color_light_t *light, uint16_t hue) {
pbio_color_light_stop_animation(light);
breathe_animation_progress = 0;
breathe_animation_hue = hue;
pbio_light_animation_init(&light->animation, pbio_color_light_breathe_next);
pbio_light_animation_start(&light->animation);
}

static uint32_t pbio_color_light_animate_next(pbio_light_animation_t *animation) {
pbio_color_light_t *light = PBIO_CONTAINER_OF(animation, pbio_color_light_t, animation);

Expand Down
2 changes: 1 addition & 1 deletion lib/pbio/sys/bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ static PT_THREAD(pbsys_bluetooth_monitor_status(struct pt *pt)) {
// wait for status to change or timeout
PT_WAIT_UNTIL(pt, pbsys_status_get_flags() != old_status_flags ||
#if PBSYS_CONFIG_HMI_NUM_SLOTS
pbsys_hmi_get_selected_program_slot() != old_program_slot ||
pbsys_status_get_selected_slot() != old_program_slot ||
#endif
etimer_expired(&timer));

Expand Down
2 changes: 1 addition & 1 deletion lib/pbio/sys/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pbio_pybricks_error_t pbsys_command(const uint8_t *data, uint32_t size) {
}
// Use payload as program ID, otherwise use active user slot.
return pbio_pybricks_error_from_pbio_error(
pbsys_main_program_request_start((size == 2 ? data[1] : pbsys_hmi_get_selected_program_slot()), PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_REMOTE));
pbsys_main_program_request_start((size == 2 ? data[1] : pbsys_status_get_selected_slot()), PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_REMOTE));
}
#if PBSYS_CONFIG_FEATURE_BUILTIN_USER_PROGRAM_REPL
case PBIO_PYBRICKS_COMMAND_START_REPL:
Expand Down
28 changes: 5 additions & 23 deletions lib/pbio/sys/hmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,11 @@
#define DEBUG_PRINT(...)
#endif

// The selected slot is not persistent across reboot, so that the first slot
// is always active on boot. This allows consistently starting programs without
// visibility of the display.
static uint8_t selected_slot = 0;

/**
* 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;
}

void pbsys_hmi_init(void) {
pbsys_status_light_init();
pbsys_hub_light_matrix_init();
}

void pbsys_hmi_handle_status_change(pbsys_status_change_t event, pbio_pybricks_status_t data) {
pbsys_status_light_handle_status_change(event, data);
}

/**
* Polls the HMI.
*
Expand Down Expand Up @@ -110,7 +92,7 @@ static pbio_error_t pbsys_hmi_launch_program_with_button(pbio_os_state_t *state)

if (pressed & PBIO_BUTTON_CENTER) {

pbio_error_t err = pbsys_main_program_request_start(selected_slot, PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_HUB_UI);
pbio_error_t err = pbsys_main_program_request_start(pbsys_status_get_selected_slot(), PBSYS_MAIN_PROGRAM_START_REQUEST_TYPE_HUB_UI);

if (err == PBIO_SUCCESS) {
// Program is available so we can leave this UI thread and
Expand All @@ -124,14 +106,14 @@ static pbio_error_t pbsys_hmi_launch_program_with_button(pbio_os_state_t *state)
}

// On right, increment slot when possible.
if ((pressed & PBIO_BUTTON_RIGHT) && selected_slot < 4) {
selected_slot++;
if (pressed & PBIO_BUTTON_RIGHT) {
pbsys_status_increment_selected_slot(true);
pbsys_hub_light_matrix_update_program_slot();
}

// On left, decrement slot when possible.
if ((pressed & PBIO_BUTTON_LEFT) && selected_slot > 0) {
selected_slot--;
if (pressed & PBIO_BUTTON_LEFT) {
pbsys_status_increment_selected_slot(false);
pbsys_hub_light_matrix_update_program_slot();
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/pbio/sys/hmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
#include <pbsys/status.h>

void pbsys_hmi_init(void);
void pbsys_hmi_handle_status_change(pbsys_status_change_t event, pbio_pybricks_status_t data);
void pbsys_hmi_poll(void);
pbio_error_t pbsys_hmi_await_program_selection(void);
uint8_t pbsys_hmi_get_selected_program_slot(void);

#endif // _PBSYS_SYS_HMI_H_
42 changes: 1 addition & 41 deletions lib/pbio/sys/light.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void pbsys_status_light_init(void) {
#endif
}

static void pbsys_status_light_update_patterns(void) {
void pbsys_status_light_handle_status_change(void) {

// Warning pattern precedence.
pbsys_status_light_indication_warning_t warning_indication = PBSYS_STATUS_LIGHT_INDICATION_WARNING_NONE;
Expand Down Expand Up @@ -222,46 +222,6 @@ static void pbsys_status_light_update_patterns(void) {
}
}

#if PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS
static uint8_t animation_progress;

static uint32_t default_user_program_light_animation_next(pbio_light_animation_t *animation) {
// The brightness pattern has the form /\ through which we cycle in N steps.
// It is reset back to the start when the user program starts.
const uint8_t animation_progress_max = 200;

pbio_color_hsv_t hsv = {
.h = PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS_HUE,
.s = 100,
.v = animation_progress < animation_progress_max / 2 ?
animation_progress :
animation_progress_max - animation_progress,
};

pbsys_status_light_main->funcs->set_hsv(pbsys_status_light_main, &hsv);

// This increment controls the speed of the pattern and wraps on completion
animation_progress = (animation_progress + 4) % animation_progress_max;

return 40;
}
#endif // PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS

void pbsys_status_light_handle_status_change(pbsys_status_change_t event, pbio_pybricks_status_t data) {
if (event == PBSYS_STATUS_CHANGE_SET || event == PBSYS_STATUS_CHANGE_CLEARED) {
pbsys_status_light_update_patterns();
}
if (event == PBSYS_STATUS_CHANGE_SET && (pbio_pybricks_status_t)(intptr_t)data == PBIO_PYBRICKS_STATUS_USER_PROGRAM_RUNNING) {
#if PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS
animation_progress = 0;
pbio_light_animation_init(&pbsys_status_light_main->animation, default_user_program_light_animation_next);
pbio_light_animation_start(&pbsys_status_light_main->animation);
#else
pbio_color_light_off(pbsys_status_light_main);
#endif // PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS
}
}

/**
* Advances the light to the next state in the pattern.
*
Expand Down
4 changes: 2 additions & 2 deletions lib/pbio/sys/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

#if PBSYS_CONFIG_STATUS_LIGHT
void pbsys_status_light_init(void);
void pbsys_status_light_handle_status_change(pbsys_status_change_t event, pbio_pybricks_status_t data);
void pbsys_status_light_handle_status_change(void);
void pbsys_status_light_poll(void);
#else
#define pbsys_status_light_init()
#define pbsys_status_light_handle_status_change(event, data)
#define pbsys_status_light_handle_status_change()
#define pbsys_status_light_poll()
#endif

Expand Down
9 changes: 8 additions & 1 deletion lib/pbio/sys/light_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static void pbsys_hub_light_matrix_show_idle_ui(uint8_t brightness) {
for (uint8_t c = 0; c < pbsys_hub_light_matrix->size; c++) {
bool is_on = r < 3 && c > 0 && c < 4;
#if PBSYS_CONFIG_HMI_NUM_SLOTS
is_on |= (r == 4 && c == pbsys_hmi_get_selected_program_slot());
is_on |= (r == 4 && c == pbsys_status_get_selected_slot());
#endif
pbsys_hub_light_matrix_set_pixel(pbsys_hub_light_matrix, r, c, is_on ? brightness : 0);
}
Expand Down Expand Up @@ -158,6 +158,13 @@ static uint32_t pbsys_hub_light_matrix_user_program_animation_next(pbio_light_an
* @param start @c true for start or @c false for stop.
*/
void pbsys_hub_light_matrix_handle_user_program_start(bool start) {

#if PBSYS_CONFIG_HUB_LIGHT_MATRIX_DISPLAY
pbio_image_fill(pbdrv_display_get_image(), 0);
pbdrv_display_update();
return;
#endif

if (start) {
// The user animation updates only a subset of pixels to save time,
// so the rest must be cleared before it starts.
Expand Down
9 changes: 9 additions & 0 deletions lib/pbio/sys/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "program_stop.h"
#include "storage.h"
#include <pbsys/program_stop.h>
#include <pbsys/light.h>
#include <pbsys/host.h>

// Singleton with information about the currently (or soon) active program.
Expand Down Expand Up @@ -103,6 +104,14 @@ int main(int argc, char **argv) {
pbsys_host_stdin_set_callback(pbsys_main_stdin_event);
pbsys_hub_light_matrix_handle_user_program_start(true);

#if PBSYS_CONFIG_STATUS_LIGHT
#if PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS
pbio_color_light_start_breathe_animation(pbsys_status_light_main, PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS_HUE);
#else
pbio_color_light_off(pbsys_status_light_main);
#endif
#endif

// Handle pending events triggered by the status change, such as
// starting status light animation.
while (pbio_os_run_processes_once()) {
Expand Down
Loading