From 09dc46a98480350b157636ffff8b89470f595f6e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 10 Mar 2020 13:12:01 -0500 Subject: Add Protomatter and FramebufferDisplay --- shared-module/framebufferio/FramebufferDisplay.c | 339 +++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 shared-module/framebufferio/FramebufferDisplay.c (limited to 'shared-module/framebufferio/FramebufferDisplay.c') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c new file mode 100644 index 000000000..967316c21 --- /dev/null +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -0,0 +1,339 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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 "shared-bindings/framebufferio/FramebufferDisplay.h" + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/display_core.h" +#include "supervisor/shared/display.h" +#include "supervisor/shared/tick.h" +#include "supervisor/usb.h" + +#include +#include + +#include "tick.h" + +void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self, + mp_obj_t framebuffer, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, + uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word, + const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, + bool auto_refresh, uint16_t native_frames_per_second) { + // Turn off auto-refresh as we init. + self->auto_refresh = false; + self->framebuffer = framebuffer; + self->framebuffer_protocol = mp_proto_get_or_throw(MP_QSTR_protocol_framebuffer, framebuffer); + + uint16_t ram_width = 0x100; + uint16_t ram_height = 0x100; + + displayio_display_core_construct(&self->core, NULL, width, height, ram_width, ram_height, colstart, rowstart, rotation, + color_depth, grayscale, pixels_in_byte_share_row, bytes_per_cell, reverse_pixels_in_byte, reverse_bytes_in_word); + + self->auto_brightness = auto_brightness; + self->first_manual_refresh = !auto_refresh; + + self->native_frames_per_second = native_frames_per_second; + self->native_ms_per_frame = 1000 / native_frames_per_second; + + supervisor_start_terminal(width, height); + + // Always set the backlight type in case we're reusing memory. + self->backlight_inout.base.type = &mp_type_NoneType; + if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { + pwmout_result_t result = common_hal_pulseio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); + if (result != PWMOUT_OK) { + self->backlight_inout.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); + common_hal_never_reset_pin(backlight_pin); + } else { + self->backlight_pwm.base.type = &pulseio_pwmout_type; + common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm); + } + } + if (!self->auto_brightness && (self->framebuffer_protocol->set_brightness != NULL || self->backlight_inout.base.type != &mp_type_NoneType)) { + common_hal_framebufferio_framebufferdisplay_set_brightness(self, brightness); + } else { + self->current_brightness = -1.0; + } + + // Set the group after initialization otherwise we may send pixels while we delay in + // initialization. + common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash); + self->auto_refresh = auto_refresh; +} + +bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, displayio_group_t* root_group) { + return displayio_display_core_show(&self->core, root_group); +} + +uint16_t common_hal_framebufferio_framebufferdisplay_get_width(framebufferio_framebufferdisplay_obj_t* self){ + return displayio_display_core_get_width(&self->core); +} + +uint16_t common_hal_framebufferio_framebufferdisplay_get_height(framebufferio_framebufferdisplay_obj_t* self){ + return displayio_display_core_get_height(&self->core); +} + +bool common_hal_framebufferio_framebufferdisplay_get_auto_brightness(framebufferio_framebufferdisplay_obj_t* self) { + return self->auto_brightness; +} + +void common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t* self, bool auto_brightness) { + self->auto_brightness = auto_brightness; +} + +mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t* self) { + return self->current_brightness; +} + +bool common_hal_framebufferio_framebufferdisplay_set_brightness(framebufferio_framebufferdisplay_obj_t* self, mp_float_t brightness) { + self->updating_backlight = true; + bool ok = false; + if (self->framebuffer_protocol->set_brightness) { + self->framebuffer_protocol->set_brightness(self->framebuffer, brightness); + ok = true; + } else if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { + common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); + ok = true; + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); + ok = true; + } + self->updating_backlight = false; + if (ok) { + self->current_brightness = brightness; + } + return ok; +} + +mp_obj_t common_hal_framebufferio_framebufferdisplay_get_framebuffer(framebufferio_framebufferdisplay_obj_t* self) { + return self->framebuffer; +} + +STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdisplay_obj_t *self) { + if (self->core.full_refresh) { + self->core.area.next = NULL; + return &self->core.area; + } else if (self->core.current_group != NULL) { + return displayio_group_get_refresh_areas(self->core.current_group, NULL); + } + return NULL; +} + +STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area) { + uint16_t buffer_size = 128; // In uint32_ts + + displayio_area_t clipped; + // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { + return true; + } + uint16_t subrectangles = 1; + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. + if (self->core.colorspace.depth < 8 && !self->core.colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / self->core.colorspace.depth; + if (rows_per_buffer % pixels_per_byte != 0) { + rows_per_buffer -= rows_per_buffer % pixels_per_byte; + } + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + uint16_t remaining_rows = displayio_area_height(&clipped); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1) + }; + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); + + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + + // COULDDO: this arithmetic only supports multiple-of-8 bpp + uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * (self->core.colorspace.depth / 8); + uint8_t *src = (uint8_t*)buffer; + size_t rowsize = (subrectangle.x2 - subrectangle.x1) * (self->core.colorspace.depth / 8); + size_t rowstride = self->core.width * (self->core.colorspace.depth/8); + for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { + memcpy(dest, src, rowsize); + dest += rowstride; + src += rowsize; + } + + // TODO(tannewt): Make refresh displays faster so we don't starve other + // background tasks. + usb_background(); + } + return true; +} + +STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { + displayio_display_core_start_refresh(&self->core); + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); + const displayio_area_t* current_area = _get_refresh_areas(self); + while (current_area != NULL) { + _refresh_area(self, current_area); + current_area = current_area->next; + } + displayio_display_core_finish_refresh(&self->core); + self->framebuffer_protocol->swapbuffers(self->framebuffer); +} + +void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t* self, int rotation){ + bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); + bool will_transposed = (rotation == 90 || rotation == 270); + if(transposed != will_transposed) { + int tmp = self->core.width; + self->core.width = self->core.height; + self->core.height = tmp; + } + displayio_display_core_set_rotation(&self->core, rotation); + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + if (self->core.current_group != NULL) { + displayio_group_update_transform(self->core.current_group, &self->core.transform); + } +} + +uint16_t common_hal_framebufferio_framebufferdisplay_get_rotation(framebufferio_framebufferdisplay_obj_t* self){ + return self->core.rotation; +} + + +bool common_hal_framebufferio_framebufferdisplay_refresh(framebufferio_framebufferdisplay_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { + if (!self->auto_refresh && !self->first_manual_refresh) { + uint64_t current_time = supervisor_ticks_ms64(); + uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; + // Test to see if the real frame time is below our minimum. + if (current_ms_since_real_refresh > maximum_ms_per_real_frame) { + mp_raise_RuntimeError(translate("Below minimum frame rate")); + } + uint32_t current_ms_since_last_call = current_time - self->last_refresh_call; + self->last_refresh_call = current_time; + // Skip the actual refresh to help catch up. + if (current_ms_since_last_call > target_ms_per_frame) { + return false; + } + uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame); + // We're ahead of the game so wait until we align with the frame rate. + while (supervisor_ticks_ms64() - self->last_refresh_call < remaining_time) { + RUN_BACKGROUND_TASKS; + } + } + self->first_manual_refresh = false; + _refresh_display(self); + return true; +} + +bool common_hal_framebufferio_framebufferdisplay_get_auto_refresh(framebufferio_framebufferdisplay_obj_t* self) { + return self->auto_refresh; +} + +void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t* self, + bool auto_refresh) { + self->first_manual_refresh = !auto_refresh; + self->auto_refresh = auto_refresh; +} + +STATIC void _update_backlight(framebufferio_framebufferdisplay_obj_t* self) { + if (!self->auto_brightness || self->updating_backlight) { + return; + } + if (supervisor_ticks_ms64() - self->last_backlight_refresh < 100) { + return; + } + // TODO(tannewt): Fade the backlight based on it's existing value and a target value. The target + // should account for ambient light when possible. + common_hal_framebufferio_framebufferdisplay_set_brightness(self, 1.0); + + self->last_backlight_refresh = supervisor_ticks_ms64(); +} + +void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self) { + _update_backlight(self); + + if (self->auto_refresh && (supervisor_ticks_ms64() - self->core.last_refresh) > self->native_ms_per_frame) { + _refresh_display(self); + } +} + +void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { + release_display_core(&self->core); + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { + common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); + common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->backlight_inout); + } + self->framebuffer_protocol->deinit(self->framebuffer); +} + +void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { + self->auto_refresh = true; + self->auto_brightness = true; + common_hal_framebufferio_framebufferdisplay_show(self, NULL); +} + +void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self) { + gc_collect_ptr(self->framebuffer); + displayio_display_core_collect_ptrs(&self->core); +} -- cgit v1.2.3 From baf04b7738bdcf234eecad9e03904c1cadc44f50 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 3 Apr 2020 10:59:06 -0500 Subject: FramebufferDisplay: remove probably not needed constructor arguments --- shared-bindings/framebufferio/FramebufferDisplay.c | 25 ++++------------------ shared-bindings/framebufferio/FramebufferDisplay.h | 5 ++--- shared-module/framebufferio/FramebufferDisplay.c | 10 ++++----- 3 files changed, 11 insertions(+), 29 deletions(-) (limited to 'shared-module/framebufferio/FramebufferDisplay.c') diff --git a/shared-bindings/framebufferio/FramebufferDisplay.c b/shared-bindings/framebufferio/FramebufferDisplay.c index 9f1df8bfa..9b761dd2d 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.c +++ b/shared-bindings/framebufferio/FramebufferDisplay.c @@ -54,20 +54,12 @@ //| //| :param framebuffer: The framebuffer that the display is connected to //| :type framebuffer: any core object implementing the framebuffer protocol -//| :param callback: Function or bound method to call when the framebuffer has been updated. The callback receives one argument, the framebuffer object. //| :param int width: Width in pixels //| :param int height: Height in pixels -//| :param int colstart: The index if the first visible column -//| :param int rowstart: The index if the first visible row //| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) //| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays //| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) -//| :param bool grayscale: True if the display only shows a single color. -//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. //| :param int bytes_per_cell: Number of bytes per addressable memory location when color_depth < 8. When greater than one, bytes share a row or column according to pixels_in_byte_share_row. -//| :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.) -//| :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.) -//| :param bool reverse_bytes_in_word: Reverses the order of bytes within a word when color_depth == 16 //| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight //| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. @@ -75,20 +67,14 @@ //| :param int native_frames_per_second: Number of display refreshes per second //| STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_framebuffer, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_backlight_pin, ARG_brightness, ARG_auto_brightness, ARG_auto_refresh, ARG_native_frames_per_second, NUM_ARGS }; + enum { ARG_framebuffer, ARG_width, ARG_height, ARG_rotation, ARG_color_depth, ARG_bytes_per_cell, ARG_backlight_pin, ARG_brightness, ARG_auto_brightness, ARG_auto_refresh, ARG_native_frames_per_second, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_framebuffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, - { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_bytes_per_cell, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, - { MP_QSTR_reverse_pixels_in_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_reverse_bytes_in_word, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, @@ -117,12 +103,9 @@ STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *t self, framebuffer, args[ARG_width].u_int, args[ARG_height].u_int, - args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, - args[ARG_pixels_in_byte_share_row].u_bool, - args[ARG_bytes_per_cell].u_bool, - args[ARG_reverse_pixels_in_byte].u_bool, - args[ARG_reverse_bytes_in_word].u_bool, + rotation, + args[ARG_color_depth].u_int, + args[ARG_bytes_per_cell].u_int, MP_OBJ_TO_PTR(backlight_pin), brightness, args[ARG_auto_brightness].u_bool, diff --git a/shared-bindings/framebufferio/FramebufferDisplay.h b/shared-bindings/framebufferio/FramebufferDisplay.h index af0bd2c41..b63439e0c 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.h +++ b/shared-bindings/framebufferio/FramebufferDisplay.h @@ -40,9 +40,8 @@ extern const mp_obj_type_t framebufferio_framebufferdisplay_type; void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self, mp_obj_t framebuffer, uint16_t width, uint16_t height, - int16_t colstart, int16_t rowstart, - uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, - uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word, + uint16_t rotation, uint16_t color_depth, + uint8_t bytes_per_cell, const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint16_t native_frames_per_second); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 967316c21..ec2fe7b31 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -42,9 +42,9 @@ #include "tick.h" void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self, - mp_obj_t framebuffer, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, - uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, - uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word, + mp_obj_t framebuffer, uint16_t width, uint16_t height, + uint16_t rotation, uint16_t color_depth, + uint8_t bytes_per_cell, const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint16_t native_frames_per_second) { // Turn off auto-refresh as we init. @@ -55,8 +55,8 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; - displayio_display_core_construct(&self->core, NULL, width, height, ram_width, ram_height, colstart, rowstart, rotation, - color_depth, grayscale, pixels_in_byte_share_row, bytes_per_cell, reverse_pixels_in_byte, reverse_bytes_in_word); + displayio_display_core_construct(&self->core, NULL, width, height, ram_width, ram_height, 0, 0, rotation, + color_depth, false, false, bytes_per_cell, false, false); self->auto_brightness = auto_brightness; self->first_manual_refresh = !auto_refresh; -- cgit v1.2.3 From ba20bc8b4322373ec9ed55ed9f299675ea2801f8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 10 Apr 2020 09:07:06 -0500 Subject: framebufferio: move backlight down to the underlying framebuffer --- shared-bindings/_protomatter/Protomatter.c | 3 +- shared-bindings/framebufferio/FramebufferDisplay.c | 17 ++---- shared-bindings/framebufferio/FramebufferDisplay.h | 3 +- shared-module/framebufferio/FramebufferDisplay.c | 65 +++++----------------- shared-module/framebufferio/FramebufferDisplay.h | 15 +++-- 5 files changed, 28 insertions(+), 75 deletions(-) (limited to 'shared-module/framebufferio/FramebufferDisplay.c') diff --git a/shared-bindings/_protomatter/Protomatter.c b/shared-bindings/_protomatter/Protomatter.c index f6ac19188..50480004c 100644 --- a/shared-bindings/_protomatter/Protomatter.c +++ b/shared-bindings/_protomatter/Protomatter.c @@ -317,8 +317,9 @@ STATIC void protomatter_protomatter_deinit_void(mp_obj_t self_in) { protomatter_protomatter_deinit(self_in); } -STATIC void protomatter_protomatter_set_brightness(mp_obj_t self_in, mp_float_t value) { +STATIC bool protomatter_protomatter_set_brightness(mp_obj_t self_in, mp_float_t value) { common_hal_protomatter_protomatter_set_paused(self_in, value <= 0); + return true; } STATIC const framebuffer_p_t protomatter_protomatter_proto = { diff --git a/shared-bindings/framebufferio/FramebufferDisplay.c b/shared-bindings/framebufferio/FramebufferDisplay.c index 9b761dd2d..538d3afb4 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.c +++ b/shared-bindings/framebufferio/FramebufferDisplay.c @@ -67,7 +67,7 @@ //| :param int native_frames_per_second: Number of display refreshes per second //| STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_framebuffer, ARG_width, ARG_height, ARG_rotation, ARG_color_depth, ARG_bytes_per_cell, ARG_backlight_pin, ARG_brightness, ARG_auto_brightness, ARG_auto_refresh, ARG_native_frames_per_second, NUM_ARGS }; + enum { ARG_framebuffer, ARG_width, ARG_height, ARG_rotation, ARG_color_depth, ARG_bytes_per_cell, ARG_auto_refresh, ARG_native_frames_per_second, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_framebuffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, @@ -75,9 +75,6 @@ STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *t { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, { MP_QSTR_bytes_per_cell, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, - { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, - { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, }; @@ -87,10 +84,6 @@ STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *t mp_obj_t framebuffer = args[ARG_framebuffer].u_obj; - const mcu_pin_obj_t* backlight_pin = validate_obj_is_free_pin_or_none(args[ARG_backlight_pin].u_obj); - - mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); - mp_int_t rotation = args[ARG_rotation].u_int; if (rotation % 90 != 0) { mp_raise_ValueError(translate("Display rotation must be in 90 degree increments")); @@ -106,9 +99,6 @@ STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *t rotation, args[ARG_color_depth].u_int, args[ARG_bytes_per_cell].u_int, - MP_OBJ_TO_PTR(backlight_pin), - brightness, - args[ARG_auto_brightness].u_bool, args[ARG_auto_refresh].u_bool, args[ARG_native_frames_per_second].u_int ); @@ -260,7 +250,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_auto_brightness_o STATIC mp_obj_t framebufferio_framebufferdisplay_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) { framebufferio_framebufferdisplay_obj_t *self = native_display(self_in); - common_hal_framebufferio_framebufferdisplay_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); + bool ok = common_hal_framebufferio_framebufferdisplay_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); + if (!ok) { + mp_raise_RuntimeError(translate("Brightness not adjustable")); + } return mp_const_none; } diff --git a/shared-bindings/framebufferio/FramebufferDisplay.h b/shared-bindings/framebufferio/FramebufferDisplay.h index b63439e0c..56ef8abc4 100644 --- a/shared-bindings/framebufferio/FramebufferDisplay.h +++ b/shared-bindings/framebufferio/FramebufferDisplay.h @@ -42,7 +42,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu mp_obj_t framebuffer, uint16_t width, uint16_t height, uint16_t rotation, uint16_t color_depth, uint8_t bytes_per_cell, - const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint16_t native_frames_per_second); bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t* self, @@ -59,7 +58,7 @@ uint16_t common_hal_framebufferio_framebufferdisplay_get_rotation(framebufferio_ void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t* self, int rotation); bool common_hal_framebufferio_framebufferdisplay_get_auto_brightness(framebufferio_framebufferdisplay_obj_t* self); -void common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t* self, bool auto_brightness); +bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t* self, bool auto_brightness); bool common_hal_framebufferio_framebufferdisplay_get_dither(framebufferio_framebufferdisplay_obj_t* self); void common_hal_framebufferio_framebufferdisplay_set_dither(framebufferio_framebufferdisplay_obj_t* self, bool dither); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index ec2fe7b31..bd0764e8e 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -45,7 +45,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu mp_obj_t framebuffer, uint16_t width, uint16_t height, uint16_t rotation, uint16_t color_depth, uint8_t bytes_per_cell, - const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint16_t native_frames_per_second) { // Turn off auto-refresh as we init. self->auto_refresh = false; @@ -58,7 +57,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu displayio_display_core_construct(&self->core, NULL, width, height, ram_width, ram_height, 0, 0, rotation, color_depth, false, false, bytes_per_cell, false, false); - self->auto_brightness = auto_brightness; self->first_manual_refresh = !auto_refresh; self->native_frames_per_second = native_frames_per_second; @@ -66,25 +64,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu supervisor_start_terminal(width, height); - // Always set the backlight type in case we're reusing memory. - self->backlight_inout.base.type = &mp_type_NoneType; - if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { - pwmout_result_t result = common_hal_pulseio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); - if (result != PWMOUT_OK) { - self->backlight_inout.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); - common_hal_never_reset_pin(backlight_pin); - } else { - self->backlight_pwm.base.type = &pulseio_pwmout_type; - common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm); - } - } - if (!self->auto_brightness && (self->framebuffer_protocol->set_brightness != NULL || self->backlight_inout.base.type != &mp_type_NoneType)) { - common_hal_framebufferio_framebufferdisplay_set_brightness(self, brightness); - } else { - self->current_brightness = -1.0; - } - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash); @@ -104,33 +83,31 @@ uint16_t common_hal_framebufferio_framebufferdisplay_get_height(framebufferio_fr } bool common_hal_framebufferio_framebufferdisplay_get_auto_brightness(framebufferio_framebufferdisplay_obj_t* self) { - return self->auto_brightness; + if (self->framebuffer_protocol->get_auto_brightness) { + return self->framebuffer_protocol->get_auto_brightness(self->framebuffer); + } + return true; } -void common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t* self, bool auto_brightness) { - self->auto_brightness = auto_brightness; +bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t* self, bool auto_brightness) { + if (self->framebuffer_protocol->set_auto_brightness) { + return self->framebuffer_protocol->set_auto_brightness(self->framebuffer, auto_brightness); + } + return false; } mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t* self) { - return self->current_brightness; + if (self->framebuffer_protocol->set_brightness) { + return self->framebuffer_protocol->get_brightness(self->framebuffer); + } + return -1; } bool common_hal_framebufferio_framebufferdisplay_set_brightness(framebufferio_framebufferdisplay_obj_t* self, mp_float_t brightness) { - self->updating_backlight = true; bool ok = false; if (self->framebuffer_protocol->set_brightness) { self->framebuffer_protocol->set_brightness(self->framebuffer, brightness); ok = true; - } else if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); - ok = true; - } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { - common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); - ok = true; - } - self->updating_backlight = false; - if (ok) { - self->current_brightness = brightness; } return ok; } @@ -295,17 +272,8 @@ void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_ } STATIC void _update_backlight(framebufferio_framebufferdisplay_obj_t* self) { - if (!self->auto_brightness || self->updating_backlight) { - return; - } - if (supervisor_ticks_ms64() - self->last_backlight_refresh < 100) { - return; - } // TODO(tannewt): Fade the backlight based on it's existing value and a target value. The target // should account for ambient light when possible. - common_hal_framebufferio_framebufferdisplay_set_brightness(self, 1.0); - - self->last_backlight_refresh = supervisor_ticks_ms64(); } void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self) { @@ -318,18 +286,11 @@ void framebufferio_framebufferdisplay_background(framebufferio_framebufferdispla void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { release_display_core(&self->core); - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); - common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); - } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { - common_hal_digitalio_digitalinout_deinit(&self->backlight_inout); - } self->framebuffer_protocol->deinit(self->framebuffer); } void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { self->auto_refresh = true; - self->auto_brightness = true; common_hal_framebufferio_framebufferdisplay_show(self, NULL); } diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index a5c8607bb..a7b91a522 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -40,22 +40,15 @@ typedef struct { mp_obj_base_t base; displayio_display_core_t core; - union { - digitalio_digitalinout_obj_t backlight_inout; - pulseio_pwmout_obj_t backlight_pwm; - }; mp_obj_t framebuffer; const struct _framebuffer_p_t *framebuffer_protocol; mp_buffer_info_t bufinfo; uint64_t last_backlight_refresh; uint64_t last_refresh_call; - mp_float_t current_brightness; uint16_t native_frames_per_second; uint16_t native_ms_per_frame; bool auto_refresh; bool first_manual_refresh; - bool auto_brightness; - bool updating_backlight; } framebufferio_framebufferdisplay_obj_t; void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self); @@ -69,14 +62,20 @@ mp_obj_t common_hal_framebufferio_framebufferdisplay_get_framebuffer(framebuffer typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); typedef void (*framebuffer_deinit_fun)(mp_obj_t); -typedef void (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); +typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); +typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); +typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); +typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); typedef struct _framebuffer_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer framebuffer_get_bufinfo_fun get_bufinfo; framebuffer_swapbuffers_fun swapbuffers; framebuffer_deinit_fun deinit; + framebuffer_get_brightness_fun get_brightness; framebuffer_set_brightness_fun set_brightness; + framebuffer_get_auto_brightness_fun get_auto_brightness; + framebuffer_set_auto_brightness_fun set_auto_brightness; } framebuffer_p_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_FRAMEBUFFERDISPLAY_H -- cgit v1.2.3