kmk_firmware/kmk/rotary_encoder.py

58 lines
1.9 KiB
Python

from kmk.pins import PULL_UP
class RotaryEncoder:
# Please don't ask. I don't know. All I know is bit_value
# works as expected. Here be dragons, etc. etc.
MIN_VALUE = False + 1 << 1 | True + 1
MAX_VALUE = True + 1 << 1 | True + 1
def __init__(self, pos_pin, neg_pin):
self.pos_pin = pos_pin
self.neg_pin = neg_pin
self.pos_pin.switch_to_input(pull=PULL_UP)
self.neg_pin.switch_to_input(pull=PULL_UP)
self.prev_bit_value = self.bit_value()
def value(self):
return (self.pos_pin.value(), self.neg_pin.value())
def bit_value(self):
'''
Returns 2, 3, 5, or 6 based on the state of the rotary encoder's two
bits. This is a total hack but it does what we need pretty efficiently.
Shrug.
'''
return self.pos_pin.value() + 1 << 1 | self.neg_pin.value() + 1
def direction(self):
'''
Compares the current rotary position against the last seen position.
Returns True if we're rotating "positively", False if we're rotating "negatively",
and None if no change could safely be detected for any reason (usually this
means the encoder itself did not change)
'''
new_value = self.bit_value()
rolling_under = self.prev_bit_value == self.MIN_VALUE and new_value == self.MAX_VALUE
rolling_over = self.prev_bit_value == self.MAX_VALUE and new_value == self.MIN_VALUE
increasing = new_value > self.prev_bit_value
decreasing = new_value < self.prev_bit_value
self.prev_bit_value = new_value
if rolling_over:
return True
elif rolling_under:
return False
if increasing:
return True
if decreasing:
return False
# Either no change, or not a type of change we can safely detect,
# so safely do nothing
return None