|
| 1 | +/* |
| 2 | + * Copyright 2023 Cisco Systems, Inc. and its affiliates |
| 3 | + * Author: Wyrdsec |
| 4 | + * |
| 5 | + * Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 6 | + * this software and associated documentation files (the "Software"), to deal in |
| 7 | + * the Software without restriction, including without limitation the rights to |
| 8 | + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| 9 | + * the Software, and to permit persons to whom the Software is furnished to do so, |
| 10 | + * subject to the following conditions: |
| 11 | + * - The above copyright notice and this permission notice shall be included in |
| 12 | + * all copies or substantial portions of the Software. |
| 13 | + * - The Software is provided "as is", without warranty of any kind, express or |
| 14 | + * implied, including but not limited to the warranties of merchantability, |
| 15 | + * fitness for a particular purpose and noninfringement. In no event shall the |
| 16 | + * authors or copyright holders be liable for any claim, damages or other |
| 17 | + * liability, whether in an action of contract, tort or otherwise, arising from, |
| 18 | + * out of or in connection with the Software or the use or other dealings in the |
| 19 | + * Software. |
| 20 | + */ |
| 21 | +#include "py/objarray.h" |
| 22 | +#include "py/runtime.h" |
| 23 | +#include "py/objproperty.h" |
| 24 | + |
| 25 | + |
| 26 | +#include "shared-bindings/aurora_epaper/aurora_framebuffer.h" |
| 27 | +#include "shared-module/aurora_epaper/aurora_framebuffer.h" |
| 28 | +#include "shared-bindings/busio/SPI.h" |
| 29 | +#include "shared-bindings/microcontroller/Pin.h" |
| 30 | +#include "shared-module/displayio/__init__.h" |
| 31 | + |
| 32 | +//| class AuroraMemoryFramebuffer: |
| 33 | +//| """A framebuffer for Pervasive Displays Aurora E-paper displays. |
| 34 | +//| |
| 35 | +//| These displays are 2 color only. |
| 36 | +//| |
| 37 | +//| This initializes a display and connects it to CircuitPython. |
| 38 | +//| |
| 39 | +//| For Example:: |
| 40 | +//| |
| 41 | +//| import busio |
| 42 | +//| import framebufferio |
| 43 | +//| from aurora_epaper import AuroraMemoryFramebuffer |
| 44 | +//| spi = busio.SPI(EINK_CLKS, EINK_MOSI, EINK_MISO) |
| 45 | +//| aurora = AuroraMemoryFramebuffer(spi, EINK_CS, EINK_RST, EINK_BUSY, EINK_DISCHARGE, HEIGHT, WIDTH) |
| 46 | +//| display = framebufferio.FramebufferDisplay(t, auto_refresh=False) |
| 47 | +//| display.refresh() |
| 48 | +//| |
| 49 | +//| For more information on how these displays are driven see: |
| 50 | +//| https://www.pervasivedisplays.com/wp-content/uploads/2023/02/4P018-00_04_G2_Aurora-Mb_COG_Driver_Interface_Timing_for_small-size_20231107.pdf |
| 51 | +//| """ |
| 52 | +//| |
| 53 | +//| def __init__( |
| 54 | +//| self, |
| 55 | +//| spi_bus: busio.SPI, |
| 56 | +//| chip_select: microcontroller.Pin, |
| 57 | +//| reset: microcontroller.Pin, |
| 58 | +//| busy: microcontroller.Pin, |
| 59 | +//| discharge: microcontroller.Pin, |
| 60 | +//| width: int, |
| 61 | +//| height: int, |
| 62 | +//| power: Optional[microcontroller.Pin] = None, |
| 63 | +//| free_bus: Optional[bool] = True, |
| 64 | +//| ) -> None: |
| 65 | +//| """Create a framebuffer for the Aurora CoG display. |
| 66 | +//| |
| 67 | +//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exibit unexpected behavior. |
| 68 | +//| |
| 69 | +//| :param busio.SPI spi_bus: The SPI bus that the display is connected to |
| 70 | +//| :param microcontroller.Pin chip_select: The pin connected to the displays chip select input |
| 71 | +//| :param microcontroller.Pin reset: The pin connected to the displays reset input |
| 72 | +//| :param microcontroller.Pin busy: The pin connected to the displays busy output |
| 73 | +//| :param microcontroller.Pin discharge: The pin connected to the displays discharge input |
| 74 | +//| :param int width: The width of the display in pixels |
| 75 | +//| :param int height: The height of the display in pixels |
| 76 | +//| :param microcontroller.Pin power: The pin that controls power to the display (optional). |
| 77 | +//| :param bool free_bus: Determines whether the SPI bus passed in will be freed when the frame buffer is freed (optional). |
| 78 | +//| """ |
| 79 | +//| ... |
| 80 | +static mp_obj_t aurora_epaper_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { |
| 81 | + enum { ARG_spi_bus, ARG_chip_select, ARG_reset, ARG_busy, ARG_discharge, ARG_width, ARG_height, ARG_power, ARG_free_bus, NUM_ARGS }; |
| 82 | + static const mp_arg_t allowed_args[] = { |
| 83 | + { MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, |
| 84 | + { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, |
| 85 | + { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, |
| 86 | + { MP_QSTR_busy, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, |
| 87 | + { MP_QSTR_discharge, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, |
| 88 | + { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, |
| 89 | + { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, |
| 90 | + { MP_QSTR_power, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 91 | + { MP_QSTR_free_bus, MP_ARG_BOOL, {.u_bool = true} }, |
| 92 | + }; |
| 93 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 94 | + MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS); |
| 95 | + |
| 96 | + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 97 | + |
| 98 | + // Pins |
| 99 | + const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj, MP_QSTR_chip_select); |
| 100 | + const mcu_pin_obj_t *reset = validate_obj_is_free_pin(args[ARG_reset].u_obj, MP_QSTR_reset); |
| 101 | + const mcu_pin_obj_t *busy = validate_obj_is_free_pin(args[ARG_busy].u_obj, MP_QSTR_busy); |
| 102 | + const mcu_pin_obj_t *discharge = validate_obj_is_free_pin(args[ARG_discharge].u_obj, MP_QSTR_discharge); |
| 103 | + const mcu_pin_obj_t *power = validate_obj_is_free_pin_or_none(args[ARG_power].u_obj, MP_QSTR_power); |
| 104 | + |
| 105 | + busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj, MP_QSTR_spi_bus); |
| 106 | + aurora_epaper_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->aurora_epaper; |
| 107 | + self->base.type = &aurora_framebuffer_type; |
| 108 | + |
| 109 | + common_hal_aurora_epaper_framebuffer_construct(self, spi, chip_select, reset, busy, discharge, power, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_free_bus].u_bool); |
| 110 | + return MP_OBJ_FROM_PTR(self); |
| 111 | +} |
| 112 | + |
| 113 | +static mp_int_t aurora_epaper_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { |
| 114 | + aurora_epaper_framebuffer_obj_t *self = self_in; |
| 115 | + if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { |
| 116 | + return 1; |
| 117 | + } |
| 118 | + *bufinfo = self->bufinfo; |
| 119 | + return 0; |
| 120 | +} |
| 121 | + |
| 122 | +//| def deinit(self) -> None: |
| 123 | +//| """Free the resources (pins, timers, etc.) associated with this |
| 124 | +//| AuroraMemoryFramebuffer instance. After deinitialization, no further operations |
| 125 | +//| may be performed.""" |
| 126 | +//| ... |
| 127 | +static mp_obj_t aurora_epaper_framebuffer_deinit(mp_obj_t self_in) { |
| 128 | + aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in; |
| 129 | + common_hal_aurora_epaper_framebuffer_deinit(self); |
| 130 | + |
| 131 | + return mp_const_none; |
| 132 | +} |
| 133 | +static MP_DEFINE_CONST_FUN_OBJ_1(aurora_epaper_framebuffer_deinit_obj, aurora_epaper_framebuffer_deinit); |
| 134 | + |
| 135 | +//| def set_temperature(self, celsius: int) -> None: |
| 136 | +//| """Set the ambient temperature (in celsius) for the display driver. |
| 137 | +//| Higher temperature means faster update speed. |
| 138 | +//| """ |
| 139 | +//| ... |
| 140 | +static mp_obj_t aurora_epaper_frambuffer_set_temperature(mp_obj_t self_in, mp_obj_t temperature) { |
| 141 | + aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in; |
| 142 | + |
| 143 | + common_hal_aurora_epaper_framebuffer_set_temperature(self, mp_obj_get_float(temperature)); |
| 144 | + |
| 145 | + return mp_const_none; |
| 146 | +} |
| 147 | +static MP_DEFINE_CONST_FUN_OBJ_2(aurora_epaper_frambuffer_set_temperature_obj, aurora_epaper_frambuffer_set_temperature); |
| 148 | + |
| 149 | +//| free_bus: bool |
| 150 | +//| """When True the spi bus passed into the device will be freed on deinit. |
| 151 | +//| If you have multiple displays this could be used to keep the other active on soft reset.""" |
| 152 | +//| ... |
| 153 | +//| |
| 154 | +static mp_obj_t aurora_epaper_framebuffer_get_free_bus(mp_obj_t self_in) { |
| 155 | + aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in; |
| 156 | + return mp_obj_new_bool(self->free_bus); |
| 157 | +} |
| 158 | +static MP_DEFINE_CONST_FUN_OBJ_1(aurora_epaper_framebuffer_get_free_bus_obj, aurora_epaper_framebuffer_get_free_bus); |
| 159 | + |
| 160 | + |
| 161 | +static mp_obj_t aurora_epaper_framebuffer_set_free_bus(mp_obj_t self_in, mp_obj_t free_bus) { |
| 162 | + aurora_epaper_framebuffer_obj_t *self = (aurora_epaper_framebuffer_obj_t *)self_in; |
| 163 | + common_hal_aurora_epaper_framebuffer_set_free_bus(self, mp_obj_is_true(free_bus)); |
| 164 | + return mp_const_none; |
| 165 | +} |
| 166 | +static MP_DEFINE_CONST_FUN_OBJ_2(aurora_epaper_framebuffer_set_free_bus_obj, aurora_epaper_framebuffer_set_free_bus); |
| 167 | + |
| 168 | +MP_PROPERTY_GETSET(aurora_epaper_framebuffer_free_bus_obj, |
| 169 | + (mp_obj_t)&aurora_epaper_framebuffer_get_free_bus_obj, |
| 170 | + (mp_obj_t)&aurora_epaper_framebuffer_set_free_bus_obj); |
| 171 | + |
| 172 | +static const mp_rom_map_elem_t aurora_epaper_framebuffer_locals_dict_table[] = { |
| 173 | + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&aurora_epaper_framebuffer_deinit_obj) }, |
| 174 | + { MP_ROM_QSTR(MP_QSTR_set_temperature), MP_ROM_PTR(&aurora_epaper_frambuffer_set_temperature_obj) }, |
| 175 | + { MP_ROM_QSTR(MP_QSTR_free_bus), MP_ROM_PTR(&aurora_epaper_framebuffer_free_bus_obj) }, |
| 176 | +}; |
| 177 | +static MP_DEFINE_CONST_DICT(aurora_epaper_framebuffer_locals_dict, aurora_epaper_framebuffer_locals_dict_table); |
| 178 | + |
| 179 | +MP_DEFINE_CONST_OBJ_TYPE( |
| 180 | + aurora_framebuffer_type, |
| 181 | + MP_QSTR_AuroraEpaperFramebuffer, |
| 182 | + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, |
| 183 | + make_new, aurora_epaper_framebuffer_make_new, |
| 184 | + locals_dict, &aurora_epaper_framebuffer_locals_dict, |
| 185 | + buffer, aurora_epaper_framebuffer_get_buffer, |
| 186 | + protocol, &aurora_epaper_framebuffer_proto |
| 187 | + ); |
0 commit comments