diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index c38ebe7..2bd095f 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -245,6 +245,7 @@ class NativePin(Pin): def close(self): self.when_changed = None self.function = 'input' + self.pull = 'up' if self.number in (2, 3) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[(self._MEM[self._func_offset] >> self._func_shift) & 7] @@ -253,7 +254,7 @@ class NativePin(Pin): try: value = self.GPIO_FUNCTIONS[value] except KeyError: - raise PinInvalidFunction('invalid function "%s" for pin %r' % self) + raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) self._MEM[self._func_offset] = ( self._MEM[self._func_offset] & ~(7 << self._func_shift) @@ -282,7 +283,7 @@ class NativePin(Pin): try: value = self.GPIO_PULL_UPS[value] except KeyError: - raise PinInvalidPull('invalid pull direction "%s" for pin %r' % self) + raise PinInvalidPull('invalid pull direction "%s" for pin %r' % (value, self)) self._MEM[self._MEM.GPPUD_OFFSET] = value sleep(0.000000214) self._MEM[self._pull_offset] = 1 << self._pull_shift diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 23bc01c..f206da3 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -13,6 +13,7 @@ from ..exc import ( PinInvalidFunction, PinSetInput, PinFixedPull, + PinInvalidPull, ) @@ -144,7 +145,7 @@ class PiGPIOPin(Pin): self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'floating' + self.pull = 'up' if self.number in (2, 3) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[self._connection.get_mode(self._number)] diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py new file mode 100644 index 0000000..e91065a --- /dev/null +++ b/tests/test_real_pins.py @@ -0,0 +1,143 @@ +from __future__ import ( + unicode_literals, + absolute_import, + print_function, + division, + ) +str = type('') + + +import io +import subprocess + +import pytest + +from gpiozero import PinFixedPull, PinInvalidPull, PinInvalidFunction + + +# This module assumes you've wired the following GPIO pins together +TEST_PIN = 22 +INPUT_PIN = 27 + + +# Skip the entire module if we're not on a Pi +def is_a_pi(): + with io.open('/proc/cpuinfo', 'r') as cpuinfo: + for line in cpuinfo: + if line.startswith('Hardware'): + hardware, colon, soc = line.strip().split(None, 2) + return soc in ('BCM2708', 'BCM2709', 'BCM2835', 'BCM2836') + else: + return False +pytestmark = pytest.mark.skipif(not is_a_pi(), reason='tests cannot run on non-Pi platforms') +del is_a_pi + + +# Try and import as many pin libraries as possible +PIN_CLASSES = [] +try: + from gpiozero.pins.rpigpio import RPiGPIOPin + PIN_CLASSES.append(RPiGPIOPin) +except ImportError: + RPiGPIOPin = None +try: + from gpiozero.pins.rpio import RPIOPin + PIN_CLASSES.append(RPIOPin) +except ImportError: + RPIOPin = None +try: + from gpiozero.pins.pigpiod import PiGPIOPin + PIN_CLASSES.append(PiGPIOPin) +except ImportError: + PiGPIOPin = None +try: + from gpiozero.pins.native import NativePin + PIN_CLASSES.append(NativePin) +except ImportError: + NativePin = None + + +@pytest.fixture(scope='module', params=PIN_CLASSES) +def pin_class(request): + # pigpiod needs to be running for PiGPIOPin + if request.param.__name__ == 'PiGPIOPin': + subprocess.check_call(['sudo', 'pigpiod']) + # Unfortunately, pigpiod provides no option for running in the + # foreground, so we have to use the sledgehammer of killall to get shot + # of it + def kill_pigpiod(): + subprocess.check_call(['sudo', 'killall', 'pigpiod']) + request.addfinalizer(kill_pigpiod) + return request.param + +@pytest.fixture +def pins(request, pin_class): + # Why return both pins in a single fixture? If we defined one fixture for + # each pin then pytest will (correctly) test RPiGPIOPin(22) against + # NativePin(27) and so on. This isn't supported, so we don't test it + test_pin = pin_class(22) + input_pin = pin_class(27) + input_pin.function = 'input' + input_pin.pull = 'down' + def fin(): + test_pin.close() + input_pin.close() + request.addfinalizer(fin) + return test_pin, input_pin + + +def test_pin_numbers(pins): + test_pin, input_pin = pins + assert test_pin.number == 22 + assert input_pin.number == 27 + +def test_function_bad(pins): + test_pin, input_pin = pins + with pytest.raises(PinInvalidFunction): + test_pin.function = 'foo' + +def test_output(pins): + test_pin, input_pin = pins + test_pin.function = 'output' + test_pin.state = 0 + assert input_pin.state == 0 + test_pin.state = 1 + assert input_pin.state == 1 + +def test_output_with_state(pins): + test_pin, input_pin = pins + test_pin.output_with_state(0) + assert input_pin.state == 0 + test_pin.output_with_state(1) + assert input_pin.state == 1 + +def test_pull(pins): + test_pin, input_pin = pins + test_pin.function = 'input' + test_pin.pull = 'up' + assert input_pin.state == 1 + test_pin.pull = 'down' + test_pin, input_pin = pins + assert input_pin.state == 0 + +def test_pull_bad(pins): + test_pin, input_pin = pins + test_pin.function = 'input' + with pytest.raises(PinInvalidPull): + test_pin.pull = 'foo' + +def test_pull_down_warning(pin_class): + pin = pin_class(2) + try: + with pytest.raises(PinFixedPull): + pin.pull = 'down' + finally: + pin.close() + +def test_input_with_pull(pins): + test_pin, input_pin = pins + test_pin.input_with_pull('up') + assert input_pin.state == 1 + test_pin.input_with_pull('down') + assert input_pin.state == 0 +