58 lines
1.9 KiB
Python
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
|