|
29 | 29 | __version__ = "0.0.0-auto.0" |
30 | 30 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_neotrellis.git" |
31 | 31 |
|
| 32 | +from typing import List, Dict, Tuple, Sequence |
32 | 33 | from time import sleep |
33 | 34 | from micropython import const |
| 35 | +from adafruit_neotrellis.neotrellis import NeoTrellis |
34 | 36 | from adafruit_seesaw.keypad import KeyEvent |
35 | 37 |
|
36 | | -_NEO_TRELLIS_NUM_KEYS = const(16) |
37 | | - |
38 | | - |
39 | | -def _key(xval): |
40 | | - return int(int(xval / 4) * 8 + (xval % 4)) |
41 | | - |
42 | | - |
43 | | -def _seesaw_key(xval): |
44 | | - return int(int(xval / 8) * 4 + (xval % 8)) |
45 | | - |
46 | 38 |
|
47 | 39 | class MultiTrellis: |
48 | 40 | """Driver for multiple connected Adafruit NeoTrellis boards.""" |
49 | 41 |
|
| 42 | + _trelli: List[List[NeoTrellis]] |
| 43 | + _rows: int |
| 44 | + _cols: int |
| 45 | + _key_pads: List[List[NeoTrellis]] |
| 46 | + |
50 | 47 | def __init__(self, neotrellis_array): |
51 | 48 | self._trelli = neotrellis_array |
52 | 49 | self._rows = len(neotrellis_array) |
53 | 50 | self._cols = len(neotrellis_array[0]) |
| 51 | + col_size_sum = [0 for _ in range(self._cols)] |
| 52 | + row_size_sum = [0 for _ in range(self._rows)] |
| 53 | + for py in range(self._rows): |
| 54 | + for px in range(self._cols): |
| 55 | + assert len(self._trelli[py]) == self._cols |
| 56 | + |
| 57 | + tr0 = self._trelli[0][px] |
| 58 | + tc0 = self._trelli[py][0] |
| 59 | + t = self._trelli[py][px] |
| 60 | + |
| 61 | + # All columns must have similar shape |
| 62 | + assert t.height == tc0.height |
| 63 | + # All rows must have similar shape |
| 64 | + assert t.width == tr0.width |
| 65 | + |
| 66 | + y_base = row_size_sum[py - 1] if py > 0 else 0 |
| 67 | + x_base = col_size_sum[px - 1] if px > 0 else 0 |
| 68 | + row_size_sum[py] = t.height + y_base |
| 69 | + col_size_sum[px] = t.width + x_base |
| 70 | + |
| 71 | + t.x_base = x_base |
| 72 | + t.y_base = y_base |
| 73 | + |
| 74 | + self._width = col_size_sum[self._cols - 1] |
| 75 | + self._height = row_size_sum[self._rows - 1] |
| 76 | + self._key_pads : List[List[NeoTrellis]] = [[None for _ in range(self._width)] |
| 77 | + for _ in range(self._height)] |
| 78 | + |
| 79 | + for py in range(self._rows): |
| 80 | + for px in range(self._cols): |
| 81 | + t = self._trelli[py][px] |
| 82 | + for ky in range(t.height): |
| 83 | + for kx in range(t.width): |
| 84 | + x = t.x_base + kx |
| 85 | + y = t.y_base + ky |
| 86 | + self._key_pads[y][x] = t |
| 87 | + |
| 88 | + @property |
| 89 | + def width(self): |
| 90 | + return self._width |
| 91 | + |
| 92 | + @property |
| 93 | + def height(self): |
| 94 | + return self._height |
| 95 | + |
| 96 | + @property |
| 97 | + def rows(self): |
| 98 | + return self._rowa |
| 99 | + |
| 100 | + @property |
| 101 | + def cols(self): |
| 102 | + return self._cols |
| 103 | + |
| 104 | + def __len__(self) -> int: |
| 105 | + return self._rows |
| 106 | + |
| 107 | + def __getitem__(self, subscript: int) -> Sequence[NeoTrellis]: |
| 108 | + return self._trelli[subscript] |
| 109 | + |
| 110 | + def get_key_pad(self, x: int, y: int) -> NeoTrellis: |
| 111 | + return self._key_pads[y][x] |
54 | 112 |
|
55 | 113 | def activate_key(self, x, y, edge, enable=True): |
56 | 114 | """Activate or deactivate a key on the trellis. x and y are the index |
57 | 115 | of the key measured from the top lefthand corner. Edge specifies what |
58 | 116 | edge to register an event on and can be NeoTrellis.EDGE_FALLING or |
59 | 117 | NeoTrellis.EDGE_RISING. enable should be set to True if the event is |
60 | 118 | to be enabled, or False if the event is to be disabled.""" |
61 | | - xkey = x % 4 |
62 | | - ykey = int(int(y % 4) * 4 / 4) |
63 | | - self._trelli[int(y / 4)][int(x / 4)].activate_key(ykey * 4 + xkey, edge, enable) |
| 119 | + pad = self._key_pads[y][x] |
| 120 | + pad.activate_key(pad.key_index(x, y), enable) |
64 | 121 |
|
65 | 122 | def set_callback(self, x, y, function): |
66 | 123 | """Set a callback function for when an event for the key at index x, y |
67 | 124 | (measured from the top lefthand corner) is detected.""" |
68 | | - xkey = x % 4 |
69 | | - ykey = int(int(y % 4) * 4 / 4) |
70 | | - self._trelli[int(y / 4)][int(x / 4)].callbacks[ykey * 4 + xkey] = function |
| 125 | + pad = self._key_pads[y][x] |
| 126 | + pad.callbacks[pad.key_index(x, y)] = function |
71 | 127 |
|
72 | 128 | def color(self, x, y, color): |
73 | 129 | """Set the color of the pixel at index x, y measured from the top |
74 | 130 | lefthand corner of the matrix""" |
75 | | - xkey = x % 4 |
76 | | - ykey = int(int(y % 4) * 4 / 4) |
77 | | - self._trelli[int(y / 4)][int(x / 4)].pixels[ykey * 4 + xkey] = color |
| 131 | + pad = self._key_pads[y][x] |
| 132 | + pad.pixels[pad.key_index(x, y)] = color |
78 | 133 |
|
79 | 134 | def sync(self): |
80 | 135 | """Read all trellis boards in the matrix and call any callbacks""" |
81 | 136 | for _n in range(self._rows): |
82 | 137 | for _m in range(self._cols): |
83 | 138 |
|
84 | 139 | _t = self._trelli[_n][_m] |
85 | | - available = _t.count |
86 | | - sleep(0.0005) |
87 | | - if available > 0: |
88 | | - available = available + 2 |
89 | | - buf = _t.read_keypad(available) |
90 | | - for raw in buf: |
91 | | - evt = KeyEvent(_seesaw_key((raw >> 2) & 0x3F), raw & 0x3) |
92 | | - if ( |
93 | | - evt.number < _NEO_TRELLIS_NUM_KEYS |
94 | | - and _t.callbacks[evt.number] is not None |
95 | | - ): |
96 | | - y = int(evt.number / 4) + _n * 4 |
97 | | - x = int(evt.number % 4) + _m * 4 |
98 | | - _t.callbacks[evt.number](x, y, evt.edge) |
| 140 | + _t.sync() |
0 commit comments