Skip to content

Commit

Permalink
Merge pull request #6 from pimoroni/feature/switch-counters
Browse files Browse the repository at this point in the history
Add switch counter support
  • Loading branch information
Gadgetoid committed Jul 8, 2021
2 parents 51a3045 + 611b5a3 commit 937db78
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 17 deletions.
57 changes: 41 additions & 16 deletions library/ioexpander/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,43 @@ def i2c_write8(self, reg, value):
msg_w = i2c_msg.write(self._i2c_addr, [reg, value])
self._i2c_dev.i2c_rdwr(msg_w)

def get_pin(self, pin):
"""Get a pin definition from its index."""
if pin < 1 or pin > len(self._pins):
raise ValueError("Pin should be in range 1-14.")

return self._pins[pin - 1]

def setup_switch_counter(self, pin, mode=IN_PU):
"""Enable switch counting on a pin."""
io_pin = self.get_pin(pin)

if io_pin.port not in (0, 1):
raise ValueError("Pin {} does not support switch counting.".format(pin))

if mode not in [IN, IN_PU]:
raise ValueError("Pin mode should be one of IN or IN_PU")

self.set_mode(pin, mode, schmitt_trigger=True)

sw_reg = [REG_SWITCH_EN_P0, REG_SWITCH_EN_P1][io_pin.port]
self.set_bit(sw_reg, io_pin.pin)

def read_switch_counter(self, pin):
"""Read the switch count value on a pin."""
io_pin = self.get_pin(pin)

if io_pin.port not in (0, 1):
raise ValueError("Pin {} does not support switch counting.".format(pin))

sw_reg = [REG_SWITCH_P00, REG_SWITCH_P10][io_pin.port] + io_pin.pin

value = self.i2c_read8(sw_reg)

# The switch counter is 7-bit
# The most significant bit encodes the current GPIO state
return value & 0x7f, value & 0x80 == 0x80

def setup_rotary_encoder(self, channel, pin_a, pin_b, pin_c=None, count_microsteps=False):
"""Set up a rotary encoder."""
channel -= 1
Expand Down Expand Up @@ -459,10 +496,7 @@ def set_pin_interrupt(self, pin, enabled):
:param enabled: True/False for enabled/disabled
"""
if pin < 1 or pin > len(self._pins):
raise ValueError("Pin should be in range 1-14.")

io_pin = self._pins[pin - 1]
io_pin = self.get_pin(pin)

self.change_bit(io_pin.reg_int_mask_p, io_pin.pin, enabled)

Expand Down Expand Up @@ -574,10 +608,7 @@ def set_mode(self, pin, mode, schmitt_trigger=False, invert=False):
:param mode: one of the supplied IN, OUT, PWM or ADC constants
"""
if pin < 1 or pin > len(self._pins):
raise ValueError("Pin should be in range 1-14.")

io_pin = self._pins[pin - 1]
io_pin = self.get_pin(pin)
if io_pin.mode == mode:
return

Expand Down Expand Up @@ -632,10 +663,7 @@ def input(self, pin, adc_timeout=1):
:param adc_timeout: Timeout (in seconds) for an ADC read (default 1.0)
"""
if pin < 1 or pin > len(self._pins):
raise ValueError("Pin should be in range 1-14.")

io_pin = self._pins[pin - 1]
io_pin = self.get_pin(pin)

if io_pin.mode == PIN_MODE_ADC:
if self._debug:
Expand Down Expand Up @@ -673,10 +701,7 @@ def output(self, pin, value):
:param value: Either True/False for OUT, or a number between 0 and PWM period for PWM.
"""
if pin < 1 or pin > len(self._pins):
raise ValueError("Pin should be in range 1-14.")

io_pin = self._pins[pin - 1]
io_pin = self.get_pin(pin)

if io_pin.mode == PIN_MODE_PWM:
if self._debug:
Expand Down
12 changes: 11 additions & 1 deletion library/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def cleanup():
"""

yield None
del sys.modules["ioexpander"]
try:
del sys.modules["ioexpander"]
except KeyError:
pass


@pytest.fixture(scope='function', autouse=False)
Expand All @@ -25,3 +28,10 @@ def smbus2():
sys.modules['smbus2'] = smbus2
yield smbus2
del sys.modules['smbus2']


@pytest.fixture(scope='function')
def ioe():
from ioexpander import IOE
yield IOE(skip_chip_id_check=True)
del sys.modules["ioexpander"]
21 changes: 21 additions & 0 deletions library/tests/test_switch_counter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest


def test_setup_switch_counter(smbus2, ioe):
ioe.setup_switch_counter(1)


def test_read_switch_counter(smbus2, ioe):
smbus2.i2c_msg.read().__iter__.return_value = [0b10000010]
assert ioe.read_switch_counter(1) == (2, True)

smbus2.i2c_msg.read().__iter__.return_value = [0b00000010]
assert ioe.read_switch_counter(1) == (2, False)


def test_switch_counter_invalid_pin(smbus2, ioe):
with pytest.raises(ValueError):
ioe.setup_switch_counter(10)

with pytest.raises(ValueError):
ioe.read_switch_counter(10)

0 comments on commit 937db78

Please sign in to comment.