From 1a1dbef992442682413f6103e36440a26bc2dad7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 25 Jan 2019 16:59:18 -0800 Subject: [PATCH] Hook up the terminal based on the first display. --- main.c | 7 ++ ports/atmel-samd/mpconfigport.h | 1 + shared-bindings/displayio/Display.c | 12 +- shared-bindings/displayio/TileGrid.c | 6 +- shared-bindings/displayio/TileGrid.h | 2 +- shared-module/displayio/Display.c | 13 ++ shared-module/displayio/Group.c | 18 ++- shared-module/displayio/TileGrid.c | 15 ++- shared-module/displayio/TileGrid.h | 1 + shared-module/displayio/__init__.c | 106 +++------------- shared-module/displayio/__init__.h | 3 + shared-module/terminalio/Terminal.c | 44 ++++++- supervisor/memory.h | 3 + supervisor/shared/display.c | 177 +++++++++++++++++++++++++++ supervisor/shared/display.h | 15 ++- supervisor/shared/memory.c | 6 + supervisor/shared/serial.c | 4 + supervisor/supervisor.mk | 3 +- tools/bitmap_font | 2 +- tools/gen_display_resources.py | 142 ++++++++++++++++++--- 20 files changed, 454 insertions(+), 126 deletions(-) create mode 100644 supervisor/shared/display.c diff --git a/main.c b/main.c index e137f7d47d..45c6da817d 100755 --- a/main.c +++ b/main.c @@ -209,6 +209,7 @@ bool run_code_py(safe_mode_t safe_mode) { #endif stop_mp(); free_memory(heap); + supervisor_move_memory(); reset_port(); reset_board_busses(); @@ -221,6 +222,10 @@ bool run_code_py(safe_mode_t safe_mode) { } // Wait for connection or character. + if (!serial_connected_at_start) { + serial_write_compressed(translate("\nCode done running. Waiting for USB.\n")); + } + bool serial_connected_before_animation = false; rgb_status_animation_t animation; prep_rgb_status_animation(&result, found_main, safe_mode, &animation); @@ -342,6 +347,7 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { reset_board(); stop_mp(); free_memory(heap); + supervisor_move_memory(); } } @@ -362,6 +368,7 @@ int run_repl(void) { reset_board(); stop_mp(); free_memory(heap); + supervisor_move_memory(); autoreload_resume(); return exit_code; } diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 811d4eda48..4c8002c561 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -467,6 +467,7 @@ extern const struct _mp_obj_module_t pixelbuf_module; mp_obj_t rtc_time_source; \ FLASH_ROOT_POINTERS \ mp_obj_t gamepad_singleton; \ + mp_obj_t terminal_tilegrid_tiles; \ NETWORK_ROOT_POINTERS \ void run_background_tasks(void); diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index d61732f6f9..1838228afa 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -133,11 +133,15 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a //| STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_t native_layer = mp_instance_cast_to_native_base(group_in, &displayio_group_type); - if (native_layer == MP_OBJ_NULL) { - mp_raise_ValueError(translate("Must be a Group subclass.")); + displayio_group_t* group = NULL; + if (group_in != mp_const_none) { + mp_obj_t native_layer = mp_instance_cast_to_native_base(group_in, &displayio_group_type); + if (native_layer == MP_OBJ_NULL) { + mp_raise_ValueError(translate("Must be a Group subclass.")); + } + group = MP_OBJ_TO_PTR(native_layer); } - displayio_group_t* group = MP_OBJ_TO_PTR(native_layer); + common_hal_displayio_display_show(self, group); return mp_const_none; } diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index b8531a9235..0026cd62f8 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -138,9 +138,9 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t); self->base.type = &displayio_tilegrid_type; - common_hal_displayio_tilegrid_construct(self, native, args[ARG_pixel_shader].u_obj, - args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y, - args[ARG_default_tile].u_int); + common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width, + args[ARG_pixel_shader].u_obj, args[ARG_width].u_int, args[ARG_height].u_int, + tile_width, tile_height, x, y, args[ARG_default_tile].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h index f553be423e..a74fa4d39a 100644 --- a/shared-bindings/displayio/TileGrid.h +++ b/shared-bindings/displayio/TileGrid.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t displayio_tilegrid_type; void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, - mp_obj_t pixel_shader, uint16_t width, uint16_t height, + uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile); void common_hal_displayio_tilegrid_get_position(displayio_tilegrid_t *self, int16_t* x, int16_t* y); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 7946111b73..fd082c19d9 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -30,6 +30,8 @@ #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/ParallelBus.h" #include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" #include @@ -47,6 +49,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->set_column_command = set_column_command; self->set_row_command = set_row_command; self->write_ram_command = write_ram_command; + self->refresh = false; self->current_group = NULL; self->colstart = colstart; self->rowstart = rowstart; @@ -86,9 +89,19 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, i += 2 + data_size; } self->end_transaction(self->bus); + + supervisor_start_terminal(width, height); + + // Set the group after initialization otherwise we may send pixels while we delay in + // initialization. + self->refresh = true; + self->current_group = &circuitpython_splash; } void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { + if (root_group == NULL) { + root_group = &circuitpython_splash; + } self->current_group = root_group; common_hal_displayio_display_refresh_soon(self); } diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index 46898fb8e3..bbbd834860 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -105,12 +105,19 @@ bool displayio_group_needs_refresh(displayio_group_t *self) { } for (int32_t i = self->size - 1; i >= 0 ; i--) { mp_obj_t layer = self->children[i]; - if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) { + if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) { + if (displayio_tilegrid_needs_refresh(layer)) { + return true; + } + } else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) { + if (displayio_group_needs_refresh(layer)) { + return true; + } + } else if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) { if (displayio_sprite_needs_refresh(layer)) { return true; } } - // TODO: Tiled layer } return false; } @@ -119,9 +126,12 @@ void displayio_group_finish_refresh(displayio_group_t *self) { self->needs_refresh = false; for (int32_t i = self->size - 1; i >= 0 ; i--) { mp_obj_t layer = self->children[i]; - if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) { + if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) { + displayio_tilegrid_finish_refresh(layer); + } else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) { + displayio_group_finish_refresh(layer); + } else if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) { displayio_sprite_finish_refresh(layer); } - // TODO: Tiled layer } } diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 44874e2838..ed724bf10d 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -33,6 +33,7 @@ #include "shared-bindings/displayio/Shape.h" void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, + uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) { uint32_t total_tiles = width * height; @@ -44,8 +45,9 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ self->tiles = (uint8_t*) m_malloc(total_tiles, false); self->inline_tiles = false; } + self->bitmap_width_in_tiles = bitmap_width_in_tiles; self->width_in_tiles = width; - self->height_in_tiles = width; + self->height_in_tiles = height; self->total_width = width * tile_width; self->total_height = height * tile_height; self->tile_width = tile_width; @@ -87,10 +89,13 @@ bool displayio_tilegrid_get_pixel(displayio_tilegrid_t *self, int16_t x, int16_t if (self->inline_tiles) { tiles = (uint8_t*) &self->tiles; } + if (tiles == NULL) { + return false; + } uint16_t tile_location = (y / self->tile_height) * self->width_in_tiles + x / self->tile_width; uint8_t tile = tiles[tile_location]; - uint16_t tile_x = tile_x = (tile % self->width_in_tiles) * self->tile_width + x % self->tile_width; - uint16_t tile_y = tile_y = (tile / self->width_in_tiles) * self->tile_height + y % self->tile_height; + uint16_t tile_x = tile_x = (tile % self->bitmap_width_in_tiles) * self->tile_width + x % self->tile_width; + uint16_t tile_y = tile_y = (tile / self->bitmap_width_in_tiles) * self->tile_height + y % self->tile_height; uint32_t value = 0; if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { @@ -118,7 +123,11 @@ void common_hal_displayio_textgrid_set_tile(displayio_tilegrid_t *self, uint16_t if (self->inline_tiles) { tiles = (uint8_t*) &self->tiles; } + if (tiles == NULL) { + return; + } tiles[y * self->width_in_tiles + x] = tile_index; + self->needs_refresh = true; } bool displayio_tilegrid_needs_refresh(displayio_tilegrid_t *self) { diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index c24a606a30..84e3e7ef23 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -38,6 +38,7 @@ typedef struct { mp_obj_t pixel_shader; uint16_t x; uint16_t y; + uint16_t bitmap_width_in_tiles; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t total_width; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 61228f8d27..dbfeacc3d5 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -9,6 +9,7 @@ #include "shared-bindings/displayio/Palette.h" #include "shared-bindings/displayio/Sprite.h" #include "supervisor/shared/display.h" +#include "supervisor/memory.h" #include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; @@ -68,76 +69,24 @@ void displayio_refresh_displays(void) { } } -uint32_t blinka_bitmap_data[32] = { - 0x00000011, 0x11000000, - 0x00000111, 0x53100000, - 0x00000111, 0x56110000, - 0x00000111, 0x11140000, - 0x00000111, 0x20002000, - 0x00000011, 0x13000000, - 0x00000001, 0x11200000, - 0x00000000, 0x11330000, - 0x00000000, 0x01122000, - 0x00001111, 0x44133000, - 0x00032323, 0x24112200, - 0x00111114, 0x44113300, - 0x00323232, 0x34112200, - 0x11111144, 0x44443300, - 0x11111111, 0x11144401, - 0x23232323, 0x21111110 -}; +void common_hal_displayio_release_displays(void) { + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; + if (bus_type == NULL) { + continue; + } else if (bus_type == &displayio_fourwire_type) { + common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); + } else if (bus_type == &displayio_parallelbus_type) { + common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus); + } + displays[i].fourwire_bus.base.type = &mp_type_NoneType; + } + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + displays[i].display.base.type = &mp_type_NoneType; + } -displayio_bitmap_t blinka_bitmap = { - .base = {.type = &displayio_bitmap_type }, - .width = 16, - .height = 16, - .data = blinka_bitmap_data, - .stride = 2, - .bits_per_value = 4, - .x_shift = 3, - .x_mask = 0x7, - .bitmask = 0xf -}; - -uint32_t blinka_transparency[1] = {0x80000000}; - -// These colors are RGB 565 with the bytes swapped. -uint32_t blinka_colors[8] = {0x78890000, 0x9F86B8FC, 0xffff0D5A, 0x0000f501, - 0x00000000, 0x00000000, 0x00000000, 0x00000000}; - -displayio_palette_t blinka_palette = { - .base = {.type = &displayio_palette_type }, - .opaque = blinka_transparency, - .colors = blinka_colors, - .color_count = 16, - .needs_refresh = false -}; - -displayio_sprite_t blinka_sprite = { - .base = {.type = &displayio_sprite_type }, - .bitmap = &blinka_bitmap, - .pixel_shader = &blinka_palette, - .x = 0, - .y = 0, - .width = 16, - .height = 16, - .needs_refresh = false -}; - -mp_obj_t splash_children[1] = { - &blinka_sprite, -}; - -displayio_group_t splash = { - .base = {.type = &displayio_group_type }, - .x = 0, - .y = 0, - .scale = 2, - .size = 1, - .max_size = 1, - .children = splash_children, - .needs_refresh = true -}; + supervisor_stop_terminal(); +} void reset_displays(void) { // The SPI buses used by FourWires may be allocated on the heap so we need to move them inline. @@ -168,23 +117,6 @@ void reset_displays(void) { continue; } displayio_display_obj_t* display = &displays[i].display; - common_hal_displayio_display_show(display, &splash); - } -} - -void common_hal_displayio_release_displays(void) { - for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; - if (bus_type == NULL) { - continue; - } else if (bus_type == &displayio_fourwire_type) { - common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); - } else if (bus_type == &displayio_parallelbus_type) { - common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus); - } - displays[i].fourwire_bus.base.type = &mp_type_NoneType; - } - for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - displays[i].display.base.type = &mp_type_NoneType; + common_hal_displayio_display_show(display, &circuitpython_splash); } } diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index fdabd4ec4e..5b56ed55cd 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -29,6 +29,7 @@ #include "shared-bindings/displayio/Display.h" #include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/ParallelBus.h" typedef struct { @@ -41,6 +42,8 @@ typedef struct { extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; +extern displayio_group_t circuitpython_splash; + void displayio_refresh_displays(void); void reset_displays(void); diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index c47f9f6cf8..1cd5d341e8 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -28,7 +28,7 @@ #include "shared-bindings/displayio/TileGrid.h" -void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t* tilegrid, uint8_t* unicode_characters, uint16_t unicode_characters_len) { +void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, displayio_tilegrid_t* tilegrid, const uint8_t* unicode_characters, uint16_t unicode_characters_len) { self->cursor_x = 0; self->cursor_y = 0; self->tilegrid = tilegrid; @@ -38,6 +38,7 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, const byte *data, size_t len, int *errcode) { const byte* i = data; + uint16_t start_y = self->cursor_y; while (i < data + len) { unichar c = utf8_get_char(i); i = utf8_next_char(i); @@ -51,6 +52,40 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con self->cursor_x = 0; } else if (c == '\n') { self->cursor_y++; + // Commands below are used by MicroPython in the REPL + } else if (c == '\b') { + if (self->cursor_x > 0) { + self->cursor_x--; + } + } else if (c == 0x1b) { + if (i[0] == '[') { + if (i[1] == 'K') { + // Clear the rest of the line. + for (uint16_t j = self->cursor_x; j < self->tilegrid->width_in_tiles; j++) { + common_hal_displayio_textgrid_set_tile(self->tilegrid, j, self->cursor_y, 0); + } + i += 2; + } else { + // Handle commands of the form \x1b[####D + uint16_t n = 0; + uint8_t j = 1; + for (; j < 6; j++) { + if ('0' <= i[j] && i[j] <= '9') { + n = n * 10 + (i[j] - '0'); + } else { + c = i[j]; + } + } + if (c == 'D') { + if (n > self->cursor_x) { + self->cursor_x = 0; + } else { + self->cursor_x -= n; + } + i += j; + } + } + } } } else { // Do a linear search of the mapping for unicode. @@ -73,6 +108,13 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con if (self->cursor_y >= self->tilegrid->height_in_tiles) { self->cursor_y %= self->tilegrid->height_in_tiles; } + if (self->cursor_y != start_y) { + // clear the new row + for (uint16_t j = 0; j < self->tilegrid->width_in_tiles; j++) { + common_hal_displayio_textgrid_set_tile(self->tilegrid, j, self->cursor_y, 0); + start_y = self->cursor_y; + } + } } return i - data; } diff --git a/supervisor/memory.h b/supervisor/memory.h index c89f14bd9e..f557744ae5 100755 --- a/supervisor/memory.h +++ b/supervisor/memory.h @@ -57,4 +57,7 @@ static inline uint16_t align32_size(uint16_t size) { return size; } +// Called after the heap is freed in case the supervisor wants to save some values. +void supervisor_move_memory(void); + #endif // MICROPY_INCLUDED_SUPERVISOR_MEMORY_H diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c new file mode 100644 index 0000000000..18693266ff --- /dev/null +++ b/supervisor/shared/display.c @@ -0,0 +1,177 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "supervisor/shared/display.h" + +#include + +#include "py/mpstate.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-bindings/displayio/Palette.h" +#include "shared-bindings/displayio/Sprite.h" +#include "supervisor/memory.h" + +extern uint32_t blinka_bitmap_data[]; +extern displayio_bitmap_t blinka_bitmap; +extern displayio_group_t circuitpython_splash; + +static supervisor_allocation* tilegrid_tiles = NULL; + +void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { + displayio_tilegrid_t* grid = &supervisor_terminal_text_grid; + uint16_t width_in_tiles = (width_px - blinka_bitmap.width) / grid->tile_width; + // determine scale based on h + uint8_t scale = 1; + if (width_in_tiles > 80) { + scale = 2; + } + width_in_tiles = (width_px - blinka_bitmap.width * scale) / (grid->tile_width * scale); + uint16_t height_in_tiles = height_px / (grid->tile_height * scale); + circuitpython_splash.scale = scale; + + uint16_t total_tiles = width_in_tiles * height_in_tiles; + + // First try to allocate outside the heap. This will fail when the VM is running. + tilegrid_tiles = allocate_memory(total_tiles, false); + uint8_t* tiles; + if (tilegrid_tiles == NULL) { + tiles = m_malloc(total_tiles, true); + MP_STATE_VM(terminal_tilegrid_tiles) = tiles; + } else { + tiles = (uint8_t*) tilegrid_tiles->ptr; + } + + if (tiles == NULL) { + return; + } + + grid->width_in_tiles = width_in_tiles; + grid->height_in_tiles = height_in_tiles; + grid->total_width = width_in_tiles * grid->tile_width; + grid->total_height = height_in_tiles * grid->tile_height; + grid->tiles = tiles; + + supervisor_terminal.cursor_x = 0; + supervisor_terminal.cursor_y = 0; +} + +void supervisor_stop_terminal(void) { + if (tilegrid_tiles != NULL) { + free_memory(tilegrid_tiles); + supervisor_terminal_text_grid.inline_tiles = false; + supervisor_terminal_text_grid.tiles = NULL; + } +} + +void supervisor_display_move_memory(void) { + displayio_tilegrid_t* grid = &supervisor_terminal_text_grid; + if (MP_STATE_VM(terminal_tilegrid_tiles) == NULL || grid->tiles != MP_STATE_VM(terminal_tilegrid_tiles)) { + return; + } + uint16_t total_tiles = grid->width_in_tiles * grid->height_in_tiles; + + tilegrid_tiles = allocate_memory(total_tiles, false); + if (tilegrid_tiles != NULL) { + memcpy(tilegrid_tiles->ptr, grid->tiles, total_tiles); + grid->tiles = (uint8_t*) tilegrid_tiles->ptr; + } else { + grid->tiles = NULL; + grid->inline_tiles = false; + } + MP_STATE_VM(terminal_tilegrid_tiles) = NULL; +} + +uint32_t blinka_bitmap_data[32] = { + 0x00000011, 0x11000000, + 0x00000111, 0x53100000, + 0x00000111, 0x56110000, + 0x00000111, 0x11140000, + 0x00000111, 0x20002000, + 0x00000011, 0x13000000, + 0x00000001, 0x11200000, + 0x00000000, 0x11330000, + 0x00000000, 0x01122000, + 0x00001111, 0x44133000, + 0x00032323, 0x24112200, + 0x00111114, 0x44113300, + 0x00323232, 0x34112200, + 0x11111144, 0x44443300, + 0x11111111, 0x11144401, + 0x23232323, 0x21111110 +}; + +displayio_bitmap_t blinka_bitmap = { + .base = {.type = &displayio_bitmap_type }, + .width = 16, + .height = 16, + .data = blinka_bitmap_data, + .stride = 2, + .bits_per_value = 4, + .x_shift = 3, + .x_mask = 0x7, + .bitmask = 0xf +}; + +uint32_t blinka_transparency[1] = {0x80000000}; + +// These colors are RGB 565 with the bytes swapped. +uint32_t blinka_colors[8] = {0x78890000, 0x9F86B8FC, 0xffff0D5A, 0x0000f501, + 0x00000000, 0x00000000, 0x00000000, 0x00000000}; + +displayio_palette_t blinka_palette = { + .base = {.type = &displayio_palette_type }, + .opaque = blinka_transparency, + .colors = blinka_colors, + .color_count = 16, + .needs_refresh = false +}; + +displayio_sprite_t blinka_sprite = { + .base = {.type = &displayio_sprite_type }, + .bitmap = &blinka_bitmap, + .pixel_shader = &blinka_palette, + .x = 0, + .y = 0, + .width = 16, + .height = 16, + .needs_refresh = false +}; + +mp_obj_t splash_children[2] = { + &blinka_sprite, + &supervisor_terminal_text_grid +}; + +displayio_group_t circuitpython_splash = { + .base = {.type = &displayio_group_type }, + .x = 0, + .y = 0, + .scale = 2, + .size = 2, + .max_size = 2, + .children = splash_children, + .needs_refresh = true +}; diff --git a/supervisor/shared/display.h b/supervisor/shared/display.h index 5c420e590f..cca9079160 100644 --- a/supervisor/shared/display.h +++ b/supervisor/shared/display.h @@ -28,8 +28,21 @@ #define MICROPY_INCLUDED_SUPERVISOR_SHARED_DISPLAY_H #include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/TileGrid.h" +#include "shared-bindings/terminalio/Terminal.h" + // These are autogenerated resources. -const displayio_bitmap_t terminal_font; +// This is fixed so it doesn't need to be in RAM. +extern const displayio_bitmap_t supervisor_terminal_font; + +// These will change so they must live in RAM. +extern displayio_tilegrid_t supervisor_terminal_text_grid; +extern terminalio_terminal_obj_t supervisor_terminal; + +void supervisor_start_terminal(uint16_t width_px, uint16_t height_px); +void supervisor_stop_terminal(void); + +void supervisor_display_move_memory(void); #endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_DISPLAY_H diff --git a/supervisor/shared/memory.c b/supervisor/shared/memory.c index 6c8be3be8a..11133415d1 100755 --- a/supervisor/shared/memory.c +++ b/supervisor/shared/memory.c @@ -28,6 +28,8 @@ #include +#include "supervisor/shared/display.h" + #define CIRCUITPY_SUPERVISOR_ALLOC_COUNT 8 static supervisor_allocation allocations[CIRCUITPY_SUPERVISOR_ALLOC_COUNT]; @@ -114,3 +116,7 @@ supervisor_allocation* allocate_memory(uint32_t length, bool high) { alloc->length = length; return alloc; } + +void supervisor_move_memory(void) { + supervisor_display_move_memory(); +} diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index c57688ddcf..ac5239a844 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -26,6 +26,8 @@ #include +#include "supervisor/shared/display.h" +#include "shared-bindings/terminalio/Terminal.h" #include "supervisor/serial.h" #include "supervisor/usb.h" @@ -48,6 +50,8 @@ bool serial_bytes_available(void) { } void serial_write_substring(const char* text, uint32_t length) { + int errcode; + common_hal_terminalio_terminal_write(&supervisor_terminal, (const uint8_t*) text, length, &errcode); if (!tud_cdc_connected()) { return; } diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 174abd9d91..0e315a7422 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -3,6 +3,7 @@ SRC_SUPERVISOR = \ supervisor/port.c \ supervisor/shared/autoreload.c \ supervisor/shared/board_busses.c \ + supervisor/shared/display.c \ supervisor/shared/filesystem.c \ supervisor/shared/flash.c \ supervisor/shared/micropython.c \ @@ -91,7 +92,7 @@ autogen_usb_descriptor.intermediate: ../../tools/gen_usb_descriptor.py Makefile --output_c_file $(BUILD)/autogen_usb_descriptor.c\ --output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h -CIRCUITPY_DISPLAY_FONT = "fonts/test.bdf" +CIRCUITPY_DISPLAY_FONT = "../../tools/Tecate-bitmap-fonts/bitmap/cherry/cherry-10-r.bdf" $(BUILD)/autogen_display_resources.c: ../../tools/gen_display_resources.py $(HEADER_BUILD)/qstrdefs.generated.h Makefile | $(HEADER_BUILD) $(STEPECHO) "GEN $@" diff --git a/tools/bitmap_font b/tools/bitmap_font index 7320e8ff94..62dd78abdd 160000 --- a/tools/bitmap_font +++ b/tools/bitmap_font @@ -1 +1 @@ -Subproject commit 7320e8ff94312c791aeed1a6956f8640e1dddc66 +Subproject commit 62dd78abdd0b823824fe15d1bab0611246145c23 diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 3bcdc9952b..27ea2a471c 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -1,9 +1,11 @@ import argparse import os +import struct import sys sys.path.append("bitmap_font") +sys.path.append("../../tools/bitmap_font") from adafruit_bitmap_font import bitmap_font @@ -14,16 +16,6 @@ parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=Tru args = parser.parse_args() -args.font - -c_file = args.output_c_file - -c_file.write("""\ - -#include "supervisor/shared/display.h" - -""") - class BitmapStub: def __init__(self, width, height, color_depth): self.width = width @@ -39,30 +31,140 @@ print(f.get_bounding_box()) real_bb = [0, 0] visible_ascii = bytes(range(0x20, 0x7f)).decode("utf-8") -all_characters = visible_ascii +extra_characters = "üàêùéáçãÍóíαψ◌" +all_characters = visible_ascii + extra_characters +filtered_characters = all_characters for c in all_characters: g = f.get_glyph(ord(c)) + if not g: + print("Font missing character:", c, ord(c)) + filtered_characters = filtered_characters.replace(c, "") + extra_characters = extra_characters.replace(c, "") + continue x, y, dx, dy = g["bounds"] - print(c, g["bounds"], g["shift"]) + #print(c, g["bounds"], g["shift"]) if g["shift"][1] != 0: raise RuntimeError("y shift") - real_bb[0] = max(max(real_bb[0], x - dx), g["shift"][0]) + real_bb[0] = max(real_bb[0], x - dx) real_bb[1] = max(real_bb[1], y - dy) -real_bb[1] += 1 -print(real_bb) +#real_bb[1] += 1 +#print(real_bb) tile_x, tile_y = real_bb +total_bits = tile_x * len(all_characters) +total_bits += 32 - total_bits % 32 +bytes_per_row = total_bits // 8 +b = bytearray(bytes_per_row * tile_y) -for c in all_characters: +for x, c in enumerate(filtered_characters): g = f.get_glyph(ord(c)) - #print(c, g["bounds"], g["shift"]) - for row in g["bitmap"].rows: + start_bit = x * tile_x + g["bounds"][2] + start_y = (tile_y - 2) - (g["bounds"][1] + g["bounds"][3]) + # print(c, g["bounds"], g["shift"], tile_y, start_y) + for y, row in enumerate(g["bitmap"].rows): for i in range(g["bounds"][0]): byte = i // 8 bit = i % 8 - # if row[byte] & (1 << (7-bit)) != 0: - # print("*",end="") + if row[byte] & (1 << (7-bit)) != 0: + overall_bit = start_bit + (start_y + y) * bytes_per_row * 8 + i + b[overall_bit // 8] |= 1 << (7 - (overall_bit % 8)) + # print("*",end="") # else: # print("_",end="") #print() + +# print(b) +# print("tile_x = {}".format(tile_x)) +# print("tile_y = {}".format(tile_y)) +# print("tiles = {}".format(len(all_characters))) +# print("font = displayio.Bitmap(tile_x * tiles, tile_y, 2)") +# for row in range(tile_y): +# print("font._load_row({}, {})".format(row, bytes(b[row*bytes_per_row:row*bytes_per_row+bytes_per_row]))) + +# for row in range(tile_y): +# for byte in b[row*bytes_per_row:row*bytes_per_row+bytes_per_row]: +# print("{:08b} ".format(byte),end="") +# print() + +c_file = args.output_c_file + +c_file.write("""\ + +#include "shared-bindings/displayio/Palette.h" +#include "supervisor/shared/display.h" + +""") + +c_file.write("""\ +uint32_t terminal_transparency[1] = {0x00000000}; + +// These colors are RGB 565 with the bytes swapped. +uint32_t terminal_colors[1] = {0xffff0000}; + +displayio_palette_t supervisor_terminal_color = { + .base = {.type = &displayio_palette_type }, + .opaque = terminal_transparency, + .colors = terminal_colors, + .color_count = 2, + .needs_refresh = false +}; +""") + +c_file.write("""\ +displayio_tilegrid_t supervisor_terminal_text_grid = {{ + .base = {{ .type = &displayio_tilegrid_type }}, + .bitmap = (displayio_bitmap_t*) &supervisor_terminal_font, + .pixel_shader = &supervisor_terminal_color, + .x = 16, + .y = 0, + .bitmap_width_in_tiles = {0}, + .width_in_tiles = 1, + .height_in_tiles = 1, + .total_width = {1}, + .total_height = {2}, + .tile_width = {1}, + .tile_height = {2}, + .tiles = NULL, + .needs_refresh = false, + .inline_tiles = false +}}; +""".format(len(all_characters), tile_x, tile_y)) + +c_file.write("""\ +const uint32_t font_bitmap_data[{}] = {{ +""".format(bytes_per_row * tile_y // 4)) + +for i, word in enumerate(struct.iter_unpack(">I", b)): + c_file.write("0x{:08x}, ".format(word[0])) + if (i + 1) % (bytes_per_row // 4) == 0: + c_file.write("\n") + +c_file.write("""\ +}; +""") + +c_file.write("""\ +const displayio_bitmap_t supervisor_terminal_font = {{ + .base = {{.type = &displayio_bitmap_type }}, + .width = {}, + .height = {}, + .data = (uint32_t*) font_bitmap_data, + .stride = {}, + .bits_per_value = 1, + .x_shift = 5, + .x_mask = 0x1f, + .bitmask = 0x1 +}}; +""".format(len(all_characters) * tile_x, tile_y, bytes_per_row / 4)) + +c_file.write("""\ +terminalio_terminal_obj_t supervisor_terminal = {{ + .base = {{.type = &terminalio_terminal_type }}, + .cursor_x = 0, + .cursor_y = 0, + .tilegrid = &supervisor_terminal_text_grid, + .unicode_characters = (const uint8_t*) "{}", + .unicode_characters_len = {} +}}; +""".format(extra_characters, len(extra_characters.encode("utf-8"))))