]> Repositories - hackapet/Adafruit_Blinka_Displayio.git/blob - displayio.py
f61eee8307d50e71407b2d88ffd76c8245e0f6e0
[hackapet/Adafruit_Blinka_Displayio.git] / displayio.py
1 """
2 `displayio`
3 """
4
5 import os
6 import digitalio
7 import time
8
9 """
10 import asyncio
11 import signal
12 import struct
13 import subprocess
14 """
15
16 # Don't import pillow if we're running in the CI. We could mock it out but that
17 # would require mocking in all reverse dependencies.
18 if "GITHUB_ACTION" not in os.environ and "READTHEDOCS" not in os.environ:
19     # This will only work on Linux
20     pass
21 else:
22     # this would be for Github Actions
23     utils = None  # pylint: disable=invalid-name
24
25 __version__ = "0.0.0-auto.0"
26 __repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
27
28 _displays = []
29 _groups = []
30
31 class _DisplayioSingleton():
32     def __init__(self):
33         pass
34
35 def release_displays():
36     """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.
37
38     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.
39     """
40     _displays.clear()
41
42
43 class Bitmap:
44     """Stores values of a certain size in a 2D array"""
45     def __init__(self, width, height, value_count):
46         """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.
47         """
48         pass
49         
50     def __getitem__(self, index):
51         """
52         Returns the value at the given index. The index can either be
53         an x,y tuple or an int equal to `y * width + x`.
54         """
55         pass
56
57     def __setitem__(self, index, value):
58         """
59         Sets the value at the given index. The index can either be
60         an x,y tuple or an int equal to `y * width + x`.
61         """
62         pass
63         
64     def fill(self, value):
65         """Fills the bitmap with the supplied palette index value."""
66         pass
67
68     @property
69     def width(self):
70         """Width of the bitmap. (read only)"""
71         pass
72
73     @property
74     def height(self):
75         """Height of the bitmap. (read only)"""
76         pass
77
78
79 class ColorConverter:
80     """Converts one color format to another."""
81     def __init__(self):
82         """Create a ColorConverter object to convert color formats.
83         Only supports RGB888 to RGB565 currently.
84         """
85         self._dither = False
86         
87     def convert(self, color):
88         "Converts the given RGB888 color to RGB565"
89         pass
90
91     @property
92     def dither(self):
93         "When true the color converter dithers the output by adding random noise when truncating to display bitdepth"
94         return self._dither
95
96     @dither.setter
97     def dither(self, value):
98         if not isinstance(value, bool):
99             raise ValueError("Value should be boolean")
100         self._dither = value
101
102
103 class Display:
104     """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.
105
106     Most people should not use this class directly. Use a specific display driver instead that will contain the initialization sequence at minimum.
107     
108     .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False, auto_refresh=True, native_frames_per_second=60)
109     
110     """
111     def __init__(self, display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False, auto_refresh=True, native_frames_per_second=60):
112         """Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`).
113
114         The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a command byte followed by a byte to determine the parameter count and if a delay is need after. When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay byte. The third through final bytes are the remaining command parameters. The next byte will begin a new command definition. Here is a portion of ILI9341 init code:
115         .. code-block:: python
116         
117             init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma
118                 b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms)
119                 b"\x29\x80\x78"# Display on then delay 0x78 (120ms)
120             )
121             display = displayio.Display(display_bus, init_sequence, width=320, height=240)
122         
123         The first command is 0xe1 with 15 (0xf) parameters following. The second and third are 0x11 and 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters. Multiple byte literals (b”“) are merged together on load. The parens are needed to allow byte literals on subsequent lines.
124
125         The initialization sequence should always leave the display memory access inline with the scan of the display to minimize tearing artifacts.
126         """
127         self._display_bus = display_bus
128         self._set_column_command=0x2a
129         self._set_row_command=0x2b
130         self._write_ram_command=0x2c
131         self._brightness_command=brightness_command
132         self._data_as_commands = data_as_commands
133         self._single_byte_bounds = single_byte_bounds
134         i = 0
135         while i < len(init_sequence):
136             command = bytes([init_sequence[i]])
137             data_size = init_sequence[i + 1]
138             delay = (data_size & 0x80) > 0
139             data_size &= ~0x80
140             data_byte = init_sequence[i + 2]
141             if (self._single_byte_bounds):
142                 data = command + init_sequence[i + 2:i + 2 + data_size]
143                 display_bus.send(True, data, toggle_every_byte=True)
144             else:
145                 display_bus.send(True, command, toggle_every_byte=True)
146                 if (data_size > 0):
147                     display_bus.send(False, init_sequence[i + 2:i + 2 + data_size])
148             delay_time_ms = 10
149             if (delay):
150                 data_size += 1
151                 delay_time_ms = init_sequence[i + 1 + data_size]
152                 if (delay_time_ms == 255):
153                     delay_time_ms = 500
154             time.sleep(delay_time_ms / 1000)
155             i += 2 + data_size
156         
157     def show(self, group):
158         """Switches to displaying the given group of layers. When group is None, the default CircuitPython terminal will be shown.
159         """
160         pass
161
162     def refresh(self, *, target_frames_per_second=60, minimum_frames_per_second=1):
163         """When auto refresh is off, waits for the target frame rate and then refreshes the display, returning True. If the call has taken too long since the last refresh call for the given target frame rate, then the refresh returns False immediately without updating the screen to hopefully help getting caught up.
164
165         If the time since the last successful refresh is below the minimum frame rate, then an exception will be raised. Set minimum_frames_per_second to 0 to disable.
166
167         When auto refresh is on, updates the display immediately. (The display will also update without calls to this.)
168         """
169         pass
170         
171     def fill_row(self, y, buffer):
172         pass
173
174     @property
175     def auto_refresh(self):
176         pass
177
178     @auto_refresh.setter
179     def auto_refresh(self, value):
180         pass
181
182     @property
183     def brightness(self):
184         """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.
185         """
186         pass
187
188     @brightness.setter
189     def brightness(self, value):
190         pass
191
192     @property
193     def auto_brightness(self):
194         """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.
195         """
196         pass
197
198     @auto_brightness.setter
199     def auto_brightness(self, value):
200         pass
201
202     @property
203     def width(self):
204         pass
205
206     @property
207     def height(self):
208         pass
209
210     @property
211     def rotation(self):
212         """The rotation of the display as an int in degrees."""
213         pass
214
215     @rotation.setter
216     def rotation(self, value):
217         pass
218
219     @property
220     def bus(self):
221         pass
222
223
224 class EPaperDisplay:
225     def __init__(self, display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, refresh_time=40, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False):
226         """
227         Create a EPaperDisplay object on the given display bus (displayio.FourWire or displayio.ParallelBus).
228
229         The start_sequence and stop_sequence are bitpacked to minimize the ram impact. Every command begins with a command byte followed by a byte to determine the parameter count and if a delay is need after. When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay byte. The third through final bytes are the remaining command parameters. The next byte will begin a new command definition.
230         """
231         pass
232
233     def show(self, group):
234         """Switches to displaying the given group of layers. When group is None, the default CircuitPython terminal will be shown.
235         """
236         pass
237
238     def refresh(self):
239         """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.
240         """
241         pass
242     @property
243     def time_to_refresh(self):
244         """Time, in fractional seconds, until the ePaper display can be refreshed."""
245         return 0
246
247     @property
248     def width(self):
249         pass
250
251     @property
252     def height(self):
253         pass
254
255     @property
256     def bus(self):
257         pass
258
259
260 class FourWire:
261     """Manage updating a display over SPI four wire protocol in the background while
262     Python code runs. It doesn’t handle display initialization.
263     """
264     def __init__(self, spi_bus, *, command, chip_select, reset=None, baudrate=24000000, polarity=0, phase=0):
265         """Create a FourWire object associated with the given pins.
266
267         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.
268         """
269         self._dc = digitalio.DigitalInOut(command)
270         self._dc.switch_to_output()
271         self.chip_select = digitalio.DigitalInOut(chip_select)
272         self.chip_select.switch_to_output(value=True)
273
274         if reset is not None:
275             self._reset = digitalio.DigitalInOut(reset)
276             self._reset.switch_to_output(value=True)
277         else:
278             self._reset = None
279         self._spi = spi_bus
280         while self._spi.try_lock():
281             pass
282         self._spi.configure(baudrate=baudrate, polarity=polarity, phase=phase)
283         self._spi.unlock()
284         
285     def reset(self):
286         if self._reset is not None:
287             self.value = False
288             time.sleep(0.001)
289             self.value = True
290             time.sleep(0.001)
291
292     def send(self, command, data, *, toggle_every_byte=False):
293         while self._spi.try_lock():
294             pass
295         self._dc.value = not command
296         if (toggle_every_byte):
297             for byte in data:
298                 self._spi.write(bytes([byte]))
299                 self.chip_select.value = True
300                 time.sleep(0.000001)
301                 self.chip_select.value = False
302         else:
303             self._spi.write(data)
304         self._spi.unlock()
305
306 class Group:
307     """Manage a group of sprites and groups and how they are inter-related."""
308     def __init__(self, *, max_size=4, scale=1, x=0, y=0):
309         """Create a Group of a given size and scale. Scale is in
310         one dimension. For example, scale=2 leads to a layer’s
311         pixel being 2x2 pixels when in the group.
312         """
313         pass
314         
315     def append(self, layer):
316         """Append a layer to the group. It will be drawn
317         above other layers.
318         """
319         pass
320
321     def insert(self, index, layer):
322         """Insert a layer into the group."""
323         pass
324         
325     def index(self, layer):
326         """Returns the index of the first copy of layer.
327         Raises ValueError if not found.
328         """
329         pass
330         
331     def pop(self, index=-1):
332         """Remove the ith item and return it."""
333         pass
334         
335     def remove(self, layer):
336         """Remove the first copy of layer. Raises ValueError
337         if it is not present."""
338         pass
339         
340     def __len__(self):
341         """Returns the number of layers in a Group"""
342         pass
343
344     def __getitem__(self, index):
345         """Returns the value at the given index."""
346         pass
347
348     def __setitem__(self, index, value):
349         """Sets the value at the given index."""
350         pass
351
352     def __delitem__(self, index):
353         """Deletes the value at the given index."""
354         pass
355
356     @property
357     def hidden(self):
358         pass
359
360     @hidden.setter
361     def hidden(self, value):
362         pass
363
364     @property
365     def scale(self):
366         pass
367
368     @scale.setter
369     def scale(self, value):
370         pass
371
372     @property
373     def x(self):
374         pass
375
376     @x.setter
377     def x(self, value):
378         pass
379
380     @property
381     def y(self):
382         pass
383
384     @y.setter
385     def y(self, value):
386         pass
387
388
389 class I2CDisplay:
390     """Manage updating a display over I2C in the background while Python code runs. It doesn’t handle display initialization.
391     """
392     def __init__(self, i2c_bus, *, device_address, reset=None):
393         """Create a I2CDisplay object associated with the given I2C bus and reset pin.
394
395         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.
396         """
397         pass
398
399     def reset(self):
400         pass
401
402     def send(self, command, data):
403         pass
404
405
406 class OnDisplayBitmap:
407     """
408     Loads values straight from disk. This minimizes memory use but can lead to much slower pixel load times.
409     These load times may result in frame tearing where only part of the image is visible."""
410     def __init__(self, file):
411         pass
412
413     @property
414     def width(self):
415         """Width of the bitmap. (read only)"""
416         pass
417
418     @property
419     def height(self):
420         """Height of the bitmap. (read only)"""
421         pass
422
423
424 class Palette:
425     """Map a pixel palette_index to a full color. Colors are transformed to the display’s format internally to save memory."""
426     def __init__(self, color_count):
427         """Create a Palette object to store a set number of colors."""
428         pass
429
430     def __len__(self):
431         """Returns the number of colors in a Palette"""
432         pass
433
434     def __setitem__(self, index, value):
435         """Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1.
436
437         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.
438         """
439         pass
440
441     def make_transparent(self, palette_index):
442         pass
443
444     def make_opaque(self, palette_index):
445         pass
446
447
448 class ParallelBus:
449     """Manage updating a display over 8-bit parallel bus in the background while Python code runs.
450     This protocol may be refered to as 8080-I Series Parallel Interface in datasheets.
451     It doesn’t handle display initialization.
452     """
453     def __init__(self, i2c_bus, *, device_address, reset=None):
454         """Create a ParallelBus object associated with the given pins. The bus is inferred from data0 by implying the next 7 additional pins on a given GPIO port.
455
456         The parallel bus and pins are then in use by the display until displayio.release_displays() is called even after a reload. (It does this so CircuitPython can use the display after your code is done.) So, the first time you initialize a display bus in code.py you should call :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run.
457         """
458         pass
459
460     def reset(self):
461         """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin is available.
462         """
463         pass
464
465     def send(self, command, data):
466         """Sends the given command value followed by the full set of data. Display state, such as
467         vertical scroll, set via ``send`` may or may not be reset once the code is done.
468         """
469         pass
470
471
472 class Shape:
473     """Create a Shape object with the given fixed size. Each pixel is one bit and is stored by the column
474     boundaries of the shape on each row. Each row’s boundary defaults to the full row.
475     """
476     def __init__(self, width, height, *, mirror_x=False, mirror_y=False):
477         """Create a Shape object with the given fixed size. Each pixel is one bit and is stored by the
478         column boundaries of the shape on each row. Each row’s boundary defaults to the full row.
479         """
480         pass
481     
482     def set_boundary(self, y, start_x, end_x):
483         """Loads pre-packed data into the given row."""
484         pass
485
486
487 class TileGrid:
488     """Position a grid of tiles sourced from a bitmap and pixel_shader combination. Multiple grids can share bitmaps and pixel shaders.
489
490     A single tile grid is also known as a Sprite.
491     """
492     def __init__(self, bitmap, *, pixel_shader, width=1, height=1, tile_width=None, tile_height=None, default_tile=0, x=0, y=0):
493         """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.
494
495         tile_width and tile_height match the height of the bitmap by default.
496         """
497         pass
498
499     @property
500     def hidden(self):
501         """True when the TileGrid is hidden. This may be False even when a part of a hidden Group."""
502         pass
503
504     @hidden.setter
505     def hidden(self, value):
506         pass
507
508     @property
509     def x(self):
510         """X position of the left edge in the parent."""
511         pass
512
513     @property
514     def y(self):
515         """Y position of the top edge in the parent."""
516         pass
517
518     @property
519     def flip_x(self):
520         """If true, the left edge rendered will be the right edge of the right-most tile."""
521         pass
522
523     @flip_x.setter
524     def flip_x(self, value):
525         pass
526
527     @property
528     def flip_y(self):
529         """If true, the top edge rendered will be the bottom edge of the bottom-most tile."""
530         pass
531
532     @flip_y.setter
533     def flip_y(self, value):
534         pass
535
536     @property
537     def transpose_xy(self):
538         """If true, the TileGrid’s axis will be swapped. When combined with mirroring, any 90 degree
539         rotation can be achieved along with the corresponding mirrored version.
540         """
541         pass
542
543     @transpose_xy.setter
544     def transpose_xy(self, value):
545         pass
546
547     @property
548     def pixel_shader(self):
549         """The pixel shader of the tilegrid."""
550         pass
551
552     def __getitem__(self, index):
553         """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``'."""
554         pass
555
556     def __setitem__(self, index, value):
557         """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``."""
558         pass