From 0a392b6543e9c0d96c71bddc6965125953e666a7 Mon Sep 17 00:00:00 2001 From: Janar Sööt Date: Sun, 14 Apr 2019 18:18:52 +0300 Subject: menu: initial support for analog buttons (#977) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Janar Sööt --- klippy/extras/buttons.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'klippy/extras/buttons.py') diff --git a/klippy/extras/buttons.py b/klippy/extras/buttons.py index 9ebd3adc..b06f1f83 100644 --- a/klippy/extras/buttons.py +++ b/klippy/extras/buttons.py @@ -7,6 +7,10 @@ import logging QUERY_TIME = .002 RETRANSMIT_COUNT = 50 +ADC_REPORT_TIME = 0.015 +ADC_DEBOUNCE_TIME = 0.025 +ADC_SAMPLE_TIME = 0.001 +ADC_SAMPLE_COUNT = 6 # Rotary encoder handler https://github.com/brianlow/Rotary # Copyright 2011 Ben Buxton (bb@cactii.net). @@ -112,6 +116,79 @@ class MCU_buttons: self.last_button = button +class MCU_ADC_buttons: + def __init__(self, printer, pin, pullup, debug=False): + self.reactor = printer.get_reactor() + self.buttons = [] + self.last_button = None + self.last_pressed = None + self.last_debouncetime = 0 + self.pullup = pullup + self.debug = debug + self.pin = pin + self.min_value = self.max_value = None + ppins = printer.lookup_object('pins') + self.mcu_adc = ppins.setup_pin('adc', self.pin) + self.mcu_adc.setup_minmax(ADC_SAMPLE_TIME, ADC_SAMPLE_COUNT) + self.mcu_adc.setup_adc_callback(ADC_REPORT_TIME, self.adc_callback) + + def setup_button(self, min_value, max_value, callback): + if self.min_value is None: + self.min_value = min_value + else: + self.min_value = min(self.min_value, min_value) + + if self.max_value is None: + self.max_value = max_value + else: + self.max_value = max(self.max_value, max_value) + + self.buttons.append((min_value, max_value, callback)) + + def adc_callback(self, read_time, read_value): + adc = max(.00001, min(.99999, read_value)) + r = self.pullup * adc / (1.0 - adc) + self.reactor.register_async_callback( + (lambda e, s=self, v=r: s.handle_button(e, v))) + + def get_button(self, value): + if (self.min_value is not None and self.max_value is not None + and self.min_value <= value <= self.max_value): + for i, (min_value, max_value, cb) in enumerate(self.buttons): + if min_value < value < max_value: + return i + return None + + def handle_button(self, eventtime, value): + btn = self.get_button(int(value)) + + # If the button changed, due to noise or pressing: + if btn != self.last_button: + # reset the debouncing timer + self.last_debouncetime = eventtime + + # button debounce check & new button pressed + if ((eventtime - self.last_debouncetime) >= ADC_DEBOUNCE_TIME + and self.last_button == btn and self.last_pressed != btn): + # release last_pressed + if self.last_pressed is not None: + self.call_button(eventtime, self.last_pressed, False) + self.last_pressed = None + if btn is not None: + self.call_button(eventtime, btn, True) + self.last_pressed = btn + + self.last_button = btn + if self.debug is True: + logging.info( + "analog pin: %s value: %d" % (self.pin, int(value))) + + def call_button(self, eventtime, button, state): + if button < len(self.buttons): + minval, maxval, callback = self.buttons[button] + callback(eventtime, state) + + ###################################################################### # Rotary Encoders ###################################################################### @@ -138,6 +215,20 @@ class PrinterButtons: def __init__(self, config): self.printer = config.get_printer() self.mcu_buttons = {} + self.adc_buttons = {} + def register_adc_button( + self, pin, min_val, max_val, pullup, callback, debug=False): + adc_buttons = self.adc_buttons.get(pin) + if adc_buttons is None: + self.adc_buttons[pin] = adc_buttons = MCU_ADC_buttons( + self.printer, pin, pullup, debug) + adc_buttons.setup_button(min_val, max_val, callback) + def register_adc_button_push( + self, pin, min_val, max_val, pullup, callback, debug=False): + def helper(eventtime, state, callback=callback): + if state: + callback(eventtime) + self.register_adc_button(pin, min_val, max_val, pullup, helper, debug) def register_buttons(self, pins, callback): # Parse pins ppins = self.printer.lookup_object('pins') -- cgit v1.2.3-70-g09d2