git.s-ol.nu hw/0x33.board/firmware / f7f24a4
update for PCB rev defcd99 s-ol a month ago
2 changed file(s) with 57 addition(s) and 151 deletion(s). Raw diff Collapse all Expand all
4747
4848 def __init__(self):
4949 self.matrix = Matrix(
50 [board.GP8, board.GP4, board.GP0, board.GP6, board.GP7, board.GP9],
51 [board.GP5, board.GP1, board.GP2, board.GP3, board.GP10],
50 # cols
51 [board.GP9, board.GP4, board.GP0, board.GP6, board.GP7, board.GP8],
52 # rows
53 [
54 board.GP13,
55 board.GP12,
56 board.GP11,
57 board.GP10,
58 board.GP5,
59 board.GP1,
60 board.GP2,
61 board.GP3,
62 board.GP22,
63 ],
5264 )
5365
54 self.pixels = NeoPixel(board.GP11, 48 + 4, auto_write=False)
66 self.pixels = NeoPixel(board.GP17, 48 + 4, auto_write=False)
5567
5668 displayio.release_displays()
5769 i2c = I2C(sda=board.GP14, scl=board.GP15, frequency=1000000)
6981 midi_out = next(p for p in usb_midi.ports if isinstance(p, usb_midi.PortOut))
7082 self.midi_usb = MIDI(midi_in, midi_out)
7183
72 self.audio_out = PWMAudioOut(left_channel=board.GP12, right_channel=board.GP13)
84 self.audio_out = PWMAudioOut(left_channel=board.GP18, right_channel=board.GP19)
85 self.i2c_in = I2C(sda=board.GP20, scl=board.GP21, frequency=1000000)
7386 self.test_file = WaveFile(open("test.wav", "rb"))
7487
7588 self.settings = Settings(
22 from digitalio import DigitalInOut, Pull
33
44
5 def range_rev(start, stop):
6 return range(stop - 1, start - 1, -1)
7
8
9 def mapping_up_down(cols, rows):
10 '''
11 Maps keys according to the following diagram:
12
13 1 2 3
14 +------
15 1| A A A
16 2| A A A
17 |
18 1| B B B
19 2| B B B
20 '''
21
22 coord_mapping = list(range(2 * cols * rows))
23 return coord_mapping
24
25
26 def mapping_up_down_mirrored(cols, rows):
27 '''
28 Maps keys according to the following diagram:
29
30 1 2 3
31 +------
32 1| A A A
33 2| A A A
34 |
35 2| B B B
36 1| B B B
37 '''
38
39 coord_mapping = []
40 coord_mapping.extend(range(cols * rows))
41 coord_mapping.extend(range_rev(cols * rows, 2 * cols * rows))
42 return coord_mapping
43
44
455 def mapping_left_right(cols, rows):
46 '''
6 """
477 Maps keys according to the following diagram:
488
499 1 2 3 1 2 3
5010 +-------------
5111 1| A A A B B B
5212 2| A A A B B B
53 '''
13 """
5414
5515 size = cols * rows
5616 coord_mapping = []
6121 return coord_mapping
6222
6323
64 def mapping_left_right_mirrored(cols, rows):
65 '''
66 Maps keys according to the following diagram:
67
68 1 2 3 3 2 1
69 +-------------
70 1| A A A B B B
71 2| A A A B B B
72 '''
73
74 size = cols * rows
75 coord_mapping = []
76 for y in range(rows):
77 yy = y * 2 * cols
78 coord_mapping.extend(range(yy, yy + cols))
79 coord_mapping.extend(range_rev(yy + size, yy + cols + size))
80 return coord_mapping
81
82
83 def mapping_interleave_cols(cols, rows):
84 '''
85 Maps keys according to the following diagram:
86
87 1 1 2 2 3 3
88 +-------------
89 1| A B A B A B
90 2| A B A B A B
91 '''
92
93 coord_mapping = []
94 mat = cols * rows
95 for i in range(mat):
96 coord_mapping.append(i)
97 coord_mapping.append(i + mat)
98 return coord_mapping
99
100
101 # these two are actually equivalent
102 mapping_interleave_rows = mapping_left_right
103
104
10524 class Matrix:
106 '''
107 A Scanner for Keyboard Matrices with Diodes in both directions.
108
109 In a bidirectional matrix, each (col, row) crossing can be used twice -
110 once with a ROW2COL diode ("A"), and once with a COL2ROW diode ("B").
111
112 The raw key numbers returned by this scanner are based on this layout ("up_down"):
25 """
26 A Scanner for Keyboard Matrices
27 The raw key numbers returned by this scanner are based on this layout:
11328
11429 C1 C2 C3
11530 +-----------
116 R1| A0 A1 A2
117 R2| A3 A4 A5
118 +-----------
119 R1| B6 B7 B8
120 R1| B9 B10 B11
121
122 If the physical layout of the matrix is different, you can pass a function
123 for `mapping`. The function is passed `len_cols` and `len_rows` and should
124 return a `coord_mapping` list.
125 Various common mappings are provided in this module, see:
126 - `kmk.scanners.bidirectional.mapping_left_right`
127 - `kmk.scanners.bidirectional.mapping_left_right_mirrored`
128 - `kmk.scanners.bidirectional.mapping_up_down`
129 - `kmk.scanners.bidirectional.mapping_up_down_mirrored`
130 - `kmk.scanners.bidirectional.mapping_interleave_rows`
131 - `kmk.scanners.bidirectional.mapping_interleave_cols`
31 R1| 0 1 2
32 R2| 3 4 5
13233
13334 :param cols: A sequence of pins that are the columns for matrix A.
13435 :param rows: A sequence of pins that are the rows for matrix A.
135 :param mapping: A coord_mapping generator function, see above.
136 '''
36 """
13737
13838 def __init__(self, cols, rows, mapping=mapping_left_right):
13939 self.len_cols = len(cols)
14040 self.len_rows = len(rows)
141 self.half_size = self.len_cols * self.len_rows
142 self.keys = self.half_size * 2
143
144 self.coord_mapping = mapping(self.len_cols, self.len_rows)
41 self.keys = self.len_cols * self.len_rows
42 self.coord_mapping = mapping(self.len_cols, self.len_rows // 2)
43 self.coord_mapping.extend(range(max(self.coord_mapping) + 1, self.keys))
14544
14645 # A pin cannot be both a row and column, detect this by combining the
14746 # two tuples into a set and validating that the length did not drop
15049 unique_pins = {repr(c) for c in cols} | {repr(r) for r in rows}
15150 assert (
15251 len(unique_pins) == self.len_cols + self.len_rows
153 ), 'Cannot use a pin as both a column and row'
52 ), "Cannot use a pin as both a column and row"
15453 del unique_pins
15554
15655 # __class__.__name__ is used instead of isinstance as the MCP230xx lib
15857 # https://github.com/adafruit/Adafruit_CircuitPython_MCP230xx/blob/3f04abbd65ba5fa938fcb04b99e92ae48a8c9406/adafruit_mcp230xx/digital_inout.py#L33
15958
16059 self.cols = [
161 x if x.__class__.__name__ == 'DigitalInOut' else DigitalInOut(x)
60 x if x.__class__.__name__ == "DigitalInOut" else DigitalInOut(x)
16261 for x in cols
16362 ]
16463 self.rows = [
165 x if x.__class__.__name__ == 'DigitalInOut' else DigitalInOut(x)
64 x if x.__class__.__name__ == "DigitalInOut" else DigitalInOut(x)
16665 for x in rows
16766 ]
16867
16968 self.state = bytearray(self.keys)
17069
17170 def scan_for_changes(self):
172 for (inputs, outputs, flip) in [
173 (self.rows, self.cols, False),
174 (self.cols, self.rows, True),
175 ]:
176 for pin in outputs:
177 pin.switch_to_input()
71 for row_pin in self.rows:
72 row_pin.switch_to_output(value=True)
17873
179 for pin in inputs:
180 pin.switch_to_input(pull=Pull.DOWN)
74 for col_pin in self.cols:
75 col_pin.switch_to_input(pull=Pull.UP)
18176
182 for oidx, opin in enumerate(outputs):
183 opin.switch_to_output(value=True)
77 for row, row_pin in enumerate(self.rows):
78 row_pin.value = False
18479
185 for iidx, ipin in enumerate(inputs):
186 if flip:
187 ba_idx = oidx * len(inputs) + iidx + self.half_size
188 else:
189 ba_idx = iidx * len(outputs) + oidx
80 for col, col_pin in enumerate(self.cols):
81 ba_idx = col + row * self.len_cols
19082
191 # cast to int to avoid
192 #
193 # >>> xyz = bytearray(3)
194 # >>> xyz[2] = True
195 # Traceback (most recent call last):
196 # File "<stdin>", line 1, in <module>
197 # OverflowError: value would overflow a 1 byte buffer
198 #
199 # I haven't dived too far into what causes this, but it's
200 # almost certainly because bool types in Python aren't just
201 # aliases to int values, but are proper pseudo-types
202 new_val = int(ipin.value)
203 old_val = self.state[ba_idx]
83 # cast to int to avoid
84 #
85 # >>> xyz = bytearray(3)
86 # >>> xyz[2] = True
87 # Traceback (most recent call last):
88 # File "<stdin>", line 1, in <module>
89 # OverflowError: value would overflow a 1 byte buffer
90 #
91 # I haven't dived too far into what causes this, but it's
92 # almost certainly because bool types in Python aren't just
93 # aliases to int values, but are proper pseudo-types
94 new_val = int(not col_pin.value)
95 old_val = self.state[ba_idx]
20496
205 if old_val != new_val:
206 self.state[ba_idx] = new_val
207 yield self.coord_mapping.index(ba_idx), new_val
97 if old_val != new_val:
98 map_idx = self.coord_mapping.index(ba_idx)
99 self.state[ba_idx] = new_val
100 yield map_idx, new_val
208101
209 opin.switch_to_input()
102 row_pin.value = True