summaryrefslogtreecommitdiff
path: root/shared-bindings/displayio
diff options
context:
space:
mode:
Diffstat (limited to 'shared-bindings/displayio')
-rw-r--r--shared-bindings/displayio/Bitmap.c172
-rw-r--r--shared-bindings/displayio/Bitmap.h5
-rw-r--r--shared-bindings/displayio/ColorConverter.c70
-rw-r--r--shared-bindings/displayio/ColorConverter.h9
-rw-r--r--shared-bindings/displayio/Display.c499
-rw-r--r--shared-bindings/displayio/Display.h75
-rw-r--r--shared-bindings/displayio/EPaperDisplay.c289
-rw-r--r--shared-bindings/displayio/EPaperDisplay.h61
-rw-r--r--shared-bindings/displayio/FourWire.c153
-rw-r--r--shared-bindings/displayio/FourWire.h34
-rw-r--r--shared-bindings/displayio/Group.c299
-rw-r--r--shared-bindings/displayio/Group.h18
-rw-r--r--shared-bindings/displayio/I2CDisplay.c133
-rw-r--r--shared-bindings/displayio/I2CDisplay.h51
-rw-r--r--shared-bindings/displayio/OnDiskBitmap.c115
-rw-r--r--shared-bindings/displayio/OnDiskBitmap.h3
-rw-r--r--shared-bindings/displayio/Palette.c86
-rw-r--r--shared-bindings/displayio/Palette.h2
-rw-r--r--shared-bindings/displayio/ParallelBus.c142
-rw-r--r--shared-bindings/displayio/ParallelBus.h53
-rw-r--r--shared-bindings/displayio/Shape.c117
-rw-r--r--shared-bindings/displayio/Shape.h (renamed from shared-bindings/displayio/Sprite.h)24
-rw-r--r--shared-bindings/displayio/Sprite.c190
-rw-r--r--shared-bindings/displayio/TileGrid.c401
-rw-r--r--shared-bindings/displayio/TileGrid.h65
-rw-r--r--shared-bindings/displayio/__init__.c57
-rw-r--r--shared-bindings/displayio/__init__.h18
27 files changed, 2680 insertions, 461 deletions
diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c
index d415127d2..a52840f2e 100644
--- a/shared-bindings/displayio/Bitmap.c
+++ b/shared-bindings/displayio/Bitmap.c
@@ -36,69 +36,164 @@
#include "shared-bindings/util.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: displayio
+//| class Bitmap:
+//| """Stores values of a certain size in a 2D array"""
//|
-//| :class:`Bitmap` -- Stores values in a 2D array
-//| ==========================================================================
+//| def __init__(self, width: int, height: int, value_count: int):
+//| """Create a Bitmap object with the given fixed size. Each pixel stores a value that is used to
+//| index into a corresponding palette. This enables differently colored sprites to share the
+//| underlying Bitmap. value_count is used to minimize the memory used to store the Bitmap.
//|
-//| Stores values of a certain size in a 2D array
+//| :param int width: The number of values wide
+//| :param int height: The number of values high
+//| :param int value_count: The number of possible pixel values."""
+//| ...
//|
-//| .. warning:: This will likely be changed before 4.0.0. Consider it very experimental.
-//|
-//| .. class:: Bitmap(width, height, value_count)
-//|
-//| Create a Bitmap object with the given fixed size. Each pixel stores a value that is used to
-//| index into a corresponding palette. This enables differently colored sprites to share the
-//| underlying Bitmap. value_count is used to minimize the memory used to store the Bitmap.
-//|
-//| :param int width: The number of values wide
-//| :param int height: The number of values high
-//| :param int value_count: The number of possible pixel values.
-//|
-STATIC mp_obj_t displayio_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 3, 3, false);
+STATIC mp_obj_t displayio_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 3, 3, false);
uint32_t width = mp_obj_get_int(pos_args[0]);
uint32_t height = mp_obj_get_int(pos_args[1]);
uint32_t value_count = mp_obj_get_int(pos_args[2]);
- uint32_t power_of_two = 1;
- while (value_count > (1U << power_of_two)) {
- power_of_two <<= 1;
+ uint32_t bits = 1;
+
+ if (value_count == 0) {
+ mp_raise_ValueError(translate("value_count must be > 0"));
+ }
+ while ((value_count - 1) >> bits) {
+ if (bits < 8) {
+ bits <<= 1;
+ } else {
+ bits += 8;
+ }
}
displayio_bitmap_t *self = m_new_obj(displayio_bitmap_t);
self->base.type = &displayio_bitmap_type;
- common_hal_displayio_bitmap_construct(self, width, height, power_of_two);
+ common_hal_displayio_bitmap_construct(self, width, height, bits);
return MP_OBJ_FROM_PTR(self);
}
+//| width: Any = ...
+//| """Width of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_bitmap_obj_get_width(mp_obj_t self_in) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_get_width_obj, displayio_bitmap_obj_get_width);
+
+const mp_obj_property_t displayio_bitmap_width_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_bitmap_get_width_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| height: Any = ...
+//| """Height of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_bitmap_obj_get_height(mp_obj_t self_in) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_height(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_get_height_obj, displayio_bitmap_obj_get_height);
+
+const mp_obj_property_t displayio_bitmap_height_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_bitmap_get_height_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
-//| .. method:: _load_row(y, data)
+//| def __getitem__(self, index: Any) -> Any:
+//| """Returns the value at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
//|
-//| Loads pre-packed data into the given row.
+//| This allows you to::
//|
-STATIC mp_obj_t displayio_bitmap_obj__load_row(mp_obj_t self_in, mp_obj_t y_in, mp_obj_t data_in) {
+//| print(bitmap[0,1])"""
+//| ...
+//|
+//| def __setitem__(self, index: Any, value: Any) -> Any:
+//| """Sets the value at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| bitmap[0,1] = 3"""
+//| ...
+//|
+STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value_obj) {
+ if (value_obj == mp_const_none) {
+ // delete item
+ mp_raise_AttributeError(translate("Cannot delete values"));
+ return mp_const_none;
+ }
+
displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
- mp_int_t y;
- if (!mp_obj_get_int_maybe(y_in, &y)) {
- mp_raise_ValueError(translate("y should be an int"));
+
+ if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) {
+ // TODO(tannewt): Implement subscr after slices support start, stop and step tuples.
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ return mp_const_none;
}
- mp_buffer_info_t bufinfo;
- if (mp_get_buffer(data_in, &bufinfo, MP_BUFFER_READ)) {
- if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) {
- mp_raise_ValueError(translate("row buffer must be a bytearray or array of type 'b' or 'B'"));
+
+ uint16_t x = 0;
+ uint16_t y = 0;
+ if (MP_OBJ_IS_SMALL_INT(index_obj)) {
+ mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj);
+ uint16_t width = common_hal_displayio_bitmap_get_width(self);
+ x = i % width;
+ y = i / width;
+ } else {
+ mp_obj_t* items;
+ mp_obj_get_array_fixed_n(index_obj, 2, &items);
+ x = mp_obj_get_int(items[0]);
+ y = mp_obj_get_int(items[1]);
+ if (x >= common_hal_displayio_bitmap_get_width(self) || y >= common_hal_displayio_bitmap_get_height(self)) {
+ mp_raise_IndexError(translate("pixel coordinates out of bounds"));
}
- uint8_t* buf = bufinfo.buf;
- common_hal_displayio_bitmap_load_row(self, y, buf, bufinfo.len);
+ }
+
+ if (value_obj == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_pixel(self, x, y));
} else {
- mp_raise_TypeError(translate("row data must be a buffer"));
+ mp_int_t value = mp_obj_get_int(value_obj);
+ if (value >= 1 << common_hal_displayio_bitmap_get_bits_per_value(self)) {
+ mp_raise_ValueError(translate("pixel value requires too many bits"));
+ }
+ common_hal_displayio_bitmap_set_pixel(self, x, y, value);
+ }
+ return mp_const_none;
+}
+
+//| def fill(self, value: Any) -> Any:
+//| """Fills the bitmap with the supplied palette index value."""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_fill(mp_obj_t self_in, mp_obj_t value_obj) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t value = mp_obj_get_int(value_obj);
+ if (value >= 1 << common_hal_displayio_bitmap_get_bits_per_value(self)) {
+ mp_raise_ValueError(translate("pixel value requires too many bits"));
}
+ common_hal_displayio_bitmap_fill(self, value);
+
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_3(displayio_bitmap__load_row_obj, displayio_bitmap_obj__load_row);
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_bitmap_fill_obj, displayio_bitmap_obj_fill);
STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR__load_row), MP_ROM_PTR(&displayio_bitmap__load_row_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_bitmap_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_bitmap_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) },
+
};
STATIC MP_DEFINE_CONST_DICT(displayio_bitmap_locals_dict, displayio_bitmap_locals_dict_table);
@@ -106,7 +201,6 @@ const mp_obj_type_t displayio_bitmap_type = {
{ &mp_type_type },
.name = MP_QSTR_Bitmap,
.make_new = displayio_bitmap_make_new,
- // TODO(tannewt): Implement subscr after slices support start, stop and step tuples.
- // .subscr = displayio_bitmap_subscr,
+ .subscr = bitmap_subscr,
.locals_dict = (mp_obj_dict_t*)&displayio_bitmap_locals_dict,
};
diff --git a/shared-bindings/displayio/Bitmap.h b/shared-bindings/displayio/Bitmap.h
index b736f9459..46c337329 100644
--- a/shared-bindings/displayio/Bitmap.h
+++ b/shared-bindings/displayio/Bitmap.h
@@ -36,6 +36,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi
void common_hal_displayio_bitmap_load_row(displayio_bitmap_t *self, uint16_t y, uint8_t* data,
uint16_t len);
+uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self);
+uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self);
+uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self);
+void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value);
uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y);
+void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c
index 670578888..33d0bdd3c 100644
--- a/shared-bindings/displayio/ColorConverter.c
+++ b/shared-bindings/displayio/ColorConverter.c
@@ -36,33 +36,38 @@
#include "shared-bindings/util.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: displayio
+//| class ColorConverter:
+//| """Converts one color format to another."""
//|
-//| :class:`ColorConverter` -- Converts one color format to another
-//| =========================================================================================
-//|
-//| Converts one color format to another.
-//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
-//|
-//| .. class:: ColorConverter()
-//|
-//| Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565
-//| currently.
+//| def __init__(self, *, dither: bool = False):
+//| """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565
+//| currently.
+//| :param bool dither: Adds random noise to dither the output image"""
+//| ...
//|
+
// TODO(tannewt): Add support for other color formats.
//|
-STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 0, 0, true);
+STATIC mp_obj_t displayio_colorconverter_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_dither};
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t);
self->base.type = &displayio_colorconverter_type;
- common_hal_displayio_colorconverter_construct(self);
+
+ common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool);
return MP_OBJ_FROM_PTR(self);
}
-//| .. method:: convert(color)
+//| def convert(self, color: Any) -> Any:
+//| """Converts the given RGB888 color to RGB565"""
+//| ...
//|
STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t color_obj) {
displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
@@ -71,14 +76,43 @@ STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t
if (!mp_obj_get_int_maybe(color_obj, &color)) {
mp_raise_ValueError(translate("color should be an int"));
}
- uint16_t output_color;
- common_hal_displayio_colorconverter_convert(self, color, &output_color);
+ _displayio_colorspace_t colorspace;
+ colorspace.depth = 16;
+ uint32_t output_color;
+ common_hal_displayio_colorconverter_convert(self, &colorspace, color, &output_color);
return MP_OBJ_NEW_SMALL_INT(output_color);
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert);
+//| dither: Any = ...
+//| """When true the color converter dithers the output by adding random noise when
+//| truncating to display bitdepth"""
+//|
+STATIC mp_obj_t displayio_colorconverter_obj_get_dither(mp_obj_t self_in) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_displayio_colorconverter_get_dither(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_get_dither_obj, displayio_colorconverter_obj_get_dither);
+
+STATIC mp_obj_t displayio_colorconverter_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_displayio_colorconverter_set_dither(self, mp_obj_is_true(dither));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_set_dither_obj, displayio_colorconverter_obj_set_dither);
+
+const mp_obj_property_t displayio_colorconverter_dither_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_colorconverter_get_dither_obj,
+ (mp_obj_t)&displayio_colorconverter_set_dither_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table);
diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h
index 71be7f543..d550d81be 100644
--- a/shared-bindings/displayio/ColorConverter.h
+++ b/shared-bindings/displayio/ColorConverter.h
@@ -29,9 +29,14 @@
#include "shared-module/displayio/ColorConverter.h"
+#include "shared-module/displayio/Palette.h"
+
extern const mp_obj_type_t displayio_colorconverter_type;
-void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self);
-bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, uint32_t input_color, uint16_t* output_color);
+void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither);
+void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color);
+
+void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither);
+bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c
new file mode 100644
index 000000000..62ef0f5d0
--- /dev/null
+++ b/shared-bindings/displayio/Display.c
@@ -0,0 +1,499 @@
+/*
+ * This file is part of the Micro Python 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/displayio/Display.h"
+
+#include <stdint.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class Display:
+//| """Manage updating a display over a display bus
+//|
+//| This initializes a display and connects it into CircuitPython. Unlike other
+//| objects in CircuitPython, Display objects live until `displayio.release_displays()`
+//| is called. This is done so that CircuitPython can use the display itself.
+//|
+//| Most people should not use this class directly. Use a specific display driver instead that will
+//| contain the initialization sequence at minimum."""
+//|
+//| def __init__(self, display_bus: Any, init_sequence: buffer, *, width: int, height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, color_depth: int = 16, grayscale: bool = False, pixels_in_byte_share_row: bool = True, bytes_per_cell: int = 1, reverse_pixels_in_byte: bool = False, set_column_command: int = 0x2a, set_row_command: int = 0x2b, write_ram_command: int = 0x2c, set_vertical_scroll: int = 0, backlight_pin: microcontroller.Pin = None, brightness_command: int = None, brightness: bool = 1.0, auto_brightness: bool = False, single_byte_bounds: bool = False, data_as_commands: bool = False, auto_refresh: bool = True, native_frames_per_second: int = 60):
+//| """Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`).
+//|
+//| The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a
+//| command byte followed by a byte to determine the parameter count and if a delay is need after.
+//| When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds.
+//| The remaining 7 bits are the parameter count excluding any delay byte. The third through final
+//| bytes are the remaining command parameters. The next byte will begin a new command definition.
+//| Here is a portion of ILI9341 init code:
+//|
+//| .. code-block:: python
+//|
+//| init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma
+//| b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms)
+//| b"\x29\x80\x78"# Display on then delay 0x78 (120ms)
+//| )
+//| display = displayio.Display(display_bus, init_sequence, width=320, height=240)
+//|
+//| The first command is 0xe1 with 15 (0xf) parameters following. The second and third are 0x11 and
+//| 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters. Multiple byte literals
+//| (b"") are merged together on load. The parens are needed to allow byte literals on subsequent
+//| lines.
+//|
+//| The initialization sequence should always leave the display memory access inline with the scan
+//| of the display to minimize tearing artifacts.
+//|
+//| :param display_bus: The bus that the display is connected to
+//| :type display_bus: displayio.FourWire or displayio.ParallelBus
+//| :param buffer init_sequence: Byte-packed initialization sequence.
+//| :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_bytes_in_word: Reverses the order of bytes within a word when color_depth == 16
+//| :param int set_column_command: Command used to set the start and end columns to update
+//| :param int set_row_command: Command used so set the start and end rows to update
+//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set.
+//| :param int set_vertical_scroll: Command used to set the first row to show
+//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight
+//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers.
+//| :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.
+//| :param bool single_byte_bounds: Display column and row commands use single bytes
+//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this.
+//| :param bool auto_refresh: Automatically refresh the screen
+//| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence.
+//| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on."""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, 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_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_init_sequence, 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 = true} },
+ { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} },
+ { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} },
+ { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} },
+ { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} },
+ { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} },
+ { 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_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_data_as_commands, 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} },
+ { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t display_bus = args[ARG_display_bus].u_obj;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ 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"));
+ }
+
+ primary_display_t *disp = allocate_display_or_raise();
+ displayio_display_obj_t *self = &disp->display;;
+ self->base.type = &displayio_display_type;
+ common_hal_displayio_display_construct(
+ self,
+ display_bus, 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,
+ args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int,
+ args[ARG_write_ram_command].u_int,
+ args[ARG_set_vertical_scroll].u_int,
+ bufinfo.buf, bufinfo.len,
+ MP_OBJ_TO_PTR(backlight_pin),
+ args[ARG_brightness_command].u_int,
+ brightness,
+ args[ARG_auto_brightness].u_bool,
+ args[ARG_single_byte_bounds].u_bool,
+ args[ARG_data_as_commands].u_bool,
+ args[ARG_auto_refresh].u_bool,
+ args[ARG_native_frames_per_second].u_int,
+ args[ARG_backlight_on_high].u_bool
+ );
+
+ return self;
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_display_obj_t* native_display(mp_obj_t display_obj) {
+ mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_display_type);
+ mp_obj_assert_native_inited(native_display);
+ return MP_OBJ_TO_PTR(native_display);
+}
+
+//| def show(self, group: Group) -> Any:
+//| """Switches to displaying the given group of layers. When group is None, the default
+//| CircuitPython terminal will be shown.
+//|
+//| :param Group group: The group to show."""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ displayio_group_t* group = NULL;
+ if (group_in != mp_const_none) {
+ group = MP_OBJ_TO_PTR(native_group(group_in));
+ }
+
+ bool ok = common_hal_displayio_display_show(self, group);
+ if (!ok) {
+ mp_raise_ValueError(translate("Group already used"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show);
+
+//| def refresh(self, *, target_frames_per_second: int = 60, minimum_frames_per_second: int = 1) -> Any:
+//| """When auto refresh is off, waits for the target frame rate and then refreshes the display,
+//| returning True. If the call has taken too long since the last refresh call for the given
+//| target frame rate, then the refresh returns False immediately without updating the screen to
+//| hopefully help getting caught up.
+//|
+//| If the time since the last successful refresh is below the minimum frame rate, then an
+//| exception will be raised. Set minimum_frames_per_second to 0 to disable.
+//|
+//| When auto refresh is on, updates the display immediately. (The display will also update
+//| without calls to this.)
+//|
+//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated.
+//| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second."""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} },
+ { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_display_obj_t *self = native_display(pos_args[0]);
+ uint32_t maximum_ms_per_real_frame = 0xffffffff;
+ mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int;
+ if (minimum_frames_per_second > 0) {
+ maximum_ms_per_real_frame = 1000 / minimum_frames_per_second;
+ }
+ return mp_obj_new_bool(common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh);
+
+//| auto_refresh: Any = ...
+//| """True when the display is refreshed automatically."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_auto_refresh(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_display_get_auto_refresh(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_refresh_obj, displayio_display_obj_get_auto_refresh);
+
+STATIC mp_obj_t displayio_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) {
+ displayio_display_obj_t *self = native_display(self_in);
+
+ common_hal_displayio_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_refresh_obj, displayio_display_obj_set_auto_refresh);
+
+const mp_obj_property_t displayio_display_auto_refresh_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_auto_refresh_obj,
+ (mp_obj_t)&displayio_display_set_auto_refresh_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| brightness: Any = ...
+//| """The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When
+//| `auto_brightness` is True, the value of `brightness` will change automatically.
+//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ mp_float_t brightness = common_hal_displayio_display_get_brightness(self);
+ if (brightness < 0) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_obj_new_float(brightness);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness);
+
+STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) {
+ displayio_display_obj_t *self = native_display(self_in);
+ common_hal_displayio_display_set_auto_brightness(self, false);
+ mp_float_t brightness = mp_obj_get_float(brightness_obj);
+ if (brightness < 0 || brightness > 1.0) {
+ mp_raise_ValueError(translate("Brightness must be 0-1.0"));
+ }
+ bool ok = common_hal_displayio_display_set_brightness(self, brightness);
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_brightness_obj, displayio_display_obj_set_brightness);
+
+const mp_obj_property_t displayio_display_brightness_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_brightness_obj,
+ (mp_obj_t)&displayio_display_set_brightness_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| auto_brightness: Any = ...
+//| """True when the display brightness is adjusted automatically, based on an ambient
+//| light sensor or other method. Note that some displays may have this set to True by default,
+//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False
+//| if `brightness` is set manually."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness);
+
+STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) {
+ displayio_display_obj_t *self = native_display(self_in);
+
+ common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_brightness_obj, displayio_display_obj_set_auto_brightness);
+
+const mp_obj_property_t displayio_display_auto_brightness_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_auto_brightness_obj,
+ (mp_obj_t)&displayio_display_set_auto_brightness_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+
+
+
+//| width: Any = ...
+//| Gets the width of the board
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width);
+
+const mp_obj_property_t displayio_display_width_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_width_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| height: Any = ...
+//| """Gets the height of the board"""
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height);
+
+const mp_obj_property_t displayio_display_height_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_height_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| rotation: Any = ...
+//| """The rotation of the display as an int in degrees."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_rotation(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_rotation(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_rotation_obj, displayio_display_obj_get_rotation);
+STATIC mp_obj_t displayio_display_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) {
+ displayio_display_obj_t *self = native_display(self_in);
+ common_hal_displayio_display_set_rotation(self, mp_obj_get_int(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_rotation_obj, displayio_display_obj_set_rotation);
+
+
+const mp_obj_property_t displayio_display_rotation_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_rotation_obj,
+ (mp_obj_t)&displayio_display_set_rotation_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| bus: Any = ...
+//| """The bus being used by the display"""
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return common_hal_displayio_display_get_bus(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus);
+
+const mp_obj_property_t displayio_display_bus_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_display_get_bus_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+
+//| def fill_row(self, y: int, buffer: bytearray) -> Any:
+//| """Extract the pixels from a single row
+//|
+//| :param int y: The top edge of the area
+//| :param bytearray buffer: The buffer in which to place the pixel data"""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_y, ARG_buffer };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = -1} },
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ displayio_display_obj_t *self = native_display(pos_args[0]);
+ mp_int_t y = args[ARG_y].u_int;
+ mp_obj_t *result = args[ARG_buffer].u_obj;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_WRITE);
+
+ if (bufinfo.typecode != BYTEARRAY_TYPECODE) {
+ mp_raise_ValueError(translate("Buffer is not a bytearray."));
+ }
+ if (self->core.colorspace.depth != 16) {
+ mp_raise_ValueError(translate("Display must have a 16 bit colorspace."));
+ }
+
+ displayio_area_t area = {
+ .x1 = 0,
+ .y1 = y,
+ .x2 = self->core.width,
+ .y2 = y + 1
+ };
+ uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth;
+ uint16_t buffer_size = self->core.width / pixels_per_word;
+ uint16_t pixels_per_buffer = displayio_area_size(&area);
+ if (pixels_per_buffer % pixels_per_word) {
+ buffer_size += 1;
+ }
+
+ uint32_t *result_buffer = bufinfo.buf;
+ size_t result_buffer_size = bufinfo.len;
+
+ if (result_buffer_size >= (buffer_size * 4)) {
+ volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1;
+ uint32_t mask[mask_length];
+
+ for (uint16_t k = 0; k < mask_length; k++) {
+ mask[k] = 0x00000000;
+ }
+
+ displayio_display_core_fill_area(&self->core, &area, mask, result_buffer);
+ return result;
+ } else {
+ mp_raise_ValueError(translate("Buffer is too small"));
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_fill_row_obj, 1, displayio_display_obj_fill_row);
+
+STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_display_refresh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_display_rotation_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table);
+
+const mp_obj_type_t displayio_display_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Display,
+ .make_new = displayio_display_make_new,
+ .locals_dict = (mp_obj_dict_t*)&displayio_display_locals_dict,
+};
diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h
new file mode 100644
index 000000000..e69c5b6b5
--- /dev/null
+++ b/shared-bindings/displayio/Display.h
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/displayio/Display.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_display_type;
+
+#define DELAY 0x80
+
+#define NO_BRIGHTNESS_COMMAND 0x100
+
+void common_hal_displayio_display_construct(displayio_display_obj_t* self,
+ mp_obj_t bus, 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,
+ uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll,
+ uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command,
+ mp_float_t brightness, bool auto_brightness,
+ bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high);
+
+bool common_hal_displayio_display_show(displayio_display_obj_t* self,
+ displayio_group_t* root_group);
+
+bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame);
+
+bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self);
+void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh);
+
+uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self);
+uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self);
+uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self);
+void common_hal_displayio_display_set_rotation(displayio_display_obj_t* self, int rotation);
+
+bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self);
+void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness);
+
+bool common_hal_displayio_display_get_dither(displayio_display_obj_t* self);
+void common_hal_displayio_display_set_dither(displayio_display_obj_t* self, bool dither);
+
+mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self);
+bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness);
+
+mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t* self);
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c
new file mode 100644
index 000000000..8b77e4df3
--- /dev/null
+++ b/shared-bindings/displayio/EPaperDisplay.c
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the Micro Python 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 "shared-bindings/displayio/EPaperDisplay.h"
+
+#include <stdint.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class EPaperDisplay:
+//| """Manage updating an epaper display over a display bus
+//|
+//| This initializes an epaper display and connects it into CircuitPython. Unlike other
+//| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()`
+//| is called. This is done so that CircuitPython can use the display itself.
+//|
+//| Most people should not use this class directly. Use a specific display driver instead that will
+//| contain the startup and shutdown sequences at minimum."""
+//|
+//| def __init__(self, display_bus: Any, start_sequence: buffer, stop_sequence: buffer, *, width: int, height: int, ram_width: int, ram_height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, set_column_window_command: int = None, set_row_window_command: int = None, single_byte_bounds: Any = False, write_black_ram_command: int, black_bits_inverted: bool = False, write_color_ram_command: int = None, color_bits_inverted: bool = False, highlight_color: int = 0x000000, refresh_display_command: int, refresh_time: float = 40, busy_pin: microcontroller.Pin = None, busy_state: bool = True, seconds_per_frame: float = 180, always_toggle_chip_select: bool = False):
+//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`).
+//|
+//| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every
+//| command begins with a command byte followed by a byte to determine the parameter count and if
+//| a delay is need after. When the top bit of the second byte is 1, the next byte will be the
+//| delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay
+//| byte. The third through final bytes are the remaining command parameters. The next byte will
+//| begin a new command definition.
+//|
+//| :param display_bus: The bus that the display is connected to
+//| :type display_bus: displayio.FourWire or displayio.ParallelBus
+//| :param buffer start_sequence: Byte-packed initialization sequence.
+//| :param buffer stop_sequence: Byte-packed initialization sequence.
+//| :param int width: Width in pixels
+//| :param int height: Height in pixels
+//| :param int ram_width: RAM width in pixels
+//| :param int ram_height: RAM 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 set_column_window_command: Command used to set the start and end columns to update
+//| :param int set_row_window_command: Command used so set the start and end rows to update
+//| :param int set_current_column_command: Command used to set the current column location
+//| :param int set_current_row_command: Command used to set the current row location
+//| :param int write_black_ram_command: Command used to write pixels values into the update region
+//| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black.
+//| :param int write_color_ram_command: Command used to write pixels values into the update region
+//| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color.
+//| :param int highlight_color: RGB888 of source color to highlight with third ePaper color.
+//| :param int refresh_display_command: Command used to start a display refresh
+//| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided.
+//| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy
+//| :param bool busy_state: State of the busy pin when the display is busy
+//| :param float seconds_per_frame: Minimum number of seconds between screen refreshes
+//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte"""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_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_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_stop_sequence, 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_ram_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_ram_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_set_column_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_row_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_current_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_current_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_write_black_ram_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} },
+ { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} },
+ { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
+ { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t display_bus = args[ARG_display_bus].u_obj;
+
+ mp_buffer_info_t start_bufinfo;
+ mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_bufinfo, MP_BUFFER_READ);
+ mp_buffer_info_t stop_bufinfo;
+ mp_get_buffer_raise(args[ARG_stop_sequence].u_obj, &stop_bufinfo, MP_BUFFER_READ);
+
+
+ const mcu_pin_obj_t* busy_pin = validate_obj_is_free_pin_or_none(args[ARG_busy_pin].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"));
+ }
+
+ primary_display_t *disp = allocate_display_or_raise();
+ displayio_epaperdisplay_obj_t *self = &disp->epaper_display;;
+
+ mp_float_t refresh_time = mp_obj_get_float(args[ARG_refresh_time].u_obj);
+ mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj);
+
+ mp_int_t write_color_ram_command = NO_COMMAND;
+ mp_int_t highlight_color = args[ARG_highlight_color].u_int;
+ if (args[ARG_write_color_ram_command].u_obj != mp_const_none) {
+ write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj);
+ }
+
+ self->base.type = &displayio_epaperdisplay_type;
+ common_hal_displayio_epaperdisplay_construct(
+ self,
+ display_bus,
+ start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len,
+ args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
+ args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int,
+ args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int,
+ args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time,
+ busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool
+ );
+
+ return self;
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_epaperdisplay_obj_t* native_display(mp_obj_t display_obj) {
+ mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_epaperdisplay_type);
+ mp_obj_assert_native_inited(native_display);
+ return MP_OBJ_TO_PTR(native_display);
+}
+
+//| def show(self, group: Group) -> Any:
+//| """Switches to displaying the given group of layers. When group is None, the default
+//| CircuitPython terminal will be shown.
+//|
+//| :param Group group: The group to show."""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ displayio_group_t* group = NULL;
+ if (group_in != mp_const_none) {
+ group = MP_OBJ_TO_PTR(native_group(group_in));
+ }
+
+ bool ok = common_hal_displayio_epaperdisplay_show(self, group);
+ if (!ok) {
+ mp_raise_ValueError(translate("Group already used"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show);
+
+//| def refresh(self, ) -> Any:
+//| """Refreshes the display immediately or raises an exception if too soon. Use
+//| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur."""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_refresh(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ bool ok = common_hal_displayio_epaperdisplay_refresh(self);
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Refresh too soon"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_obj, displayio_epaperdisplay_obj_refresh);
+
+//| time_to_refresh: Any = ...
+//| """Time, in fractional seconds, until the ePaper display can be refreshed."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self) / 1000.0);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh);
+
+const mp_obj_property_t displayio_epaperdisplay_time_to_refresh_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_time_to_refresh_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| width: Any = ...
+//| """Gets the width of the display in pixels"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_width(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_width_obj, displayio_epaperdisplay_obj_get_width);
+
+const mp_obj_property_t displayio_epaperdisplay_width_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_width_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| height: Any = ...
+//| """Gets the height of the display in pixels"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_height(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_height_obj, displayio_epaperdisplay_obj_get_height);
+
+const mp_obj_property_t displayio_epaperdisplay_height_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_height_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| bus: Any = ...
+//| """The bus being used by the display"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return common_hal_displayio_epaperdisplay_get_bus(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus);
+
+const mp_obj_property_t displayio_epaperdisplay_bus_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_bus_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+
+STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table);
+
+const mp_obj_type_t displayio_epaperdisplay_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_EPaperDisplay,
+ .make_new = displayio_epaperdisplay_make_new,
+ .locals_dict = (mp_obj_dict_t*)&displayio_epaperdisplay_locals_dict,
+};
diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h
new file mode 100644
index 000000000..e4b81c883
--- /dev/null
+++ b/shared-bindings/displayio/EPaperDisplay.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the Micro Python 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/displayio/EPaperDisplay.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_epaperdisplay_type;
+
+#define DELAY 0x80
+
+#define NO_COMMAND 0x100
+
+void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self,
+ mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len,
+ uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation,
+ uint16_t set_column_window_command, uint16_t set_row_window_command,
+ uint16_t set_current_column_command, uint16_t set_current_row_command,
+ uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
+ const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select);
+
+bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self);
+
+bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group);
+
+// Returns time in milliseconds.
+uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self);
+
+uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self);
+uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self);
+
+mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c
index c0d60bd3b..5ee4ec5a9 100644
--- a/shared-bindings/displayio/FourWire.c
+++ b/shared-bindings/displayio/FourWire.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2018-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
@@ -32,81 +32,128 @@
#include "py/binary.h"
#include "py/objproperty.h"
#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: displayio
+//| class FourWire:
+//| """Manage updating a display over SPI four wire protocol in the background while Python code runs.
+//| It doesn't handle display initialization."""
//|
-//| :class:`FourWire` -- Manage updating a display over SPI four wire protocol
-//| ==========================================================================
+//| def __init__(self, spi_bus: busio.SPI, *, command: microcontroller.Pin, chip_select: microcontroller.Pin, reset: microcontroller.Pin = None, baudrate: int = 24000000, polarity: int = 0, phase: int = 0):
+//| """Create a FourWire object associated with the given pins.
//|
-//| Manage updating a display over SPI four wire protocol in the background while Python code runs.
-//| It doesn't handle display initialization.
+//| The SPI bus and pins are then in use by the display until `displayio.release_displays()` is
+//| called even after a reload. (It does this so CircuitPython can use the display after your code
+//| is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
+//| :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines
+//| :param microcontroller.Pin command: Data or command pin
+//| :param microcontroller.Pin chip_select: Chip select pin
+//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used
+//| :param int baudrate: Maximum baudrate in Hz for the display on the bus
+//| :param int polarity: the base state of the clock line (0 or 1)
+//| :param int phase: the edge of the clock that data is captured. First (0)
+//| or second (1). Rising or falling depends on clock polarity."""
+//| ...
//|
-//| .. class:: FourWire(*, clock, data, command, chip_select, width, height, colstart, rowstart,
-//| color_depth, set_column_command, set_row_command, write_ram_command)
-//|
-//| Create a FourWire object associated with the given pins.
-//|
-STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_raise_NotImplementedError(translate("displayio is a work in progress"));
- return mp_const_none;
-}
+STATIC mp_obj_t displayio_fourwire_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_spi_bus, ARG_command, ARG_chip_select, ARG_reset, ARG_baudrate, ARG_polarity, ARG_phase };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_baudrate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 24000000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
+ mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
-//| .. method:: send(command, data)
-//|
-//|
-STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- mp_raise_NotImplementedError(translate("displayio is a work in progress"));
+ mp_obj_t spi = args[ARG_spi_bus].u_obj;
+ displayio_fourwire_obj_t* self = &allocate_display_bus_or_raise()->fourwire_bus;
+ self->base.type = &displayio_fourwire_type;
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 1, displayio_fourwire_obj_send);
+ uint8_t polarity = args[ARG_polarity].u_int;
+ if (polarity != 0 && polarity != 1) {
+ mp_raise_ValueError(translate("Invalid polarity"));
+ }
+ uint8_t phase = args[ARG_phase].u_int;
+ if (phase != 0 && phase != 1) {
+ mp_raise_ValueError(translate("Invalid phase"));
+ }
-//| .. method:: show(group)
-//|
-//| Switches do displaying the given group of elements.
-//|
-STATIC mp_obj_t displayio_fourwire_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
- displayio_fourwire_obj_t *self = MP_OBJ_TO_PTR(self_in);
- displayio_group_t* group = MP_OBJ_TO_PTR(group_in);
- common_hal_displayio_fourwire_show(self, group);
- return mp_const_none;
+ common_hal_displayio_fourwire_construct(self,
+ MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int, polarity, phase);
+ return self;
}
-MP_DEFINE_CONST_FUN_OBJ_2(displayio_fourwire_show_obj, displayio_fourwire_obj_show);
-//| .. method:: refresh_soon()
-//|
-//| Queues up a display refresh that happens in the background.
+//| def reset(self, ) -> Any:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
//|
-STATIC mp_obj_t displayio_fourwire_obj_refresh_soon(mp_obj_t self_in) {
- displayio_fourwire_obj_t *self = MP_OBJ_TO_PTR(self_in);
- common_hal_displayio_fourwire_refresh_soon(self);
+STATIC mp_obj_t displayio_fourwire_obj_reset(mp_obj_t self_in) {
+ displayio_fourwire_obj_t *self = self_in;
+
+ if (!common_hal_displayio_fourwire_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_refresh_soon_obj, displayio_fourwire_obj_refresh_soon);
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_reset_obj, displayio_fourwire_obj_reset);
-//| .. method:: wait_for_frame()
+//| def send(self, command: Any, data: Any, *, toggle_every_byte: Any = False) -> Any:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
//|
-//| Waits until the next frame has been transmitted to the display unless the wait count is
-//| behind the rendered frames. In that case, this will return immediately with the wait count.
-//|
-STATIC mp_obj_t displayio_fourwire_obj_wait_for_frame(mp_obj_t self_in) {
- displayio_fourwire_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_fourwire_wait_for_frame(self));
-}
-MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_wait_for_frame_obj, displayio_fourwire_obj_wait_for_frame);
+STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_command, ARG_data, ARG_toggle_every_byte };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_toggle_every_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t command_int = args[ARG_command].u_int;
+ if (command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ displayio_fourwire_obj_t *self = pos_args[0];
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_displayio_fourwire_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED;
+ if (args[ARG_toggle_every_byte].u_bool) {
+ chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE;
+ }
+ common_hal_displayio_fourwire_send(self, DISPLAY_COMMAND, chip_select, &command, 1);
+ common_hal_displayio_fourwire_send(self, DISPLAY_DATA, chip_select, ((uint8_t*) bufinfo.buf), bufinfo.len);
+ common_hal_displayio_fourwire_end_transaction(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 3, displayio_fourwire_obj_send);
STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_fourwire_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) },
- { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_fourwire_show_obj) },
- { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_fourwire_refresh_soon_obj) },
- { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_fourwire_wait_for_frame_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_fourwire_locals_dict, displayio_fourwire_locals_dict_table);
diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h
index fc51f558d..ac186d2c3 100644
--- a/shared-bindings/displayio/FourWire.h
+++ b/shared-bindings/displayio/FourWire.h
@@ -27,39 +27,29 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
-#include "common-hal/displayio/FourWire.h"
+#include "shared-module/displayio/FourWire.h"
+
+#include "shared-bindings/displayio/__init__.h"
#include "common-hal/microcontroller/Pin.h"
#include "shared-module/displayio/Group.h"
extern const mp_obj_type_t displayio_fourwire_type;
-// TODO(tannewt): Split this apart into FourWire and a Display object because the dimensions and
-// commands are also used for the parallel buses.
void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self,
- const mcu_pin_obj_t* clock, const mcu_pin_obj_t* data, const mcu_pin_obj_t* command,
- const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset, uint16_t width, uint16_t height,
- int16_t colstart, int16_t rowstart, uint16_t color_depth,
- uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command);
-
-int32_t common_hal_displayio_fourwire_wait_for_frame(displayio_fourwire_obj_t* self);
-
-bool common_hal_displayio_fourwire_begin_transaction(displayio_fourwire_obj_t* self);
-
-void common_hal_displayio_fourwire_send(displayio_fourwire_obj_t* self, bool command, uint8_t *data, uint32_t data_length);
+ busio_spi_obj_t* spi, const mcu_pin_obj_t* command,
+ const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset, uint32_t baudrate,
+ uint8_t polarity, uint8_t phase);
-void common_hal_displayio_fourwire_end_transaction(displayio_fourwire_obj_t* self);
+void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self);
-void common_hal_displayio_fourwire_show(displayio_fourwire_obj_t* self, displayio_group_t* root_group);
+bool common_hal_displayio_fourwire_reset(mp_obj_t self);
+bool common_hal_displayio_fourwire_bus_free(mp_obj_t self);
-void common_hal_displayio_fourwire_refresh_soon(displayio_fourwire_obj_t* self);
+bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self);
-void displayio_fourwire_start_region_update(displayio_fourwire_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
-void displayio_fourwire_finish_region_update(displayio_fourwire_obj_t* self);
-bool displayio_fourwire_frame_queued(displayio_fourwire_obj_t* self);
+void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length);
-bool displayio_fourwire_refresh_queued(displayio_fourwire_obj_t* self);
-void displayio_fourwire_finish_refresh(displayio_fourwire_obj_t* self);
-bool displayio_fourwire_send_pixels(displayio_fourwire_obj_t* self, uint32_t* pixels, uint32_t length);
+void common_hal_displayio_fourwire_end_transaction(mp_obj_t self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
diff --git a/shared-bindings/displayio/Group.c b/shared-bindings/displayio/Group.c
index 98257673b..b6f96883b 100644
--- a/shared-bindings/displayio/Group.c
+++ b/shared-bindings/displayio/Group.c
@@ -31,71 +31,307 @@
#include "lib/utils/context_manager_helpers.h"
#include "py/binary.h"
#include "py/objproperty.h"
+#include "py/objtype.h"
#include "py/runtime.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: displayio
+//| class Group:
+//| """Manage a group of sprites and groups and how they are inter-related."""
//|
-//| :class:`Group` -- Group together sprites and subgroups
-//| ==========================================================================
+//| def __init__(self, *, max_size: int = 4, scale: int = 1, x: int = 0, y: int = 0):
+//| """Create a Group of a given size and scale. Scale is in one dimension. For example, scale=2
+//| leads to a layer's pixel being 2x2 pixels when in the group.
//|
-//| Manage a group of sprites and groups and how they are inter-related.
+//| :param int max_size: The maximum group size.
+//| :param int scale: Scale of layer pixels in one dimension.
+//| :param int x: Initial x position within the parent.
+//| :param int y: Initial y position within the parent."""
+//| ...
//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
-//|
-//| .. class:: Group(*, max_size=4)
-//|
-//| Create a Group of a given size.
-//|
-//| :param int max_size: The maximum group size.
-//|
-STATIC mp_obj_t displayio_group_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 0, 0, true);
- mp_map_t kw_args;
- mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
- enum { ARG_max_size };
+STATIC mp_obj_t displayio_group_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_max_size, ARG_scale, ARG_x, ARG_y };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_max_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4} },
+ { MP_QSTR_scale, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_int_t max_size = args[ARG_max_size].u_int;
if (max_size < 1) {
- mp_raise_ValueError(translate("Group must have size at least 1"));
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_size);
+ }
+
+ mp_int_t scale = args[ARG_scale].u_int;
+ if (scale < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_scale);
}
displayio_group_t *self = m_new_obj(displayio_group_t);
self->base.type = &displayio_group_type;
- common_hal_displayio_group_construct(self, max_size);
+ common_hal_displayio_group_construct(self, max_size, scale, args[ARG_x].u_int, args[ARG_y].u_int);
return MP_OBJ_FROM_PTR(self);
}
-//| .. method:: append(layer)
+// Helper to ensure we have the native super class instead of a subclass.
+displayio_group_t* native_group(mp_obj_t group_obj) {
+ mp_obj_t native_group = mp_instance_cast_to_native_base(group_obj, &displayio_group_type);
+ if (native_group == MP_OBJ_NULL) {
+ mp_raise_ValueError_varg(translate("Must be a %q subclass."), MP_QSTR_Group);
+ }
+ mp_obj_assert_native_inited(native_group);
+ return MP_OBJ_TO_PTR(native_group);
+}
+
+//| hidden: Any = ...
+//| """True when the Group and all of it's layers are not visible. When False, the Group's layers
+//| are visible if they haven't been hidden."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_hidden(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return mp_obj_new_bool(common_hal_displayio_group_get_hidden(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_hidden_obj, displayio_group_obj_get_hidden);
+
+STATIC mp_obj_t displayio_group_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ common_hal_displayio_group_set_hidden(self, mp_obj_is_true(hidden_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_hidden_obj, displayio_group_obj_set_hidden);
+
+const mp_obj_property_t displayio_group_hidden_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_group_get_hidden_obj,
+ (mp_obj_t)&displayio_group_set_hidden_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| scale: Any = ...
+//| """Scales each pixel within the Group in both directions. For example, when scale=2 each pixel
+//| will be represented by 2x2 pixels."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_scale(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_scale(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_scale_obj, displayio_group_obj_get_scale);
+
+STATIC mp_obj_t displayio_group_obj_set_scale(mp_obj_t self_in, mp_obj_t scale_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t scale = mp_obj_get_int(scale_obj);
+ if (scale < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_scale);
+ }
+ common_hal_displayio_group_set_scale(self, scale);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_scale_obj, displayio_group_obj_set_scale);
+
+const mp_obj_property_t displayio_group_scale_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_group_get_scale_obj,
+ (mp_obj_t)&displayio_group_set_scale_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| x: Any = ...
+//| """X position of the Group in the parent."""
//|
-//| Append a layer to the group. It will be drawn above other layers.
+STATIC mp_obj_t displayio_group_obj_get_x(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_x_obj, displayio_group_obj_get_x);
+
+STATIC mp_obj_t displayio_group_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ common_hal_displayio_group_set_x(self, x);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_x_obj, displayio_group_obj_set_x);
+
+const mp_obj_property_t displayio_group_x_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_group_get_x_obj,
+ (mp_obj_t)&displayio_group_set_x_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| y: Any = ...
+//| """Y position of the Group in the parent."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_y(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_y_obj, displayio_group_obj_get_y);
+
+STATIC mp_obj_t displayio_group_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t y = mp_obj_get_int(y_obj);
+ common_hal_displayio_group_set_y(self, y);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_y_obj, displayio_group_obj_set_y);
+
+const mp_obj_property_t displayio_group_y_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_group_get_y_obj,
+ (mp_obj_t)&displayio_group_set_y_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| def append(self, layer: Any) -> Any:
+//| """Append a layer to the group. It will be drawn above other layers."""
+//| ...
//|
STATIC mp_obj_t displayio_group_obj_append(mp_obj_t self_in, mp_obj_t layer) {
- displayio_group_t *self = MP_OBJ_TO_PTR(self_in);
- common_hal_displayio_group_append(self, layer);
+ displayio_group_t *self = native_group(self_in);
+ common_hal_displayio_group_insert(self, common_hal_displayio_group_get_len(self), layer);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_append_obj, displayio_group_obj_append);
-//| .. method:: pop()
+//| def insert(self, index: Any, layer: Any) -> Any:
+//| """Insert a layer into the group."""
+//| ...
//|
-//| Remove the last item and return it.
+STATIC mp_obj_t displayio_group_obj_insert(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t layer) {
+ displayio_group_t *self = native_group(self_in);
+ size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false);
+ common_hal_displayio_group_insert(self, index, layer);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(displayio_group_insert_obj, displayio_group_obj_insert);
+
+
+//| def index(self, layer: Any) -> Any:
+//| """Returns the index of the first copy of layer. Raises ValueError if not found."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_index(mp_obj_t self_in, mp_obj_t layer) {
+ displayio_group_t *self = native_group(self_in);
+ mp_int_t index = common_hal_displayio_group_index(self, layer);
+ if (index < 0) {
+ mp_raise_ValueError(translate("object not in sequence"));
+ }
+ return MP_OBJ_NEW_SMALL_INT(index);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_index_obj, displayio_group_obj_index);
+
+//| def pop(self, i: Any = -1) -> Any:
+//| """Remove the ith item and return it."""
+//| ...
//|
-STATIC mp_obj_t displayio_group_obj_pop(mp_obj_t self_in) {
- displayio_group_t *self = MP_OBJ_TO_PTR(self_in);
- return common_hal_displayio_group_pop(self);
+STATIC mp_obj_t displayio_group_obj_pop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_i };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i, MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_group_t *self = native_group(pos_args[0]);
+
+ size_t index = mp_get_index(&displayio_group_type,
+ common_hal_displayio_group_get_len(self),
+ MP_OBJ_NEW_SMALL_INT(args[ARG_i].u_int),
+ false);
+ return common_hal_displayio_group_pop(self, index);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_pop_obj, 1, displayio_group_obj_pop);
+
+
+//| def remove(self, layer: Any) -> Any:
+//| """Remove the first copy of layer. Raises ValueError if it is not present."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_remove(mp_obj_t self_in, mp_obj_t layer) {
+ mp_obj_t index = displayio_group_obj_index(self_in, layer);
+ displayio_group_t *self = native_group(self_in);
+
+ common_hal_displayio_group_pop(self, MP_OBJ_SMALL_INT_VALUE(index));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_remove_obj, displayio_group_obj_remove);
+
+//| def __len__(self, ) -> Any:
+//| """Returns the number of layers in a Group"""
+//| ...
+//|
+STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ uint16_t len = common_hal_displayio_group_get_len(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len);
+ default: return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __getitem__(self, index: Any) -> Any:
+//| """Returns the value at the given index.
+//|
+//| This allows you to::
+//|
+//| print(group[0])"""
+//| ...
+//|
+//| def __setitem__(self, index: Any, value: Any) -> Any:
+//| """Sets the value at the given index.
+//|
+//| This allows you to::
+//|
+//| group[0] = sprite"""
+//| ...
+//|
+//| def __delitem__(self, index: Any) -> Any:
+//| """Deletes the value at the given index.
+//|
+//| This allows you to::
+//|
+//| del group[0]"""
+//| ...
+//|
+STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) {
+ displayio_group_t *self = native_group(self_in);
+
+ if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false);
+
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ return common_hal_displayio_group_get(self, index);
+ } else if (value == MP_OBJ_NULL) {
+ common_hal_displayio_group_pop(self, index);
+ } else {
+ common_hal_displayio_group_set(self, index, value);
+ }
+ }
+ return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_pop_obj, displayio_group_obj_pop);
STATIC const mp_rom_map_elem_t displayio_group_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_group_hidden_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&displayio_group_scale_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_group_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_group_y_obj) },
{ MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&displayio_group_append_obj) },
+ { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&displayio_group_insert_obj) },
+ { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&displayio_group_index_obj) },
{ MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&displayio_group_pop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&displayio_group_remove_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_group_locals_dict, displayio_group_locals_dict_table);
@@ -103,5 +339,8 @@ const mp_obj_type_t displayio_group_type = {
{ &mp_type_type },
.name = MP_QSTR_Group,
.make_new = displayio_group_make_new,
+ .subscr = group_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
.locals_dict = (mp_obj_dict_t*)&displayio_group_locals_dict,
};
diff --git a/shared-bindings/displayio/Group.h b/shared-bindings/displayio/Group.h
index a85098e6d..942a207f2 100644
--- a/shared-bindings/displayio/Group.h
+++ b/shared-bindings/displayio/Group.h
@@ -31,9 +31,23 @@
extern const mp_obj_type_t displayio_group_type;
+displayio_group_t* native_group(mp_obj_t group_obj);
-void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size);
+void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y);
+uint32_t common_hal_displayio_group_get_scale(displayio_group_t* self);
+void common_hal_displayio_group_set_scale(displayio_group_t* self, uint32_t scale);
+bool common_hal_displayio_group_get_hidden(displayio_group_t* self);
+void common_hal_displayio_group_set_hidden(displayio_group_t* self, bool hidden);
+mp_int_t common_hal_displayio_group_get_x(displayio_group_t* self);
+void common_hal_displayio_group_set_x(displayio_group_t* self, mp_int_t x);
+mp_int_t common_hal_displayio_group_get_y(displayio_group_t* self);
+void common_hal_displayio_group_set_y(displayio_group_t* self, mp_int_t y);
void common_hal_displayio_group_append(displayio_group_t* self, mp_obj_t layer);
-mp_obj_t common_hal_displayio_group_pop(displayio_group_t* self);
+void common_hal_displayio_group_insert(displayio_group_t* self, size_t index, mp_obj_t layer);
+size_t common_hal_displayio_group_get_len(displayio_group_t* self);
+mp_obj_t common_hal_displayio_group_pop(displayio_group_t* self, size_t index);
+mp_int_t common_hal_displayio_group_index(displayio_group_t* self, mp_obj_t layer);
+mp_obj_t common_hal_displayio_group_get(displayio_group_t* self, size_t index);
+void common_hal_displayio_group_set(displayio_group_t* self, size_t index, mp_obj_t layer);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c
new file mode 100644
index 000000000..0cfac6672
--- /dev/null
+++ b/shared-bindings/displayio/I2CDisplay.c
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the Micro Python 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 "shared-bindings/displayio/I2CDisplay.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class I2CDisplay:
+//| """Manage updating a display over I2C in the background while Python code runs.
+//| It doesn't handle display initialization."""
+//|
+//| def __init__(self, i2c_bus: busio.I2C, *, device_address: int, reset: microcontroller.Pin = None):
+//| """Create a I2CDisplay object associated with the given I2C bus and reset pin.
+//|
+//| The I2C bus and pins are then in use by the display until `displayio.release_displays()` is
+//| called even after a reload. (It does this so CircuitPython can use the display after your code
+//| is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
+//|
+//| :param busio.I2C i2c_bus: The I2C bus that make up the clock and data lines
+//| :param int device_address: The I2C address of the device
+//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used"""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_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_i2c_bus, ARG_device_address, ARG_reset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i2c_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_device_address, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ mp_obj_t i2c = args[ARG_i2c_bus].u_obj;
+ displayio_i2cdisplay_obj_t* self = &allocate_display_bus_or_raise()->i2cdisplay_bus;
+ self->base.type = &displayio_i2cdisplay_type;
+
+ common_hal_displayio_i2cdisplay_construct(self,
+ MP_OBJ_TO_PTR(i2c), args[ARG_device_address].u_int, reset);
+ return self;
+}
+
+//| def reset(self, ) -> Any:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_obj_reset(mp_obj_t self_in) {
+ displayio_i2cdisplay_obj_t *self = self_in;
+
+ if (!common_hal_displayio_i2cdisplay_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_i2cdisplay_reset_obj, displayio_i2cdisplay_obj_reset);
+
+//| def send(self, command: Any, data: Any) -> Any:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) {
+ mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj);
+ if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ uint8_t full_command[bufinfo.len + 1];
+ full_command[0] = command;
+ memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len);
+ common_hal_displayio_i2cdisplay_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, full_command, bufinfo.len + 1);
+ common_hal_displayio_i2cdisplay_end_transaction(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send);
+
+STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_i2cdisplay_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table);
+
+const mp_obj_type_t displayio_i2cdisplay_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2CDisplay,
+ .make_new = displayio_i2cdisplay_make_new,
+ .locals_dict = (mp_obj_dict_t*)&displayio_i2cdisplay_locals_dict,
+};
diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h
new file mode 100644
index 000000000..bae53c491
--- /dev/null
+++ b/shared-bindings/displayio/I2CDisplay.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
+
+#include "shared-module/displayio/I2CDisplay.h"
+
+#include "shared-bindings/displayio/__init__.h"
+#include "common-hal/microcontroller/Pin.h"
+
+extern const mp_obj_type_t displayio_i2cdisplay_type;
+
+void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self,
+ busio_i2c_obj_t* i2c, uint16_t device_address, const mcu_pin_obj_t* reset);
+
+void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self);
+
+bool common_hal_displayio_i2cdisplay_reset(mp_obj_t self);
+bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self);
+
+bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self);
+
+void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length);
+
+void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
diff --git a/shared-bindings/displayio/OnDiskBitmap.c b/shared-bindings/displayio/OnDiskBitmap.c
index d3d413da1..170873653 100644
--- a/shared-bindings/displayio/OnDiskBitmap.c
+++ b/shared-bindings/displayio/OnDiskBitmap.c
@@ -29,57 +29,54 @@
#include <stdint.h>
#include "py/runtime.h"
+#include "py/objproperty.h"
#include "supervisor/shared/translate.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
-//| .. currentmodule:: displayio
-//|
-//| :class:`OnDiskBitmap` -- Loads pixels straight from disk
-//| ==========================================================================
-//|
-//| Loads values straight from disk. This minimizes memory use but can lead to
-//| much slower pixel load times. These load times may result in frame tearing where only part of
-//| the image is visible.
+//| class OnDiskBitmap:
+//| """Loads values straight from disk. This minimizes memory use but can lead to
+//| much slower pixel load times. These load times may result in frame tearing where only part of
+//| the image is visible.
//|
-//| .. warning:: This will likely be changed before 4.0.0. Consider it very experimental.
+//| It's easiest to use on a board with a built in display such as the `Hallowing M0 Express
+//| <https://www.adafruit.com/product/3900>`_.
//|
-//| It's easiest to use on a board with a built in display such as the `Hallowing M0 Express
-//| <https://www.adafruit.com/product/3900>`_.
+//| .. code-block:: Python
//|
-//| .. code-block:: Python
+//| import board
+//| import displayio
+//| import time
+//| import pulseio
//|
-//| import board
-//| import displayio
-//| import time
-//| import pulseio
+//| board.DISPLAY.auto_brightness = False
+//| board.DISPLAY.brightness = 0
+//| splash = displayio.Group()
+//| board.DISPLAY.show(splash)
//|
-//| backlight = pulseio.PWMOut(board.TFT_BACKLIGHT)
-//| splash = displayio.Group()
-//| board.DISPLAY.show(splash)
+//| with open("/sample.bmp", "rb") as f:
+//| odb = displayio.OnDiskBitmap(f)
+//| face = displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter())
+//| splash.append(face)
+//| # Wait for the image to load.
+//| board.DISPLAY.refresh(target_frames_per_second=60)
//|
-//| with open("/sample.bmp", "rb") as f:
-//| odb = displayio.OnDiskBitmap(f)
-//| face = displayio.Sprite(odb, pixel_shader=displayio.ColorConverter(), position=(0,0))
-//| splash.append(face)
-//| # Wait for the image to load.
-//| board.DISPLAY.wait_for_frame()
+//| # Fade up the backlight
+//| for i in range(100):
+//| board.DISPLAY.brightness = 0.01 * i
+//| time.sleep(0.05)
//|
-//| # Fade up the backlight
-//| for i in range(100):
-//| backlight.duty_cycle = i * (2 ** 15) // 100
-//| time.sleep(0.01)
+//| # Wait forever
+//| while True:
+//| pass"""
//|
-//| # Wait forever
-//| while True:
-//| pass
+//| def __init__(self, file: file):
+//| """Create an OnDiskBitmap object with the given file.
//|
-//| .. class:: OnDiskBitmap(file)
+//| :param file file: The open bitmap file"""
+//| ...
//|
-//| Create an OnDiskBitmap object with the given file.
-//|
-//| :param file file: The open bitmap file
-//|
-STATIC mp_obj_t displayio_ondiskbitmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
+STATIC mp_obj_t displayio_ondiskbitmap_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_arg_check_num(n_args, kw_args, 1, 1, false);
if (!MP_OBJ_IS_TYPE(pos_args[0], &mp_type_fileio)) {
mp_raise_TypeError(translate("file must be a file opened in byte mode"));
@@ -92,7 +89,47 @@ STATIC mp_obj_t displayio_ondiskbitmap_make_new(const mp_obj_type_t *type, size_
return MP_OBJ_FROM_PTR(self);
}
+//| width: Any = ...
+//| """Width of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_width(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_ondiskbitmap_get_width(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_width_obj, displayio_ondiskbitmap_obj_get_width);
+
+const mp_obj_property_t displayio_ondiskbitmap_width_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_ondiskbitmap_get_width_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+
+};
+
+//| height: Any = ...
+//| """Height of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_height(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_ondiskbitmap_get_height(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_height_obj, displayio_ondiskbitmap_obj_get_height);
+
+const mp_obj_property_t displayio_ondiskbitmap_height_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_ondiskbitmap_get_height_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+
+};
+
STATIC const mp_rom_map_elem_t displayio_ondiskbitmap_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_ondiskbitmap_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_ondiskbitmap_width_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_ondiskbitmap_locals_dict, displayio_ondiskbitmap_locals_dict_table);
diff --git a/shared-bindings/displayio/OnDiskBitmap.h b/shared-bindings/displayio/OnDiskBitmap.h
index ab8b8dcd8..9a6c81f8f 100644
--- a/shared-bindings/displayio/OnDiskBitmap.h
+++ b/shared-bindings/displayio/OnDiskBitmap.h
@@ -37,4 +37,7 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self,
uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *bitmap,
int16_t x, int16_t y);
+uint16_t common_hal_displayio_ondiskbitmap_get_height(displayio_ondiskbitmap_t *self);
+
+uint16_t common_hal_displayio_ondiskbitmap_get_width(displayio_ondiskbitmap_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c
index 7086d0ab1..871b2b06a 100644
--- a/shared-bindings/displayio/Palette.c
+++ b/shared-bindings/displayio/Palette.c
@@ -36,34 +36,32 @@
#include "shared-bindings/util.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: displayio
-//|
-//| :class:`Palette` -- Stores a mapping from bitmap pixel palette_indexes to display colors
-//| =========================================================================================
-//|
-//| Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
-//| save memory.
-//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
+
+
+
+
+
+
+//| class Palette:
+//| """Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
+//| save memory."""
//|
-//| .. class:: Palette(color_count)
+//| def __init__(self, color_count: int):
+//| """Create a Palette object to store a set number of colors.
//|
-//| Create a Palette object to store a set number of colors.
+//| :param int color_count: The number of colors in the Palette"""
+//| ...
//|
-//| :param int color_count: The number of colors in the Palette
// TODO(tannewt): Add support for other color formats.
// TODO(tannewt): Add support for 8-bit alpha blending.
//|
-STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 1, 1, true);
- mp_map_t kw_args;
- mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
+STATIC mp_obj_t displayio_palette_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_color_count };
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_color_count, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
displayio_palette_t *self = m_new_obj(displayio_palette_t);
self->base.type = &displayio_palette_type;
@@ -72,6 +70,36 @@ STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_a
return MP_OBJ_FROM_PTR(self);
}
+//| def __len__(self, ) -> Any:
+//| """Returns the number of colors in a Palette"""
+//| ...
+//|
+STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_BOOL: return mp_const_true;
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_len(self));
+ default: return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __setitem__(self, index: Any, value: Any) -> Any:
+//| """Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1.
+//|
+//| The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value).
+//| Value can be an int, bytes (3 bytes (RGB) or 4 bytes (RGB + pad byte)), bytearray,
+//| or a tuple or list of 3 integers.
+//|
+//| This allows you to::
+//|
+//| palette[0] = 0xFFFFFF # set using an integer
+//| palette[1] = b'\xff\xff\x00' # set using 3 bytes
+//| palette[2] = b'\xff\xff\x00\x00' # set using 4 bytes
+//| palette[3] = bytearray(b'\x00\x00\xFF') # set using a bytearay of 3 or 4 bytes
+//| palette[4] = (10, 20, 30) # set using a tuple of 3 integers"""
+//| ...
+//|
STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
if (value == MP_OBJ_NULL) {
// delete item
@@ -81,12 +109,18 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val
if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {
return MP_OBJ_NULL;
}
- // index read is not supported
- if (value == MP_OBJ_SENTINEL) {
- return MP_OBJ_NULL;
- }
displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
size_t index = mp_get_index(&displayio_palette_type, self->color_count, index_in, false);
+ // index read
+ if (value == MP_OBJ_SENTINEL) {
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_color(self, index));
+ }
+
+ // Convert a tuple or list to a bytearray.
+ if (MP_OBJ_IS_TYPE(value, &mp_type_tuple) ||
+ MP_OBJ_IS_TYPE(value, &mp_type_list)) {
+ value = mp_type_bytes.make_new(&mp_type_bytes, 1, &value, NULL);
+ }
uint32_t color;
mp_int_t int_value;
@@ -107,13 +141,13 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val
}
color = int_value;
} else {
- mp_raise_TypeError(translate("color buffer must be a buffer or int"));
+ mp_raise_TypeError(translate("color buffer must be a buffer, tuple, list, or int"));
}
common_hal_displayio_palette_set_color(self, index, color);
return mp_const_none;
}
-//| .. method:: make_transparent(palette_index)
+//| def make_transparent(self, palette_index: Any) -> Any: ...
//|
STATIC mp_obj_t displayio_palette_obj_make_transparent(mp_obj_t self_in, mp_obj_t palette_index_obj) {
displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
@@ -127,7 +161,7 @@ STATIC mp_obj_t displayio_palette_obj_make_transparent(mp_obj_t self_in, mp_obj_
}
MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_make_transparent_obj, displayio_palette_obj_make_transparent);
-//| .. method:: make_opaque(palette_index)
+//| def make_opaque(self, palette_index: Any) -> Any: ...
//|
STATIC mp_obj_t displayio_palette_obj_make_opaque(mp_obj_t self_in, mp_obj_t palette_index_obj) {
displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
@@ -152,5 +186,7 @@ const mp_obj_type_t displayio_palette_type = {
.name = MP_QSTR_Palette,
.make_new = displayio_palette_make_new,
.subscr = palette_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
.locals_dict = (mp_obj_dict_t*)&displayio_palette_locals_dict,
};
diff --git a/shared-bindings/displayio/Palette.h b/shared-bindings/displayio/Palette.h
index 767fc7b63..8c9fe11e3 100644
--- a/shared-bindings/displayio/Palette.h
+++ b/shared-bindings/displayio/Palette.h
@@ -33,6 +33,8 @@ extern const mp_obj_type_t displayio_palette_type;
void common_hal_displayio_palette_construct(displayio_palette_t* self, uint16_t color_count);
void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t palette_index, uint32_t color);
+uint32_t common_hal_displayio_palette_get_color(displayio_palette_t* self, uint32_t palette_index);
+uint32_t common_hal_displayio_palette_get_len(displayio_palette_t* self);
void common_hal_displayio_palette_make_opaque(displayio_palette_t* self, uint32_t palette_index);
void common_hal_displayio_palette_make_transparent(displayio_palette_t* self, uint32_t palette_index);
diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c
new file mode 100644
index 000000000..eb75ecc03
--- /dev/null
+++ b/shared-bindings/displayio/ParallelBus.c
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the Micro Python 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 "shared-bindings/displayio/ParallelBus.h"
+
+#include <stdint.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class ParallelBus:
+//| """Manage updating a display over 8-bit parallel bus in the background while Python code runs. This
+//| protocol may be refered to as 8080-I Series Parallel Interface in datasheets. It doesn't handle
+//| display initialization."""
+//|
+//| def __init__(self, *, data0: microcontroller.Pin, command: microcontroller.Pin, chip_select: microcontroller.Pin, write: microcontroller.Pin, read: microcontroller.Pin, reset: microcontroller.Pin):
+//| """Create a ParallelBus object associated with the given pins. The bus is inferred from data0
+//| by implying the next 7 additional pins on a given GPIO port.
+//|
+//| The parallel bus and pins are then in use by the display until `displayio.release_displays()`
+//| is called even after a reload. (It does this so CircuitPython can use the display after your
+//| code is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
+//|
+//| :param microcontroller.Pin data0: The first data pin. The rest are implied
+//| :param microcontroller.Pin command: Data or command pin
+//| :param microcontroller.Pin chip_select: Chip select pin
+//| :param microcontroller.Pin write: Write pin
+//| :param microcontroller.Pin read: Read pin
+//| :param microcontroller.Pin reset: Reset pin"""
+//| ...
+//|
+STATIC mp_obj_t displayio_parallelbus_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_data0, ARG_command, ARG_chip_select, ARG_write, ARG_read, ARG_reset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data0, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_write, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_read, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj);
+ mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
+ mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ mcu_pin_obj_t *write = validate_obj_is_free_pin(args[ARG_write].u_obj);
+ mcu_pin_obj_t *read = validate_obj_is_free_pin(args[ARG_read].u_obj);
+ mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj);
+
+ displayio_parallelbus_obj_t* self = &allocate_display_bus_or_raise()->parallel_bus;
+ self->base.type = &displayio_parallelbus_type;
+
+ common_hal_displayio_parallelbus_construct(self, data0, command, chip_select, write, read, reset);
+ return self;
+}
+
+//| def reset(self, ) -> Any:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
+//|
+
+STATIC mp_obj_t displayio_parallelbus_obj_reset(mp_obj_t self_in) {
+ displayio_parallelbus_obj_t *self = self_in;
+
+ if (!common_hal_displayio_parallelbus_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_parallelbus_reset_obj, displayio_parallelbus_obj_reset);
+
+//| def send(self, command: Any, data: Any) -> Any:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
+//|
+STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) {
+ mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj);
+ if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_displayio_parallelbus_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ common_hal_displayio_parallelbus_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1);
+ common_hal_displayio_parallelbus_send(self, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*) bufinfo.buf), bufinfo.len);
+ common_hal_displayio_parallelbus_end_transaction(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(displayio_parallelbus_send_obj, displayio_parallelbus_obj_send);
+
+STATIC const mp_rom_map_elem_t displayio_parallelbus_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_parallelbus_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_parallelbus_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_parallelbus_locals_dict, displayio_parallelbus_locals_dict_table);
+
+const mp_obj_type_t displayio_parallelbus_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ParallelBus,
+ .make_new = displayio_parallelbus_make_new,
+ .locals_dict = (mp_obj_dict_t*)&displayio_parallelbus_locals_dict,
+};
diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h
new file mode 100644
index 000000000..be2aef7d4
--- /dev/null
+++ b/shared-bindings/displayio/ParallelBus.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_PARALLELBUS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_PARALLELBUS_H
+
+#include "common-hal/displayio/ParallelBus.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/displayio/__init__.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_parallelbus_type;
+
+void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* self,
+ const mcu_pin_obj_t* data0, const mcu_pin_obj_t* command, const mcu_pin_obj_t* chip_select,
+ const mcu_pin_obj_t* write, const mcu_pin_obj_t* read, const mcu_pin_obj_t* reset);
+
+void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self);
+
+bool common_hal_displayio_parallelbus_reset(mp_obj_t self);
+bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self);
+
+bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self);
+
+void common_hal_displayio_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length);
+
+void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_PARALLELBUS_H
diff --git a/shared-bindings/displayio/Shape.c b/shared-bindings/displayio/Shape.c
new file mode 100644
index 000000000..fce89c771
--- /dev/null
+++ b/shared-bindings/displayio/Shape.c
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the Micro Python 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 "shared-bindings/displayio/Shape.h"
+
+#include <stdint.h>
+
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Shape:
+//| """Represents a shape made by defining boundaries that may be mirrored."""
+//|
+//| def __init__(self, width: int, height: int, *, mirror_x: bool = False, mirror_y: bool = False):
+//| """Create a Shape object with the given fixed size. Each pixel is one bit and is stored by the
+//| column boundaries of the shape on each row. Each row's boundary defaults to the full row.
+//|
+//| :param int width: The number of pixels wide
+//| :param int height: The number of pixels high
+//| :param bool mirror_x: When true the left boundary is mirrored to the right.
+//| :param bool mirror_y: When true the top boundary is mirrored to the bottom."""
+//| ...
+//|
+STATIC mp_obj_t displayio_shape_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_width, ARG_height, ARG_mirror_x, ARG_mirror_y };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_mirror_x, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_mirror_y, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t width = args[ARG_width].u_int;
+ if (width < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_width);
+ }
+ mp_int_t height = args[ARG_height].u_int;
+ if (height < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_height);
+ }
+
+ displayio_shape_t *self = m_new_obj(displayio_shape_t);
+ self->base.type = &displayio_shape_type;
+ common_hal_displayio_shape_construct(self,
+ width,
+ height,
+ args[ARG_mirror_x].u_bool,
+ args[ARG_mirror_y].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+//| def set_boundary(self, y: Any, start_x: Any, end_x: Any) -> Any:
+//| """Loads pre-packed data into the given row."""
+//| ...
+//|
+STATIC mp_obj_t displayio_shape_obj_set_boundary(size_t n_args, const mp_obj_t *args) {
+ (void) n_args;
+ displayio_shape_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t y;
+ if (!mp_obj_get_int_maybe(args[1], &y)) {
+ mp_raise_ValueError(translate("y should be an int"));
+ }
+ mp_int_t start_x;
+ if (!mp_obj_get_int_maybe(args[2], &start_x)) {
+ mp_raise_ValueError(translate("start_x should be an int"));
+ }
+ mp_int_t end_x;
+ if (!mp_obj_get_int_maybe(args[3], &end_x)) {
+ mp_raise_ValueError(translate("end_x should be an int"));
+ }
+ common_hal_displayio_shape_set_boundary(self, y, start_x, end_x);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(displayio_shape_set_boundary_obj, 4, 4, displayio_shape_obj_set_boundary);
+
+STATIC const mp_rom_map_elem_t displayio_shape_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_set_boundary), MP_ROM_PTR(&displayio_shape_set_boundary_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_shape_locals_dict, displayio_shape_locals_dict_table);
+
+const mp_obj_type_t displayio_shape_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Shape,
+ .make_new = displayio_shape_make_new,
+ .locals_dict = (mp_obj_dict_t*)&displayio_shape_locals_dict,
+};
diff --git a/shared-bindings/displayio/Sprite.h b/shared-bindings/displayio/Shape.h
index 1944e1d74..d08a38782 100644
--- a/shared-bindings/displayio/Sprite.h
+++ b/shared-bindings/displayio/Shape.h
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ * 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
@@ -24,20 +24,18 @@
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SPRITE_H
-#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SPRITE_H
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
-#include "shared-module/displayio/Sprite.h"
+#include "shared-module/displayio/Shape.h"
-extern const mp_obj_type_t displayio_sprite_type;
+extern const mp_obj_type_t displayio_shape_type;
-void common_hal_displayio_sprite_construct(displayio_sprite_t *self, mp_obj_t bitmap,
- mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t x, uint16_t y);
+void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t width,
+ uint32_t height, bool mirror_x, bool mirror_y);
-void common_hal_displayio_sprite_get_position(displayio_sprite_t *self, int16_t* x, int16_t* y);
-void common_hal_displayio_sprite_set_position(displayio_sprite_t *self, int16_t x, int16_t y);
+void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x,
+ uint16_t end_x);
+uint32_t common_hal_displayio_shape_get_pixel(void *shape, int16_t x, int16_t y);
-mp_obj_t common_hal_displayio_sprite_get_pixel_shader(displayio_sprite_t *self);
-void common_hal_displayio_sprite_set_pixel_shader(displayio_sprite_t *self, mp_obj_t pixel_shader);
-
-#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SPRITE_H
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
diff --git a/shared-bindings/displayio/Sprite.c b/shared-bindings/displayio/Sprite.c
deleted file mode 100644
index 69c1a5896..000000000
--- a/shared-bindings/displayio/Sprite.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * This file is part of the Micro Python 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/displayio/Sprite.h"
-
-#include <stdint.h>
-
-#include "lib/utils/context_manager_helpers.h"
-#include "py/binary.h"
-#include "py/objproperty.h"
-#include "py/runtime.h"
-#include "shared-bindings/displayio/Bitmap.h"
-#include "shared-bindings/displayio/ColorConverter.h"
-#include "shared-bindings/displayio/OnDiskBitmap.h"
-#include "shared-bindings/displayio/Palette.h"
-#include "supervisor/shared/translate.h"
-
-void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) {
- // TODO(tannewt): Support any value sequence such as bytearray or bytes.
- mp_obj_tuple_t *position = MP_OBJ_TO_PTR(position_obj);
- if (MP_OBJ_IS_TYPE(position_obj, &mp_type_tuple) && position->len == 2) {
- *x = mp_obj_get_int(position->items[0]);
- *y = mp_obj_get_int(position->items[1]);
- } else if (position != mp_const_none) {
- mp_raise_TypeError(translate("position must be 2-tuple"));
- }
-}
-
-//| .. currentmodule:: displayio
-//|
-//| :class:`Sprite` -- A particular copy of an image to display
-//| ==========================================================================
-//|
-//| Position a particular image and pixel_shader combination. Multiple sprites can share bitmaps
-//| pixel shaders.
-//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
-//|
-//| .. class:: Sprite(bitmap, *, pixel_shader, position, width, height)
-//|
-//| Create a Sprite object. The bitmap is source for 2d pixels. The pixel_shader is used to
-//| convert the value and its location to a display native pixel color. This may be a simple color
-//| palette lookup, a gradient, a pattern or a color transformer.
-//|
-//|
-STATIC mp_obj_t displayio_sprite_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
- mp_arg_check_num(n_args, n_kw, 1, 4, true);
- mp_map_t kw_args;
- mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
- enum { ARG_bitmap, ARG_pixel_shader, ARG_position, ARG_width, ARG_height };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_bitmap, MP_ARG_OBJ | MP_ARG_REQUIRED },
- { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY },
- { MP_QSTR_position, MP_ARG_OBJ | MP_ARG_KW_ONLY },
- { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1} },
- { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1} },
- };
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- mp_obj_t bitmap = args[ARG_bitmap].u_obj;
-
- uint16_t width;
- uint16_t height;
- if (MP_OBJ_IS_TYPE(bitmap, &displayio_bitmap_type)) {
- displayio_bitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
- width = bmp->width;
- height = bmp->height;
- } else if (MP_OBJ_IS_TYPE(bitmap, &displayio_ondiskbitmap_type)) {
- displayio_ondiskbitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
- width = bmp->width;
- height = bmp->height;
- } else {
- mp_raise_TypeError(translate("unsupported bitmap type"));
- }
- int16_t x = 0;
- int16_t y = 0;
- mp_obj_t position_obj = args[ARG_position].u_obj;
- unpack_position(position_obj, &x, &y);
-
- displayio_sprite_t *self = m_new_obj(displayio_sprite_t);
- self->base.type = &displayio_sprite_type;
- common_hal_displayio_sprite_construct(self, bitmap, args[ARG_pixel_shader].u_obj,
- width, height, x, y);
- return MP_OBJ_FROM_PTR(self);
-}
-
-//| .. attribute:: position
-//|
-//| The position of the top-left corner of the sprite.
-//|
-STATIC mp_obj_t displayio_sprite_obj_get_position(mp_obj_t self_in) {
- displayio_sprite_t *self = MP_OBJ_TO_PTR(self_in);
- int16_t x;
- int16_t y;
- common_hal_displayio_sprite_get_position(self, &x, &y);
-
- mp_obj_t coords[2];
- coords[0] = mp_obj_new_int(x);
- coords[1] = mp_obj_new_int(y);
-
- return mp_obj_new_tuple(2, coords);
-}
-MP_DEFINE_CONST_FUN_OBJ_1(displayio_sprite_get_position_obj, displayio_sprite_obj_get_position);
-
-STATIC mp_obj_t displayio_sprite_obj_set_position(mp_obj_t self_in, mp_obj_t value) {
- displayio_sprite_t *self = MP_OBJ_TO_PTR(self_in);
-
- int16_t x = 0;
- int16_t y = 0;
- unpack_position(value, &x, &y);
-
- common_hal_displayio_sprite_set_position(self, x, y);
-
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_2(displayio_sprite_set_position_obj, displayio_sprite_obj_set_position);
-
-const mp_obj_property_t displayio_sprite_position_obj = {
- .base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&displayio_sprite_get_position_obj,
- (mp_obj_t)&displayio_sprite_set_position_obj,
- (mp_obj_t)&mp_const_none_obj},
-};
-
-//| .. attribute:: pixel_shader
-//|
-//| The pixel shader of the sprite.
-//|
-STATIC mp_obj_t displayio_sprite_obj_get_pixel_shader(mp_obj_t self_in) {
- displayio_sprite_t *self = MP_OBJ_TO_PTR(self_in);
- return common_hal_displayio_sprite_get_pixel_shader(self);
-}
-MP_DEFINE_CONST_FUN_OBJ_1(displayio_sprite_get_pixel_shader_obj, displayio_sprite_obj_get_pixel_shader);
-
-STATIC mp_obj_t displayio_sprite_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) {
- displayio_sprite_t *self = MP_OBJ_TO_PTR(self_in);
- if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) {
- mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter"));
- }
-
- common_hal_displayio_sprite_set_pixel_shader(self, pixel_shader);
-
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_2(displayio_sprite_set_pixel_shader_obj, displayio_sprite_obj_set_pixel_shader);
-
-const mp_obj_property_t displayio_sprite_pixel_shader_obj = {
- .base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&displayio_sprite_get_pixel_shader_obj,
- (mp_obj_t)&displayio_sprite_set_pixel_shader_obj,
- (mp_obj_t)&mp_const_none_obj},
-};
-
-STATIC const mp_rom_map_elem_t displayio_sprite_locals_dict_table[] = {
- // Properties
- { MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&displayio_sprite_position_obj) },
- { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_sprite_pixel_shader_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(displayio_sprite_locals_dict, displayio_sprite_locals_dict_table);
-
-const mp_obj_type_t displayio_sprite_type = {
- { &mp_type_type },
- .name = MP_QSTR_Sprite,
- .make_new = displayio_sprite_make_new,
- .locals_dict = (mp_obj_dict_t*)&displayio_sprite_locals_dict,
-};
diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c
new file mode 100644
index 000000000..01fba46a5
--- /dev/null
+++ b/shared-bindings/displayio/TileGrid.c
@@ -0,0 +1,401 @@
+/*
+ * This file is part of the Micro Python 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/displayio/TileGrid.h"
+
+#include <stdint.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Bitmap.h"
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+#include "shared-bindings/displayio/Palette.h"
+#include "shared-bindings/displayio/Shape.h"
+#include "supervisor/shared/translate.h"
+
+//| class TileGrid:
+//| """A grid of tiles sourced out of one bitmap
+//|
+//| Position a grid of tiles sourced from a bitmap and pixel_shader combination. Multiple grids
+//| can share bitmaps and pixel shaders.
+//|
+//| A single tile grid is also known as a Sprite."""
+//|
+//| def __init__(self, bitmap: displayio.Bitmap, *, pixel_shader: displayio.Palette, width: int = 1, height: int = 1, tile_width: int = None, tile_height: int = None, default_tile: int = 0, x: int = 0, y: int = 0):
+//| """Create a TileGrid object. The bitmap is source for 2d pixels. The pixel_shader is used to
+//| convert the value and its location to a display native pixel color. This may be a simple color
+//| palette lookup, a gradient, a pattern or a color transformer.
+//|
+//| tile_width and tile_height match the height of the bitmap by default.
+//|
+//| :param displayio.Bitmap bitmap: The bitmap storing one or more tiles.
+//| :param displayio.Palette pixel_shader: The pixel shader that produces colors from values
+//| :param int width: Width of the grid in tiles.
+//| :param int height: Height of the grid in tiles.
+//| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+//| :param int tile_height: Height of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+//| :param int default_tile: Default tile index to show.
+//| :param int x: Initial x position of the left edge within the parent.
+//| :param int y: Initial y position of the top edge within the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_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_bitmap, ARG_pixel_shader, ARG_width, ARG_height, ARG_tile_width, ARG_tile_height, ARG_default_tile, ARG_x, ARG_y };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_tile_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_tile_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_default_tile, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t bitmap = args[ARG_bitmap].u_obj;
+
+ uint16_t bitmap_width;
+ uint16_t bitmap_height;
+ mp_obj_t native = mp_instance_cast_to_native_base(bitmap, &displayio_shape_type);
+ if (native != MP_OBJ_NULL) {
+ displayio_shape_t* bmp = MP_OBJ_TO_PTR(native);
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else if (MP_OBJ_IS_TYPE(bitmap, &displayio_bitmap_type)) {
+ displayio_bitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else if (MP_OBJ_IS_TYPE(bitmap, &displayio_ondiskbitmap_type)) {
+ displayio_ondiskbitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap);
+ }
+ mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
+ if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type) &&
+ !MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type)) {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader);
+ }
+ uint16_t tile_width = args[ARG_tile_width].u_int;
+ if (tile_width == 0) {
+ tile_width = bitmap_width;
+ }
+ uint16_t tile_height = args[ARG_tile_height].u_int;
+ if (tile_height == 0) {
+ tile_height = bitmap_height;
+ }
+ if (bitmap_width % tile_width != 0) {
+ mp_raise_ValueError(translate("Tile width must exactly divide bitmap width"));
+ }
+ if (bitmap_height % tile_height != 0) {
+ mp_raise_ValueError(translate("Tile height must exactly divide bitmap height"));
+ }
+
+ int16_t x = args[ARG_x].u_int;
+ int16_t y = args[ARG_y].u_int;
+
+ displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
+ self->base.type = &displayio_tilegrid_type;
+ common_hal_displayio_tilegrid_construct(self, native,
+ bitmap_width / tile_width, bitmap_height / tile_height,
+ pixel_shader, 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);
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_tilegrid_t* native_tilegrid(mp_obj_t tilegrid_obj) {
+ mp_obj_t native_tilegrid = mp_instance_cast_to_native_base(tilegrid_obj, &displayio_tilegrid_type);
+ mp_obj_assert_native_inited(native_tilegrid);
+ return MP_OBJ_TO_PTR(native_tilegrid);
+}
+//| hidden: Any = ...
+//| """True when the TileGrid is hidden. This may be False even when a part of a hidden Group."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_hidden(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_hidden(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_hidden_obj, displayio_tilegrid_obj_get_hidden);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_hidden(self, mp_obj_is_true(hidden_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_hidden_obj, displayio_tilegrid_obj_set_hidden);
+
+const mp_obj_property_t displayio_tilegrid_hidden_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_hidden_obj,
+ (mp_obj_t)&displayio_tilegrid_set_hidden_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| x: Any = ...
+//| """X position of the left edge in the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_x(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_x_obj, displayio_tilegrid_obj_get_x);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ common_hal_displayio_tilegrid_set_x(self, x);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_x_obj, displayio_tilegrid_obj_set_x);
+
+const mp_obj_property_t displayio_tilegrid_x_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_x_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| y: Any = ...
+//| """Y position of the top edge in the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_y(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_y_obj, displayio_tilegrid_obj_get_y);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ mp_int_t y = mp_obj_get_int(y_obj);
+ common_hal_displayio_tilegrid_set_y(self, y);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_y_obj, displayio_tilegrid_obj_set_y);
+
+const mp_obj_property_t displayio_tilegrid_y_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_y_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| flip_x: Any = ...
+//| """If true, the left edge rendered will be the right edge of the right-most tile."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_flip_x(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_x_obj, displayio_tilegrid_obj_get_flip_x);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_flip_x(mp_obj_t self_in, mp_obj_t flip_x_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_flip_x(self, mp_obj_is_true(flip_x_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_x_obj, displayio_tilegrid_obj_set_flip_x);
+
+const mp_obj_property_t displayio_tilegrid_flip_x_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_flip_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_x_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| flip_y: Any = ...
+//| """If true, the top edge rendered will be the bottom edge of the bottom-most tile."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_flip_y(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_y_obj, displayio_tilegrid_obj_get_flip_y);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_flip_y(mp_obj_t self_in, mp_obj_t flip_y_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_flip_y(self, mp_obj_is_true(flip_y_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_y_obj, displayio_tilegrid_obj_set_flip_y);
+
+const mp_obj_property_t displayio_tilegrid_flip_y_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_flip_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_y_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+
+//| transpose_xy: Any = ...
+//| """If true, the TileGrid's axis will be swapped. When combined with mirroring, any 90 degree
+//| rotation can be achieved along with the corresponding mirrored version."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_transpose_xy(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_transpose_xy(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_transpose_xy_obj, displayio_tilegrid_obj_get_transpose_xy);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_transpose_xy(mp_obj_t self_in, mp_obj_t transpose_xy_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_transpose_xy(self, mp_obj_is_true(transpose_xy_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_transpose_xy_obj, displayio_tilegrid_obj_set_transpose_xy);
+
+const mp_obj_property_t displayio_tilegrid_transpose_xy_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_transpose_xy_obj,
+ (mp_obj_t)&displayio_tilegrid_set_transpose_xy_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| pixel_shader: Any = ...
+//| """The pixel shader of the tilegrid."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return common_hal_displayio_tilegrid_get_pixel_shader(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_pixel_shader_obj, displayio_tilegrid_obj_get_pixel_shader);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) {
+ mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter"));
+ }
+
+ common_hal_displayio_tilegrid_set_pixel_shader(self, pixel_shader);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_pixel_shader_obj, displayio_tilegrid_obj_set_pixel_shader);
+
+const mp_obj_property_t displayio_tilegrid_pixel_shader_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_tilegrid_get_pixel_shader_obj,
+ (mp_obj_t)&displayio_tilegrid_set_pixel_shader_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| def __getitem__(self, index: Any) -> Any:
+//| """Returns the tile index at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| print(grid[0])"""
+//| ...
+//|
+//| def __setitem__(self, index: Any, tile_index: Any) -> Any:
+//| """Sets the tile index at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| grid[0] = 10
+//|
+//| or::
+//|
+//| grid[0,0] = 10"""
+//| ...
+//|
+STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+
+ if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ uint16_t x = 0;
+ uint16_t y = 0;
+ if (MP_OBJ_IS_SMALL_INT(index_obj)) {
+ mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj);
+ uint16_t width = common_hal_displayio_tilegrid_get_width(self);
+ x = i % width;
+ y = i / width;
+ } else {
+ mp_obj_t* items;
+ mp_obj_get_array_fixed_n(index_obj, 2, &items);
+ x = mp_obj_get_int(items[0]);
+ y = mp_obj_get_int(items[1]);
+ }
+ if (x >= common_hal_displayio_tilegrid_get_width(self) ||
+ y >= common_hal_displayio_tilegrid_get_height(self)) {
+ mp_raise_IndexError(translate("Tile index out of bounds"));
+ }
+
+ if (value_obj == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile(self, x, y));
+ } else if (value_obj == mp_const_none) {
+ return MP_OBJ_NULL; // op not supported
+ } else {
+ mp_int_t value = mp_obj_get_int(value_obj);
+ if (value < 0 || value > 255) {
+ mp_raise_ValueError(translate("Tile value out of bounds"));
+ }
+ common_hal_displayio_tilegrid_set_tile(self, x, y, value);
+ }
+ }
+ return mp_const_none;
+}
+
+STATIC const mp_rom_map_elem_t displayio_tilegrid_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_tilegrid_hidden_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_tilegrid_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_tilegrid_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&displayio_tilegrid_flip_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&displayio_tilegrid_flip_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_transpose_xy), MP_ROM_PTR(&displayio_tilegrid_transpose_xy_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_tilegrid_pixel_shader_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_tilegrid_locals_dict, displayio_tilegrid_locals_dict_table);
+
+const mp_obj_type_t displayio_tilegrid_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TileGrid,
+ .make_new = displayio_tilegrid_make_new,
+ .subscr = tilegrid_subscr,
+ .locals_dict = (mp_obj_dict_t*)&displayio_tilegrid_locals_dict,
+};
diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h
new file mode 100644
index 000000000..0ee1c7883
--- /dev/null
+++ b/shared-bindings/displayio/TileGrid.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the Micro Python 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
+
+#include "shared-module/displayio/TileGrid.h"
+
+extern const mp_obj_type_t displayio_tilegrid_type;
+
+void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
+ uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_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);
+
+bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t* self);
+void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t* self, bool hidden);
+mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x);
+mp_int_t common_hal_displayio_tilegrid_get_y(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_y(displayio_tilegrid_t *self, mp_int_t y);
+mp_obj_t common_hal_displayio_tilegrid_get_pixel_shader(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_pixel_shader(displayio_tilegrid_t *self, mp_obj_t pixel_shader);
+
+
+bool common_hal_displayio_tilegrid_get_flip_x(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_flip_x(displayio_tilegrid_t *self, bool flip_x);
+bool common_hal_displayio_tilegrid_get_flip_y(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_flip_y(displayio_tilegrid_t *self, bool flip_y);
+bool common_hal_displayio_tilegrid_get_transpose_xy(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_transpose_xy(displayio_tilegrid_t *self, bool transpose_xy);
+
+uint16_t common_hal_displayio_tilegrid_get_width(displayio_tilegrid_t *self);
+uint16_t common_hal_displayio_tilegrid_get_height(displayio_tilegrid_t *self);
+
+uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
+void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index);
+
+// Private API for scrolling the TileGrid.
+void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c
index 0610d71f6..b791336b5 100644
--- a/shared-bindings/displayio/__init__.c
+++ b/shared-bindings/displayio/__init__.c
@@ -32,53 +32,56 @@
#include "shared-bindings/displayio/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/Display.h"
+#include "shared-bindings/displayio/EPaperDisplay.h"
#include "shared-bindings/displayio/FourWire.h"
#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/displayio/I2CDisplay.h"
#include "shared-bindings/displayio/OnDiskBitmap.h"
#include "shared-bindings/displayio/Palette.h"
-#include "shared-bindings/displayio/Sprite.h"
+#include "shared-bindings/displayio/ParallelBus.h"
+#include "shared-bindings/displayio/Shape.h"
+#include "shared-bindings/displayio/TileGrid.h"
-//| :mod:`displayio` --- Native display driving
-//| =========================================================================
-//|
-//| .. module:: displayio
-//| :synopsis: Native helpers for driving displays
-//| :platform: SAMD21, SAMD51
+//| """Native helpers for driving displays
//|
//| The `displayio` module contains classes to manage display output
-//| including synchronizing with refresh rates and partial updating. It does
-//| not include display initialization commands. It should live in a Python
-//| driver for use when a display is connected to a board. It should also be
-//| built into the board init when the board has the display on it.
-//|
-//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
-//|
-//| Libraries
-//|
-//| .. toctree::
-//| :maxdepth: 3
+//| including synchronizing with refresh rates and partial updating."""
//|
-//| Bitmap
-//| ColorConverter
-//| FourWire
-//| Group
-//| OnDiskBitmap
-//| Palette
-//| Sprite
+
+
+//| def release_displays() -> Any:
+//| """Releases any actively used displays so their busses and pins can be used again. This will also
+//| release the builtin display on boards that have one. You will need to reinitialize it yourself
+//| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing.
//|
-//| All libraries change hardware state but are never deinit
+//| Use this once in your code.py if you initialize a display. Place it right before the
+//| initialization so the display is active as long as possible."""
+//| ...
//|
+STATIC mp_obj_t displayio_release_displays(void) {
+ common_hal_displayio_release_displays();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(displayio_release_displays_obj, displayio_release_displays);
STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_displayio) },
{ MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) },
{ MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) },
+ { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) },
+ { MP_ROM_QSTR(MP_QSTR_EPaperDisplay), MP_ROM_PTR(&displayio_epaperdisplay_type) },
{ MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) },
{ MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) },
{ MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) },
- { MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&displayio_sprite_type) },
+ { MP_ROM_QSTR(MP_QSTR_Shape), MP_ROM_PTR(&displayio_shape_type) },
+ { MP_ROM_QSTR(MP_QSTR_TileGrid), MP_ROM_PTR(&displayio_tilegrid_type) },
{ MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2CDisplay), MP_ROM_PTR(&displayio_i2cdisplay_type) },
+ { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&displayio_parallelbus_type) },
+
+ { MP_ROM_QSTR(MP_QSTR_release_displays), MP_ROM_PTR(&displayio_release_displays_obj) },
};
STATIC MP_DEFINE_CONST_DICT(displayio_module_globals, displayio_module_globals_table);
diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h
index a6663bf57..a7748d029 100644
--- a/shared-bindings/displayio/__init__.h
+++ b/shared-bindings/displayio/__init__.h
@@ -29,6 +29,22 @@
#include "py/obj.h"
-// Nothing now.
+typedef enum {
+ DISPLAY_COMMAND,
+ DISPLAY_DATA
+} display_byte_type_t;
+
+typedef enum {
+ CHIP_SELECT_UNTOUCHED,
+ CHIP_SELECT_TOGGLE_EVERY_BYTE
+} display_chip_select_behavior_t;
+
+typedef bool (*display_bus_bus_reset)(mp_obj_t bus);
+typedef bool (*display_bus_bus_free)(mp_obj_t bus);
+typedef bool (*display_bus_begin_transaction)(mp_obj_t bus);
+typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length);
+typedef void (*display_bus_end_transaction)(mp_obj_t bus);
+
+void common_hal_displayio_release_displays(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H