Skip to content

Commit abb070c

Browse files
committed
SwArray: Add keymap bound method.
1 parent 0767405 commit abb070c

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

v3/docs/EVENTS.md

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,8 @@ async def main():
517517
asyncio.run(main())
518518
```
519519
Constructor mandatory args:
520-
* `rowpins` A list or tuple of initialised output pins.
521-
* `colpins` A list or tuple of initialised input pins (pulled down).
520+
* `rowpins` A list or tuple of initialised open drain output pins.
521+
* `colpins` A list or tuple of initialised input pins (pulled up).
522522

523523
Constructor optional keyword only args:
524524
* `buffer=bytearray(10)` Keyboard buffer.
@@ -554,7 +554,7 @@ async def repeat(tim, uart, ch): # Send at least one char
554554

555555
async def main(): # Run forever
556556
rowpins = [Pin(p, Pin.OPEN_DRAIN) for p in range(10, 14)]
557-
colpins = [Pin(p, Pin.IN, Pin.PULL_DOWN) for p in range(16, 20)]
557+
colpins = [Pin(p, Pin.IN, Pin.PULL_UP) for p in range(16, 20)]
558558
uart = UART(0, 9600, tx=0, rx=1)
559559
pad = Keyboard(rowpins, colpins)
560560
tim = Delay_ms(duration=200) # 200ms auto repeat timer
@@ -575,6 +575,8 @@ high value. If the capacitance between wires is high, spurious keypresses may be
575575
registered. To prevent this it is wise to add physical resistors between the
576576
input pins and 3.3V. A value in the region of 1KΩ to 5KΩ is recommended.
577577

578+
###### [Contents](./EVENTS.md#0-contents)
579+
578580
## 6.4 SwArray
579581
```python
580582
from primitives import SwArray
@@ -588,8 +590,8 @@ are made. The diodes prevent this.
588590
![Image](./isolate.png)
589591

590592
Constructor mandatory args:
591-
* `rowpins` A list or tuple of initialised output pins.
592-
* `colpins` A list or tuple of initialised input pins (pulled down).
593+
* `rowpins` A list or tuple of initialised open drain output pins.
594+
* `colpins` A list or tuple of initialised input pins (pulled up).
593595
* `cfg` An integer defining conditions requiring a response. See Module
594596
Constants below.
595597

@@ -601,32 +603,40 @@ Constructor optional keyword only args:
601603
that causes actions after a button press, for example on release or auto-repeat
602604
while pressed.
603605

606+
Synchronous bound method:
607+
* `keymap()` Return an integer representing a bitmap of the debounced state of
608+
all switches in the array. 1 == closed.
609+
604610
Class variables:
605-
* `debounce_ms = 50`
606-
* `long_press_ms = 1000`
607-
* `double_click_ms = 400`
611+
* `debounce_ms = 50` Assumed maximum duration of contact bounce.
612+
* `long_press_ms = 1000` Threshold for long press detection.
613+
* `double_click_ms = 400` Threshold for double-click detection.
608614

