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
|
# -*- coding: utf-8 -*-
# Support for menu button press tracking
#
# Copyright (C) 2018 Janar Sööt <janar.soot@gmail.com>
# Copyright (C) 2020 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
LONG_PRESS_DURATION = 0.800
TIMER_DELAY = 0.200
class MenuKeys:
def __init__(self, config, callback):
self.printer = config.get_printer()
self.reactor = self.printer.get_reactor()
self.callback = callback
buttons = self.printer.load_object(config, "buttons")
# Register rotary encoder
encoder_pins = config.get("encoder_pins", None)
encoder_steps_per_detent = config.getchoice(
"encoder_steps_per_detent", [2, 4], 4
)
if encoder_pins is not None:
try:
pin1, pin2 = encoder_pins.split(",")
except:
raise config.error("Unable to parse encoder_pins")
buttons.register_rotary_encoder(
pin1.strip(),
pin2.strip(),
self.encoder_cw_callback,
self.encoder_ccw_callback,
encoder_steps_per_detent,
)
self.encoder_fast_rate = config.getfloat("encoder_fast_rate", 0.030, above=0.0)
self.last_encoder_cw_eventtime = 0
self.last_encoder_ccw_eventtime = 0
# Register click button
self.is_short_click = False
self.click_timer = self.reactor.register_timer(self.long_click_event)
self.register_button(config, "click_pin", self.click_callback, False)
# Register other buttons
self.register_button(config, "back_pin", self.back_callback)
self.register_button(config, "up_pin", self.up_callback)
self.register_button(config, "down_pin", self.down_callback)
self.register_button(config, "kill_pin", self.kill_callback)
def register_button(self, config, name, callback, push_only=True):
pin = config.get(name, None)
if pin is None:
return
buttons = self.printer.lookup_object("buttons")
if config.get("analog_range_" + name, None) is None:
if push_only:
buttons.register_button_push(pin, callback)
else:
buttons.register_buttons([pin], callback)
return
amin, amax = config.getfloatlist("analog_range_" + name, count=2)
pullup = config.getfloat("analog_pullup_resistor", 4700.0, above=0.0)
if push_only:
buttons.register_adc_button_push(pin, amin, amax, pullup, callback)
else:
buttons.register_adc_button(pin, amin, amax, pullup, callback)
# Rotary encoder callbacks
def encoder_cw_callback(self, eventtime):
fast_rate = (
eventtime - self.last_encoder_cw_eventtime
) <= self.encoder_fast_rate
self.last_encoder_cw_eventtime = eventtime
if fast_rate:
self.callback("fast_up", eventtime)
else:
self.callback("up", eventtime)
def encoder_ccw_callback(self, eventtime):
fast_rate = (
eventtime - self.last_encoder_ccw_eventtime
) <= self.encoder_fast_rate
self.last_encoder_ccw_eventtime = eventtime
if fast_rate:
self.callback("fast_down", eventtime)
else:
self.callback("down", eventtime)
# Click handling
def long_click_event(self, eventtime):
self.is_short_click = False
self.callback("long_click", eventtime)
return self.reactor.NEVER
def click_callback(self, eventtime, state):
if state:
self.is_short_click = True
self.reactor.update_timer(self.click_timer, eventtime + LONG_PRESS_DURATION)
elif self.is_short_click:
self.reactor.update_timer(self.click_timer, self.reactor.NEVER)
self.callback("click", eventtime)
# Other button callbacks
def back_callback(self, eventtime):
self.callback("back", eventtime)
def up_callback(self, eventtime):
self.callback("up", eventtime)
def down_callback(self, eventtime):
self.callback("down", eventtime)
def kill_callback(self, eventtime):
self.printer.invoke_shutdown("Shutdown due to kill button!")
|