aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/shared-bindings/displayio
diff options
context:
space:
mode:
Diffstat (limited to 'circuitpython/shared-bindings/displayio')
-rw-r--r--circuitpython/shared-bindings/displayio/Bitmap.c370
-rw-r--r--circuitpython/shared-bindings/displayio/Bitmap.h50
-rw-r--r--circuitpython/shared-bindings/displayio/ColorConverter.c152
-rw-r--r--circuitpython/shared-bindings/displayio/ColorConverter.h47
-rw-r--r--circuitpython/shared-bindings/displayio/Colorspace.c77
-rw-r--r--circuitpython/shared-bindings/displayio/Display.c524
-rw-r--r--circuitpython/shared-bindings/displayio/Display.h74
-rw-r--r--circuitpython/shared-bindings/displayio/EPaperDisplay.c363
-rw-r--r--circuitpython/shared-bindings/displayio/EPaperDisplay.h62
-rw-r--r--circuitpython/shared-bindings/displayio/FourWire.c172
-rw-r--r--circuitpython/shared-bindings/displayio/FourWire.h56
-rw-r--r--circuitpython/shared-bindings/displayio/Group.c355
-rw-r--r--circuitpython/shared-bindings/displayio/Group.h53
-rw-r--r--circuitpython/shared-bindings/displayio/I2CDisplay.c134
-rw-r--r--circuitpython/shared-bindings/displayio/I2CDisplay.h52
-rw-r--r--circuitpython/shared-bindings/displayio/OnDiskBitmap.c161
-rw-r--r--circuitpython/shared-bindings/displayio/OnDiskBitmap.h43
-rw-r--r--circuitpython/shared-bindings/displayio/Palette.c216
-rw-r--r--circuitpython/shared-bindings/displayio/Palette.h43
-rw-r--r--circuitpython/shared-bindings/displayio/Shape.c117
-rw-r--r--circuitpython/shared-bindings/displayio/Shape.h41
-rw-r--r--circuitpython/shared-bindings/displayio/TileGrid.c502
-rw-r--r--circuitpython/shared-bindings/displayio/TileGrid.h71
-rw-r--r--circuitpython/shared-bindings/displayio/__init__.c106
-rw-r--r--circuitpython/shared-bindings/displayio/__init__.h68
-rw-r--r--circuitpython/shared-bindings/displayio/area.c0
26 files changed, 3909 insertions, 0 deletions
diff --git a/circuitpython/shared-bindings/displayio/Bitmap.c b/circuitpython/shared-bindings/displayio/Bitmap.c
new file mode 100644
index 0000000..3af152f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Bitmap.c
@@ -0,0 +1,370 @@
+/*
+ * 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/Bitmap.h"
+#include "shared-module/displayio/Bitmap.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Bitmap:
+//| """Stores values of a certain size in a 2D array
+//|
+//| Bitmaps can be treated as read-only buffers. If the number of bits in a pixel is 8, 16, or 32; and the number of bytes
+//| per row is a multiple of 4, then the resulting memoryview will correspond directly with the bitmap's contents. Otherwise,
+//| the bitmap data is packed into the memoryview with unspecified padding.
+//|
+//| A Bitmap can be treated as a buffer, allowing its content to be
+//| viewed and modified using e.g., with ``ulab.numpy.frombuffer``,
+//| but the `displayio.Bitmap.dirty` method must be used to inform
+//| displayio when a bitmap was modified through the buffer interface.
+//|
+//| `bitmaptools.arrayblit` can also be useful to move data efficiently
+//| into a Bitmap.
+//| """
+//|
+//| def __init__(self, width: int, height: int, value_count: int) -> None:
+//| """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 *all_args) {
+ mp_arg_check_num(n_args, n_kw, 3, 3, false);
+ uint32_t width = mp_obj_get_int(all_args[0]);
+ uint32_t height = mp_obj_get_int(all_args[1]);
+ uint32_t value_count = mp_obj_get_int(all_args[2]);
+ 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, bits);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+//| width: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_bitmap_width_obj,
+ (mp_obj_t)&displayio_bitmap_get_width_obj);
+
+//| height: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_bitmap_height_obj,
+ (mp_obj_t)&displayio_bitmap_get_height_obj);
+
+//| def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+//| """Returns 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::
+//|
+//| print(bitmap[0,1])"""
+//| ...
+//|
+//| def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None:
+//| """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);
+
+ 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;
+ }
+
+ 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"));
+ }
+ }
+
+ if (value_obj == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_pixel(self, x, y));
+ } else {
+ mp_uint_t value = (mp_uint_t)mp_obj_get_int(value_obj);
+ if ((value >> common_hal_displayio_bitmap_get_bits_per_value(self)) != 0) {
+ 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 blit(self, x: int, y: int, source_bitmap: Bitmap, *, x1: int, y1: int, x2: int, y2: int, skip_index: int) -> None:
+//| """Inserts the source_bitmap region defined by rectangular boundaries
+//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
+//|
+//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
+//| corner will be placed
+//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
+//| corner will be placed
+//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
+//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
+//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
+//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+//| :param int skip_index: bitmap palette index in the source that will not be copied,
+//| set to None to copy all pixels"""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_x, ARG_y, ARG_source, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index};
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ {MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ {MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
+ {MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
+ {MP_QSTR_skip_index, 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 - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ int16_t x = args[ARG_x].u_int;
+ int16_t y = args[ARG_y].u_int;
+
+ displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);
+
+
+ // ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
+ if (self->bits_per_value < source->bits_per_value) {
+ mp_raise_ValueError(translate("source palette too large"));
+ }
+
+ int16_t x1 = args[ARG_x1].u_int;
+ int16_t y1 = args[ARG_y1].u_int;
+ int16_t x2, y2;
+ // if x2 or y2 is None, then set as the maximum size of the source bitmap
+ if (args[ARG_x2].u_obj == mp_const_none) {
+ x2 = source->width;
+ } else {
+ x2 = mp_obj_get_int(args[ARG_x2].u_obj);
+ }
+ // int16_t y2;
+ if (args[ARG_y2].u_obj == mp_const_none) {
+ y2 = source->height;
+ } else {
+ y2 = mp_obj_get_int(args[ARG_y2].u_obj);
+ }
+
+ // Check x,y are within self (target) bitmap boundary
+ if ((x < 0) || (y < 0) || (x > self->width) || (y > self->height)) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+ // Check x1,y1,x2,y2 are within source bitmap boundary
+ if ((x1 < 0) || (x1 > source->width) ||
+ (y1 < 0) || (y1 > source->height) ||
+ (x2 < 0) || (x2 > source->width) ||
+ (y2 < 0) || (y2 > source->height)) {
+ mp_raise_ValueError(translate("out of range of source"));
+ }
+
+ // Ensure x1 < x2 and y1 < y2
+ if (x1 > x2) {
+ int16_t temp = x2;
+ x2 = x1;
+ x1 = temp;
+ }
+ if (y1 > y2) {
+ int16_t temp = y2;
+ y2 = y1;
+ y1 = temp;
+ }
+
+ uint32_t skip_index;
+ bool skip_index_none; // flag whether skip_value was None
+
+ if (args[ARG_skip_index].u_obj == mp_const_none) {
+ skip_index = 0;
+ skip_index_none = true;
+ } else {
+ skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
+ skip_index_none = false;
+ }
+
+ common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 1, displayio_bitmap_obj_blit);
+
+//| def fill(self, value: int) -> None:
+//| """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_uint_t value = (mp_uint_t)mp_obj_get_int(value_obj);
+ if ((value >> common_hal_displayio_bitmap_get_bits_per_value(self)) != 0) {
+ 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_2(displayio_bitmap_fill_obj, displayio_bitmap_obj_fill);
+
+//| def dirty(self, x1: int=0, y1: int=0, x2: int=-1, y2:int = -1) -> None:
+//| """Inform displayio of bitmap updates done via the buffer
+//| protocol.
+//|
+//| :param int x1: Minimum x-value for rectangular bounding box to be considered as modified
+//| :param int y1: Minimum y-value for rectangular bounding box to be considered as modified
+//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be considered as modified
+//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be considered as modified
+//|
+//| If x1 or y1 are not specified, they are taken as 0. If x2 or y2
+//| are not specified, or are given as -1, they are taken as the width
+//| and height of the image. Thus, calling dirty() with the
+//| default arguments treats the whole bitmap as modified.
+//|
+//| When a bitmap is modified through the buffer protocol, the
+//| display will not be properly updated unless the bitmap is
+//| notified of the "dirty rectangle" that encloses all modified
+//| pixels."""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_dirty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ enum { ARG_x1, ARG_y1, ARG_x2, ARG_y2 };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_x1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_y1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_x2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_y2, 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_area_t dirty_area = {
+ .x1 = args[ARG_x1].u_int,
+ .y1 = args[ARG_y1].u_int,
+ .x2 = args[ARG_x2].u_int == -1 ? self->width : args[ARG_x2].u_int,
+ .y2 = args[ARG_y2].u_int == -1 ? self->height : args[ARG_y2].u_int,
+ };
+
+ displayio_bitmap_set_dirty_area(self, &dirty_area);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_dirty_obj, 0, displayio_bitmap_obj_dirty);
+
+STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = {
+ { 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_blit), MP_ROM_PTR(&displayio_bitmap_blit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dirty), MP_ROM_PTR(&displayio_bitmap_dirty_obj) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_bitmap_locals_dict, displayio_bitmap_locals_dict_table);
+
+// (the get_buffer protocol returns 0 for success, 1 for failure)
+STATIC mp_int_t bitmap_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_displayio_bitmap_get_buffer(self, bufinfo, flags);
+}
+
+const mp_obj_type_t displayio_bitmap_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Bitmap,
+ .make_new = displayio_bitmap_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_bitmap_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = bitmap_subscr,
+ .buffer_p = { .get_buffer = bitmap_get_buffer },
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Bitmap.h b/circuitpython/shared-bindings/displayio/Bitmap.h
new file mode 100644
index 0000000..4580475
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Bitmap.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
+
+#include "shared-module/displayio/Bitmap.h"
+
+extern const mp_obj_type_t displayio_bitmap_type;
+
+void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t width,
+ uint32_t height, uint32_t bits_per_value);
+
+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);
+void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source,
+ int16_t x1, int16_t y1, int16_t x2, int16_t y2,
+ uint32_t skip_index, bool skip_index_none);
+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);
+int common_hal_displayio_bitmap_get_buffer(displayio_bitmap_t *self, mp_buffer_info_t *bufinfo, mp_uint_t flags);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
diff --git a/circuitpython/shared-bindings/displayio/ColorConverter.c b/circuitpython/shared-bindings/displayio/ColorConverter.c
new file mode 100644
index 0000000..18b8866
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/ColorConverter.c
@@ -0,0 +1,152 @@
+/*
+ * 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/ColorConverter.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/enum.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class ColorConverter:
+//| """Converts one color format to another."""
+//|
+//| def __init__(self, *, input_colorspace: Colorspace=Colorspace.RGB888, dither: bool = False) -> None:
+//| """Create a ColorConverter object to convert color formats.
+//|
+//| :param Colorspace colorspace: The source colorspace, one of the Colorspace constants
+//| :param bool dither: Adds random noise to dither the output image"""
+//| ...
+//|
+
+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 *all_args) {
+ enum { ARG_dither, ARG_input_colorspace };
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_input_colorspace, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (void *)&displayio_colorspace_RGB888_obj} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_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, args[ARG_dither].u_bool, (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_input_colorspace].u_obj));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def convert(self, color: int) -> int:
+//| """Converts the given color to RGB565 according to the Colorspace"""
+//| ...
+//|
+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);
+
+ mp_int_t color;
+ if (!mp_obj_get_int_maybe(color_obj, &color)) {
+ mp_raise_ValueError(translate("color should be an int"));
+ }
+ _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: bool
+//| """When `True` the ColorConverter 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);
+
+MP_PROPERTY_GETSET(displayio_colorconverter_dither_obj,
+ (mp_obj_t)&displayio_colorconverter_get_dither_obj,
+ (mp_obj_t)&displayio_colorconverter_set_dither_obj);
+
+//| def make_transparent(self, color: int) -> None:
+//| """Set the transparent color or index for the ColorConverter. This will
+//| raise an Exception if there is already a selected transparent index.
+//|
+//| :param int color: The color to be transparent"""
+//|
+STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_obj_t transparent_color_obj) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj);
+ common_hal_displayio_colorconverter_make_transparent(self, transparent_color);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent);
+
+//| def make_opaque(self, color: int) -> None:
+//| """Make the ColorConverter be opaque and have no transparent pixels.
+//|
+//| :param int color: [IGNORED] Use any value"""
+//|
+STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj);
+ common_hal_displayio_colorconverter_make_opaque(self, transparent_color);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque);
+
+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) },
+ { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_colorconverter_make_transparent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_colorconverter_make_opaque_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table);
+
+const mp_obj_type_t displayio_colorconverter_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ColorConverter,
+ .make_new = displayio_colorconverter_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_colorconverter_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/ColorConverter.h b/circuitpython/shared-bindings/displayio/ColorConverter.h
new file mode 100644
index 0000000..12fa8da
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/ColorConverter.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
+
+#include "shared-bindings/displayio/__init__.h"
+#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 dither, displayio_colorspace_t input_colorspace);
+void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t *colorspace, uint32_t input_color, uint32_t *output_color);
+uint32_t displayio_colorconverter_convert_pixel(displayio_colorspace_t colorspace, uint32_t pixel);
+
+void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t *self, bool dither);
+bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t *self);
+
+void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t *self, uint32_t transparent_color);
+void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t *self, uint32_t transparent_color);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
diff --git a/circuitpython/shared-bindings/displayio/Colorspace.c b/circuitpython/shared-bindings/displayio/Colorspace.c
new file mode 100644
index 0000000..3692dc2
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Colorspace.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler 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 "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/displayio/__init__.h"
+
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB888, DISPLAYIO_COLORSPACE_RGB888);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB565, DISPLAYIO_COLORSPACE_RGB565);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB565_SWAPPED, DISPLAYIO_COLORSPACE_RGB565_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB555, DISPLAYIO_COLORSPACE_RGB555);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB555_SWAPPED, DISPLAYIO_COLORSPACE_RGB555_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR565, DISPLAYIO_COLORSPACE_BGR565);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR565_SWAPPED, DISPLAYIO_COLORSPACE_BGR565_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR555, DISPLAYIO_COLORSPACE_BGR555);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR555_SWAPPED, DISPLAYIO_COLORSPACE_BGR555_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, L8, DISPLAYIO_COLORSPACE_L8);
+
+//| class Colorspace:
+//| """The colorspace for a `ColorConverter` to operate in"""
+//|
+//| RGB888: Colorspace
+//| """The standard 24-bit colorspace. Bits 0-7 are blue, 8-15 are green, and 16-24 are red. (0xRRGGBB)"""
+//|
+//| RGB565: Colorspace
+//| """The standard 16-bit colorspace. Bits 0-4 are blue, bits 5-10 are green, and 11-15 are red (0bRRRRRGGGGGGBBBBB)"""
+//|
+//| RGB565_SWAPPED: Colorspace
+//| """The swapped 16-bit colorspace. First, the high and low 8 bits of the number are swapped, then they are interpreted as for RGB565"""
+//|
+//| RGB555: Colorspace
+//| """The standard 15-bit colorspace. Bits 0-4 are blue, bits 5-9 are green, and 11-14 are red. The top bit is ignored. (0bxRRRRRGGGGGBBBBB)"""
+//|
+//| RGB555_SWAPPED: Colorspace
+//| """The swapped 15-bit colorspace. First, the high and low 8 bits of the number are swapped, then they are interpreted as for RGB555"""
+//|
+MAKE_ENUM_MAP(displayio_colorspace) {
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB888),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB565),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB565_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB555),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB555_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR565),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR565_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR555),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR555_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, L8),
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_colorspace_locals_dict, displayio_colorspace_locals_table);
+
+MAKE_PRINTER(displayio, displayio_colorspace);
+MAKE_ENUM_TYPE(displayio, ColorSpace, displayio_colorspace);
diff --git a/circuitpython/shared-bindings/displayio/Display.c b/circuitpython/shared-bindings/displayio/Display.c
new file mode 100644
index 0000000..b19c0ba
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Display.c
@@ -0,0 +1,524 @@
+/*
+ * 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 "shared/runtime/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"
+
+//| _DisplayBus = Union['FourWire', 'paralleldisplay.ParallelBus', 'I2CDisplay']
+//| """:py:class:`FourWire`, :py:class:`paralleldisplay.ParallelBus` or :py:class:`I2CDisplay`"""
+//|
+
+//|
+//| 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: _DisplayBus, init_sequence: ReadableBuffer, *, 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, backlight_pin: Optional[microcontroller.Pin] = None, brightness_command: Optional[int] = None, brightness: float = 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, backlight_on_high: bool = True, SH1107_addressing: bool = False) -> None:
+//| r"""Create a Display object on the given display bus (`FourWire`, `ParallelBus` or `I2CDisplay`).
+//|
+//| 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 delay. When the top bit
+//| of the second byte is 1 (0x80), a delay will occur after the command parameters are sent.
+//| The remaining 7 bits are the parameter count excluding any delay byte. The bytes following
+//| are the parameters. When the delay bit is set, a single byte after the parameters specifies
+//| the delay duration in milliseconds. The value 0xff will lead to an extra long 500 ms delay
+//| instead of 255 ms. The next byte will begin a new command definition.
+//| Here is an example:
+//|
+//| .. 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\x81\xaa\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 is 0x11 with 0
+//| parameters and a 120ms (0x78) delay. The third command is 0x29 with one parameter 0xaa and a
+//| 120ms delay (0x78). 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 _DisplayBus: FourWire, ParallelBus or I2CDisplay
+//| :param ~circuitpython_typing.ReadableBuffer 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 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 float 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.
+//| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set
+//| :param int set_vertical_scroll: This parameter is accepted but ignored for backwards compatibility. It will be removed in a future release.
+//| """
+//| ...
+//|
+STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_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,
+ ARG_SH1107_addressing };
+ 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_QSTR_SH1107_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_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"));
+ }
+
+ const bool sh1107_addressing = args[ARG_SH1107_addressing].u_bool;
+ const mp_int_t color_depth = args[ARG_color_depth].u_int;
+ if (sh1107_addressing && color_depth != 1) {
+ mp_raise_ValueError_varg(translate("%q must be 1 when %q is True"), MP_QSTR_color_depth, MP_QSTR_SH1107_addressing);
+ }
+
+ 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,
+ color_depth, 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,
+ 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,
+ sh1107_addressing
+ );
+
+ 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_obj_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) -> None:
+//| """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: Optional[int] = None, minimum_frames_per_second: int = 0) -> bool:
+//| """When auto_refresh is off, and :py:attr:`target_frames_per_second` is not `None` this 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. The default :py:attr:`minimum_frames_per_second` of 0 disables this behavior.
+//|
+//| When auto_refresh is off, and :py:attr:`target_frames_per_second` is `None` this
+//| will update the display immediately.
+//|
+//| When auto_refresh is on, updates the display immediately. (The display will also update
+//| without calls to this.)
+//|
+//| :param Optional[int] target_frames_per_second: The target frame rate that :py:func:`refresh` should try to
+//| achieve. Set to `None` for immediate refresh.
+//| :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_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_minimum_frames_per_second, 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 - 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;
+ }
+
+ uint32_t target_ms_per_frame;
+ if (args[ARG_target_frames_per_second].u_obj == mp_const_none) {
+ target_ms_per_frame = 0xffffffff;
+ } else {
+ target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj);
+ }
+
+ return mp_obj_new_bool(common_hal_displayio_display_refresh(self, target_ms_per_frame, maximum_ms_per_real_frame));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh);
+
+//| auto_refresh: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_display_auto_refresh_obj,
+ (mp_obj_t)&displayio_display_get_auto_refresh_obj,
+ (mp_obj_t)&displayio_display_set_auto_refresh_obj);
+
+//| brightness: float
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_display_brightness_obj,
+ (mp_obj_t)&displayio_display_get_brightness_obj,
+ (mp_obj_t)&displayio_display_set_brightness_obj);
+
+//| auto_brightness: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_display_auto_brightness_obj,
+ (mp_obj_t)&displayio_display_get_auto_brightness_obj,
+ (mp_obj_t)&displayio_display_set_auto_brightness_obj);
+
+
+
+
+//| width: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_display_width_obj,
+ (mp_obj_t)&displayio_display_get_width_obj);
+
+//| height: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_display_height_obj,
+ (mp_obj_t)&displayio_display_get_height_obj);
+
+//| rotation: int
+//| """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);
+
+
+MP_PROPERTY_GETSET(displayio_display_rotation_obj,
+ (mp_obj_t)&displayio_display_get_rotation_obj,
+ (mp_obj_t)&displayio_display_set_rotation_obj);
+
+//| bus: _DisplayBus
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_display_bus_obj,
+ (mp_obj_t)&displayio_display_get_bus_obj);
+
+//| root_group: Group
+//| """The root group on the display."""
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_root_group(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return common_hal_displayio_display_get_root_group(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_root_group_obj, displayio_display_obj_get_root_group);
+
+MP_PROPERTY_GETTER(displayio_display_root_group_obj,
+ (mp_obj_t)&displayio_display_get_root_group_obj);
+
+
+//| def fill_row(self, y: int, buffer: WriteableBuffer) -> WriteableBuffer:
+//| """Extract the pixels from a single row
+//|
+//| :param int y: The top edge of the area
+//| :param ~circuitpython_typing.WriteableBuffer 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 (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) },
+ { MP_ROM_QSTR(MP_QSTR_root_group), MP_ROM_PTR(&displayio_display_root_group_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/circuitpython/shared-bindings/displayio/Display.h b/circuitpython/shared-bindings/displayio/Display.h
new file mode 100644
index 0000000..f193e61
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Display.h
@@ -0,0 +1,74 @@
+/*
+ * 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 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 *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 SH1107_addressing);
+
+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);
+mp_obj_t common_hal_displayio_display_get_root_group(displayio_display_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
diff --git a/circuitpython/shared-bindings/displayio/EPaperDisplay.c b/circuitpython/shared-bindings/displayio/EPaperDisplay.c
new file mode 100644
index 0000000..94d2978
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/EPaperDisplay.c
@@ -0,0 +1,363 @@
+/*
+ * 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 "shared/runtime/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: _DisplayBus,
+//| start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *,
+//| width: int, height: int, ram_width: int, ram_height: int,
+//| colstart: int = 0, rowstart: int = 0, rotation: int = 0,
+//| set_column_window_command: Optional[int] = None,
+//| set_row_window_command: Optional[int] = None,
+//| set_current_column_command: Optional[int] = None,
+//| set_current_row_command: Optional[int] = None,
+//| write_black_ram_command: int, black_bits_inverted: bool = False,
+//| write_color_ram_command: Optional[int] = None,
+//| color_bits_inverted: bool = False, highlight_color: int = 0x000000,
+//| refresh_display_command: int, refresh_time: float = 40,
+//| busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True,
+//| seconds_per_frame: float = 180, always_toggle_chip_select: bool = False,
+//| grayscale: bool = False, two_byte_sequence_length: bool = False) -> None:
+//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `paralleldisplay.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
+//| delay. When the top bit of the second byte is 1 (0x80), a delay will occur after the command
+//| parameters are sent. The remaining 7 bits are the parameter count excluding any delay
+//| byte. The bytes following are the parameters. When the delay bit is set, a single byte after
+//| the parameters specifies the delay duration in milliseconds. The value 0xff will lead to an
+//| extra long 500 ms delay instead of 255 ms. The next byte will begin a new command definition.
+//|
+//| :param display_bus: The bus that the display is connected to
+//| :type _DisplayBus: displayio.FourWire or paralleldisplay.ParallelBus
+//| :param ~circuitpython_typing.ReadableBuffer start_sequence: Byte-packed initialization sequence.
+//| :param ~circuitpython_typing.ReadableBuffer 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
+//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale
+//| :param bool two_byte_sequence_length: When true, use two bytes to define sequence length"""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_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, ARG_grayscale, ARG_two_byte_sequence_length };
+ 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_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_two_byte_sequence_length, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_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, args[ARG_grayscale].u_bool, args[ARG_two_byte_sequence_length].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_obj_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) -> None:
+//| """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 update_refresh_mode(self, start_sequence: ReadableBuffer, seconds_per_frame: float = 180) -> None:
+//| """Updates the ``start_sequence`` and ``seconds_per_frame`` parameters to enable
+//| varying the refresh mode of the display."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_update_refresh_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_start_sequence, ARG_seconds_per_frame };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_seconds_per_frame, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
+ };
+ displayio_epaperdisplay_obj_t *self = native_display(pos_args[0]);
+ 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);
+
+ // Get parameters
+ mp_buffer_info_t start_sequence;
+ mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_sequence, MP_BUFFER_READ);
+ float seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj);
+
+ // Update parameters
+ displayio_epaperdisplay_change_refresh_mode_parameters(self, &start_sequence, seconds_per_frame);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_epaperdisplay_update_refresh_mode_obj, 1, displayio_epaperdisplay_update_refresh_mode);
+
+//| def refresh(self) -> None:
+//| """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: float
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_time_to_refresh_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_time_to_refresh_obj);
+
+//| busy: bool
+//| """True when the display is refreshing. This uses the ``busy_pin`` when available or the
+//| ``refresh_time`` otherwise."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_busy(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_epaperdisplay_get_busy(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_busy_obj, displayio_epaperdisplay_obj_get_busy);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_busy_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_busy_obj);
+
+//| width: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_width_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_width_obj);
+
+//| height: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_height_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_height_obj);
+
+//| rotation: int
+//| """The rotation of the display as an int in degrees."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_rotation(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_rotation(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_rotation_obj, displayio_epaperdisplay_obj_get_rotation);
+STATIC mp_obj_t displayio_epaperdisplay_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ common_hal_displayio_epaperdisplay_set_rotation(self, mp_obj_get_int(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_set_rotation_obj, displayio_epaperdisplay_obj_set_rotation);
+
+
+MP_PROPERTY_GETSET(displayio_epaperdisplay_rotation_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_rotation_obj,
+ (mp_obj_t)&displayio_epaperdisplay_set_rotation_obj);
+
+//| bus: _DisplayBus
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_bus_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_bus_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_update_refresh_mode), MP_ROM_PTR(&displayio_epaperdisplay_update_refresh_mode_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_rotation), MP_ROM_PTR(&displayio_epaperdisplay_rotation_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) },
+ { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&displayio_epaperdisplay_busy_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/circuitpython/shared-bindings/displayio/EPaperDisplay.h b/circuitpython/shared-bindings/displayio/EPaperDisplay.h
new file mode 100644
index 0000000..ba6dffc
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/EPaperDisplay.h
@@ -0,0 +1,62 @@
+/*
+ * 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 NO_COMMAND 0x100
+
+void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t *self,
+ mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, const 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 grayscale, bool two_byte_sequence_length);
+
+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);
+bool common_hal_displayio_epaperdisplay_get_busy(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);
+uint16_t common_hal_displayio_epaperdisplay_get_rotation(displayio_epaperdisplay_obj_t *self);
+void common_hal_displayio_epaperdisplay_set_rotation(displayio_epaperdisplay_obj_t *self, int rotation);
+
+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/circuitpython/shared-bindings/displayio/FourWire.c b/circuitpython/shared-bindings/displayio/FourWire.c
new file mode 100644
index 0000000..90aa5c6
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/FourWire.c
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * 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
+ * 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/FourWire.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/busio/SPI.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 FourWire:
+//| """Manage updating a display over SPI four wire protocol in the background while Python code runs.
+//| It doesn't handle display initialization."""
+//|
+//| def __init__(self, spi_bus: busio.SPI, *, command: Optional[microcontroller.Pin], chip_select: microcontroller.Pin, reset: Optional[microcontroller.Pin] = None, baudrate: int = 24000000, polarity: int = 0, phase: int = 0) -> None:
+//| """Create a FourWire object associated with the given pins.
+//|
+//| 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.
+//|
+//| If the ``command`` pin is not specified, a 9-bit SPI mode will be simulated by adding a
+//| data/command bit to every bit being transmitted, and splitting the resulting data back
+//| into 8-bit bytes for transmission. The extra bits that this creates at the end are ignored
+//| by the receiving device.
+//|
+//| :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines
+//| :param microcontroller.Pin command: Data or command pin. When None, 9-bit SPI is simulated.
+//| :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."""
+//| ...
+//|
+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 *all_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, {.u_obj = mp_const_none} },
+ { 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_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *command = validate_obj_is_free_pin_or_none(args[ARG_command].u_obj);
+ const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ mp_obj_t spi = mp_arg_validate_type(args[ARG_spi_bus].u_obj, &busio_spi_type, MP_QSTR_spi_bus);
+
+ displayio_fourwire_obj_t *self = &allocate_display_bus_or_raise()->fourwire_bus;
+ self->base.type = &displayio_fourwire_type;
+
+ 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"));
+ }
+
+ common_hal_displayio_fourwire_construct(self,
+ MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int, polarity, phase);
+ return self;
+}
+
+//| def reset(self) -> None:
+//| """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_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_reset_obj, displayio_fourwire_obj_reset);
+
+//| def send(self, command: int, data: ReadableBuffer, *, toggle_every_byte: bool = False) -> None:
+//| """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_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, 1, 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) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_fourwire_locals_dict, displayio_fourwire_locals_dict_table);
+
+const mp_obj_type_t displayio_fourwire_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_FourWire,
+ .make_new = displayio_fourwire_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_fourwire_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/FourWire.h b/circuitpython/shared-bindings/displayio/FourWire.h
new file mode 100644
index 0000000..300327f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/FourWire.h
@@ -0,0 +1,56 @@
+/*
+ * 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_FOURWIRE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_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;
+
+void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t *self,
+ 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_deinit(displayio_fourwire_obj_t *self);
+
+bool common_hal_displayio_fourwire_reset(mp_obj_t self);
+bool common_hal_displayio_fourwire_bus_free(mp_obj_t self);
+
+bool common_hal_displayio_fourwire_begin_transaction(mp_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, const uint8_t *data, uint32_t data_length);
+
+void common_hal_displayio_fourwire_end_transaction(mp_obj_t self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
diff --git a/circuitpython/shared-bindings/displayio/Group.c b/circuitpython/shared-bindings/displayio/Group.c
new file mode 100644
index 0000000..188331f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Group.c
@@ -0,0 +1,355 @@
+/*
+ * 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/Group.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/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"
+
+//| class Group:
+//| """Manage a group of sprites and groups and how they are inter-related."""
+//|
+//| def __init__(self, *, scale: int = 1, x: int = 0, y: int = 0) -> None:
+//| """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.
+//|
+//| :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."""
+//| ...
+//|
+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 *all_args) {
+ enum { ARG_scale, ARG_x, ARG_y };
+ static const mp_arg_t allowed_args[] = {
+ { 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_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ 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, scale, args[ARG_x].u_int, args[ARG_y].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// 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_obj_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: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_group_hidden_obj,
+ (mp_obj_t)&displayio_group_get_hidden_obj,
+ (mp_obj_t)&displayio_group_set_hidden_obj);
+
+//| scale: int
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_group_scale_obj,
+ (mp_obj_t)&displayio_group_get_scale_obj,
+ (mp_obj_t)&displayio_group_set_scale_obj);
+
+//| x: int
+//| """X position of the Group in the parent."""
+//|
+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);
+
+MP_PROPERTY_GETSET(displayio_group_x_obj,
+ (mp_obj_t)&displayio_group_get_x_obj,
+ (mp_obj_t)&displayio_group_set_x_obj);
+
+//| y: int
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_group_y_obj,
+ (mp_obj_t)&displayio_group_get_y_obj,
+ (mp_obj_t)&displayio_group_set_y_obj);
+
+//| def append(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """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 = 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);
+
+//| def insert(self, index: int, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Insert a layer into the group."""
+//| ...
+//|
+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);
+ if ((size_t)MP_OBJ_SMALL_INT_VALUE(index_obj) == common_hal_displayio_group_get_len(self)) {
+ return displayio_group_obj_append(self_in, layer);
+ }
+ 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: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> int:
+//| """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: int = -1) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]:
+//| """Remove the ith item and return it."""
+//| ...
+//|
+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: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """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 __bool__(self) -> bool:
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """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: int) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]:
+//| """Returns the value at the given index.
+//|
+//| This allows you to::
+//|
+//| print(group[0])"""
+//| ...
+//|
+//| def __setitem__(self, index: int, value: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Sets the value at the given index.
+//|
+//| This allows you to::
+//|
+//| group[0] = sprite"""
+//| ...
+//|
+//| def __delitem__(self, index: int) -> None:
+//| """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;
+}
+
+//| def sort(self, key: function, reverse: bool) -> None:
+//| """Sort the members of the group."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ displayio_group_t *self = native_group(pos_args[0]);
+ mp_obj_t *args = m_new(mp_obj_t, n_args);
+ for (size_t i = 1; i < n_args; ++i) {
+ args[i] = pos_args[i];
+ }
+ args[0] = MP_OBJ_FROM_PTR(self->members);
+ return mp_obj_list_sort(n_args, args, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_sort_obj, 1, displayio_group_obj_sort);
+
+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) },
+ { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&displayio_group_sort_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_group_locals_dict, displayio_group_locals_dict_table);
+
+const mp_obj_type_t displayio_group_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Group,
+ .make_new = displayio_group_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_group_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = group_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Group.h b/circuitpython/shared-bindings/displayio/Group.h
new file mode 100644
index 0000000..266fce9
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Group.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
+
+#include "shared-module/displayio/Group.h"
+
+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 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);
+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/circuitpython/shared-bindings/displayio/I2CDisplay.c b/circuitpython/shared-bindings/displayio/I2CDisplay.c
new file mode 100644
index 0000000..fbfbd04
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/I2CDisplay.c
@@ -0,0 +1,134 @@
+/*
+ * 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 "shared/runtime/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/busio/I2C.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: Optional[microcontroller.Pin] = None) -> 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, size_t n_kw, const mp_obj_t *all_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_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c_bus].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus);
+ 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) -> None:
+//| """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: int, data: ReadableBuffer) -> None:
+//| """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/circuitpython/shared-bindings/displayio/I2CDisplay.h b/circuitpython/shared-bindings/displayio/I2CDisplay.h
new file mode 100644
index 0000000..d40cd19
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/I2CDisplay.h
@@ -0,0 +1,52 @@
+/*
+ * 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, const 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/circuitpython/shared-bindings/displayio/OnDiskBitmap.c b/circuitpython/shared-bindings/displayio/OnDiskBitmap.c
new file mode 100644
index 0000000..aa749bf
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/OnDiskBitmap.c
@@ -0,0 +1,161 @@
+/*
+ * 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/OnDiskBitmap.h"
+
+#include <stdint.h>
+
+#include "py/runtime.h"
+#include "py/objproperty.h"
+#include "supervisor/shared/translate.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+
+//| 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.
+//|
+//| 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
+//|
+//| import board
+//| import displayio
+//| import time
+//| import pulseio
+//|
+//| board.DISPLAY.auto_brightness = False
+//| board.DISPLAY.brightness = 0
+//| splash = displayio.Group()
+//| board.DISPLAY.show(splash)
+//|
+//| odb = displayio.OnDiskBitmap('/sample.bmp')
+//| face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
+//| splash.append(face)
+//| # Wait for the image to load.
+//| board.DISPLAY.refresh(target_frames_per_second=60)
+//|
+//| # Fade up the backlight
+//| for i in range(100):
+//| board.DISPLAY.brightness = 0.01 * i
+//| time.sleep(0.05)
+//|
+//| # Wait forever
+//| while True:
+//| pass"""
+//|
+//| def __init__(self, file: Union[str,typing.BinaryIO]) -> None:
+//| """Create an OnDiskBitmap object with the given file.
+//|
+//| :param file file: The name of the bitmap file. For backwards compatibility, a file opened in binary mode may also be passed.
+//|
+//| Older versions of CircuitPython required a file opened in binary
+//| mode. CircuitPython 7.0 modified OnDiskBitmap so that it takes a
+//| filename instead, and opens the file internally. A future version
+//| of CircuitPython will remove the ability to pass in an opened 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 *all_args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_obj_t arg = all_args[0];
+
+ if (mp_obj_is_str(arg)) {
+ arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb));
+ }
+ if (!mp_obj_is_type(arg, &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+
+ displayio_ondiskbitmap_t *self = m_new_obj(displayio_ondiskbitmap_t);
+ self->base.type = &displayio_ondiskbitmap_type;
+ common_hal_displayio_ondiskbitmap_construct(self, MP_OBJ_TO_PTR(arg));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| width: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_ondiskbitmap_width_obj,
+ (mp_obj_t)&displayio_ondiskbitmap_get_width_obj);
+
+//| height: int
+//| """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);
+
+MP_PROPERTY_GETTER(displayio_ondiskbitmap_height_obj,
+ (mp_obj_t)&displayio_ondiskbitmap_get_height_obj);
+
+//| pixel_shader: Union[ColorConverter, Palette]
+//| """The image's pixel_shader. The type depends on the underlying
+//| bitmap's structure. The pixel shader can be modified (e.g., to set the
+//| transparent pixel or, for palette shaded images, to update the palette.)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_pixel_shader(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_displayio_ondiskbitmap_get_pixel_shader(self);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_pixel_shader_obj, displayio_ondiskbitmap_obj_get_pixel_shader);
+
+const mp_obj_property_t displayio_ondiskbitmap_pixel_shader_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_ondiskbitmap_get_pixel_shader_obj,
+ (mp_obj_t)MP_ROM_NONE,
+ (mp_obj_t)MP_ROM_NONE},
+};
+
+
+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_pixel_shader), MP_ROM_PTR(&displayio_ondiskbitmap_pixel_shader_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);
+
+const mp_obj_type_t displayio_ondiskbitmap_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_OnDiskBitmap,
+ .make_new = displayio_ondiskbitmap_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_ondiskbitmap_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/OnDiskBitmap.h b/circuitpython/shared-bindings/displayio/OnDiskBitmap.h
new file mode 100644
index 0000000..6d534ec
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/OnDiskBitmap.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
+
+#include "shared-module/displayio/OnDiskBitmap.h"
+#include "extmod/vfs_fat.h"
+
+extern const mp_obj_type_t displayio_ondiskbitmap_type;
+
+void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, pyb_file_obj_t *file);
+
+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);
+mp_obj_t common_hal_displayio_ondiskbitmap_get_pixel_shader(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/circuitpython/shared-bindings/displayio/Palette.c b/circuitpython/shared-bindings/displayio/Palette.c
new file mode 100644
index 0000000..ad6d7c3
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Palette.c
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 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/Palette.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/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 "supervisor/shared/translate.h"
+
+//| class Palette:
+//| """Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
+//| save memory."""
+//|
+//| def __init__(self, color_count: int) -> None:
+//| """Create a Palette object to store a set number of colors.
+//|
+//| :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 *all_args) {
+ enum { ARG_color_count };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_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;
+ common_hal_displayio_palette_construct(self, args[ARG_color_count].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def __bool__(self) -> bool:
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """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 __getitem__(self, index: int) -> Optional[int]:
+//| r"""Return the pixel color at the given index as an integer."""
+//| ...
+//|
+//| def __setitem__(self, index: int, value: Union[int, ReadableBuffer, Tuple[int, int, int]]) -> None:
+//| r"""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
+ return MP_OBJ_NULL; // op not supported
+ }
+ // Slicing not supported. Use a duplicate Palette to swap multiple colors atomically.
+ if (mp_obj_is_type(index_in, &mp_type_slice)) {
+ 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, 0, &value);
+ }
+
+ uint32_t color;
+ mp_int_t int_value;
+ mp_buffer_info_t bufinfo;
+ if (mp_get_buffer(value, &bufinfo, MP_BUFFER_READ)) {
+ if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) {
+ mp_raise_ValueError(translate("color buffer must be a bytearray or array of type 'b' or 'B'"));
+ }
+ uint8_t *buf = bufinfo.buf;
+ if (bufinfo.len == 3 || bufinfo.len == 4) {
+ color = buf[0] << 16 | buf[1] << 8 | buf[2];
+ } else {
+ mp_raise_ValueError(translate("color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)"));
+ }
+ } else if (mp_obj_get_int_maybe(value, &int_value)) {
+ if (int_value < 0 || int_value > 0xffffff) {
+ mp_raise_TypeError(translate("color must be between 0x000000 and 0xffffff"));
+ }
+ color = int_value;
+ } else {
+ 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;
+}
+
+//| def make_transparent(self, palette_index: int) -> None:
+//| ...
+//|
+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);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ common_hal_displayio_palette_make_transparent(self, palette_index);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_make_transparent_obj, displayio_palette_obj_make_transparent);
+
+//| def make_opaque(self, palette_index: int) -> None:
+//| ...
+//|
+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);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ common_hal_displayio_palette_make_opaque(self, palette_index);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_make_opaque_obj, displayio_palette_obj_make_opaque);
+
+//| def is_transparent(self, palette_index: int) -> bool:
+//| """Returns `True` if the palette index is transparent. Returns `False` if opaque."""
+//| ...
+//|
+STATIC mp_obj_t displayio_palette_obj_is_transparent(mp_obj_t self_in, mp_obj_t palette_index_obj) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ return mp_obj_new_bool(common_hal_displayio_palette_is_transparent(self, palette_index));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_is_transparent_obj, displayio_palette_obj_is_transparent);
+
+STATIC const mp_rom_map_elem_t displayio_palette_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_palette_make_transparent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_palette_make_opaque_obj) },
+ { MP_ROM_QSTR(MP_QSTR_is_transparent), MP_ROM_PTR(&displayio_palette_is_transparent_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_palette_locals_dict, displayio_palette_locals_dict_table);
+
+const mp_obj_type_t displayio_palette_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Palette,
+ .make_new = displayio_palette_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_palette_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = palette_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Palette.h b/circuitpython/shared-bindings/displayio/Palette.h
new file mode 100644
index 0000000..d9a7980
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Palette.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
+
+#include "shared-module/displayio/Palette.h"
+
+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);
+bool common_hal_displayio_palette_is_transparent(displayio_palette_t *self, uint32_t palette_index);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
diff --git a/circuitpython/shared-bindings/displayio/Shape.c b/circuitpython/shared-bindings/displayio/Shape.c
new file mode 100644
index 0000000..f39e782
--- /dev/null
+++ b/circuitpython/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) -> None:
+//| """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, size_t n_kw, const mp_obj_t *all_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_kw_array(n_args, n_kw, all_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: int, start_x: int, end_x: int) -> None:
+//| """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/circuitpython/shared-bindings/displayio/Shape.h b/circuitpython/shared-bindings/displayio/Shape.h
new file mode 100644
index 0000000..961b57c
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Shape.h
@@ -0,0 +1,41 @@
+/*
+ * 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_SHAPE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
+
+#include "shared-module/displayio/Shape.h"
+
+extern const mp_obj_type_t displayio_shape_type;
+
+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_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);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
diff --git a/circuitpython/shared-bindings/displayio/TileGrid.c b/circuitpython/shared-bindings/displayio/TileGrid.c
new file mode 100644
index 0000000..113721b
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/TileGrid.c
@@ -0,0 +1,502 @@
+/*
+ * 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 "shared/runtime/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: Union[Bitmap, OnDiskBitmap, Shape], *, pixel_shader: Union[ColorConverter, Palette], width: int = 1, height: int = 1, tile_width: Optional[int] = None, tile_height: Optional[int] = None, default_tile: int = 0, x: int = 0, y: int = 0) -> None:
+//| """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.
+//|
+//| To save RAM usage, tile values are only allowed in the range from 0 to 255 inclusive (single byte values).
+//|
+//| tile_width and tile_height match the height of the bitmap by default.
+//|
+//| :param Bitmap,OnDiskBitmap,Shape bitmap: The bitmap storing one or more tiles.
+//| :param ColorConverter,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, size_t n_kw, const mp_obj_t *all_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_kw_array(n_args, n_kw, all_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_obj_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_obj_cast_to_native_base(tilegrid_obj, &displayio_tilegrid_type);
+ mp_obj_assert_native_inited(native_tilegrid);
+ return MP_OBJ_TO_PTR(native_tilegrid);
+}
+
+//| hidden: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_hidden_obj,
+ (mp_obj_t)&displayio_tilegrid_get_hidden_obj,
+ (mp_obj_t)&displayio_tilegrid_set_hidden_obj);
+
+//| x: int
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_x_obj,
+ (mp_obj_t)&displayio_tilegrid_get_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_x_obj);
+
+//| y: int
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_y_obj,
+ (mp_obj_t)&displayio_tilegrid_get_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_y_obj);
+
+//| width: int
+//| """Width of the tilegrid in tiles."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_width(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_width_obj, displayio_tilegrid_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_width_obj,
+ (mp_obj_t)&displayio_tilegrid_get_width_obj);
+
+//| height: int
+//| """Height of the tilegrid in tiles."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_height(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_height_obj, displayio_tilegrid_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_height_obj,
+ (mp_obj_t)&displayio_tilegrid_get_height_obj);
+
+//| tile_width: int
+//| """Width of a single tile in pixels."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_tile_width(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_tile_width_obj, displayio_tilegrid_obj_get_tile_width);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_tile_width_obj,
+ (mp_obj_t)&displayio_tilegrid_get_tile_width_obj);
+
+//| tile_height: int
+//| """Height of a single tile in pixels."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_tile_height(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_tile_height_obj, displayio_tilegrid_obj_get_tile_height);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_tile_height_obj,
+ (mp_obj_t)&displayio_tilegrid_get_tile_height_obj);
+
+//| flip_x: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_flip_x_obj,
+ (mp_obj_t)&displayio_tilegrid_get_flip_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_x_obj);
+
+//| flip_y: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_flip_y_obj,
+ (mp_obj_t)&displayio_tilegrid_get_flip_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_y_obj);
+
+
+//| transpose_xy: bool
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_transpose_xy_obj,
+ (mp_obj_t)&displayio_tilegrid_get_transpose_xy_obj,
+ (mp_obj_t)&displayio_tilegrid_set_transpose_xy_obj);
+
+//| pixel_shader: Union[ColorConverter, Palette]
+//| """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);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_pixel_shader_obj,
+ (mp_obj_t)&displayio_tilegrid_get_pixel_shader_obj,
+ (mp_obj_t)&displayio_tilegrid_set_pixel_shader_obj);
+
+//| bitmap: Union[Bitmap,OnDiskBitmap,Shape]
+//| """The bitmap of the tilegrid."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_bitmap(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return common_hal_displayio_tilegrid_get_bitmap(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_bitmap_obj, displayio_tilegrid_obj_get_bitmap);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_bitmap(mp_obj_t self_in, mp_obj_t bitmap) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ uint16_t new_bitmap_width;
+ uint16_t new_bitmap_height;
+ mp_obj_t native = mp_obj_cast_to_native_base(bitmap, &displayio_shape_type);
+ if (native != MP_OBJ_NULL) {
+ displayio_shape_t *bmp = MP_OBJ_TO_PTR(native);
+ new_bitmap_width = bmp->width;
+ new_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;
+ new_bitmap_width = bmp->width;
+ new_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;
+ new_bitmap_width = bmp->width;
+ new_bitmap_height = bmp->height;
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap);
+ }
+
+ mp_obj_t old_native = mp_obj_cast_to_native_base(self->bitmap, &displayio_shape_type);
+ if (old_native != MP_OBJ_NULL) {
+ displayio_shape_t *old_bmp = MP_OBJ_TO_PTR(old_native);
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ } else if (mp_obj_is_type(self->bitmap, &displayio_bitmap_type)) {
+ displayio_bitmap_t *old_bmp = MP_OBJ_TO_PTR(self->bitmap);
+ old_native = self->bitmap;
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ } else if (mp_obj_is_type(self->bitmap, &displayio_ondiskbitmap_type)) {
+ displayio_ondiskbitmap_t *old_bmp = MP_OBJ_TO_PTR(self->bitmap);
+ old_native = self->bitmap;
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ }
+
+ common_hal_displayio_tilegrid_set_bitmap(self, bitmap);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_bitmap_obj, displayio_tilegrid_obj_set_bitmap);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_bitmap_obj,
+ (mp_obj_t)&displayio_tilegrid_get_bitmap_obj,
+ (mp_obj_t)&displayio_tilegrid_set_bitmap_obj);
+
+//| def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+//| """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: Union[Tuple[int, int], int], value: int) -> None:
+//| """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_width), MP_ROM_PTR(&displayio_tilegrid_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_tilegrid_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tile_width), MP_ROM_PTR(&displayio_tilegrid_tile_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tile_height), MP_ROM_PTR(&displayio_tilegrid_tile_height_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) },
+ { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&displayio_tilegrid_bitmap_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 },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_TileGrid,
+ .make_new = displayio_tilegrid_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_tilegrid_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = tilegrid_subscr,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/TileGrid.h b/circuitpython/shared-bindings/displayio/TileGrid.h
new file mode 100644
index 0000000..2c79412
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/TileGrid.h
@@ -0,0 +1,71 @@
+/*
+ * 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);
+
+mp_obj_t common_hal_displayio_tilegrid_get_bitmap(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_bitmap(displayio_tilegrid_t *self, mp_obj_t bitmap);
+
+
+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);
+
+uint16_t common_hal_displayio_tilegrid_get_tile_width(displayio_tilegrid_t *self);
+uint16_t common_hal_displayio_tilegrid_get_tile_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/circuitpython/shared-bindings/displayio/__init__.c b/circuitpython/shared-bindings/displayio/__init__.c
new file mode 100644
index 0000000..2e52f12
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/__init__.c
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#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"
+#if CIRCUITPY_PARALLELDISPLAY
+#include "shared-bindings/paralleldisplay/ParallelBus.h"
+#endif
+#include "shared-bindings/displayio/Shape.h"
+#include "shared-bindings/displayio/TileGrid.h"
+
+//| """Native helpers for driving displays
+//|
+//| The `displayio` module contains classes to manage display output
+//| including synchronizing with refresh rates and partial updating.
+//|
+//| For more a more thorough explanation and guide for using `displayio`, please
+//| refer to `this Learn guide
+//| <https://learn.adafruit.com/circuitpython-display-support-using-displayio>`_.
+//| """
+//|
+
+//| import paralleldisplay
+
+//| def release_displays() -> None:
+//| """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.
+//|
+//| 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_Colorspace), MP_ROM_PTR(&displayio_colorspace_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_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) },
+ #if CIRCUITPY_PARALLELDISPLAY
+ { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&paralleldisplay_parallelbus_type) },
+ #endif
+
+ { 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);
+
+const mp_obj_module_t displayio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&displayio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_displayio, displayio_module, CIRCUITPY_DISPLAYIO);
diff --git a/circuitpython/shared-bindings/displayio/__init__.h b/circuitpython/shared-bindings/displayio/__init__.h
new file mode 100644
index 0000000..b297e4d
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/__init__.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
+
+#include "py/enum.h"
+#include "py/obj.h"
+
+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 enum displayio_colorspace {
+ DISPLAYIO_COLORSPACE_RGB888,
+ DISPLAYIO_COLORSPACE_RGB565,
+ DISPLAYIO_COLORSPACE_RGB555,
+ DISPLAYIO_COLORSPACE_RGB565_SWAPPED,
+ DISPLAYIO_COLORSPACE_RGB555_SWAPPED,
+ DISPLAYIO_COLORSPACE_BGR565,
+ DISPLAYIO_COLORSPACE_BGR555,
+ DISPLAYIO_COLORSPACE_BGR565_SWAPPED,
+ DISPLAYIO_COLORSPACE_BGR555_SWAPPED,
+ DISPLAYIO_COLORSPACE_L8,
+} displayio_colorspace_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, const uint8_t *data, uint32_t data_length);
+typedef void (*display_bus_end_transaction)(mp_obj_t bus);
+
+void common_hal_displayio_release_displays(void);
+
+extern const mp_obj_type_t displayio_colorspace_type;
+extern const cp_enum_obj_t displayio_colorspace_RGB888_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
diff --git a/circuitpython/shared-bindings/displayio/area.c b/circuitpython/shared-bindings/displayio/area.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/area.c