Add a pwm option to the RGBLED and Motor constructors

...along with the other necessary changes required, to allow them to
optionally be used with non-PWM-capable pins
This commit is contained in:
Andrew Scheller
2016-04-29 12:06:29 +01:00
parent 1b7dad5fa4
commit c9461c50d3
7 changed files with 378 additions and 141 deletions

View File

@@ -378,67 +378,6 @@ def test_output_pwm_pulse_foreground():
(0.04, 0),
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_pulse_background():
pin = MockPWMPin(2)
with PWMOutputDevice(pin) as device:
device.pulse(0.2, 0.2, n=2)
device._blink_thread.join()
pin.assert_states_and_times([
(0.0, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_output_pwm_pulse_foreground():
pin = MockPWMPin(2)
with PWMOutputDevice(pin) as device:
device.pulse(0.2, 0.2, n=2, background=False)
pin.assert_states_and_times([
(0.0, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
(0.04, 0.2),
(0.04, 0.4),
(0.04, 0.6),
(0.04, 0.8),
(0.04, 1),
(0.04, 0.8),
(0.04, 0.6),
(0.04, 0.4),
(0.04, 0.2),
(0.04, 0),
])
def test_output_pwm_blink_interrupt():
pin = MockPWMPin(2)
with PWMOutputDevice(pin) as device:
@@ -461,9 +400,47 @@ def test_rgbled_initial_value():
assert isclose(g.state, 0.2)
assert isclose(b.state, 0.0)
def test_rgbled_initial_value_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False, initial_value=(0, 1, 1)) as device:
assert r.state == 0
assert g.state == 1
assert b.state == 1
def test_rgbled_initial_bad_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with pytest.raises(ValueError):
RGBLED(r, g, b, initial_value=(0.1, 0.2, 1.2))
def test_rgbled_initial_bad_value_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with pytest.raises(ValueError):
RGBLED(r, g, b, pwm=False, initial_value=(0.1, 0.2, 0))
def test_rgbled_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b) as device:
assert isinstance(device._leds[0], PWMLED)
assert isinstance(device._leds[1], PWMLED)
assert isinstance(device._leds[2], PWMLED)
assert not device.is_active
assert device.value == (0, 0, 0)
device.on()
assert device.is_active
assert device.value == (1, 1, 1)
device.off()
assert not device.is_active
assert device.value == (0, 0, 0)
device.value = (0.5, 0.5, 0.5)
assert device.is_active
assert device.value == (0.5, 0.5, 0.5)
def test_rgbled_value_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
assert isinstance(device._leds[0], LED)
assert isinstance(device._leds[1], LED)
assert isinstance(device._leds[2], LED)
assert not device.is_active
assert device.value == (0, 0, 0)
device.on()
@@ -473,6 +450,33 @@ def test_rgbled_value():
assert not device.is_active
assert device.value == (0, 0, 0)
def test_rgbled_bad_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b) as device:
with pytest.raises(ValueError):
device.value = (2, 0, 0)
with RGBLED(r, g, b) as device:
with pytest.raises(ValueError):
device.value = (0, -1, 0)
def test_rgbled_bad_value_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = (2, 0, 0)
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = (0, -1, 0)
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = (0.5, 0, 0)
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = (0, 0.5, 0)
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = (0, 0, 0.5)
def test_rgbled_toggle():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b) as device:
@@ -485,6 +489,18 @@ def test_rgbled_toggle():
assert not device.is_active
assert device.value == (0, 0, 0)
def test_rgbled_toggle_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
assert not device.is_active
assert device.value == (0, 0, 0)
device.toggle()
assert device.is_active
assert device.value == (1, 1, 1)
device.toggle()
assert not device.is_active
assert device.value == (0, 0, 0)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_background():
@@ -506,6 +522,27 @@ def test_rgbled_blink_background():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_background_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
start = time()
device.blink(0.1, 0.1, n=2)
assert isclose(time() - start, 0, abs_tol=0.05)
device._blink_thread.join()
assert isclose(time() - start, 0.4, abs_tol=0.05)
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_foreground():
@@ -525,6 +562,25 @@ def test_rgbled_blink_foreground():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_blink_foreground_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
start = time()
device.blink(0.1, 0.1, n=2, background=False)
assert isclose(time() - start, 0.4, abs_tol=0.05)
expected = [
(0.0, 0),
(0.0, 1),
(0.1, 0),
(0.1, 1),
(0.1, 0)
]
r.assert_states_and_times(expected)
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_fade_background():
@@ -562,6 +618,12 @@ def test_rgbled_fade_background():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
def test_rgbled_fade_background_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.blink(0, 0, 0.2, 0.2, n=2)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_fade_foreground():
@@ -597,6 +659,12 @@ def test_rgbled_fade_foreground():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
def test_rgbled_fade_foreground_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.blink(0, 0, 0.2, 0.2, n=2, background=False)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_pulse_background():
@@ -634,6 +702,12 @@ def test_rgbled_pulse_background():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
def test_rgbled_pulse_background_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.pulse(0.2, 0.2, n=2)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy')
def test_rgbled_pulse_foreground():
@@ -669,6 +743,12 @@ def test_rgbled_pulse_foreground():
g.assert_states_and_times(expected)
b.assert_states_and_times(expected)
def test_rgbled_pulse_foreground_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
with pytest.raises(ValueError):
device.pulse(0.2, 0.2, n=2, background=False)
def test_rgbled_blink_interrupt():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b) as device:
@@ -679,6 +759,16 @@ def test_rgbled_blink_interrupt():
g.assert_states([0, 1, 0])
b.assert_states([0, 1, 0])
def test_rgbled_blink_interrupt_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
device.blink(1, 0.1)
sleep(0.2)
device.off() # should interrupt while on
r.assert_states([0, 1, 0])
g.assert_states([0, 1, 0])
b.assert_states([0, 1, 0])
def test_rgbled_close():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b) as device:
@@ -688,6 +778,15 @@ def test_rgbled_close():
device.close()
assert device.closed
def test_rgbled_close_nonpwm():
r, g, b = (MockPin(i) for i in (1, 2, 3))
with RGBLED(r, g, b, pwm=False) as device:
assert not device.closed
device.close()
assert device.closed
device.close()
assert device.closed
def test_motor_missing_pins():
with pytest.raises(ValueError):
Motor()
@@ -697,7 +796,18 @@ def test_motor_pins():
b = MockPWMPin(2)
with Motor(f, b) as device:
assert device.forward_device.pin is f
assert isinstance(device.forward_device, PWMOutputDevice)
assert device.backward_device.pin is b
assert isinstance(device.backward_device, PWMOutputDevice)
def test_motor_pins_nonpwm():
f = MockPin(1)
b = MockPin(2)
with Motor(f, b, pwm=False) as device:
assert device.forward_device.pin is f
assert isinstance(device.forward_device, DigitalOutputDevice)
assert device.backward_device.pin is b
assert isinstance(device.backward_device, DigitalOutputDevice)
def test_motor_close():
f = MockPWMPin(1)
@@ -710,6 +820,15 @@ def test_motor_close():
device.close()
assert device.closed
def test_motor_close_nonpwm():
f = MockPin(1)
b = MockPin(2)
with Motor(f, b, pwm=False) as device:
device.close()
assert device.closed
assert device.forward_device.pin is None
assert device.backward_device.pin is None
def test_motor_value():
f = MockPWMPin(1)
b = MockPWMPin(2)
@@ -726,6 +845,27 @@ def test_motor_value():
assert device.is_active
assert device.value == 0.5
assert b.state == 0 and f.state == 0.5
device.value = -0.5
assert device.is_active
assert device.value == -0.5
assert b.state == 0.5 and f.state == 0
device.value = 0
assert not device.is_active
assert not device.value
assert b.state == 0 and f.state == 0
def test_motor_value_nonpwm():
f = MockPin(1)
b = MockPin(2)
with Motor(f, b, pwm=False) as device:
device.value = -1
assert device.is_active
assert device.value == -1
assert b.state == 1 and f.state == 0
device.value = 1
assert device.is_active
assert device.value == 1
assert b.state == 0 and f.state == 1
device.value = 0
assert not device.is_active
assert not device.value
@@ -735,9 +875,24 @@ def test_motor_bad_value():
f = MockPWMPin(1)
b = MockPWMPin(2)
with Motor(f, b) as device:
with pytest.raises(ValueError):
device.value = -2
with pytest.raises(ValueError):
device.value = 2
def test_motor_bad_value_nonpwm():
f = MockPin(1)
b = MockPin(2)
with Motor(f, b, pwm=False) as device:
with pytest.raises(ValueError):
device.value = -2
with pytest.raises(ValueError):
device.value = 2
with pytest.raises(ValueError):
device.value = 0.5
with pytest.raises(ValueError):
device.value = -0.5
def test_motor_reverse():
f = MockPWMPin(1)
b = MockPWMPin(2)
@@ -748,4 +903,20 @@ def test_motor_reverse():
device.reverse()
assert device.value == -1
assert b.state == 1 and f.state == 0
device.backward(0.5)
assert device.value == -0.5
assert b.state == 0.5 and f.state == 0
device.reverse()
assert device.value == 0.5
assert b.state == 0 and f.state == 0.5
def test_motor_reverse_nonpwm():
f = MockPin(1)
b = MockPin(2)
with Motor(f, b, pwm=False) as device:
device.forward()
assert device.value == 1
assert b.state == 0 and f.state == 1
device.reverse()
assert device.value == -1
assert b.state == 1 and f.state == 0