-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.py
More file actions
149 lines (118 loc) · 4.51 KB
/
code.py
File metadata and controls
149 lines (118 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import asyncio
import board
import countio
import digitalio
import time
import keypad
import analogio
import microcontroller
import usb_hid
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
class Knob:
button_toggle_time = 0
button_toggled = False
button_mode_count = 0
def __init__(self, name, double_rotate_fix, pin_sw, pin_dt, pin_clk):
pin_dt.direction = digitalio.Direction.INPUT
pin_clk.direction = digitalio.Direction.INPUT
self.name = name
self.double_rotate_fix = double_rotate_fix
self.pin_sw = pin_sw
self.pin_dt = pin_dt
self.pin_clk = pin_clk
self.button_clk_value = pin_clk.value
# Configure existing volume knobs
knobs = [
Knob(
"Left",
False,
analogio.AnalogIn(board.GP26), # sw
digitalio.DigitalInOut(board.GP14) , # dt
digitalio.DigitalInOut(board.GP27) # clk
),
Knob(
"Right",
True,
analogio.AnalogIn(board.GP29), # sw
digitalio.DigitalInOut(board.GP8) , # dt
digitalio.DigitalInOut(board.GP28) # clk
)
]
# debounce fix
BUTTON_MIN_HOLD = 0.08
BUTTON_MAX_VAL_CLK_TRUE = 10_000
BUTTON_MAX_VAL_CLK_FALSE = 1_000
SLEEP = 0.001
USB_CONTROL = ConsumerControl(usb_hid.devices)
async def on_rotate(knob, val):
# False: Clockwise
direction = knob.pin_dt.value == val
if not knob.button_toggled: # debounce fix
knob.button_toggle_time = 0
if knob.double_rotate_fix: # double rotate fix
if not hasattr(knob, "double_rotate_state") or knob.double_rotate_state != direction:
knob.double_rotate_state = direction
return
knob.double_rotate_state = None
print(f"{knob.name} - Rotate: {direction}")
if direction:
USB_CONTROL.send(ConsumerControlCode.VOLUME_DECREMENT)
else:
USB_CONTROL.send(ConsumerControlCode.VOLUME_INCREMENT)
async def on_button_press(knob):
print(f"{knob.name} - Button: Press")
USB_CONTROL.send(ConsumerControlCode.PLAY_PAUSE)
async def on_button_release(knob):
hold_time = time.monotonic() - knob.button_toggle_time - BUTTON_MIN_HOLD
print(f"{knob.name} - Button: Release ({hold_time} s)")
# bootloader mode
if hold_time > 5:
knob.button_mode_count = knob.button_mode_count + 1
if knob.button_mode_count == 2:
print(f"{knob.name} - Entering bootloader...")
await asyncio.sleep(1)
microcontroller.on_next_reset(microcontroller.RunMode.UF2)
microcontroller.reset()
else:
knob.button_mode_count = 0
async def main():
tasks = [ ]
for knob in knobs:
tasks.append(asyncio.create_task(catch_interrupt(knob.pin_clk, knob, on_rotate)))
tasks.append(asyncio.create_task(catch_button_toggle(knob)))
await asyncio.gather(*tasks)
async def catch_interrupt(pin, knob, onChange):
while True:
new_state = knob.pin_clk.value
if new_state != knob.button_clk_value:
knob.button_clk_value = new_state
await onChange(knob, new_state)
await asyncio.sleep(SLEEP)
async def catch_button_toggle(knob):
last_state = False
while True:
# prints different values when (not) clicked depending on rotating state
max_val = BUTTON_MAX_VAL_CLK_TRUE if knob.button_clk_value else BUTTON_MAX_VAL_CLK_FALSE
new_state = knob.pin_sw.value < max_val
# debug
#print(f"{knob.name} - {knob.pin_sw.value} {knob.button_clk_value} {new_state} {max_val}")
# State changed
if new_state != last_state:
last_state = new_state
# Use time to make sure it was pressed (fix inconsistent states)
if not new_state:
knob.button_toggle_time = time.monotonic()
else:
# Released button
if knob.button_toggled:
knob.button_toggled = False
await on_button_release(knob)
knob.button_toggle_time = 0
# Make sure button is humanly pressed for min x ms
else:
if knob.button_toggle_time != 0 and not knob.button_toggled and (time.monotonic() - knob.button_toggle_time) > BUTTON_MIN_HOLD:
knob.button_toggled = True
await on_button_press(knob)
await asyncio.sleep(SLEEP)
asyncio.run(main())