feat: Make button mapping configurable
- Remove Pin to button mapping from hwconfig, replace with a simple list of Pins to which buttons are attached - Add BUTTON_MAP to config.json which maps indices in the HW button list to button names - Update utils.Buttons to use the button map to connect the correct pins to the matching key codes Signed-off-by: Matthias Blankertz <matthias@blankertz.org>
This commit is contained in:
@@ -30,10 +30,12 @@ RC522_SS = Pin.board.GP13
|
||||
LED_DIN = Pin.board.GP16
|
||||
|
||||
# Buttons
|
||||
BUTTON_VOLUP = Pin.board.GP17
|
||||
BUTTON_VOLDOWN = Pin.board.GP19
|
||||
BUTTON_NEXT = Pin.board.GP18
|
||||
BUTTON_POWER = Pin.board.GP21
|
||||
BUTTONS = [Pin.board.GP17,
|
||||
Pin.board.GP18,
|
||||
Pin.board.GP19,
|
||||
Pin.board.GP20,
|
||||
Pin.board.GP21,
|
||||
]
|
||||
|
||||
# Power
|
||||
POWER_EN = Pin.board.GP22
|
||||
|
||||
@@ -29,10 +29,10 @@ RC522_SS = Pin.board.GP13
|
||||
LED_DIN = Pin.board.GP16
|
||||
|
||||
# Buttons
|
||||
BUTTON_VOLUP = Pin.board.GP17
|
||||
BUTTON_VOLDOWN = Pin.board.GP19
|
||||
BUTTON_NEXT = Pin.board.GP18
|
||||
BUTTON_POWER = None
|
||||
BUTTONS = [Pin.board.GP17,
|
||||
Pin.board.GP18,
|
||||
Pin.board.GP19,
|
||||
]
|
||||
|
||||
# Power
|
||||
POWER_EN = None
|
||||
|
||||
@@ -89,9 +89,7 @@ def run():
|
||||
# Setup app
|
||||
deps = app.Dependencies(mp3player=lambda the_app: MP3Player(audioctx, the_app),
|
||||
nfcreader=lambda the_app: Nfc(reader, the_app),
|
||||
buttons=lambda the_app: Buttons(the_app, pin_volup=hwconfig.BUTTON_VOLUP,
|
||||
pin_voldown=hwconfig.BUTTON_VOLDOWN,
|
||||
pin_next=hwconfig.BUTTON_NEXT),
|
||||
buttons=lambda the_app: Buttons(the_app, config, hwconfig),
|
||||
playlistdb=lambda _: playlistdb,
|
||||
hwconfig=lambda _: hwconfig,
|
||||
leds=lambda _: LedManager(np),
|
||||
@@ -124,5 +122,5 @@ def builddb():
|
||||
|
||||
if __name__ == '__main__':
|
||||
time.sleep(1)
|
||||
if machine.Pin(hwconfig.BUTTON_VOLUP, machine.Pin.IN, machine.Pin.PULL_UP).value() != 0:
|
||||
if machine.Pin(hwconfig.BUTTONS[0], machine.Pin.IN, machine.Pin.PULL_UP).value() != 0:
|
||||
run()
|
||||
|
||||
@@ -17,14 +17,27 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class Buttons:
|
||||
def __init__(self, cb: "ButtonCallback", pin_volup=17, pin_voldown=19, pin_next=18):
|
||||
self.VOLUP = micropython.const(1)
|
||||
self.VOLDOWN = micropython.const(2)
|
||||
self.NEXT = micropython.const(3)
|
||||
VOLUP = micropython.const(1)
|
||||
VOLDOWN = micropython.const(2)
|
||||
NEXT = micropython.const(3)
|
||||
PREV = micropython.const(4)
|
||||
PLAY_PAUSE = micropython.const(5)
|
||||
KEYMAP = {VOLUP: 'VOLUP',
|
||||
VOLDOWN: 'VOLDOWN',
|
||||
NEXT: 'NEXT',
|
||||
PREV: 'PREV',
|
||||
PLAY_PAUSE: 'PLAY_PAUSE'}
|
||||
|
||||
def __init__(self, cb: "ButtonCallback", config, hwconfig):
|
||||
self.button_map = config.get_button_map()
|
||||
self.hw_buttons = hwconfig.BUTTONS
|
||||
self.cb = cb
|
||||
self.buttons = {machine.Pin(pin_volup, machine.Pin.IN, machine.Pin.PULL_UP): self.VOLUP,
|
||||
machine.Pin(pin_voldown, machine.Pin.IN, machine.Pin.PULL_UP): self.VOLDOWN,
|
||||
machine.Pin(pin_next, machine.Pin.IN, machine.Pin.PULL_UP): self.NEXT}
|
||||
self.buttons = dict()
|
||||
for key_id, key_name in self.KEYMAP.items():
|
||||
pin = self._get_pin(key_name)
|
||||
if pin is None:
|
||||
continue
|
||||
self.buttons[pin] = key_id
|
||||
self.int_flag = asyncio.ThreadSafeFlag()
|
||||
self.pressed: list[int] = []
|
||||
self.last: dict[int, int] = {}
|
||||
@@ -32,6 +45,17 @@ class Buttons:
|
||||
button.irq(handler=self._interrupt, trigger=machine.Pin.IRQ_FALLING | machine.Pin.IRQ_RISING)
|
||||
asyncio.create_task(self.task())
|
||||
|
||||
def _get_pin(self, key):
|
||||
key_id = self.button_map.get(key, None)
|
||||
if key_id is None:
|
||||
return None
|
||||
if key_id < 0 or key_id >= len(self.hw_buttons):
|
||||
return None
|
||||
pin = self.hw_buttons[key_id]
|
||||
if pin is not None:
|
||||
pin.init(machine.Pin.IN, machine.Pin.PULL_UP)
|
||||
return pin
|
||||
|
||||
def _interrupt(self, button):
|
||||
keycode = self.buttons[button]
|
||||
last = self.last.get(keycode, 0)
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
from errno import ENOENT
|
||||
import json
|
||||
import os
|
||||
try:
|
||||
from typing import TYPE_CHECKING, Mapping
|
||||
except ImportError:
|
||||
TYPE_CHECKING = False
|
||||
|
||||
|
||||
class Configuration:
|
||||
@@ -11,6 +15,13 @@ class Configuration:
|
||||
'LED_COUNT': 1,
|
||||
'IDLE_TIMEOUT_SECS': 60,
|
||||
'TAG_TIMEOUT_SECS': 5,
|
||||
'BUTTON_MAP': {
|
||||
'PLAY_PAUSE': 4,
|
||||
'VOLUP': 0,
|
||||
'VOLDOWN': 2,
|
||||
'PREV': None,
|
||||
'NEXT': 1,
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, config_path='/config.json'):
|
||||
@@ -49,11 +60,14 @@ class Configuration:
|
||||
def _get(self, key):
|
||||
return self.config.get(key, self.DEFAULT_CONFIG[key])
|
||||
|
||||
def get_led_count(self):
|
||||
def get_led_count(self) -> int:
|
||||
return self._get('LED_COUNT')
|
||||
|
||||
def get_idle_timeout(self):
|
||||
def get_idle_timeout(self) -> int:
|
||||
return self._get('IDLE_TIMEOUT_SECS')
|
||||
|
||||
def get_tag_timeout(self):
|
||||
def get_tag_timeout(self) -> int:
|
||||
return self._get('TAG_TIMEOUT_SECS')
|
||||
|
||||
def get_button_map(self) -> Mapping[str, int | None]:
|
||||
return self._get('BUTTON_MAP')
|
||||
|
||||
Reference in New Issue
Block a user