609615
Module constants.
610-
The `cfg` constructor arg may be defined as the bitwise or of these constants.
611-
If the `CLOSE` bit is specified, switch closures will be reported
612-
* `CLOSE = const(1)` Contact closure.
613-
* `OPEN = const(2)` Contact opening.
614-
* `LONG = const(4)` Contact closure longer than `long_press_ms`.
615-
* `DOUBLE = const(8)` Two closures in less than `double_click_ms`.
616-
* `SUPPRESS = const(16)` # Disambiguate. For explanation see `EButton`.
617-
618-
The `SwArray` class is subclassed from [Ringbuf queue](./EVENTS.md#7-ringbuf-queue)
619-
enabling scan codes and event types to be retrieved with an asynchronous iterator.
620-
616+
The folowing constants are provided to simplify defining the `cfg` constructor
617+
arg. This may be defined as a bitwise or of selected constants. For example if
618+
the `CLOSE` bit is specified, switch closures will be reported. An omitted event
619+
will be ignored. Where the array comprises switches it is usual to specify only
620+
`CLOSE` and/or `OPEN`. This invokes a more efficient mode of operation because
621+
timing is not required.
622+
* `CLOSE` Report contact closure.
623+
* `OPEN` Contact opening.
624+
* `LONG` Contact closure longer than `long_press_ms`.
625+
* `DOUBLE` Two closures in less than `double_click_ms`.
626+
* `SUPPRESS` Disambiguate. For explanation see `EButton`.
627+
628+
The `SwArray` class is subclassed from [Ringbuf queue](./EVENTS.md#7-ringbuf-queue).
629+
This is an asynchronous iterator, enabling scan codes and event types to be
630+
retrieved as state changes occur with `async for`:
621631
```python
622632
import asyncio
623633
from primitives.sw_array import SwArray, CLOSE, OPEN, LONG, DOUBLE, SUPPRESS
624634
from machine import Pin
625635
rowpins = [Pin(p, Pin.OPEN_DRAIN) for p in range(10, 14)]
626636
colpins = [Pin(p, Pin.IN, Pin.PULL_UP) for p in range(16, 20)]
637+
cfg = CLOSE | OPEN #LONG | DOUBLE | SUPPRESS
627638

628639
async def main():
629-
cfg = CLOSE | OPEN #LONG | DOUBLE | SUPPRESS
630640
swa = SwArray(rowpins, colpins, cfg)
631641
async for scan_code, evt in swa:
632642
print(scan_code, evt)
@@ -635,6 +645,12 @@ async def main():
635645

636646
asyncio.run(main())
637647
```
648+
##### Application note
649+
650+
Scanning of the array occurs rapidly, and built-in pull-up resistors have a
651+
high value. If the capacitance between wires is high, spurious closures may be
652+
registered. To prevent this it is wise to add physical resistors between the
653+
input pins and 3.3V. A value in the region of 1KΩ to 5KΩ is recommended.
638654

639655
###### [Contents](./EVENTS.md#0-contents)
640656

v3/primitives/sw_array.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ async def scan(self, nkeys, db_delay):
4747
OPEN = const(2)
4848
LONG = const(4)
4949
DOUBLE = const(8)
50-
SUPPRESS = const(16) # Disambiguate
50+
SUPPRESS = const(16) # Disambiguate: see docs.
5151

52-
# Entries in queue are (scan_code, event) where event is an OR of above constants
53-
# Tuples/lists of pins. Rows are OUT, cols are IN
52+
# Entries in queue are (scan_code, event) where event is an OR of above constants.
53+
# rowpins/colpins are tuples/lists of pins. Rows are OUT, cols are IN.
54+
# cfg is a logical OR of above constants. If a bit is 0 that state will never be reported.
5455
class SwArray(RingbufQueue):
5556
debounce_ms = 50 # Attributes can be varied by user
5657
long_press_ms = 1000
@@ -60,12 +61,12 @@ def __init__(self, rowpins, colpins, cfg, *, bufsize=10):
6061
self._rowpins = rowpins
6162
self._colpins = colpins
6263
self._cfg = cfg
63-
self._state = 0 # State of all keys as bitmap
64+
self._state = 0 # State of all buttons as bitmap
6465
self._flags = 0 # Busy bitmap
6566
self._basic = not bool(cfg & (SUPPRESS | LONG | DOUBLE)) # Basic mode
6667
self._suppress = bool(cfg & SUPPRESS)
6768
for opin in self._rowpins: # Initialise output pins
68-
opin(1)
69+
opin(1) # open circuit
6970
asyncio.create_task(self._scan(len(rowpins) * len(colpins)))
7071

7172
def __getitem__(self, scan_code):
@@ -96,6 +97,8 @@ async def _finish(self, sc): # Tidy up. If necessary await a contact open
9697
self._put(sc, OPEN)
9798
self._busy(sc, False)
9899

100+
def keymap(self): # Return a bitmap of debounced state of all buttons/switches
101+
return self._state
99102
# Handle long, double. Switch has closed.
100103
async def _defer(self, sc):
101104
# Wait for contact closure to be registered: let calling loop complete
@@ -123,7 +126,7 @@ async def _defer(self, sc):
123126
async def _scan(self, nkeys):
124127
db_delay = SwArray.debounce_ms
125128
while True:
126-
cur = 0 # Current bitmap of logical key states (1 == pressed)
129+
cur = 0 # Current bitmap of logical button states (1 == pressed)
127130
for opin in self._rowpins:
128131
opin(0) # Assert output
129132
for ipin in self._colpins:
@@ -133,7 +136,7 @@ async def _scan(self, nkeys):
133136
curb = cur # Copy current bitmap
134137
if changed := (cur ^ self._state): # 1's are newly canged button(s)
135138
for sc in range(nkeys):
136-
if (changed & 1): # Current key has changed state
139+
if (changed & 1): # Current button has changed state
137140
if self._basic: # No timed behaviour
138141
self._put(sc, CLOSE if cur & 1 else OPEN)
139142
elif cur & 1: # Closed

0 commit comments

Comments
 (0)