|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +// Copyright (c) 2025 The Pybricks Authors |
| 3 | +// |
| 4 | +// Display driver for a Virtual Hub |
| 5 | + |
| 6 | +#include <pbdrv/config.h> |
| 7 | + |
| 8 | +#if PBDRV_CONFIG_DISPLAY_VIRTUAL |
| 9 | + |
| 10 | +#include <stdio.h> |
| 11 | +#include <string.h> |
| 12 | + |
| 13 | +#include <pbdrv/display.h> |
| 14 | + |
| 15 | +#include <pbio/error.h> |
| 16 | +#include <pbio/image.h> |
| 17 | +#include <pbio/os.h> |
| 18 | + |
| 19 | +/** |
| 20 | + * User frame buffer. Each value is one pixel with value: |
| 21 | + * |
| 22 | + * 0: Empty / White |
| 23 | + * 1: Light Grey |
| 24 | + * 2: Dark Grey |
| 25 | + * 3: Black |
| 26 | + * |
| 27 | + * Non-atomic updated by the application are allowed. |
| 28 | + */ |
| 29 | +static uint8_t pbdrv_display_user_frame[PBDRV_CONFIG_DISPLAY_NUM_ROWS][PBDRV_CONFIG_DISPLAY_NUM_COLS] __attribute__((section(".noinit"), used)); |
| 30 | + |
| 31 | +/** |
| 32 | + * "Hardware" buffer of the virtual display. |
| 33 | + */ |
| 34 | +static uint8_t pbdrv_display_hardware_frame[PBDRV_CONFIG_DISPLAY_NUM_ROWS][PBDRV_CONFIG_DISPLAY_NUM_COLS] __attribute__((section(".noinit"), used)); |
| 35 | + |
| 36 | +/** |
| 37 | + * Flag to indicate that the user frame has been updated and needs to be |
| 38 | + * encoded and sent to the display driver. |
| 39 | + */ |
| 40 | +static bool pbdrv_display_user_frame_update_requested; |
| 41 | + |
| 42 | +static pbio_os_process_t pbdrv_display_virtual_process; |
| 43 | + |
| 44 | +/** |
| 45 | + * Display driver process. Initializes the display and updates the display |
| 46 | + * with the user frame buffer if the user data was updated. |
| 47 | + */ |
| 48 | +static pbio_error_t pbdrv_display_virtual_process_thread(pbio_os_state_t *state, void *context) { |
| 49 | + |
| 50 | + PBIO_OS_ASYNC_BEGIN(state); |
| 51 | + |
| 52 | + // Clear display to start with. |
| 53 | + memset(&pbdrv_display_user_frame, 0, sizeof(pbdrv_display_user_frame)); |
| 54 | + pbdrv_display_user_frame_update_requested = true; |
| 55 | + |
| 56 | + // Update the display with the user frame buffer, if changed. |
| 57 | + for (;;) { |
| 58 | + PBIO_OS_AWAIT_UNTIL(state, pbdrv_display_user_frame_update_requested); |
| 59 | + pbdrv_display_user_frame_update_requested = false; |
| 60 | + memcpy(pbdrv_display_hardware_frame, pbdrv_display_user_frame, sizeof(pbdrv_display_hardware_frame)); |
| 61 | + } |
| 62 | + |
| 63 | + PBIO_OS_ASYNC_END(PBIO_SUCCESS); |
| 64 | +} |
| 65 | + |
| 66 | +/** |
| 67 | + * Image corresponding to the display. |
| 68 | + */ |
| 69 | +static pbio_image_t display_image; |
| 70 | + |
| 71 | +/** |
| 72 | + * Initialize the display driver. |
| 73 | + */ |
| 74 | +void pbdrv_display_init(void) { |
| 75 | + |
| 76 | + // Initialize image. |
| 77 | + pbio_image_init(&display_image, (uint8_t *)pbdrv_display_user_frame, |
| 78 | + PBDRV_CONFIG_DISPLAY_NUM_COLS, PBDRV_CONFIG_DISPLAY_NUM_ROWS, |
| 79 | + PBDRV_CONFIG_DISPLAY_NUM_COLS); |
| 80 | + |
| 81 | + pbio_os_process_start(&pbdrv_display_virtual_process, pbdrv_display_virtual_process_thread, NULL); |
| 82 | +} |
| 83 | + |
| 84 | +pbio_image_t *pbdrv_display_get_image(void) { |
| 85 | + return &display_image; |
| 86 | +} |
| 87 | + |
| 88 | +uint8_t pbdrv_display_get_max_value(void) { |
| 89 | + return 3; |
| 90 | +} |
| 91 | + |
| 92 | +void pbdrv_display_update(void) { |
| 93 | + pbdrv_display_user_frame_update_requested = true; |
| 94 | + pbio_os_request_poll(); |
| 95 | +} |
| 96 | + |
| 97 | +#endif // PBDRV_CONFIG_DISPLAY_VIRTUAL |
0 commit comments