diff --git a/klippy/extras/display/menu.py b/klippy/extras/display/menu.py index 8c0ffeb5..e99b367c 100644 --- a/klippy/extras/display/menu.py +++ b/klippy/extras/display/menu.py @@ -6,7 +6,7 @@ # # This file may be distributed under the terms of the GNU GPLv3 license. import os, logging, sys, ast, re, string - +from . import menu_keys class error(Exception): pass @@ -963,7 +963,6 @@ menu_items = { MENU_UPDATE_DELAY = .100 TIMER_DELAY = .200 -LONG_PRESS_DURATION = 0.800 BLINK_FAST_SEQUENCE = (True, True, False, False) BLINK_SLOW_SEQUENCE = (True, True, True, True, False, False, False) @@ -993,118 +992,10 @@ class MenuManager: self.cols, self.rows = lcd_chip.get_dimensions() self.timeout = config.getint('menu_timeout', 0) self.timer = 0 - # buttons - self.encoder_pins = config.get('encoder_pins', None) - self.click_pin = config.get('click_pin', None) - self.back_pin = config.get('back_pin', None) - self.up_pin = config.get('up_pin', None) - self.down_pin = config.get('down_pin', None) - self.kill_pin = config.get('kill_pin', None) - # analog button ranges - self.analog_range_click_pin = config.get( - 'analog_range_click_pin', None) - self.analog_range_back_pin = config.get( - 'analog_range_back_pin', None) - self.analog_range_up_pin = config.get( - 'analog_range_up_pin', None) - self.analog_range_down_pin = config.get( - 'analog_range_down_pin', None) - self.analog_range_kill_pin = config.get( - 'analog_range_kill_pin', None) - self._last_click_press = 0 - self.analog_pullup = config.getfloat( - 'analog_pullup_resistor', 4700., above=0.) - self._encoder_fast_rate = config.getfloat( - 'encoder_fast_rate', .03, above=0.) - self._last_encoder_cw_eventtime = 0 - self._last_encoder_ccw_eventtime = 0 - # printer objects - self.buttons = self.printer.load_object(config, "buttons") # register itself for printer callbacks self.printer.add_object('menu', self) self.printer.register_event_handler("klippy:ready", self.handle_ready) - # register buttons & encoder - if self.buttons: - # digital buttons - if self.encoder_pins: - try: - pin1, pin2 = self.encoder_pins.split(',') - except Exception: - raise config.error("Unable to parse encoder_pins") - self.buttons.register_rotary_encoder( - pin1.strip(), pin2.strip(), - self.encoder_cw_callback, self.encoder_ccw_callback) - if self.click_pin: - if self.analog_range_click_pin is not None: - try: - p_min, p_max = map( - float, self.analog_range_click_pin.split(',')) - except Exception: - raise config.error( - "Unable to parse analog_range_click_pin") - self.buttons.register_adc_button( - self.click_pin, p_min, p_max, self.analog_pullup, - self.click_callback) - else: - self.buttons.register_buttons( - [self.click_pin], self.click_callback) - if self.back_pin: - if self.analog_range_back_pin is not None: - try: - p_min, p_max = map( - float, self.analog_range_back_pin.split(',')) - except Exception: - raise config.error( - "Unable to parse analog_range_back_pin") - self.buttons.register_adc_button_push( - self.back_pin, p_min, p_max, self.analog_pullup, - self.back_callback) - else: - self.buttons.register_button_push( - self.back_pin, self.back_callback) - if self.up_pin: - if self.analog_range_up_pin is not None: - try: - p_min, p_max = map( - float, self.analog_range_up_pin.split(',')) - except Exception: - raise config.error( - "Unable to parse analog_range_up_pin") - self.buttons.register_adc_button_push( - self.up_pin, p_min, p_max, self.analog_pullup, - self.up_callback) - else: - self.buttons.register_button_push( - self.up_pin, self.up_callback) - if self.down_pin: - if self.analog_range_down_pin is not None: - try: - p_min, p_max = map( - float, self.analog_range_down_pin.split(',')) - except Exception: - raise config.error( - "Unable to parse analog_range_down_pin") - self.buttons.register_adc_button_push( - self.down_pin, p_min, p_max, self.analog_pullup, - self.down_callback) - else: - self.buttons.register_button_push( - self.down_pin, self.down_callback) - if self.kill_pin: - if self.analog_range_kill_pin is not None: - try: - p_min, p_max = map( - float, self.analog_range_kill_pin.split(',')) - except Exception: - raise config.error( - "Unable to parse analog_range_kill_pin") - self.buttons.register_adc_button_push( - self.kill_pin, p_min, p_max, self.analog_pullup, - self.kill_callback) - else: - self.buttons.register_button_push( - self.kill_pin, self.kill_callback) - + menu_keys.MenuKeys(config, self.key_event) # Add MENU commands self.gcode.register_mux_command("MENU", "DO", 'dump', self.cmd_DO_DUMP, desc=self.cmd_DO_help) @@ -1144,12 +1035,6 @@ class MenuManager: ) if self.timeout_idx == 0: self.timeout_check(eventtime) - # check long press - if (self._last_click_press > 0 and ( - eventtime - self._last_click_press) >= LONG_PRESS_DURATION): - # long click - self._last_click_press = 0 - self._long_click_callback(eventtime) return eventtime + TIMER_DELAY def timeout_check(self, eventtime): @@ -1588,29 +1473,6 @@ class MenuManager: msg = "{0} = {1}".format(key1, self.parameters.get(key1)) gcmd.respond_info(msg) - # buttons & 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 - self.up(fast_rate) - - def encoder_ccw_callback(self, eventtime): - fast_rate = ((eventtime - self._last_encoder_ccw_eventtime) - <= self._encoder_fast_rate) - self._last_encoder_ccw_eventtime = eventtime - self.down(fast_rate) - - def click_callback(self, eventtime, state): - if self.click_pin: - if state: - self._last_click_press = eventtime - elif self._last_click_press > 0: - if (eventtime - self._last_click_press) < LONG_PRESS_DURATION: - # short click - self._last_click_press = 0 - self._short_click_callback(eventtime) - def _short_click_callback(self, eventtime): if self.is_running(): self.select() @@ -1636,19 +1498,18 @@ class MenuManager: if container.is_editing(): self.select(True) - def back_callback(self, eventtime): - if self.back_pin: + def key_event(self, key, eventtime): + if key == 'click': + self._short_click_callback(eventtime) + elif key == 'long_click': + self._long_click_callback(eventtime) + elif key == 'up': + self.up(False) + elif key == 'fast_up': + self.up(True) + elif key == 'down': + self.down(False) + elif key == 'fast_down': + self.down(True) + elif key == 'back': self.back() - - def up_callback(self, eventtime): - if self.up_pin: - self.up() - - def down_callback(self, eventtime): - if self.down_pin: - self.down() - - def kill_callback(self, eventtime): - if self.kill_pin: - # Emergency Stop - self.printer.invoke_shutdown("Shutdown due to kill button!") diff --git a/klippy/extras/display/menu_keys.py b/klippy/extras/display/menu_keys.py new file mode 100644 index 00000000..b99c1076 --- /dev/null +++ b/klippy/extras/display/menu_keys.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +# Support for menu button press tracking +# +# Copyright (C) 2018 Janar Sööt +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +LONG_PRESS_DURATION = 0.800 +TIMER_DELAY = .200 + +class MenuKeys: + def __init__(self, config, callback): + self.printer = config.get_printer() + self.callback = callback + # buttons + self.encoder_pins = config.get('encoder_pins', None) + self.click_pin = config.get('click_pin', None) + self.back_pin = config.get('back_pin', None) + self.up_pin = config.get('up_pin', None) + self.down_pin = config.get('down_pin', None) + self.kill_pin = config.get('kill_pin', None) + # analog button ranges + self.analog_range_click_pin = config.get( + 'analog_range_click_pin', None) + self.analog_range_back_pin = config.get( + 'analog_range_back_pin', None) + self.analog_range_up_pin = config.get( + 'analog_range_up_pin', None) + self.analog_range_down_pin = config.get( + 'analog_range_down_pin', None) + self.analog_range_kill_pin = config.get( + 'analog_range_kill_pin', None) + self._last_click_press = 0 + self.analog_pullup = config.getfloat( + 'analog_pullup_resistor', 4700., above=0.) + self._encoder_fast_rate = config.getfloat( + 'encoder_fast_rate', .03, above=0.) + self._last_encoder_cw_eventtime = 0 + self._last_encoder_ccw_eventtime = 0 + # printer objects + self.buttons = self.printer.load_object(config, "buttons") + # register buttons & encoder + if self.buttons: + # digital buttons + if self.encoder_pins: + try: + pin1, pin2 = self.encoder_pins.split(',') + except Exception: + raise config.error("Unable to parse encoder_pins") + self.buttons.register_rotary_encoder( + pin1.strip(), pin2.strip(), + self.encoder_cw_callback, self.encoder_ccw_callback) + if self.click_pin: + if self.analog_range_click_pin is not None: + try: + p_min, p_max = map( + float, self.analog_range_click_pin.split(',')) + except Exception: + raise config.error( + "Unable to parse analog_range_click_pin") + self.buttons.register_adc_button( + self.click_pin, p_min, p_max, self.analog_pullup, + self.click_callback) + else: + self.buttons.register_buttons( + [self.click_pin], self.click_callback) + if self.back_pin: + if self.analog_range_back_pin is not None: + try: + p_min, p_max = map( + float, self.analog_range_back_pin.split(',')) + except Exception: + raise config.error( + "Unable to parse analog_range_back_pin") + self.buttons.register_adc_button_push( + self.back_pin, p_min, p_max, self.analog_pullup, + self.back_callback) + else: + self.buttons.register_button_push( + self.back_pin, self.back_callback) + if self.up_pin: + if self.analog_range_up_pin is not None: + try: + p_min, p_max = map( + float, self.analog_range_up_pin.split(',')) + except Exception: + raise config.error( + "Unable to parse analog_range_up_pin") + self.buttons.register_adc_button_push( + self.up_pin, p_min, p_max, self.analog_pullup, + self.up_callback) + else: + self.buttons.register_button_push( + self.up_pin, self.up_callback) + if self.down_pin: + if self.analog_range_down_pin is not None: + try: + p_min, p_max = map( + float, self.analog_range_down_pin.split(',')) + except Exception: + raise config.error( + "Unable to parse analog_range_down_pin") + self.buttons.register_adc_button_push( + self.down_pin, p_min, p_max, self.analog_pullup, + self.down_callback) + else: + self.buttons.register_button_push( + self.down_pin, self.down_callback) + if self.kill_pin: + if self.analog_range_kill_pin is not None: + try: + p_min, p_max = map( + float, self.analog_range_kill_pin.split(',')) + except Exception: + raise config.error( + "Unable to parse analog_range_kill_pin") + self.buttons.register_adc_button_push( + self.kill_pin, p_min, p_max, self.analog_pullup, + self.kill_callback) + else: + self.buttons.register_button_push( + self.kill_pin, self.kill_callback) + # start timer + reactor = self.printer.get_reactor() + reactor.register_timer(self.timer_event, reactor.NOW) + + def timer_event(self, eventtime): + # check long press + if (self._last_click_press > 0 and ( + eventtime - self._last_click_press) >= LONG_PRESS_DURATION): + # long click + self._last_click_press = 0 + self.callback('long_click', eventtime) + return eventtime + TIMER_DELAY + + # buttons & 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) + + def click_callback(self, eventtime, state): + if self.click_pin: + if state: + self._last_click_press = eventtime + elif self._last_click_press > 0: + if (eventtime - self._last_click_press) < LONG_PRESS_DURATION: + # short click + self._last_click_press = 0 + self.callback('click', eventtime) + + def back_callback(self, eventtime): + if self.back_pin: + self.callback('back', eventtime) + + def up_callback(self, eventtime): + if self.up_pin: + self.callback('up', eventtime) + + def down_callback(self, eventtime): + if self.down_pin: + self.callback('down', eventtime) + + def kill_callback(self, eventtime): + if self.kill_pin: + # Emergency Stop + self.printer.invoke_shutdown("Shutdown due to kill button!")