From 726e861238ce43c62eaf6c29f7784cb1b39cb53c Mon Sep 17 00:00:00 2001 From: Stewart Date: Mon, 7 Nov 2016 22:09:59 +0000 Subject: [PATCH 01/62] Add pinout command-line tool --- gpiozero/cli/__init__.py | 0 gpiozero/cli/pinout.py | 66 ++++++++++++++++++++++++++++++++++++++++ tests/cli/test_pinout.py | 40 ++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 gpiozero/cli/__init__.py create mode 100644 gpiozero/cli/pinout.py create mode 100644 tests/cli/test_pinout.py diff --git a/gpiozero/cli/__init__.py b/gpiozero/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py new file mode 100644 index 0000000..8c60322 --- /dev/null +++ b/gpiozero/cli/pinout.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +""" +pinout.py - gpiozero command-line pinout tool. + +Output Raspberry Pi GPIO pinout information. +""" + +from __future__ import unicode_literals, absolute_import, print_function, division + +import argparse +import sys + +from gpiozero import * + + +def parse_args(args): + parser = argparse.ArgumentParser( + description=__doc__ + ) + + parser.add_argument( + '-r', '--revision', + dest='revision', + default='', + help='RPi revision. Default is to autodetect revision of current device' + ) + + parser.add_argument( + '-c', '--color', + action="store_true", + default=None, + help='Force colored output (by default, the output will include ANSI' + 'color codes if run in a color-capable terminal). See also --monochrome' + ) + + parser.add_argument( + '-m', '--monochrome', + dest='color', + action='store_false', + help='Force monochrome output. See also --color' + ) + + try: + args = parser.parse_args(args) + except argparse.ArgumentError as ex: + print('Error parsing arguments.') + parser.error(str(ex.message)) + exit(-1) + return args + + +def main(): + args = parse_args(sys.argv[1:]) + + if args.revision == '': + try: + pi_info().pprint(color=args.color) + except IOError: + print('This device is not an Raspberry Pi?') + exit(2) + else: + pi_info(args.revision).pprint(color=args.color) + + +if __name__ == '__main__': + main() diff --git a/tests/cli/test_pinout.py b/tests/cli/test_pinout.py new file mode 100644 index 0000000..8aac0df --- /dev/null +++ b/tests/cli/test_pinout.py @@ -0,0 +1,40 @@ +from __future__ import ( + unicode_literals, + absolute_import, + print_function, + division, + ) +str = type('') + + +import pytest + +import cli.pinout as pinout + + +def test_args_incorrect(): + with pytest.raises(SystemExit) as ex: + pinout.parse_args(['--nonexistentarg']) + assert ex.value.code == 2 + + +def test_args_color(): + args = pinout.parse_args([]) + assert args.color is None + args = pinout.parse_args(['--color']) + assert args.color is True + args = pinout.parse_args(['--monochrome']) + assert args.color is False + + +def test_args_revision(): + args = pinout.parse_args(['--revision', '000d']) + assert args.revision == '000d' + + +def test_help(capsys): + with pytest.raises(SystemExit) as ex: + pinout.parse_args(['--help']) + out, err = capsys.readouterr() + assert 'GPIO pinout' in out + assert ex.value.code == 0 From 5f47bcd3796193af0649565e61372b87b4a59821 Mon Sep 17 00:00:00 2001 From: Stewart Date: Mon, 7 Nov 2016 22:34:21 +0000 Subject: [PATCH 02/62] Add terse documentation for pinout tool --- docs/cli_pinout.rst | 26 ++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 27 insertions(+) create mode 100644 docs/cli_pinout.rst diff --git a/docs/cli_pinout.rst b/docs/cli_pinout.rst new file mode 100644 index 0000000..4f8950b --- /dev/null +++ b/docs/cli_pinout.rst @@ -0,0 +1,26 @@ +================== +Command-line Tools +================== + +Pinout +====== + +The gpiozero package contains a database of information about the various +revisions of Raspberry Pi. This is queried by the ``pinout`` command-line +tool to write details of the GPIO pins available. + +Unless specified, the revision of the current device will be detected. A +particular revision may be selected with the --revision command-line +option. *e.g.*: + + pinout.py --revision 000d + +By default, the output will include ANSI color codes if run in a color-capable +terminal. This behaviour may be overridden by the --color or --monochrome +options to force colored or non-colored output, respectively. *e.g.*: + + pinout.py --monochrome + +Full usage details are available with: + + pinout.py --help diff --git a/docs/index.rst b/docs/index.rst index 256db1e..c4245c4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,6 +18,7 @@ Table of Contents api_tools api_pins api_exc + cli_pinout changelog license From a812bfedebd1937b22a5c38a21d8c05fa30f5edb Mon Sep 17 00:00:00 2001 From: Stewart Date: Mon, 7 Nov 2016 22:34:41 +0000 Subject: [PATCH 03/62] Fix minor typo --- gpiozero/cli/pinout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py index 8c60322..8e652dc 100644 --- a/gpiozero/cli/pinout.py +++ b/gpiozero/cli/pinout.py @@ -56,7 +56,7 @@ def main(): try: pi_info().pprint(color=args.color) except IOError: - print('This device is not an Raspberry Pi?') + print('This device is not a Raspberry Pi?') exit(2) else: pi_info(args.revision).pprint(color=args.color) From 48d792439524945110e50f21f8172bd6924c1096 Mon Sep 17 00:00:00 2001 From: Stewart Date: Mon, 7 Nov 2016 22:46:46 +0000 Subject: [PATCH 04/62] Fix import in tests --- tests/cli/test_pinout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/test_pinout.py b/tests/cli/test_pinout.py index 8aac0df..3dbc840 100644 --- a/tests/cli/test_pinout.py +++ b/tests/cli/test_pinout.py @@ -9,7 +9,7 @@ str = type('') import pytest -import cli.pinout as pinout +import gpiozero.cli.pinout as pinout def test_args_incorrect(): From 02938b48ecca15f270adbe917d297a71be3a74db Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 5 Dec 2016 21:03:06 +0000 Subject: [PATCH 05/62] Tidy up pinout tool PR --- docs/{cli_pinout.rst => cli_tools.rst} | 12 ++++++------ docs/index.rst | 2 +- gpiozero/cli/pinout.py | 4 ++-- setup.py | 3 +++ 4 files changed, 12 insertions(+), 9 deletions(-) rename docs/{cli_pinout.rst => cli_tools.rst} (73%) mode change 100644 => 100755 gpiozero/cli/pinout.py diff --git a/docs/cli_pinout.rst b/docs/cli_tools.rst similarity index 73% rename from docs/cli_pinout.rst rename to docs/cli_tools.rst index 4f8950b..a92ec71 100644 --- a/docs/cli_pinout.rst +++ b/docs/cli_tools.rst @@ -11,16 +11,16 @@ tool to write details of the GPIO pins available. Unless specified, the revision of the current device will be detected. A particular revision may be selected with the --revision command-line -option. *e.g.*: +option. e.g:: - pinout.py --revision 000d + pinout --revision 000d By default, the output will include ANSI color codes if run in a color-capable terminal. This behaviour may be overridden by the --color or --monochrome -options to force colored or non-colored output, respectively. *e.g.*: +options to force colored or non-colored output, respectively. e.g:: - pinout.py --monochrome + pinout --monochrome -Full usage details are available with: +Full usage details are available with:: - pinout.py --help + pinout --help diff --git a/docs/index.rst b/docs/index.rst index c4245c4..6ea2d2a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,7 @@ Table of Contents api_tools api_pins api_exc - cli_pinout + cli_tools changelog license diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py old mode 100644 new mode 100755 index 8e652dc..d28cc1c --- a/gpiozero/cli/pinout.py +++ b/gpiozero/cli/pinout.py @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -pinout.py - gpiozero command-line pinout tool. +pinout - gpiozero command-line pinout tool. Output Raspberry Pi GPIO pinout information. """ @@ -56,7 +56,7 @@ def main(): try: pi_info().pprint(color=args.color) except IOError: - print('This device is not a Raspberry Pi?') + print('This device is not a Raspberry Pi') exit(2) else: pi_info(args.revision).pprint(color=args.color) diff --git a/setup.py b/setup.py index a7ea6ae..6d70a29 100644 --- a/setup.py +++ b/setup.py @@ -75,6 +75,9 @@ __entry_points__ = { 'MockPin = gpiozero.pins.mock:MockPin', 'MockPWMPin = gpiozero.pins.mock:MockPWMPin', ], + 'console_scripts': [ + 'pinout = gpiozero.cli.pinout:main', + ] } From a1b3847cab0bdbace72e7b1967fb01421066843d Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Tue, 6 Dec 2016 13:36:59 +0000 Subject: [PATCH 06/62] Grammar --- docs/cli_tools.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cli_tools.rst b/docs/cli_tools.rst index a92ec71..1d6c5e2 100644 --- a/docs/cli_tools.rst +++ b/docs/cli_tools.rst @@ -11,13 +11,13 @@ tool to write details of the GPIO pins available. Unless specified, the revision of the current device will be detected. A particular revision may be selected with the --revision command-line -option. e.g:: +option. For example:: pinout --revision 000d By default, the output will include ANSI color codes if run in a color-capable terminal. This behaviour may be overridden by the --color or --monochrome -options to force colored or non-colored output, respectively. e.g:: +options to force colored or non-colored output, respectively. For example:: pinout --monochrome From 117e4f59720de9d13ddb4eaa439915addb616f1d Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Tue, 6 Dec 2016 13:39:16 +0000 Subject: [PATCH 07/62] Use from to import rather than rename --- tests/cli/test_pinout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/test_pinout.py b/tests/cli/test_pinout.py index 3dbc840..afc52f6 100644 --- a/tests/cli/test_pinout.py +++ b/tests/cli/test_pinout.py @@ -9,7 +9,7 @@ str = type('') import pytest -import gpiozero.cli.pinout as pinout +from gpiozero.cli import pinout def test_args_incorrect(): From fc54667f3476942624c0d22877edf7bf6bacd4d5 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Sun, 18 Dec 2016 03:33:50 +0000 Subject: [PATCH 08/62] More small tidyups - switch to using sys.exit instead of exit - always exit with error-code 1 - don't bother testing error-codes - documentation wording tweak --- docs/cli_tools.rst | 2 +- gpiozero/cli/pinout.py | 4 ++-- tests/cli/test_pinout.py | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/cli_tools.rst b/docs/cli_tools.rst index 1d6c5e2..1b1443d 100644 --- a/docs/cli_tools.rst +++ b/docs/cli_tools.rst @@ -7,7 +7,7 @@ Pinout The gpiozero package contains a database of information about the various revisions of Raspberry Pi. This is queried by the ``pinout`` command-line -tool to write details of the GPIO pins available. +tool to output details of the GPIO pins available. Unless specified, the revision of the current device will be detected. A particular revision may be selected with the --revision command-line diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py index d28cc1c..70b84c8 100755 --- a/gpiozero/cli/pinout.py +++ b/gpiozero/cli/pinout.py @@ -45,7 +45,7 @@ def parse_args(args): except argparse.ArgumentError as ex: print('Error parsing arguments.') parser.error(str(ex.message)) - exit(-1) + sys.exit(1) return args @@ -57,7 +57,7 @@ def main(): pi_info().pprint(color=args.color) except IOError: print('This device is not a Raspberry Pi') - exit(2) + sys.exit(1) else: pi_info(args.revision).pprint(color=args.color) diff --git a/tests/cli/test_pinout.py b/tests/cli/test_pinout.py index afc52f6..7e47b1e 100644 --- a/tests/cli/test_pinout.py +++ b/tests/cli/test_pinout.py @@ -15,8 +15,6 @@ from gpiozero.cli import pinout def test_args_incorrect(): with pytest.raises(SystemExit) as ex: pinout.parse_args(['--nonexistentarg']) - assert ex.value.code == 2 - def test_args_color(): args = pinout.parse_args([]) @@ -26,15 +24,12 @@ def test_args_color(): args = pinout.parse_args(['--monochrome']) assert args.color is False - def test_args_revision(): args = pinout.parse_args(['--revision', '000d']) assert args.revision == '000d' - def test_help(capsys): with pytest.raises(SystemExit) as ex: pinout.parse_args(['--help']) out, err = capsys.readouterr() assert 'GPIO pinout' in out - assert ex.value.code == 0 From ac02f5349c0f5f088170443ba32a9f561dc2e8ff Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Sun, 8 Jan 2017 12:55:16 +0000 Subject: [PATCH 09/62] Update debian package description --- debian/control | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/debian/control b/debian/control index 77a9cf3..ef78323 100644 --- a/debian/control +++ b/debian/control @@ -14,11 +14,12 @@ Section: python Depends: ${misc:Depends}, ${python:Depends} Recommends: python-rpi.gpio, python-spidev Suggests: python-gpiozero-docs -Description: Simple API for controlling devices attached to the GPIO pins. - gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify - interaction with devices connected to the GPIO pins, from simple buttons and - LEDs, up to various add-on boards. The API tries to adhere closely to Python's - idioms and naming conventions. +Description: Simple API for controlling devices attached to a Raspberry Pi's +GPIO pins. gpiozero builds on various pin libraries to provide a set of classes +designed to simplify interaction with devices connected to the GPIO pins, from +simple buttons and LEDs, up to various add-on boards. The API tries to adhere +closely to Python's idioms and naming conventions, and features alternative +programming paradigm approaches. . This is the Python 2 version of the package. @@ -28,11 +29,12 @@ Section: python Depends: ${misc:Depends}, ${python3:Depends} Recommends: python3-rpi.gpio, python3-spidev Suggests: python-gpiozero-docs -Description: Simple API for controlling devices attached to the GPIO pins. - gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify - interaction with devices connected to the GPIO pins, from simple buttons and - LEDs, up to various add-on boards. The API tries to adhere closely to Python's - idioms and naming conventions. +Description: Simple API for controlling devices attached to a Raspberry Pi's +GPIO pins. gpiozero builds on various pin libraries to provide a set of classes +designed to simplify interaction with devices connected to the GPIO pins, from +simple buttons and LEDs, up to various add-on boards. The API tries to adhere +closely to Python's idioms and naming conventions, and features alternative +programming paradigm approaches. . This is the Python 3 version of the package. @@ -40,10 +42,11 @@ Package: python-gpiozero-doc Architecture: all Section: doc Depends: ${sphinxdoc:Depends}, ${misc:Depends} -Description: Documentation for the gpiozero API - gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify - interaction with devices connected to the GPIO pins, from simple buttons and - LEDs, up to various add-on boards. The API tries to adhere closely to Python's - idioms and naming conventions. +Description: Simple API for controlling devices attached to a Raspberry Pi's +GPIO pins. gpiozero builds on various pin libraries to provide a set of classes +designed to simplify interaction with devices connected to the GPIO pins, from +simple buttons and LEDs, up to various add-on boards. The API tries to adhere +closely to Python's idioms and naming conventions, and features alternative +programming paradigm approaches. . This is the version independent documentation for the package. From 17024c9ba3637335c8a31a124e15726c89afc302 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Sun, 22 Jan 2017 16:51:42 +0000 Subject: [PATCH 10/62] Separate out the revision-code parsing and decoding --- gpiozero/pins/data.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index ab133d0..24e637b 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -825,6 +825,11 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( # PPPP - Processor (0=2835, 1=2836, 2=2837) # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero) # RRRR - Revision (0, 1, 2, etc.) + revcode_memory = (revision & 0x700000) >> 20 + revcode_manufacturer = (revision & 0xf0000) >> 16 + revcode_processor = (revision & 0xf000) >> 12 + revcode_type = (revision & 0xff0) >> 4 + revcode_revision = (revision & 0x0f) try: model = { 0: 'A', @@ -835,15 +840,15 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( 6: 'CM', 8: '3B', 9: 'Zero', - }[(revision & 0xff0) >> 4] + }[revcode_type] if model in ('A', 'B'): pcb_revision = { 0: '1.0', # is this right? 1: '1.0', 2: '2.0', - }[revision & 0x0f] + }[revcode_revision] else: - pcb_revision = '1.%d' % (revision & 0x0f) + pcb_revision = '1.%d' % revcode_revision released = { 'A': '2013Q1', 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', @@ -858,17 +863,17 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( 0: 'BCM2835', 1: 'BCM2836', 2: 'BCM2837', - }[(revision & 0xf000) >> 12] + }[revcode_processor] manufacturer = { 0: 'Sony', 1: 'Egoman', 2: 'Embest', - }[(revision & 0xf0000) >> 16] + }[revcode_manufacturer] memory = { 0: 256, 1: 512, 2: 1024, - }[(revision & 0x700000) >> 20] + }[revcode_memory] storage = { 'A': 'SD', 'B': 'SD', From 1b2415a4c29ca4200d2b49d5d677fe8c57500603 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Sun, 22 Jan 2017 17:10:32 +0000 Subject: [PATCH 11/62] Supply 'default' values for some of the pi-revision fields, where appropriate --- gpiozero/pins/data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 24e637b..5243ec9 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -846,7 +846,7 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( 0: '1.0', # is this right? 1: '1.0', 2: '2.0', - }[revcode_revision] + }.get(revcode_revision, 'Unknown') else: pcb_revision = '1.%d' % revcode_revision released = { @@ -868,12 +868,12 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( 0: 'Sony', 1: 'Egoman', 2: 'Embest', - }[revcode_manufacturer] + }.get(revcode_manufacturer, 'Unknown') memory = { 0: 256, 1: 512, 2: 1024, - }[revcode_memory] + }.get(revcode_memory, 0) storage = { 'A': 'SD', 'B': 'SD', From 218ca4b527e52b6e0d5ea11584587e8a23112651 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Wed, 8 Feb 2017 13:54:41 +0000 Subject: [PATCH 12/62] Include licence in sdist. --- MANIFEST.in | 1 + setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 40b7bf4..c0b7b32 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include README.rst recursive-include tests *.py +include LICENCE.txt diff --git a/setup.py b/setup.py index 5c03634..6cc8f26 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ except ImportError: pass __project__ = 'gpiozero' -__version__ = '1.3.1' +__version__ = '1.3.1.post1' __author__ = 'Ben Nuttall' __author_email__ = 'ben@raspberrypi.org' __url__ = 'https://github.com/RPi-Distro/python-gpiozero' From 4e2798dcd080b61479fbe2382184d24dc505440e Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 11:47:04 +0000 Subject: [PATCH 13/62] Add Compute Module 3 details (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 2d39fe1..2eaa85c 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -235,6 +235,23 @@ CM_SODIMM = { 199: ('VBAT', False), 200: ('VBAT', False), } +CM3_SODIMM = CM_SODIMM.copy() +CM3_SODIMM.update({ + 4: ('NC / SDX VREF', False), + 6: ('NC / SDX VREF', False), + 8: (GND, False), + 10: ('NC / SDX CLK', False), + 12: ('NC / SDX CMD', False), + 14: (GND, False), + 16: ('NC / SDX D0', False), + 18: ('NC / SDX D1', False), + 20: (GND, False), + 22: ('NC / SDX D2', False), + 24: ('NC / SDX D3', False), + 88: ('HDMI HPD N 1V8', False), + 90: ('EMMC EN N 1V8', False), + }) + # The following data is sourced from a combination of the following locations: # # http://elinux.org/RPi_HardwareHistory @@ -266,6 +283,7 @@ PI_REVISIONS = { 0xa02082: ('3B', '1.2', '2016Q1', 'BCM2837', 'Sony', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 0xa22082: ('3B', '1.2', '2016Q1', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 0x900093: ('Zero', '1.3', '2016Q2', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 1, 0, {'P1': PLUS_P1}, ), + 0xa020a0: ('CM3', '1.0', '2017Q1', 'BCM2837', 'Sony', 1024, 'eMMC / off-board', 1, 0, False, False, 2, 2, {'SODIMM': CM3_SODIMM},), } @@ -500,7 +518,7 @@ def _parse_pi_revision(revision): # MMM - Memory size (0=256, 1=512, 2=1024) # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest) # PPPP - Processor (0=2835, 1=2836, 2=2837) - # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero) + # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero, 10=CM3) # RRRR - Revision (0, 1, or 2) if not (revision & 0x800000): raise PinUnknownPi('cannot parse "%x"; this is not a new-style revision' % revision) @@ -514,6 +532,7 @@ def _parse_pi_revision(revision): 6: 'CM', 8: '3B', 9: 'Zero', + 10: 'CM3', }[(revision & 0xff0) >> 4] if model in ('A', 'B'): pcb_revision = { @@ -532,6 +551,7 @@ def _parse_pi_revision(revision): 'CM': '2014Q2', '3B': '2016Q1', 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', + 'CM3': '2017Q1', }[model] soc = { 0: 'BCM2835', @@ -552,6 +572,7 @@ def _parse_pi_revision(revision): 'A': 'SD', 'B': 'SD', 'CM': 'eMMC', + 'CM3': 'eMMC / off-board', }.get(model, 'MicroSD') usb = { 'A': 1, @@ -559,12 +580,14 @@ def _parse_pi_revision(revision): 'Zero': 1, 'B': 2, 'CM': 0, + 'CM3': 1, }.get(model, 4) ethernet = { 'A': 0, 'A+': 0, 'Zero': 0, 'CM': 0, + 'CM3': 0, }.get(model, 1) wifi = { '3B': True, @@ -575,6 +598,7 @@ def _parse_pi_revision(revision): csi = { 'Zero': 0 if pcb_revision == '1.0' else 1, 'CM': 2, + 'CM3': 2, }.get(model, 1) dsi = { 'Zero': 0, @@ -583,6 +607,7 @@ def _parse_pi_revision(revision): 'A': {'P1': REV2_P1, 'P5': REV2_P5}, 'B': {'P1': REV2_P1, 'P5': REV2_P5} if pcb_revision == '2.0' else {'P1': REV1_P1}, 'CM': {'SODIMM': CM_SODIMM}, + 'CM3': {'SODIMM': CM3_SODIMM}, }.get(model, {'P1': PLUS_P1}) except KeyError: raise PinUnknownPi('unable to parse new-style revision "%x"' % revision) From dc0c119cbbd1c3e6bff75d308dc74f433257a86d Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 12:00:40 +0000 Subject: [PATCH 14/62] Add Sony Japan manufactured Pi 3B details (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 2eaa85c..8310d42 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -284,6 +284,7 @@ PI_REVISIONS = { 0xa22082: ('3B', '1.2', '2016Q1', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 0x900093: ('Zero', '1.3', '2016Q2', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 1, 0, {'P1': PLUS_P1}, ), 0xa020a0: ('CM3', '1.0', '2017Q1', 'BCM2837', 'Sony', 1024, 'eMMC / off-board', 1, 0, False, False, 2, 2, {'SODIMM': CM3_SODIMM},), + 0xa32082: ('3B', '1.2', '2016Q4', 'BCM2837', 'Sony Japan', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), } @@ -516,7 +517,7 @@ def _parse_pi_revision(revision): # uuuuuuuu - Unused # F - New flag (1=valid new-style revision, 0=old-style) # MMM - Memory size (0=256, 1=512, 2=1024) - # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest) + # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest, 3=Sony Japan) # PPPP - Processor (0=2835, 1=2836, 2=2837) # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero, 10=CM3) # RRRR - Revision (0, 1, or 2) @@ -542,17 +543,6 @@ def _parse_pi_revision(revision): }[revision & 0x0f] else: pcb_revision = '1.%d' % (revision & 0x0f) - released = { - 'A': '2013Q1', - 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', - 'A+': '2014Q4', - 'B+': '2014Q3', - '2B': '2015Q1', - 'CM': '2014Q2', - '3B': '2016Q1', - 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', - 'CM3': '2017Q1', - }[model] soc = { 0: 'BCM2835', 1: 'BCM2836', @@ -562,12 +552,24 @@ def _parse_pi_revision(revision): 0: 'Sony', 1: 'Egoman', 2: 'Embest', + 3: 'Sony Japan', }[(revision & 0xf0000) >> 16] memory = { 0: 256, 1: 512, 2: 1024, }[(revision & 0x700000) >> 20] + released = { + 'A': '2013Q1', + 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', + 'A+': '2014Q4', + 'B+': '2014Q3', + '2B': '2015Q1', + 'CM': '2014Q2', + '3B': '2016Q1' if manufacturer == 'Sony' or manufacturer == 'Embest' else '2016Q4', + 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', + 'CM3': '2017Q1', + }[model] storage = { 'A': 'SD', 'B': 'SD', From 8c7bd5f51f5987398d478a16438b765600d9d1eb Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 12:19:33 +0000 Subject: [PATCH 15/62] Add Pi Zero W details (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 8310d42..2b76d4e 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -285,6 +285,7 @@ PI_REVISIONS = { 0x900093: ('Zero', '1.3', '2016Q2', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 1, 0, {'P1': PLUS_P1}, ), 0xa020a0: ('CM3', '1.0', '2017Q1', 'BCM2837', 'Sony', 1024, 'eMMC / off-board', 1, 0, False, False, 2, 2, {'SODIMM': CM3_SODIMM},), 0xa32082: ('3B', '1.2', '2016Q4', 'BCM2837', 'Sony Japan', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), + 0x9000c1: ('Zero W', '1.1', '2017Q1', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, True, True, 1, 0, {'P1': PLUS_P1}, ), } @@ -519,7 +520,7 @@ def _parse_pi_revision(revision): # MMM - Memory size (0=256, 1=512, 2=1024) # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest, 3=Sony Japan) # PPPP - Processor (0=2835, 1=2836, 2=2837) - # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero, 10=CM3) + # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero, 10=CM3, 12=Zero W) # RRRR - Revision (0, 1, or 2) if not (revision & 0x800000): raise PinUnknownPi('cannot parse "%x"; this is not a new-style revision' % revision) @@ -534,6 +535,7 @@ def _parse_pi_revision(revision): 8: '3B', 9: 'Zero', 10: 'CM3', + 12: 'Zero W, }[(revision & 0xff0) >> 4] if model in ('A', 'B'): pcb_revision = { @@ -569,6 +571,7 @@ def _parse_pi_revision(revision): '3B': '2016Q1' if manufacturer == 'Sony' or manufacturer == 'Embest' else '2016Q4', 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', 'CM3': '2017Q1', + 'Zero W': '2017Q1', }[model] storage = { 'A': 'SD', @@ -580,6 +583,7 @@ def _parse_pi_revision(revision): 'A': 1, 'A+': 1, 'Zero': 1, + 'Zero W': 1, 'B': 2, 'CM': 0, 'CM3': 1, @@ -588,22 +592,27 @@ def _parse_pi_revision(revision): 'A': 0, 'A+': 0, 'Zero': 0, + 'Zero W': 0, 'CM': 0, 'CM3': 0, }.get(model, 1) wifi = { '3B': True, + 'Zero W': True, }.get(model, False) bluetooth = { '3B': True, + 'Zero W': True, }.get(model, False) csi = { 'Zero': 0 if pcb_revision == '1.0' else 1, + 'Zero W': 1, 'CM': 2, 'CM3': 2, }.get(model, 1) dsi = { 'Zero': 0, + 'Zero W': 0, }.get(model, csi) headers = { 'A': {'P1': REV2_P1, 'P5': REV2_P5}, From 71fed0e851f3d404646dbb0a950f61283761b597 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 12:34:58 +0000 Subject: [PATCH 16/62] Add BCM2837-based Pi2B details (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 2b76d4e..0780482 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -286,6 +286,7 @@ PI_REVISIONS = { 0xa020a0: ('CM3', '1.0', '2017Q1', 'BCM2837', 'Sony', 1024, 'eMMC / off-board', 1, 0, False, False, 2, 2, {'SODIMM': CM3_SODIMM},), 0xa32082: ('3B', '1.2', '2016Q4', 'BCM2837', 'Sony Japan', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 0x9000c1: ('Zero W', '1.1', '2017Q1', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, True, True, 1, 0, {'P1': PLUS_P1}, ), + 0xa22042: ('2B', '1.2', '2016Q3', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), } @@ -566,7 +567,7 @@ def _parse_pi_revision(revision): 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', 'A+': '2014Q4', 'B+': '2014Q3', - '2B': '2015Q1', + '2B': '2015Q1' if pcb_revision == '1.1' else '2016Q3', 'CM': '2014Q2', '3B': '2016Q1' if manufacturer == 'Sony' or manufacturer == 'Embest' else '2016Q4', 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', From 82050d3d5a79bba3dfc3888399c5269d1a806aca Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 12:40:35 +0000 Subject: [PATCH 17/62] Add details for 512MB Pi A+ (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 0780482..4ab152a 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -287,6 +287,7 @@ PI_REVISIONS = { 0xa32082: ('3B', '1.2', '2016Q4', 'BCM2837', 'Sony Japan', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ), 0x9000c1: ('Zero W', '1.1', '2017Q1', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, True, True, 1, 0, {'P1': PLUS_P1}, ), 0xa22042: ('2B', '1.2', '2016Q3', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), + 0x900021: ('A+', '1.1', '2016Q3', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ), } @@ -565,7 +566,7 @@ def _parse_pi_revision(revision): released = { 'A': '2013Q1', 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', - 'A+': '2014Q4', + 'A+': '2014Q4' if memory == 512 else '2016Q3', 'B+': '2014Q3', '2B': '2015Q1' if pcb_revision == '1.1' else '2016Q3', 'CM': '2014Q2', From 5b91e55e96fbf5a187ac9bad5e4a52f4debcbc57 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 3 Mar 2017 12:43:03 +0000 Subject: [PATCH 18/62] Add details for Chinese Pi Zero (on top of v1.3.1.post1) --- gpiozero/pins/data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 4ab152a..343f001 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -288,6 +288,7 @@ PI_REVISIONS = { 0x9000c1: ('Zero W', '1.1', '2017Q1', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, True, True, 1, 0, {'P1': PLUS_P1}, ), 0xa22042: ('2B', '1.2', '2016Q3', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ), 0x900021: ('A+', '1.1', '2016Q3', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ), + 0x920093: ('Zero', '1.3', '2016Q2', 'BCM2835', 'Embest', 512, 'MicroSD', 1, 0, False, False, 1, 0, {'P1': PLUS_P1}, ), } From f5f827c0ece2e6f441e460a6144d0ea830464232 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Fri, 3 Mar 2017 13:11:49 +0000 Subject: [PATCH 19/62] Add missing quote --- gpiozero/pins/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 343f001..af933ea 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -538,7 +538,7 @@ def _parse_pi_revision(revision): 8: '3B', 9: 'Zero', 10: 'CM3', - 12: 'Zero W, + 12: 'Zero W', }[(revision & 0xff0) >> 4] if model in ('A', 'B'): pcb_revision = { From 2e7543d3151ee048facb79c666ba5ea5053b33c4 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Fri, 3 Mar 2017 13:18:36 +0000 Subject: [PATCH 20/62] Release v1.3.2 --- docs/changelog.rst | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e360b9d..185c8e8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,11 @@ Changelog .. currentmodule:: gpiozero +Release 1.3.2 (2017-03-03) +========================== + +* Fix issue with :func:`pi_info` breaking on unknown Pi models + Release 1.3.1 (2016-08-31 ... later) ==================================== diff --git a/setup.py b/setup.py index 6cc8f26..e615e7f 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ except ImportError: pass __project__ = 'gpiozero' -__version__ = '1.3.1.post1' +__version__ = '1.3.2' __author__ = 'Ben Nuttall' __author_email__ = 'ben@raspberrypi.org' __url__ = 'https://github.com/RPi-Distro/python-gpiozero' From 7d8de63f6d7755e51a5b4037fa14e481437cc862 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 6 Mar 2017 16:40:16 +0000 Subject: [PATCH 21/62] Correct classname in docstring PingDevice -> PingServer --- gpiozero/other_devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/other_devices.py b/gpiozero/other_devices.py index ccc77b5..f89ea0c 100644 --- a/gpiozero/other_devices.py +++ b/gpiozero/other_devices.py @@ -54,7 +54,7 @@ class PingServer(InternalDevice): self._fire_events() def __repr__(self): - return '' % self.host + return '' % self.host @property def value(self): From 1951b0f23454333c877fbf7fcc698cf28858bcc2 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 13 Mar 2017 13:20:37 +0000 Subject: [PATCH 22/62] Add changelog entry for 1.3.2 release --- debian/changelog | 6 ++++++ docs/changelog.rst | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/debian/changelog b/debian/changelog index 9984e1c..6c6b4d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +gpiozero (1.3.2) stable; urgency=low + + * Added new Pi models to stop "pi_info" breaking + + -- Ben Nuttall Fri, 03 Mar 2017 13:18:00 +0100 + gpiozero (1.3.1) stable; urgency=low * Fixed hardware SPI support which Dave broke in 1.3.0. Sorry! diff --git a/docs/changelog.rst b/docs/changelog.rst index e360b9d..5658b39 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,11 @@ Changelog .. currentmodule:: gpiozero +Release 1.3.2 (2017-03-03) +========================== + +* Added new Pi models to stop :func:`pi_info` breaking + Release 1.3.1 (2016-08-31 ... later) ==================================== From 97ffabe764d810afa572f5ca3aa7ced0a5a56a6f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 13 Jun 2017 16:02:07 +0100 Subject: [PATCH 23/62] Fix up missing board stuff Also ensure the Zero W gets represented properly on board output and tidy up some spacing --- gpiozero/pins/data.py | 106 +++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 8d60c9c..20d8ce0 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -152,18 +152,18 @@ ZERO12_BOARD = """\ {style:white on green},-------------------------.{style:reset} {style:white on green}| {P1:{style} col2}{style:white on green} P1 |{style:reset} {style:white on green}| {P1:{style} col1}{style:white on green} |{style:reset} -{style:black on white}---+{style:white on green} {style:on black}+----+{style:on green} {style:bold}PiZero{style:normal} |{style:reset} -{style:black on white} sd|{style:white on green} {style:on black}|SoC |{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} |{style:reset} -{style:black on white}---+|hdmi|{style:white on green} {style:on black}+----+{style:on green} {style:black on white}usb{style:on green} {style:black on white}pwr{style:white on green} |{style:reset} +{style:black on white}---+{style:white on green} {style:on black}+---+{style:on green} {style:bold}PiZero{style:normal} |{style:reset} +{style:black on white} sd|{style:white on green} {style:on black}|SoC|{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} |{style:reset} +{style:black on white}---+|hdmi|{style:white on green} {style:on black}+---+{style:on green} {style:black on white}usb{style:on green} {style:black on white}pwr{style:white on green} |{style:reset} {style:white on green}`---{style:black on white}| |{style:white on green}--------{style:black on white}| |{style:white on green}-{style:black on white}| |{style:white on green}-'{style:reset}""" ZERO13_BOARD = """\ {style:white on green}.-------------------------.{style:reset} {style:white on green}| {P1:{style} col2}{style:white on green} P1 |{style:reset} {style:white on green}| {P1:{style} col1}{style:white on green} {style:black on white}|c{style:reset} -{style:black on white}---+{style:white on green} {style:on black}+----+{style:on green} {style:bold}PiZero{style:normal} {style:black on white}|s{style:reset} -{style:black on white} sd|{style:white on green} {style:on black}|SoC |{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} {style:black on white}|i{style:reset} -{style:black on white}---+|hdmi|{style:white on green} {style:on black}+----+{style:on green} {style:black on white}usb{style:on green} {style:on white}pwr{style:white on green} |{style:reset} +{style:black on white}---+{style:white on green} {style:on black}+---+{style:on green} {style:bold}Pi{model:6s}{style:normal}{style:black on white}|s{style:reset} +{style:black on white} sd|{style:white on green} {style:on black}|SoC|{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} {style:black on white}|i{style:reset} +{style:black on white}---+|hdmi|{style:white on green} {style:on black}+---+{style:on green} {style:black on white}usb{style:on green} {style:on white}pwr{style:white on green} |{style:reset} {style:white on green}`---{style:black on white}| |{style:white on green}--------{style:black on white}| |{style:white on green}-{style:black on white}| |{style:white on green}-'{style:reset}""" CM_BOARD = """\ @@ -838,20 +838,21 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( # uuuuuuuu - Unused # F - New flag (1=valid new-style revision, 0=old-style) # MMM - Memory size (0=256, 1=512, 2=1024) - # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest) + # CCCC - Manufacturer (0=Sony, 1=Egoman, 2=Embest, 3=Sony Japan) # PPPP - Processor (0=2835, 1=2836, 2=2837) - # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, 8=3B, 9=Zero) + # TTTTTTTT - Type (0=A, 1=B, 2=A+, 3=B+, 4=2B, 5=Alpha (??), 6=CM, + # 8=3B, 9=Zero, 10=CM3, 12=Zero W) # RRRR - Revision (0, 1, 2, etc.) try: model = { - 0: 'A', - 1: 'B', - 2: 'A+', - 3: 'B+', - 4: '2B', - 6: 'CM', - 8: '3B', - 9: 'Zero', + 0: 'A', + 1: 'B', + 2: 'A+', + 3: 'B+', + 4: '2B', + 6: 'CM', + 8: '3B', + 9: 'Zero', 10: 'CM3', 12: 'Zero W', }[(revision & 0xff0) >> 4] @@ -880,64 +881,73 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( 2: 1024, }[(revision & 0x700000) >> 20] released = { - 'A': '2013Q1', - 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', - 'A+': '2014Q4' if memory == 512 else '2016Q3', - 'B+': '2014Q3', - '2B': '2015Q1' if pcb_revision == '1.1' else '2016Q3', - 'CM': '2014Q2', - '3B': '2016Q1' if manufacturer == 'Sony' or manufacturer == 'Embest' else '2016Q4', - 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', - 'CM3': '2017Q1', + 'A': '2013Q1', + 'B': '2012Q1' if pcb_revision == '1.0' else '2012Q4', + 'A+': '2014Q4' if memory == 512 else '2016Q3', + 'B+': '2014Q3', + '2B': '2015Q1' if pcb_revision == '1.1' else '2016Q3', + 'CM': '2014Q2', + '3B': '2016Q1' if manufacturer in ('Sony', 'Embest') else '2016Q4', + 'Zero': '2015Q4' if pcb_revision == '1.0' else '2016Q2', + 'CM3': '2017Q1', 'Zero W': '2017Q1', }[model] storage = { - 'A': 'SD', - 'B': 'SD', - 'CM': 'eMMC', + 'A': 'SD', + 'B': 'SD', + 'CM': 'eMMC', 'CM3': 'eMMC / off-board', }.get(model, 'MicroSD') usb = { - 'A': 1, - 'A+': 1, - 'Zero': 1, + 'A': 1, + 'A+': 1, + 'Zero': 1, 'Zero W': 1, - 'B': 2, - 'CM': 0, - 'CM3': 1, + 'B': 2, + 'CM': 0, + 'CM3': 1, }.get(model, 4) ethernet = { - 'A': 0, - 'A+': 0, - 'Zero': 0, + 'A': 0, + 'A+': 0, + 'Zero': 0, 'Zero W': 0, - 'CM': 0, - 'CM3': 0, + 'CM': 0, + 'CM3': 0, }.get(model, 1) wifi = { - '3B': True, + '3B': True, 'Zero W': True, }.get(model, False) bluetooth = { - '3B': True, + '3B': True, 'Zero W': True, }.get(model, False) csi = { - 'Zero': 0 if pcb_revision == '1.0' else 1, + 'Zero': 0 if pcb_revision == '1.0' else 1, 'Zero W': 1, - 'CM': 2, - 'CM3': 2, + 'CM': 2, + 'CM3': 2, }.get(model, 1) dsi = { - 'Zero': 0, + 'Zero': 0, 'Zero W': 0, }.get(model, csi) headers = { - 'A': {'P1': REV2_P1, 'P5': REV2_P5}, - 'B': {'P1': REV2_P1, 'P5': REV2_P5} if pcb_revision == '2.0' else {'P1': REV1_P1}, - 'CM': {'SODIMM': CM_SODIMM}, + 'A': {'P1': REV2_P1, 'P5': REV2_P5}, + 'B': {'P1': REV2_P1, 'P5': REV2_P5} if pcb_revision == '2.0' else {'P1': REV1_P1}, + 'CM': {'SODIMM': CM_SODIMM}, 'CM3': {'SODIMM': CM3_SODIMM}, }.get(model, {'P1': PLUS_P1}) + board = { + 'A': A_BOARD, + 'B': REV1_BOARD if pcb_revision == '1.0' else REV2_BOARD, + 'A+': APLUS_BOARD, + 'CM': CM_BOARD, + 'CM3': CM_BOARD, + 'Zero': ZERO12_BOARD if pcb_revision == '1.2' else ZERO13_BOARD, + 'Zero W': ZERO13_BOARD, + }.get(model, BPLUS_BOARD) except KeyError: raise PinUnknownPi('unable to parse new-style revision "%x"' % revision) else: From 4725c6b68c3ab4331cff2a93790f3bf27d601d1e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 13 Jun 2017 16:15:15 +0100 Subject: [PATCH 24/62] Tidy up pinout a little: Ensure all error messages are printed on stderr instead of stdout; make sure all errors formatted the same and that argparse's default exit codes are followed --- gpiozero/cli/pinout.py | 95 +++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py index 70b84c8..b12b622 100755 --- a/gpiozero/cli/pinout.py +++ b/gpiozero/cli/pinout.py @@ -10,57 +10,56 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi import argparse import sys -from gpiozero import * +from gpiozero import pi_info -def parse_args(args): - parser = argparse.ArgumentParser( - description=__doc__ - ) +class PinoutTool(object): + def __init__(self): + self.parser = argparse.ArgumentParser( + description=__doc__ + ) + self.parser.add_argument( + '-r', '--revision', + dest='revision', + default='', + help='RPi revision. Default is to autodetect revision of current device' + ) + self.parser.add_argument( + '-c', '--color', + action="store_true", + default=None, + help='Force colored output (by default, the output will include ANSI' + 'color codes if run in a color-capable terminal). See also --monochrome' + ) + self.parser.add_argument( + '-m', '--monochrome', + dest='color', + action='store_false', + help='Force monochrome output. See also --color' + ) - parser.add_argument( - '-r', '--revision', - dest='revision', - default='', - help='RPi revision. Default is to autodetect revision of current device' - ) - - parser.add_argument( - '-c', '--color', - action="store_true", - default=None, - help='Force colored output (by default, the output will include ANSI' - 'color codes if run in a color-capable terminal). See also --monochrome' - ) - - parser.add_argument( - '-m', '--monochrome', - dest='color', - action='store_false', - help='Force monochrome output. See also --color' - ) - - try: - args = parser.parse_args(args) - except argparse.ArgumentError as ex: - print('Error parsing arguments.') - parser.error(str(ex.message)) - sys.exit(1) - return args - - -def main(): - args = parse_args(sys.argv[1:]) - - if args.revision == '': + def __call__(self, args=None): + if args is None: + args = sys.argv[1:] try: - pi_info().pprint(color=args.color) - except IOError: - print('This device is not a Raspberry Pi') - sys.exit(1) - else: - pi_info(args.revision).pprint(color=args.color) + return self.main(self.parser.parse_args(args)) or 0 + except argparse.ArgumentError as e: + # argparse errors are already nicely formatted, print to stderr and + # exit with code 2 + raise e + except Exception as e: + # Output anything else nicely formatted on stderr and exit code 1 + self.parser.exit(1, '{prog}: error: {message}\n'.format( + prog=self.parser.prog, message=e)) + + def main(self, args): + if args.revision == '': + try: + pi_info().pprint(color=args.color) + except IOError: + raise IOError('This device is not a Raspberry Pi') + else: + pi_info(args.revision).pprint(color=args.color) -if __name__ == '__main__': - main() +main = PinoutTool() From d6475f64d8aab75de55c8ce0f67165aab22a3610 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 13 Jun 2017 16:17:24 +0100 Subject: [PATCH 25/62] Added pinout.xyz link, per Ben's suggestion --- gpiozero/cli/pinout.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gpiozero/cli/pinout.py b/gpiozero/cli/pinout.py index b12b622..f027147 100755 --- a/gpiozero/cli/pinout.py +++ b/gpiozero/cli/pinout.py @@ -60,6 +60,8 @@ class PinoutTool(object): raise IOError('This device is not a Raspberry Pi') else: pi_info(args.revision).pprint(color=args.color) + print('') + print('For further information, please refer to https://pinout.xyz/') main = PinoutTool() From b7aa7e85064430dc95e74a0f676f0484fee12733 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 13 Jun 2017 16:23:27 +0100 Subject: [PATCH 26/62] Fix up pinout tests so they work with new structure --- tests/cli/test_pinout.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/cli/test_pinout.py b/tests/cli/test_pinout.py index 7e47b1e..a8b0718 100644 --- a/tests/cli/test_pinout.py +++ b/tests/cli/test_pinout.py @@ -9,27 +9,27 @@ str = type('') import pytest -from gpiozero.cli import pinout +from gpiozero.cli.pinout import main def test_args_incorrect(): with pytest.raises(SystemExit) as ex: - pinout.parse_args(['--nonexistentarg']) + main(['pinout', '--nonexistentarg']) def test_args_color(): - args = pinout.parse_args([]) + args = main.parser.parse_args([]) assert args.color is None - args = pinout.parse_args(['--color']) + args = main.parser.parse_args(['--color']) assert args.color is True - args = pinout.parse_args(['--monochrome']) + args = main.parser.parse_args(['--monochrome']) assert args.color is False def test_args_revision(): - args = pinout.parse_args(['--revision', '000d']) + args = main.parser.parse_args(['--revision', '000d']) assert args.revision == '000d' def test_help(capsys): with pytest.raises(SystemExit) as ex: - pinout.parse_args(['--help']) + main(['pinout', '--help']) out, err = capsys.readouterr() assert 'GPIO pinout' in out From b43aeb8fecb64a653d1a415c0a77dca37aeb440b Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 13 Jun 2017 19:23:23 +0100 Subject: [PATCH 27/62] Fix #518 Apparently debian splits pkg_resources out from setuptools. Still, we need pkg_resources as a runtime dependency, not just a build dependency as the pin factory entry points now rely upon it. --- debian/control | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 77a9cf3..2bca808 100644 --- a/debian/control +++ b/debian/control @@ -11,7 +11,7 @@ X-Python3-Version: >= 3.2 Package: python-gpiozero Architecture: all Section: python -Depends: ${misc:Depends}, ${python:Depends} +Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources Recommends: python-rpi.gpio, python-spidev Suggests: python-gpiozero-docs Description: Simple API for controlling devices attached to the GPIO pins. @@ -25,7 +25,7 @@ Description: Simple API for controlling devices attached to the GPIO pins. Package: python3-gpiozero Architecture: all Section: python -Depends: ${misc:Depends}, ${python3:Depends} +Depends: ${misc:Depends}, ${python3:Depends}, python3-pkg-resources Recommends: python3-rpi.gpio, python3-spidev Suggests: python-gpiozero-docs Description: Simple API for controlling devices attached to the GPIO pins. From ff29e2625b04722cc9235cc477ecf9ec50b18fd5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 16 Jun 2017 10:01:59 +0100 Subject: [PATCH 28/62] Fixed format of the Description field --- debian/control | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/debian/control b/debian/control index ef78323..02e3bc9 100644 --- a/debian/control +++ b/debian/control @@ -14,12 +14,12 @@ Section: python Depends: ${misc:Depends}, ${python:Depends} Recommends: python-rpi.gpio, python-spidev Suggests: python-gpiozero-docs -Description: Simple API for controlling devices attached to a Raspberry Pi's -GPIO pins. gpiozero builds on various pin libraries to provide a set of classes -designed to simplify interaction with devices connected to the GPIO pins, from -simple buttons and LEDs, up to various add-on boards. The API tries to adhere -closely to Python's idioms and naming conventions, and features alternative -programming paradigm approaches. +Description: Simple API for controlling devices attached to a Pi's GPIO pins. + gpiozero builds on various pin libraries to provide a set of classes designed + to simplify interaction with devices connected to the GPIO pins, from simple + buttons and LEDs, up to various add-on boards. The API tries to adhere closely + to Python's idioms and naming conventions, and features alternative + programming paradigm approaches. . This is the Python 2 version of the package. @@ -29,12 +29,12 @@ Section: python Depends: ${misc:Depends}, ${python3:Depends} Recommends: python3-rpi.gpio, python3-spidev Suggests: python-gpiozero-docs -Description: Simple API for controlling devices attached to a Raspberry Pi's -GPIO pins. gpiozero builds on various pin libraries to provide a set of classes -designed to simplify interaction with devices connected to the GPIO pins, from -simple buttons and LEDs, up to various add-on boards. The API tries to adhere -closely to Python's idioms and naming conventions, and features alternative -programming paradigm approaches. +Description: Simple API for controlling devices attached to a Pi's GPIO pins. + gpiozero builds on various pin libraries to provide a set of classes designed + to simplify interaction with devices connected to the GPIO pins, from simple + buttons and LEDs, up to various add-on boards. The API tries to adhere closely + to Python's idioms and naming conventions, and features alternative + programming paradigm approaches. . This is the Python 3 version of the package. @@ -42,11 +42,11 @@ Package: python-gpiozero-doc Architecture: all Section: doc Depends: ${sphinxdoc:Depends}, ${misc:Depends} -Description: Simple API for controlling devices attached to a Raspberry Pi's -GPIO pins. gpiozero builds on various pin libraries to provide a set of classes -designed to simplify interaction with devices connected to the GPIO pins, from -simple buttons and LEDs, up to various add-on boards. The API tries to adhere -closely to Python's idioms and naming conventions, and features alternative -programming paradigm approaches. +Description: Simple API for controlling devices attached to a Pi's GPIO pins. + gpiozero builds on various pin libraries to provide a set of classes designed + to simplify interaction with devices connected to the GPIO pins, from simple + buttons and LEDs, up to various add-on boards. The API tries to adhere closely + to Python's idioms and naming conventions, and features alternative + programming paradigm approaches. . This is the version independent documentation for the package. From ce6217c14fddf5a39edbc94c920f0fcd1e425620 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 27 Sep 2016 00:30:57 +0100 Subject: [PATCH 29/62] Fix #459 - properly support remote SPI with pigpio Sorry! Dave's messing around with the pin implementations again. Hopefully the last time. The pin_factory is now really a factory object which can be asked to produce individual pins or pin-based interfaces like SPI (which can be supported properly via pigpio). --- docs/api_exc.rst | 28 +- docs/api_pins.rst | 125 ++++---- docs/images/composed_devices.pdf | Bin 12980 -> 12979 bytes docs/images/composed_devices.png | Bin 34694 -> 34875 bytes docs/notes.rst | 11 +- docs/recipes.rst | 10 +- gpiozero/__init__.py | 47 +-- gpiozero/devices.py | 205 ++++++++---- gpiozero/exc.py | 32 +- gpiozero/input_devices.py | 14 +- gpiozero/mixins.py | 2 +- gpiozero/output_devices.py | 22 +- gpiozero/pins/__init__.py | 514 +++++++++++++++++++++++++++---- gpiozero/pins/data.py | 62 ++-- gpiozero/pins/local.py | 241 +++++++++++++++ gpiozero/pins/mock.py | 117 +++---- gpiozero/pins/native.py | 140 ++++----- gpiozero/pins/pi.py | 214 +++++++++++++ gpiozero/pins/pigpiod.py | 417 +++++++++++++++++++------ gpiozero/pins/rpigpio.py | 94 +++--- gpiozero/pins/rpio.py | 108 +++---- gpiozero/pins/spi.py | 86 ++++++ gpiozero/spi.py | 419 ------------------------- gpiozero/spi_devices.py | 6 +- setup.py | 12 +- tests/conftest.py | 10 + tests/test_boards.py | 255 +++++++-------- tests/test_devices.py | 75 ++--- tests/test_inputs.py | 57 ++-- tests/test_mock_pin.py | 62 ++-- tests/test_outputs.py | 190 ++++++------ tests/test_pins_data.py | 58 ++-- tests/test_spi.py | 126 ++++---- tests/test_spi_devices.py | 8 +- 34 files changed, 2311 insertions(+), 1456 deletions(-) create mode 100644 gpiozero/pins/local.py create mode 100644 gpiozero/pins/pi.py create mode 100644 gpiozero/pins/spi.py delete mode 100644 gpiozero/spi.py create mode 100644 tests/conftest.py diff --git a/docs/api_exc.rst b/docs/api_exc.rst index 3a8b932..f68ed72 100644 --- a/docs/api_exc.rst +++ b/docs/api_exc.rst @@ -59,6 +59,20 @@ Errors .. autoexception:: SPIBadArgs +.. autoexception:: SPIBadChannel + +.. autoexception:: SPIFixedClockMode + +.. autoexception:: SPIInvalidClockMode + +.. autoexception:: SPIFixedBitOrder + +.. autoexception:: SPIFixedSelect + +.. autoexception:: SPIFixedWordSize + +.. autoexception:: SPIInvalidWordSize + .. autoexception:: GPIODeviceError .. autoexception:: GPIODeviceClosed @@ -83,23 +97,31 @@ Errors .. autoexception:: PinInvalidEdges +.. autoexception:: PinInvalidBounce + .. autoexception:: PinSetInput .. autoexception:: PinFixedPull .. autoexception:: PinEdgeDetectUnsupported +.. autoexception:: PinGPIOUnsupported + +.. autoexception:: PinSPIUnsupported + .. autoexception:: PinPWMError .. autoexception:: PinPWMUnsupported .. autoexception:: PinPWMFixedValue +.. autoexception:: PinUnknownPi + .. autoexception:: PinMultiplePins .. autoexception:: PinNoPins -.. autoexception:: PinUnknownPi +.. autoexception:: PinInvalidPin Warnings ======== @@ -110,3 +132,7 @@ Warnings .. autoexception:: SPISoftwareFallback +.. autoexception:: PinFactoryFallback + +.. autoexception:: PinNonPhysical + diff --git a/docs/api_pins.rst b/docs/api_pins.rst index 97723ca..fd8e0e6 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -11,68 +11,68 @@ are concerned with. However, some users may wish to take advantage of the capabilities of alternative GPIO implementations or (in future) use GPIO extender chips. This is the purpose of the pins portion of the library. -When you construct a device, you pass in a GPIO pin number. However, what the -library actually expects is a :class:`Pin` implementation. If it finds a simple -integer number instead, it uses one of the following classes to provide the -:class:`Pin` implementation (classes are listed in favoured order): +When you construct a device, you pass in a pin specification. However, what the +library actually expects is a :class:`Pin` implementation. If it finds anything +else, it uses the existing ``Device._pin_factory`` to construct a :class:`Pin` +implementation based on the specification. -1. :class:`gpiozero.pins.rpigpio.RPiGPIOPin` +Changing the pin factory +======================== -2. :class:`gpiozero.pins.rpio.RPIOPin` +The default pin factory can be replaced by specifying a value for the +``GPIOZERO_PIN_FACTORY`` environment variable. For example: -3. :class:`gpiozero.pins.pigpiod.PiGPIOPin` +.. code-block:: console -4. :class:`gpiozero.pins.native.NativePin` + pi@raspberrypi $ GPIOZERO_PIN_FACTORY=native python + Python 3.4.2 (default, Oct 19 2014, 13:31:11) + [GCC 4.9.1] on linux + Type "help", "copyright", "credits" or "license" for more information. + >>> import gpiozero + >>> gpiozero.Device._pin_factory + -You can change the default pin implementation by over-writing the -``pin_factory`` global in the ``devices`` module like so:: +The following values, and the corresponding :class:`Factory` and :class:`Pin` +classes are listed in the table below. Factories are listed in the order that +they are tried by default. - from gpiozero.pins.native import NativePin - import gpiozero.devices - # Force the default pin implementation to be NativePin - gpiozero.devices.pin_factory = NativePin ++---------+-----------------------------------------------+-------------------------------------------+ +| Name | Factory class | Pin class | ++=========+===============================================+===========================================+ +| rpigpio | :class:`gpiozero.pins.rpigpio.RPiGPIOFactory` | :class:`gpiozero.pins.rpigpio.RPiGPIOPin` | ++---------+-----------------------------------------------+-------------------------------------------+ +| rpio | :class:`gpiozero.pins.rpio.RPIOFactory` | :class:`gpiozero.pins.rpio.RPIOPin` | ++---------+-----------------------------------------------+-------------------------------------------+ +| pigpio | :class:`gpiozero.pins.pigpiod.PiGPIOFactory` | :class:`gpiozero.pins.pigpiod.PiGPIOPin` | ++---------+-----------------------------------------------+-------------------------------------------+ +| native | :class:`gpiozero.pins.native.NativeFactory` | :class:`gpiozero.pins.native.NativePin` | ++---------+-----------------------------------------------+-------------------------------------------+ + +If you need to change the default pin factory from within a script, use the +``Device._set_pin_factory`` class method, passing in the instance of the new +factory to use. This is only supported at script startup (replacing the factory +closes all existing pin instances which can have interesting consequences for +any devices using them):: + + from gpiozero.pins.native import NativeFactory + from gpiozero import * + Device._set_pin_factory(NativeFactory()) from gpiozero import LED # This will now use NativePin instead of RPiGPIOPin led = LED(16) -``pin_factory`` is a concrete descendent of the abstract :class:`Pin` class. -The descendent may take additional parameters in its constructor provided they -are optional; GPIO Zero will expect to be able to construct instances with -nothing more than an integer pin number. - -However, the descendent may take default information from additional sources. +Certain factories may take default information from additional sources. For example, to default to creating pins with :class:`gpiozero.pins.pigpiod.PiGPIOPin` on a remote pi called ``remote-pi`` you can set the :envvar:`PIGPIO_ADDR` environment variable when running your -script:: +script: - $ PIGPIO_ADDR=remote-pi python my_script.py +.. code-block:: console -It is worth noting that instead of passing an integer to device constructors, -you can pass an object derived from :class:`Pin` itself:: - - from gpiozero.pins.native import NativePin - from gpiozero import LED - - led = LED(NativePin(16)) - -In future, this separation of pins and devices should also permit the library -to utilize pins that are part of IO extender chips. For example:: - - from gpiozero import IOExtender, LED - - ext = IOExtender() - led = LED(ext.pins[0]) - led.on() - -.. warning:: - - While the devices API is now considered stable and won't change in - backwards incompatible ways, the pins API is *not* yet considered stable. - It is potentially subject to change in future versions. We welcome any - comments from testers! + $ export GPIOZERO_PIN_FACTORY=pigpio + $ PIGPIO_ADDR=remote-pi python3 my_script.py .. warning:: @@ -83,41 +83,48 @@ to utilize pins that are part of IO extender chips. For example:: actual raspberry pie, you have only yourself to blame. -RPiGPIOPin -========== +RPi.GPIO +======== + +.. autoclass:: gpiozero.pins.rpigpio.RPiGPIOFactory .. autoclass:: gpiozero.pins.rpigpio.RPiGPIOPin -RPIOPin -======= +RPIO +==== + +.. autoclass:: gpiozero.pins.rpio.RPIOFactory .. autoclass:: gpiozero.pins.rpio.RPIOPin -PiGPIOPin -========= +PiGPIO +====== + +.. autoclass:: gpiozero.pins.pigpiod.PiGPIOFactory .. autoclass:: gpiozero.pins.pigpiod.PiGPIOPin -NativePin -========= +Native +====== + +.. autoclass:: gpiozero.pins.native.NativeFactory .. autoclass:: gpiozero.pins.native.NativePin -Abstract Pin +Base classes ============ +.. autoclass:: Factory + :members: + .. autoclass:: Pin :members: - -Local Pin -========= - -.. autoclass:: LocalPin +.. autoclass:: SPI :members: diff --git a/docs/images/composed_devices.pdf b/docs/images/composed_devices.pdf index 387e179ef6a7d42e38ded90c51285360a37ab9fb..6bdefbafe7b5c35e14591023a97c18df99aa53ac 100644 GIT binary patch delta 8335 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 j55~w(!VdgTH9x=D|Kil*4 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 diff --git a/docs/images/composed_devices.png b/docs/images/composed_devices.png index 692c1b17f633b280d86da90b38fdf2c7bf85e321..d076f4d5a28bb2897b9579debb7e90bfbea3942f 100644 GIT binary patch literal 34875 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�Q+9uol#q(IdCz?WI`cUGvrzjOzX)LPlAsxc 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 diff --git a/docs/notes.rst b/docs/notes.rst index 7c4ba69..859647f 100644 --- a/docs/notes.rst +++ b/docs/notes.rst @@ -4,6 +4,7 @@ Notes .. currentmodule:: gpiozero + .. _keep-your-script-running: Keep your script running @@ -46,6 +47,7 @@ events to be detected:: button.when_pressed = hello pause() + Importing from GPIO Zero ======================== @@ -70,12 +72,15 @@ In this case, all references to items within GPIO Zero must be prefixed:: button = gpiozero.Button(2) + How can I tell what version of gpiozero I have installed? ========================================================= The gpiozero library relies on the setuptools package for installation services. You can use the setuptools ``pkg_resources`` API to query which -version of gpiozero is available in your Python environment like so:: +version of gpiozero is available in your Python environment like so: + +.. code-block:: pycon >>> from pkg_resources import require >>> require('gpiozero') @@ -89,7 +94,9 @@ the first entry in the list will be the version that ``import gpiozero`` will import. If you receive the error "No module named pkg_resources", you need to install -the ``pip`` utility. This can be done with the following command in Raspbian:: +the ``pip`` utility. This can be done with the following command in Raspbian: + +.. code-block:: console $ sudo apt-get install python-pip diff --git a/docs/recipes.rst b/docs/recipes.rst index 5c64dd3..93bb0bd 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -9,7 +9,7 @@ library. Please note that all recipes are written assuming Python 3. Recipes *may* work under Python 2, but no guarantees! -.. _pin_numbering: +.. _pin-numbering: Pin Numbering ============= @@ -429,7 +429,9 @@ functionality without the need to wire up your own LEDs (also useful because the power and activity LEDs are "known good"). Firstly you need to disable the usual triggers for the built-in LEDs. This can -be done from the terminal with the following commands:: +be done from the terminal with the following commands: + +.. code-block:: console $ echo none | sudo tee /sys/class/leds/led0/trigger $ echo gpio | sudo tee /sys/class/leds/led1/trigger @@ -439,7 +441,9 @@ Now you can control the LEDs with gpiozero like so: .. literalinclude:: examples/led_builtin.py To revert the LEDs to their usual purpose you can either reboot your Pi or -run the following commands:: +run the following commands: + +.. code-block:: console $ echo mmc0 | sudo tee /sys/class/leds/led0/trigger $ echo input | sudo tee /sys/class/leds/led1/trigger diff --git a/gpiozero/__init__.py b/gpiozero/__init__.py index e147943..31e8dc3 100644 --- a/gpiozero/__init__.py +++ b/gpiozero/__init__.py @@ -6,8 +6,9 @@ from __future__ import ( ) from .pins import ( + Factory, Pin, - LocalPin, + SPI, ) from .pins.data import ( PiBoardInfo, @@ -15,47 +16,9 @@ from .pins.data import ( PinInfo, pi_info, ) -from .exc import ( - GPIOZeroError, - DeviceClosed, - BadEventHandler, - BadWaitTime, - BadQueueLen, - CompositeDeviceError, - CompositeDeviceBadName, - CompositeDeviceBadOrder, - CompositeDeviceBadDevice, - SPIError, - SPIBadArgs, - EnergenieSocketMissing, - EnergenieBadSocket, - GPIODeviceError, - GPIODeviceClosed, - GPIOPinInUse, - GPIOPinMissing, - InputDeviceError, - OutputDeviceError, - OutputDeviceBadValue, - PinError, - PinInvalidFunction, - PinInvalidState, - PinInvalidPull, - PinInvalidEdges, - PinSetInput, - PinFixedPull, - PinEdgeDetectUnsupported, - PinPWMError, - PinPWMUnsupported, - PinPWMFixedValue, - PinUnknownPi, - PinMultiplePins, - PinNoPins, - GPIOZeroWarning, - SPIWarning, - SPISoftwareFallback, - PinWarning, - PinNonPhysical, -) +# Yes, import * is naughty, but exc imports nothing else so there's no cross +# contamination here ... and besides, have you *seen* the list lately?! +from .exc import * from .devices import ( Device, GPIODevice, diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 001f1d0..c8c5b49 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -10,15 +10,16 @@ str = type('') import os import atexit import weakref +import warnings from collections import namedtuple from itertools import chain from types import FunctionType -from threading import RLock +from threading import Lock import pkg_resources +from .pins import Pin from .threads import _threads_shutdown -from .pins import _pins_shutdown from .mixins import ( ValuesMixin, SharedMixin, @@ -32,52 +33,11 @@ from .exc import ( GPIOPinMissing, GPIOPinInUse, GPIODeviceClosed, + PinFactoryFallback, ) from .compat import frozendict -def _default_pin_factory(name=os.getenv('GPIOZERO_PIN_FACTORY', None)): - group = 'gpiozero_pin_factories' - if name is None: - # If no factory is explicitly specified, try various names in - # "preferred" order. Note that in this case we only select from - # gpiozero distribution so without explicitly specifying a name (via - # the environment) it's impossible to auto-select a factory from - # outside the base distribution - # - # We prefer RPi.GPIO here as it supports PWM, and all Pi revisions. If - # no third-party libraries are available, however, we fall back to a - # pure Python implementation which supports platforms like PyPy - dist = pkg_resources.get_distribution('gpiozero') - for name in ('RPiGPIOPin', 'RPIOPin', 'PiGPIOPin', 'NativePin'): - try: - return pkg_resources.load_entry_point(dist, group, name) - except ImportError: - pass - raise BadPinFactory('Unable to locate any default pin factory!') - else: - for factory in pkg_resources.iter_entry_points(group, name): - return factory.load() - raise BadPinFactory('Unable to locate pin factory "%s"' % name) - -pin_factory = _default_pin_factory() - - -_PINS = set() -_PINS_LOCK = RLock() # Yes, this needs to be re-entrant - -def _shutdown(): - _threads_shutdown() - with _PINS_LOCK: - while _PINS: - _PINS.pop().close() - # Any cleanup routines registered by pins libraries must be called *after* - # cleanup of pin objects used by devices - _pins_shutdown() - -atexit.register(_shutdown) - - class GPIOMeta(type): # NOTE Yes, this is a metaclass. Don't be scared - it's a simple one. @@ -106,7 +66,7 @@ class GPIOMeta(type): # already exists. Only construct the instance if the key's new. key = cls._shared_key(*args, **kwargs) try: - self = cls._INSTANCES[key] + self = cls._instances[key] self._refs += 1 except (KeyError, ReferenceError) as e: self = super(GPIOMeta, cls).__call__(*args, **kwargs) @@ -122,14 +82,14 @@ class GPIOMeta(type): old_close() finally: try: - del cls._INSTANCES[key] + del cls._instances[key] except KeyError: # If the _refs go negative (too many closes) # just ignore the resulting KeyError here - # it's already gone pass self.close = close - cls._INSTANCES[key] = weakref.proxy(self) + cls._instances[key] = weakref.proxy(self) else: # Construct the instance as normal self = super(GPIOMeta, cls).__call__(*args, **kwargs) @@ -229,13 +189,100 @@ class GPIOBase(GPIOMeta(nstr('GPIOBase'), (), {})): class Device(ValuesMixin, GPIOBase): """ Represents a single device of any type; GPIO-based, SPI-based, I2C-based, - etc. This is the base class of the device hierarchy. It defines the - basic services applicable to all devices (specifically the :attr:`is_active` + etc. This is the base class of the device hierarchy. It defines the basic + services applicable to all devices (specifically the :attr:`is_active` property, the :attr:`value` property, and the :meth:`close` method). """ + _pin_factory = None # instance of a Factory sub-class + _reservations = {} # maps pin addresses to lists of devices + _res_lock = Lock() + def __repr__(self): return "" % (self.__class__.__name__) + @classmethod + def _set_pin_factory(cls, new_factory): + if cls._pin_factory is not None: + cls._pin_factory.close() + cls._pin_factory = new_factory + + def _reserve_pins(self, *pins_or_addresses): + """ + Called to indicate that the device reserves the right to use the + specified *pins_or_addresses*. This should be done during device + construction. If pins are reserved, you must ensure that the + reservation is released by eventually called :meth:`_release_pins`. + + The *pins_or_addresses* can be actual :class:`Pin` instances or the + addresses of pin instances (each address is a tuple of strings). The + latter form is permitted to ensure that devices do not have to + construct :class:`Pin` objects to reserve pins. This is important as + constructing a pin often configures it (e.g. as an input) which + conflicts with alternate pin functions like SPI. + """ + addresses = ( + p.address if isinstance(p, Pin) else p + for p in pins_or_addresses + ) + with self._res_lock: + for address in addresses: + try: + conflictors = self._reservations[address] + except KeyError: + conflictors = [] + self._reservations[address] = conflictors + for device_ref in conflictors: + device = device_ref() + if device is not None and self._conflicts_with(device): + raise GPIOPinInUse( + 'pin %s is already in use by %r' % ( + '/'.join(address), device) + ) + conflictors.append(weakref.ref(self)) + + def _release_pins(self, *pins_or_addresses): + """ + Releases the reservation of this device against *pins_or_addresses*. + This is typically called during :meth:`close` to clean up reservations + taken during construction. Releasing a reservation that is not + currently held will be silently ignored (to permit clean-up after + failed / partial construction). + """ + addresses = ( + p.address if isinstance(p, Pin) else p + for p in pins_or_addresses + ) + with self._res_lock: + for address in addresses: + self._reservations[address] = [ + ref for ref in self._reservations[address] + if ref() not in (self, None) # may as well clean up dead refs + ] + + def _release_all(self): + """ + Releases all pin reservations taken out by this device. See + :meth:`_release_pins` for further information). + """ + with self._res_lock: + Device._reservations = { + address: [ + ref for ref in conflictors + if ref() not in (self, None) + ] + for address, conflictors in self._reservations.items() + } + + def _conflicts_with(self, other): + """ + Called by :meth:`_reserve_pin` to test whether the *other* + :class:`Device` using a common pin conflicts with this device's intent + to use it. The default is ``True`` indicating that all devices conflict + with common pins. Sub-classes may override this to permit more nuanced + replies. + """ + return True + @property def value(self): """ @@ -378,14 +425,12 @@ class GPIODevice(Device): self._pin = None if pin is None: raise GPIOPinMissing('No pin given') - if isinstance(pin, int): - pin = pin_factory(pin) - with _PINS_LOCK: - if pin in _PINS: - raise GPIOPinInUse( - 'pin %r is already in use by another gpiozero object' % pin - ) - _PINS.add(pin) + if isinstance(pin, Pin): + self._reserve_pins(pin) + else: + # Check you can reserve *before* constructing the pin + self._reserve_pins(self._pin_factory.pin_address(pin)) + pin = self._pin_factory.pin(pin) self._pin = pin self._active_state = True self._inactive_state = False @@ -402,12 +447,10 @@ class GPIODevice(Device): def close(self): super(GPIODevice, self).close() - with _PINS_LOCK: - pin = self._pin + if self._pin is not None: + self._release_pins(self._pin) + self._pin.close() self._pin = None - if pin in _PINS: - _PINS.remove(pin) - pin.close() @property def closed(self): @@ -441,3 +484,41 @@ class GPIODevice(Device): except DeviceClosed: return "" % self.__class__.__name__ + +# Defined last to ensure Device is defined before attempting to load any pin +# factory; pin factories want to load spi which in turn relies on devices (for +# the soft-SPI implementation) +def _default_pin_factory(name=os.getenv('GPIOZERO_PIN_FACTORY', None)): + group = 'gpiozero_pin_factories' + if name is None: + # If no factory is explicitly specified, try various names in + # "preferred" order. Note that in this case we only select from + # gpiozero distribution so without explicitly specifying a name (via + # the environment) it's impossible to auto-select a factory from + # outside the base distribution + # + # We prefer RPi.GPIO here as it supports PWM, and all Pi revisions. If + # no third-party libraries are available, however, we fall back to a + # pure Python implementation which supports platforms like PyPy + dist = pkg_resources.get_distribution('gpiozero') + for name in ('rpigpio', 'rpio', 'pigpio', 'native'): + try: + return pkg_resources.load_entry_point(dist, group, name)() + except Exception as e: + warnings.warn( + PinFactoryFallback( + 'Failed to load factory %s: %s' % (name, str(e)))) + raise BadPinFactory('Unable to load any default pin factory!') + else: + for factory in pkg_resources.iter_entry_points(group, name.lower()): + return factory.load()() + raise BadPinFactory('Unable to find pin factory "%s"' % name) + +Device._set_pin_factory(_default_pin_factory()) + +def _shutdown(): + _threads_shutdown() + Device._set_pin_factory(None) + +atexit.register(_shutdown) + diff --git a/gpiozero/exc.py b/gpiozero/exc.py index aedc96f..9ed9361 100644 --- a/gpiozero/exc.py +++ b/gpiozero/exc.py @@ -52,6 +52,24 @@ class SPIBadArgs(SPIError, ValueError): class SPIBadChannel(SPIError, ValueError): "Error raised when an invalid channel is given to an :class:`AnalogInputDevice`" +class SPIFixedClockMode(SPIError, AttributeError): + "Error raised when the SPI clock mode cannot be changed" + +class SPIInvalidClockMode(SPIError, ValueError): + "Error raised when an invalid clock mode is given to an SPI implementation" + +class SPIFixedBitOrder(SPIError, AttributeError): + "Error raised when the SPI bit-endianness cannot be changed" + +class SPIFixedSelect(SPIError, AttributeError): + "Error raised when the SPI select polarity cannot be changed" + +class SPIFixedWordSize(SPIError, AttributeError): + "Error raised when the number of bits per word cannot be changed" + +class SPIInvalidWordSize(SPIError, ValueError): + "Error raised when an invalid (out of range) number of bits per word is specified" + class GPIODeviceError(GPIOZeroError): "Base class for errors specific to the GPIODevice hierarchy" @@ -62,7 +80,7 @@ class GPIOPinInUse(GPIODeviceError): "Error raised when attempting to use a pin already in use by another device" class GPIOPinMissing(GPIODeviceError, ValueError): - "Error raised when a pin number is not specified" + "Error raised when a pin specification is not given" class InputDeviceError(GPIODeviceError): "Base class for errors specific to the InputDevice hierarchy" @@ -100,6 +118,12 @@ class PinFixedPull(PinError, AttributeError): class PinEdgeDetectUnsupported(PinError, AttributeError): "Error raised when attempting to use edge detection on unsupported pins" +class PinGPIOUnsupported(PinError, NotImplementedError): + "Error raised when attempting to obtain a GPIO interface on unsupported pins" + +class PinSPIUnsupported(PinError, NotImplementedError): + "Error raised when attempting to obtain an SPI interface on unsupported pins" + class PinPWMError(PinError): "Base class for errors related to PWM implementations" @@ -118,6 +142,9 @@ class PinMultiplePins(PinError, RuntimeError): class PinNoPins(PinError, RuntimeError): "Error raised when no pins support the requested function" +class PinInvalidPin(PinError, ValueError): + "Error raised when an invalid pin specification is provided" + class GPIOZeroWarning(Warning): "Base class for all warnings in GPIO Zero" @@ -130,6 +157,9 @@ class SPISoftwareFallback(SPIWarning): class PinWarning(GPIOZeroWarning): "Base class for warnings related to pin implementations" +class PinFactoryFallback(PinWarning): + "Warning raised when a default pin factory fails to load and a fallback is tried" + class PinNonPhysical(PinWarning): "Warning raised when a non-physical pin is specified in a constructor" diff --git a/gpiozero/input_devices.py b/gpiozero/input_devices.py index 8a4e592..e65b769 100644 --- a/gpiozero/input_devices.py +++ b/gpiozero/input_devices.py @@ -165,7 +165,7 @@ class SmoothedInputDevice(EventsMixin, InputDevice): if self.partial or self._queue.full.is_set(): return super(SmoothedInputDevice, self).__repr__() else: - return "" % ( + return "" % ( self.__class__.__name__, self.pin, self.pull_up) @property @@ -240,7 +240,7 @@ class Button(HoldMixin, DigitalInputDevice): print("The button was pressed!") :param int pin: - The GPIO pin which the button is attached to. See :ref:`pin_numbering` + The GPIO pin which the button is attached to. See :ref:`pin-numbering` for valid pin numbers. :param bool pull_up: @@ -302,7 +302,7 @@ class LineSensor(SmoothedInputDevice): pause() :param int pin: - The GPIO pin which the sensor is attached to. See :ref:`pin_numbering` + The GPIO pin which the sensor is attached to. See :ref:`pin-numbering` for valid pin numbers. :param int queue_len: @@ -371,7 +371,7 @@ class MotionSensor(SmoothedInputDevice): print("Motion detected!") :param int pin: - The GPIO pin which the sensor is attached to. See :ref:`pin_numbering` + The GPIO pin which the sensor is attached to. See :ref:`pin-numbering` for valid pin numbers. :param int queue_len: @@ -435,7 +435,7 @@ class LightSensor(SmoothedInputDevice): print("Light detected!") :param int pin: - The GPIO pin which the sensor is attached to. See :ref:`pin_numbering` + The GPIO pin which the sensor is attached to. See :ref:`pin-numbering` for valid pin numbers. :param int queue_len: @@ -543,11 +543,11 @@ class DistanceSensor(SmoothedInputDevice): :param int echo: The GPIO pin which the ECHO pin is attached to. See - :ref:`pin_numbering` for valid pin numbers. + :ref:`pin-numbering` for valid pin numbers. :param int trigger: The GPIO pin which the TRIG pin is attached to. See - :ref:`pin_numbering` for valid pin numbers. + :ref:`pin-numbering` for valid pin numbers. :param int queue_len: The length of the queue used to store values read from the sensor. diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index a2e390e..669617f 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -127,7 +127,7 @@ class SharedMixin(object): When :meth:`close` is called, an internal reference counter will be decremented and the instance will only close when it reaches zero. """ - _INSTANCES = {} + _instances = {} def __del__(self): self._refs = 0 diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 1b3c2e2..9c24ba6 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -128,8 +128,8 @@ class DigitalOutputDevice(OutputDevice): """ def __init__(self, pin=None, active_high=True, initial_value=False): self._blink_thread = None - super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value) self._controller = None + super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value) @property def value(self): @@ -217,7 +217,7 @@ class LED(DigitalOutputDevice): led.on() :param int pin: - The GPIO pin which the LED is attached to. See :ref:`pin_numbering` for + The GPIO pin which the LED is attached to. See :ref:`pin-numbering` for valid pin numbers. :param bool active_high: @@ -252,7 +252,7 @@ class Buzzer(DigitalOutputDevice): bz.on() :param int pin: - The GPIO pin which the buzzer is attached to. See :ref:`pin_numbering` + The GPIO pin which the buzzer is attached to. See :ref:`pin-numbering` for valid pin numbers. :param bool active_high: @@ -276,7 +276,7 @@ class PWMOutputDevice(OutputDevice): Generic output device configured for pulse-width modulation (PWM). :param int pin: - The GPIO pin which the device is attached to. See :ref:`pin_numbering` + The GPIO pin which the device is attached to. See :ref:`pin-numbering` for valid pin numbers. :param bool active_high: @@ -483,7 +483,7 @@ class PWMLED(PWMOutputDevice): an optional resistor to prevent the LED from burning out. :param int pin: - The GPIO pin which the LED is attached to. See :ref:`pin_numbering` for + The GPIO pin which the LED is attached to. See :ref:`pin-numbering` for valid pin numbers. :param bool active_high: @@ -562,8 +562,12 @@ class RGBLED(SourceMixin, Device): raise GPIOPinMissing('red, green, and blue pins must be provided') LEDClass = PWMLED if pwm else LED super(RGBLED, self).__init__() - self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) - self.value = initial_value + try: + self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) + self.value = initial_value + except: + self.close() + raise red = _led_property(0) green = _led_property(1) @@ -926,7 +930,7 @@ class Servo(SourceMixin, CompositeDevice): sleep(1) :param int pin: - The GPIO pin which the device is attached to. See :ref:`pin_numbering` + The GPIO pin which the device is attached to. See :ref:`pin-numbering` for valid pin numbers. :param float initial_value: @@ -1116,7 +1120,7 @@ class AngularServo(Servo): expectations of minimum and maximum. :param int pin: - The GPIO pin which the device is attached to. See :ref:`pin_numbering` + The GPIO pin which the device is attached to. See :ref:`pin-numbering` for valid pin numbers. :param float initial_angle: diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index 3503145..f88cb11 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -1,3 +1,5 @@ +# vim: set fileencoding=utf-8: + from __future__ import ( unicode_literals, absolute_import, @@ -6,32 +8,124 @@ from __future__ import ( ) str = type('') -import io - -from .data import pi_info from ..exc import ( PinInvalidFunction, PinSetInput, PinFixedPull, + PinSPIUnsupported, PinPWMUnsupported, PinEdgeDetectUnsupported, + SPIFixedClockMode, + SPIFixedBitOrder, + SPIFixedSelect, + SPIFixedWordSize, ) -PINS_CLEANUP = [] -def _pins_shutdown(): - for routine in PINS_CLEANUP: - routine() +class Factory(object): + """ + Generates pins, SPI, and I2C interfaces for devices. This is an abstract + base class for pin factories. Descendents must override: + + * :meth:`_get_address` + * :meth:`pin_address` + + Descendents may override: + + * :meth:`close` + * :meth:`pin` + * :meth:`spi` + * :meth:`_get_pi_info` + """ + + def close(self): + """ + Closes the pin factory. This is expected to clean up all resources + manipulated by the factory. It it typically called at script + termination. + """ + pass + + def pin(self, spec): + """ + Creates an instance of a :class:`Pin` descendent representing the + specified pin. + + .. warning:: + + Descendents must ensure that pin instances representing the same + hardware are identical; i.e. two separate invocations of + :meth:`pin` for the same pin specification must return the same + object. + """ + raise PinGPIOUnsupported("GPIO not supported by this pin factory") + + def pin_address(self, spec): + """ + Returns the address that a pin *would* have if constructed from the + given *spec*. + + This unusual method is used by the pin reservation system to check + for conflicts *prior* to pin construction; with most implementations, + pin construction implicitly alters the state of the pin (e.g. setting + it to an input). This allows pin reservation to take place without + affecting the state of other components. + """ + raise NotImplementedError + + def spi(self, **spi_args): + """ + Returns an instance of an :class:`SPI` interface, for the specified SPI + *port* and *device*, or for the specified pins (*clock_pin*, + *mosi_pin*, *miso_pin*, and *select_pin*). Only one of the schemes can + be used; attempting to mix *port* and *device* with pin numbers will + raise :exc:`SPIBadArgs`. + """ + raise PinSPIUnsupported('SPI not supported by this pin factory') + + def _get_address(self): + raise NotImplementedError + + address = property( + lambda self: self._get_address(), + doc="""\ + Returns a tuple of strings representing the address of the factory. + For the Pi itself this is a tuple of one string representing the Pi's + address (e.g. "localhost"). Expander chips can return a tuple appending + whatever string they require to uniquely identify the expander chip + amongst all factories in the system. + + .. note:: + + This property *must* return an immutable object capable of being + used as a dictionary key. + """) + + def _get_pi_info(self): + return None + + pi_info = property( + lambda self: self._get_pi_info(), + doc="""\ + Returns a :class:`PiBoardInfo` instance representing the Pi that + instances generated by this factory will be attached to. + + If the pins represented by this class are not *directly* attached to a + Pi (e.g. the pin is attached to a board attached to the Pi, or the pins + are not on a Pi at all), this may return ``None``. + """) class Pin(object): """ - Abstract base class representing a GPIO pin or a pin from an IO extender. + Abstract base class representing a pin attached to some form of controller, + be it GPIO, SPI, ADC, etc. Descendents should override property getters and setters to accurately represent the capabilities of pins. The following functions *must* be overridden: + * :meth:`_get_address` * :meth:`_get_function` * :meth:`_set_function` * :meth:`_get_state` @@ -39,6 +133,8 @@ class Pin(object): The following functions *may* be overridden if applicable: * :meth:`close` + * :meth:`output_with_state` + * :meth:`input_with_pull` * :meth:`_set_state` * :meth:`_get_frequency` * :meth:`_set_frequency` @@ -50,20 +146,10 @@ class Pin(object): * :meth:`_set_edges` * :meth:`_get_when_changed` * :meth:`_set_when_changed` - * :meth:`pi_info` - * :meth:`output_with_state` - * :meth:`input_with_pull` - - .. warning:: - - Descendents must ensure that pin instances representing the same - physical hardware are identical, right down to object identity. The - framework relies on this to correctly clean up resources at interpreter - shutdown. """ def __repr__(self): - return "Abstract pin" + return self.address[-1] def close(self): """ @@ -105,6 +191,18 @@ class Pin(object): self.function = 'input' self.pull = pull + def _get_address(self): + raise NotImplementedError + + address = property( + lambda self: self._get_address(), + doc="""\ + The address of the pin. This property is a tuple of strings constructed + from the owning factory's address with the unique address of the pin + appended to it. The tuple as a whole uniquely identifies the pin + amongst all pins attached to the system. + """) + def _get_function(self): return "input" @@ -140,10 +238,19 @@ class Pin(object): doc="""\ The state of the pin. This is 0 for low, and 1 for high. As a low level view of the pin, no swapping is performed in the case of pull ups (see - :attr:`pull` for more information). + :attr:`pull` for more information): - If PWM is currently active (when :attr:`frequency` is not ``None``), - this represents the PWM duty cycle as a value between 0.0 and 1.0. + .. code-block:: text + + HIGH - - - - > ,---------------------- + | + | + LOW ----------------' + + Descendents which implement analog, or analog-like capabilities can + return values between 0 and 1. For example, pins implementing PWM + (where :attr:`frequency` is not ``None``) return a value between 0.0 + and 1.0 representing the current PWM duty cycle. If a pin is currently configured for input, and an attempt is made to set this attribute, :exc:`PinSetInput` will be raised. If an invalid @@ -205,6 +312,26 @@ class Pin(object): detection, measured in seconds. If bounce detection is not currently in use, this is ``None``. + For example, if :attr:`edge` is currently "rising", :attr:`bounce` is + currently 5/1000 (5ms), then the waveform below will only fire + :attr:`when_changed` on two occasions despite there being three rising + edges: + + .. code-block:: text + + TIME 0...1...2...3...4...5...6...7...8...9...10..11..12 ms + + bounce elimination |===================| |============== + + HIGH - - - - > ,--. ,--------------. ,--. + | | | | | | + | | | | | | + LOW ----------------' `-' `-' `----------- + : : + : : + when_changed when_changed + fires fires + If the pin does not support edge detection, attempts to set this property will raise :exc:`PinEdgeDetectUnsupported`. If the pin supports edge detection, the class must implement bounce detection, @@ -223,7 +350,18 @@ class Pin(object): doc="""\ The edge that will trigger execution of the function or bound method assigned to :attr:`when_changed`. This can be one of the strings - "both" (the default), "rising", "falling", or "none". + "both" (the default), "rising", "falling", or "none": + + .. code-block:: text + + HIGH - - - - > ,--------------. + | | + | | + LOW --------------------' `-------------- + : : + : : + Fires when_changed "both" "both" + when edges is ... "rising" "falling" If the pin does not support edge detection, attempts to set this property will raise :exc:`PinEdgeDetectUnsupported`. @@ -247,48 +385,300 @@ class Pin(object): property will raise :exc:`PinEdgeDetectUnsupported`. """) - @classmethod - def pi_info(cls): - """ - Returns a :class:`PiBoardInfo` instance representing the Pi that - instances of this pin class will be attached to. - If the pins represented by this class are not *directly* attached to a - Pi (e.g. the pin is attached to a board attached to the Pi, or the pins - are not on a Pi at all), this may return ``None``. - """ - return None - - -class LocalPin(Pin): +class SPI(object): """ - Abstract base class representing pins attached locally to a Pi. This forms - the base class for local-only pin interfaces (:class:`RPiGPIOPin`, - :class:`RPIOPin`, and :class:`NativePin`). + Abstract interface for `Serial Peripheral Interface`_ (SPI) implementations. + Descendents *must* override the following: + + * :meth:`transfer` + * :meth:`_get_clock_mode` + + Descendents *may* override the following methods: + + * :meth:`read` + * :meth:`write` + * :meth:`_set_clock_mode` + * :meth:`_get_lsb_first` + * :meth:`_set_lsb_first` + * :meth:`_get_select_high` + * :meth:`_set_select_high` + * :meth:`_get_bits_per_word` + * :meth:`_set_bits_per_word` + + .. _Serial Peripheral Interface: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus """ - _PI_REVISION = None - @classmethod - def pi_info(cls): + def read(self, n): """ - Returns a :class:`PiBoardInfo` instance representing the local Pi. - The Pi's revision is determined by reading :file:`/proc/cpuinfo`. If - no valid revision is found, returns ``None``. - """ - # Cache the result as we can reasonably assume it won't change during - # runtime (this is LocalPin after all; descendents that deal with - # remote Pis should inherit from Pin instead) - if cls._PI_REVISION is None: - with io.open('/proc/cpuinfo', 'r') as f: - for line in f: - if line.startswith('Revision'): - revision = line.split(':')[1].strip().lower() - overvolted = revision.startswith('100') - if overvolted: - revision = revision[-4:] - cls._PI_REVISION = revision - break - if cls._PI_REVISION is None: - return None # something weird going on - return pi_info(cls._PI_REVISION) + Read *n* words of data from the SPI interface, returning them as a + sequence of unsigned ints, each no larger than the configured + :attr:`bits_per_word` of the interface. + + This method is typically used with read-only devices that feature + half-duplex communication. See :meth:`transfer` for full duplex + communication. + """ + return self.transfer((0,) * n) + + def write(self, data): + """ + Write *data* to the SPI interface. *data* must be a sequence of + unsigned integer words each of which will fit within the configured + :attr:`bits_per_word` of the interface. The method returns the number + of words written to the interface (which may be less than or equal to + the length of *data*). + + This method is typically used with write-only devices that feature + half-duplex communication. See :meth:`transfer` for full duplex + communication. + """ + return len(self.transfer(data)) + + def transfer(self, data): + """ + Write *data* to the SPI interface. *data* must be a sequence of + unsigned integer words each of which will fit within the configured + :attr:`bits_per_word` of the interface. The method returns the sequence + of words read from the interface while writing occurred (full duplex + communication). + + The length of the sequence returned dictates the number of words of + *data* written to the interface. Each word in the returned sequence + will be an unsigned integer no larger than the configured + :attr:`bits_per_word` of the interface. + """ + raise NotImplementedError + + @property + def clock_polarity(self): + """ + The polarity of the SPI clock pin. If this is ``False`` (the default), + the clock pin will idle low, and pulse high. Setting this to ``True`` + will cause the clock pin to idle high, and pulse low. On many data + sheets this is documented as the CPOL value. + + The following diagram illustrates the waveform when + :attr:`clock_polarity` is ``False`` (the default), equivalent to CPOL + 0: + + .. code-block:: text + + on on on on on on on + ,---. ,---. ,---. ,---. ,---. ,---. ,---. + CLK | | | | | | | | | | | | | | + | | | | | | | | | | | | | | + ------' `---' `---' `---' `---' `---' `---' `------ + idle off off off off off off idle + + The following diagram illustrates the waveform when + :attr:`clock_polarity` is ``True``, equivalent to CPOL 1: + + .. code-block:: text + + idle off off off off off off idle + ------. ,---. ,---. ,---. ,---. ,---. ,---. ,------ + | | | | | | | | | | | | | | + CLK | | | | | | | | | | | | | | + `---' `---' `---' `---' `---' `---' `---' + on on on on on on on + """ + return bool(self.clock_mode & 2) + + @clock_polarity.setter + def clock_polarity(self, value): + self.clock_mode = self.clock_mode & (~2) | (bool(value) << 1) + + @property + def clock_phase(self): + """ + The phase of the SPI clock pin. If this is ``False`` (the default), + data will be read from the MISO pin when the clock pin activates. + Setting this to ``True`` will cause data to be read from the MISO pin + when the clock pin deactivates. On many data sheets this is documented + as the CPHA value. Whether the clock edge is rising or falling when the + clock is considered activated is controlled by the + :attr:`clock_polarity` attribute (corresponding to CPOL). + + The following diagram indicates when data is read when + :attr:`clock_polarity` is ``False``, and :attr:`clock_phase` is + ``False`` (the default), equivalent to CPHA 0: + + .. code-block:: text + + ,---. ,---. ,---. ,---. ,---. ,---. ,---. + CLK | | | | | | | | | | | | | | + | | | | | | | | | | | | | | + ----' `---' `---' `---' `---' `---' `---' `------- + : : : : : : : + MISO---. ,---. ,---. ,---. ,---. ,---. ,---. + / \ / \ / \ / \ / \ / \ / \\ + -{ Bit X Bit X Bit X Bit X Bit X Bit X Bit }------ + \ / \ / \ / \ / \ / \ / \ / + `---' `---' `---' `---' `---' `---' `---' + + The following diagram indicates when data is read when + :attr:`clock_polarity` is ``False``, but :attr:`clock_phase` is + ``True``, equivalent to CPHA 1: + + .. code-block:: text + + ,---. ,---. ,---. ,---. ,---. ,---. ,---. + CLK | | | | | | | | | | | | | | + | | | | | | | | | | | | | | + ----' `---' `---' `---' `---' `---' `---' `------- + : : : : : : : + MISO ,---. ,---. ,---. ,---. ,---. ,---. ,---. + / \ / \ / \ / \ / \ / \ / \\ + -----{ Bit X Bit X Bit X Bit X Bit X Bit X Bit }-- + \ / \ / \ / \ / \ / \ / \ / + `---' `---' `---' `---' `---' `---' `---' + """ + return bool(self.clock_mode & 1) + + @clock_phase.setter + def clock_phase(self, value): + self.clock_mode = self.clock_mode & (~1) | bool(value) + + def _get_clock_mode(self): + raise NotImplementedError + + def _set_clock_mode(self, value): + raise SPIFixedClockMode("clock_mode cannot be changed on %r" % self) + + clock_mode = property( + lambda self: self._get_clock_mode(), + lambda self, value: self._set_clock_mode(value), + doc="""\ + Presents a value representing the :attr:`clock_polarity` and + :attr:`clock_phase` attributes combined according to the following + table: + + +------+-----------------+--------------+ + | mode | polarity (CPOL) | phase (CPHA) | + +======+=================+==============+ + | 0 | False | False | + | 1 | False | True | + | 2 | True | False | + | 3 | True | True | + +------+-----------------+--------------+ + + Adjusting this value adjusts both the :attr:`clock_polarity` and + :attr:`clock_phase` attributes simultaneously. + """) + + def _get_lsb_first(self): + return False + + def _set_lsb_first(self, value): + raise SPIFixedBitOrder("lsb_first cannot be changed on %r" % self) + + lsb_first = property( + lambda self: self._get_lsb_first(), + lambda self, value: self._set_lsb_first(value), + doc="""\ + Controls whether words are read and written LSB in (Least Significant + Bit first) order. The default is ``False`` indicating that words are + read and written in MSB (Most Significant Bit first) order. + Effectively, this controls the `Bit endianness`_ of the connection. + + The following diagram shows the a word containing the number 5 (binary + 0101) transmitted on MISO with :attr:`bits_per_word` set to 4, and + :attr:`clock_mode` set to 0, when :attr:`lsb_first` is ``False`` (the + default): + + .. code-block:: text + + ,---. ,---. ,---. ,---. + CLK | | | | | | | | + | | | | | | | | + ----' `---' `---' `---' `----- + : ,-------. : ,-------. + MISO: | : | : | : | + : | : | : | : | + ----------' : `-------' : `---- + : : : : + MSB LSB + + And now with :attr:`lsb_first` set to ``True`` (and all other + parameters the same): + + .. code-block:: text + + ,---. ,---. ,---. ,---. + CLK | | | | | | | | + | | | | | | | | + ----' `---' `---' `---' `----- + ,-------. : ,-------. : + MISO: | : | : | : + | : | : | : | : + --' : `-------' : `----------- + : : : : + LSB MSB + + .. _Bit endianness: https://en.wikipedia.org/wiki/Endianness#Bit_endianness + """) + + def _get_select_high(self): + return False + + def _set_select_high(self, value): + raise SPIFixedSelect("select_high cannot be changed on %r" % self) + + select_high = property( + lambda self: self._get_select_high(), + lambda self, value: self._set_select_high(value), + doc="""\ + If ``False`` (the default), the chip select line is considered active + when it is pulled low. When set to ``True``, the chip select line is + considered active when it is driven high. + + The following diagram shows the waveform of the chip select line, and + the clock when :attr:`clock_polarity` is ``False``, and + :attr:`select_high` is ``False`` (the default): + + .. code-block:: text + + ---. ,------ + __ | | + CS | chip is selected, and will react to clock | idle + `-----------------------------------------------------' + + ,---. ,---. ,---. ,---. ,---. ,---. ,---. + CLK | | | | | | | | | | | | | | + | | | | | | | | | | | | | | + ----' `---' `---' `---' `---' `---' `---' `------- + + And when :attr:`select_high` is ``True``: + + .. code-block:: text + + ,-----------------------------------------------------. + CS | chip is selected, and will react to clock | idle + | | + ---' `------ + + ,---. ,---. ,---. ,---. ,---. ,---. ,---. + CLK | | | | | | | | | | | | | | + | | | | | | | | | | | | | | + ----' `---' `---' `---' `---' `---' `---' `------- + """) + + def _get_bits_per_word(self): + return 8 + + def _set_bits_per_word(self, value): + raise SPIFixedWordSize("bits_per_word cannot be changed on %r" % self) + + bits_per_word = property( + lambda self: self._get_bits_per_word(), + lambda self, value: self._set_bits_per_word(value), + doc="""\ + Controls the number of bits that make up a word, and thus where the + word boundaries appear in the data stream, and the maximum value of a + word. Defaults to 8 meaning that words are effectively bytes. + + Several implementations do not support non-byte-sized words. + """) + diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 03d046e..4dbbda3 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -13,7 +13,7 @@ from itertools import cycle from operator import attrgetter from collections import namedtuple -from ..exc import PinUnknownPi, PinMultiplePins, PinNoPins +from ..exc import PinUnknownPi, PinMultiplePins, PinNoPins, PinInvalidPin # Some useful constants for describing pins @@ -119,8 +119,8 @@ A_BOARD = """\ BPLUS_BOARD = """\ {style:white on green},--------------------------------.{style:reset} -{style:white on green}| {P1:{style} col2}{style:white on green} P1 {style:black on white}+===={style:reset} -{style:white on green}| {P1:{style} col1}{style:white on green} {style:black on white}| USB{style:reset} +{style:white on green}| {J8:{style} col2}{style:white on green} J8 {style:black on white}+===={style:reset} +{style:white on green}| {J8:{style} col1}{style:white on green} {style:black on white}| USB{style:reset} {style:white on green}| {style:black on white}+===={style:reset} {style:white on green}| {style:bold}Pi Model {model:2s} V{pcb_revision:3s}{style:normal} |{style:reset} {style:white on green}| {style:on black}+----+{style:on green} {style:black on white}+===={style:reset} @@ -134,8 +134,8 @@ BPLUS_BOARD = """\ APLUS_BOARD = """\ {style:white on green},--------------------------.{style:reset} -{style:white on green}| {P1:{style} col2}{style:white on green} P1 |{style:reset} -{style:white on green}| {P1:{style} col1}{style:white on green} |{style:reset} +{style:white on green}| {J8:{style} col2}{style:white on green} J8 |{style:reset} +{style:white on green}| {J8:{style} col1}{style:white on green} |{style:reset} {style:white on green}| |{style:reset} {style:white on green}| {style:bold}Pi Model {model:2s} V{pcb_revision:3s}{style:normal} |{style:reset} {style:white on green}| {style:on black}+----+{style:on green} {style:black on white}+===={style:reset} @@ -149,8 +149,8 @@ APLUS_BOARD = """\ ZERO12_BOARD = """\ {style:white on green},-------------------------.{style:reset} -{style:white on green}| {P1:{style} col2}{style:white on green} P1 |{style:reset} -{style:white on green}| {P1:{style} col1}{style:white on green} |{style:reset} +{style:white on green}| {J8:{style} col2}{style:white on green} J8 |{style:reset} +{style:white on green}| {J8:{style} col1}{style:white on green} |{style:reset} {style:black on white}---+{style:white on green} {style:on black}+---+{style:on green} {style:bold}PiZero{style:normal} |{style:reset} {style:black on white} sd|{style:white on green} {style:on black}|SoC|{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} |{style:reset} {style:black on white}---+|hdmi|{style:white on green} {style:on black}+---+{style:on green} {style:black on white}usb{style:on green} {style:black on white}pwr{style:white on green} |{style:reset} @@ -158,8 +158,8 @@ ZERO12_BOARD = """\ ZERO13_BOARD = """\ {style:white on green}.-------------------------.{style:reset} -{style:white on green}| {P1:{style} col2}{style:white on green} P1 |{style:reset} -{style:white on green}| {P1:{style} col1}{style:white on green} {style:black on white}|c{style:reset} +{style:white on green}| {J8:{style} col2}{style:white on green} J8 |{style:reset} +{style:white on green}| {J8:{style} col1}{style:white on green} {style:black on white}|c{style:reset} {style:black on white}---+{style:white on green} {style:on black}+---+{style:on green} {style:bold}Pi{model:6s}{style:normal}{style:black on white}|s{style:reset} {style:black on white} sd|{style:white on green} {style:on black}|SoC|{style:on green} {style:bold}V{pcb_revision:3s}{style:normal} {style:black on white}|i{style:reset} {style:black on white}---+|hdmi|{style:white on green} {style:on black}+---+{style:on green} {style:black on white}usb{style:on green} {style:on white}pwr{style:white on green} |{style:reset} @@ -216,7 +216,7 @@ REV2_P5 = { 7: (GND, False), 8: (GND, False), } -PLUS_P1 = { +PLUS_J8 = { 1: (V3_3, False), 2: (V5, False), 3: (GPIO2, True), 4: (V5, False), 5: (GPIO3, True), 6: (GND, False), @@ -379,12 +379,12 @@ PI_REVISIONS = { 0xd: ('B', '2.0', '2012Q4', 'BCM2835', 'Egoman', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5}, REV2_BOARD, ), 0xe: ('B', '2.0', '2012Q4', 'BCM2835', 'Sony', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5}, REV2_BOARD, ), 0xf: ('B', '2.0', '2012Q4', 'BCM2835', 'Qisda', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5}, REV2_BOARD, ), - 0x10: ('B+', '1.2', '2014Q3', 'BCM2835', 'Sony', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, BPLUS_BOARD, ), + 0x10: ('B+', '1.2', '2014Q3', 'BCM2835', 'Sony', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'J8': PLUS_J8}, BPLUS_BOARD, ), 0x11: ('CM', '1.1', '2014Q2', 'BCM2835', 'Sony', 512, 'eMMC', 1, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, CM_BOARD, ), - 0x12: ('A+', '1.1', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, APLUS_BOARD, ), - 0x13: ('B+', '1.2', '2015Q1', 'BCM2835', 'Egoman', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, BPLUS_BOARD, ), + 0x12: ('A+', '1.1', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'J8': PLUS_J8}, APLUS_BOARD, ), + 0x13: ('B+', '1.2', '2015Q1', 'BCM2835', 'Egoman', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'J8': PLUS_J8}, BPLUS_BOARD, ), 0x14: ('CM', '1.1', '2014Q2', 'BCM2835', 'Embest', 512, 'eMMC', 1, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, CM_BOARD, ), - 0x15: ('A+', '1.1', '2014Q4', 'BCM2835', 'Embest', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, APLUS_BOARD, ), + 0x15: ('A+', '1.1', '2014Q4', 'BCM2835', 'Embest', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'J8': PLUS_J8}, APLUS_BOARD, ), } @@ -529,7 +529,8 @@ class HeaderInfo(namedtuple('HeaderInfo', ( from gpiozero import * - print('{0:full}'.format(pi_info().headers['P1'])) + print('{0}'.format(pi_info().headers['J8'])) + print('{0:full}'.format(pi_info().headers['J8'])) print('{0:col2}'.format(pi_info().headers['P1'])) print('{0:row1}'.format(pi_info().headers['P1'])) @@ -537,10 +538,9 @@ class HeaderInfo(namedtuple('HeaderInfo', ( the use of `ANSI color codes`_. If neither is specified, ANSI codes will only be used if stdout is detected to be a tty:: - print('{0:color row2}'.format(pi_info().headers['P1'])) # force use of ANSI codes + print('{0:color row2}'.format(pi_info().headers['J8'])) # force use of ANSI codes print('{0:mono row2}'.format(pi_info().headers['P1'])) # force plain ASCII - .. _ANSI color codes: https://en.wikipedia.org/wiki/ANSI_escape_code The following attributes are defined: .. automethod:: pprint @@ -548,7 +548,7 @@ class HeaderInfo(namedtuple('HeaderInfo', ( .. attribute:: name The name of the header, typically as it appears silk-screened on the - board (e.g. "P1"). + board (e.g. "P1" or "J8"). .. attribute:: rows @@ -561,6 +561,8 @@ class HeaderInfo(namedtuple('HeaderInfo', ( .. attribute:: pins A dictionary mapping physical pin numbers to :class:`PinInfo` tuples. + + .. _ANSI color codes: https://en.wikipedia.org/wiki/ANSI_escape_code """ __slots__ = () # workaround python issue #24931 @@ -685,6 +687,7 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( from gpiozero import * + print('{0}'.format(pi_info())) print('{0:full}'.format(pi_info())) print('{0:board}'.format(pi_info())) print('{0:specs}'.format(pi_info())) @@ -801,8 +804,8 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( A dictionary which maps header labels to :class:`HeaderInfo` tuples. For example, to obtain information about header P1 you would query - ``headers['P1']``. To obtain information about pin 12 on header P1 you - would query ``headers['P1'].pins[12]``. + ``headers['P1']``. To obtain information about pin 12 on header J8 you + would query ``headers['J8'].pins[12]``. A rendered version of this data can be obtained by using the :class:`PiBoardInfo` object in a format string:: @@ -937,10 +940,10 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( }.get(model, csi) headers = { 'A': {'P1': REV2_P1, 'P5': REV2_P5}, - 'B': {'P1': REV2_P1, 'P5': REV2_P5} if pcb_revision == '2.0' else {'P1': REV1_P1}, + 'B': {'P1': REV1_P1} if pcb_revision == '1.0' else {'P1': REV2_P1, 'P5': REV2_P5}, 'CM': {'SODIMM': CM_SODIMM}, 'CM3': {'SODIMM': CM3_SODIMM}, - }.get(model, {'P1': PLUS_P1}) + }.get(model, {'J8': PLUS_J8}) board = { 'A': A_BOARD, 'B': REV1_BOARD if pcb_revision == '1.0' else REV2_BOARD, @@ -1115,8 +1118,8 @@ class PiBoardInfo(namedtuple('PiBoardInfo', ( """ Pretty-print a representation of the board along with header diagrams. - If *color* is ``None`` (the default, the diagram will include ANSI - color codes if stdout is a color-capable terminal). Otherwise *color* + If *color* is ``None`` (the default), the diagram will include ANSI + color codes if stdout is a color-capable terminal. Otherwise *color* can be set to ``True`` or ``False`` to force color or monochrome output. """ @@ -1134,13 +1137,10 @@ def pi_info(revision=None): the model of Pi it is running on and return information about that. """ if revision is None: - # NOTE: This import is declared locally for two reasons. Firstly it - # avoids a circular dependency (devices->pins->pins.data->devices). - # Secondly, pin_factory is one global which might potentially be - # re-written by a user's script at runtime hence we should re-import - # here in case it's changed since initialization - from ..devices import pin_factory - result = pin_factory.pi_info() + # The reason this import is located here is to avoid a circular + # dependency; devices->pins.local->pins.data->devices + from ..devices import Device + result = Device._pin_factory.pi_info if result is None: raise PinUnknownPi('The default pin_factory is not attached to a Pi') else: diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py new file mode 100644 index 0000000..f61f4eb --- /dev/null +++ b/gpiozero/pins/local.py @@ -0,0 +1,241 @@ +from __future__ import ( + unicode_literals, + absolute_import, + print_function, + division, + ) +str = type('') + +import io +import weakref +import warnings + +try: + from spidev import SpiDev +except ImportError: + SpiDev = None + +from . import SPI +from .pi import PiFactory, PiPin +from .spi import SPISoftwareBus +from ..devices import Device, SharedMixin +from ..output_devices import OutputDevice +from ..exc import DeviceClosed, PinUnknownPi, SPIInvalidClockMode + + +class LocalPiFactory(PiFactory): + """ + Abstract base class representing pins attached locally to a Pi. This forms + the base class for local-only pin interfaces (:class:`RPiGPIOPin`, + :class:`RPIOPin`, and :class:`NativePin`). + """ + pins = {} + + def __init__(self): + super(LocalPiFactory, self).__init__() + self.spi_hardware_class = LocalPiHardwareSPI + self.spi_software_class = LocalPiSoftwareSPI + self.shared_spi_hardware_class = LocalPiHardwareSPIShared + self.shared_spi_software_class = LocalPiSoftwareSPIShared + # Override the pins dict to be this class' pins dict. This is a bit of + # a dirty hack, but ensures that anyone evil enough to mix pin + # implementations doesn't try and control the same pin with different + # backends + self.pins = LocalPiFactory.pins + + def _get_address(self): + return ('localhost',) + + def _get_revision(self): + # Cache the result as we can reasonably assume it won't change during + # runtime (this is LocalPin after all; descendents that deal with + # remote Pis should inherit from Pin instead) + with io.open('/proc/cpuinfo', 'r') as f: + for line in f: + if line.startswith('Revision'): + revision = line.split(':')[1].strip().lower() + overvolted = revision.startswith('100') + if overvolted: + revision = revision[-4:] + return revision + raise PinUnknownPi('unable to locate Pi revision in /proc/cpuinfo') + + +class LocalPiPin(PiPin): + """ + Abstract base class representing a multi-function GPIO pin attached to the + local Raspberry Pi. + """ + pass + + +class LocalPiHardwareSPI(SPI, Device): + def __init__(self, factory, port, device): + if SpiDev is None: + raise ImportError('failed to import spidev') + self._port = port + self._device = device + self._intf = None + self._address = factory.address + ('SPI(port=%d, device=%d)' % (port, device),) + super(LocalPiHardwareSPI, self).__init__() + self._reserve_pins( + factory.pin_address(11), + factory.pin_address(10), + factory.pin_address(9), + factory.pin_address((8, 7)[device]) + ) + self._intf = SpiDev() + self._intf.open(port, device) + self._intf.max_speed_hz = 500000 + + def _conflicts_with(self, other): + return not ( + isinstance(other, LocalPiHardwareSPI) and + (self._port, self._device) != (other._port, other._device) + ) + + def close(self): + if self._intf: + try: + self._intf.close() + finally: + self._intf = None + self._release_all() + super(LocalPiHardwareSPI, self).close() + + @property + def closed(self): + return self._intf is None + + def __repr__(self): + try: + self._check_open() + return 'SPI(port=%d, device=%d)' % (self._port, self._device) + except DeviceClosed: + return 'SPI(closed)' + + def transfer(self, data): + """ + Writes data (a list of integer words where each word is assumed to have + :attr:`bits_per_word` bits or less) to the SPI interface, and reads an + equivalent number of words, returning them as a list of integers. + """ + return self._intf.xfer2(data) + + def _get_clock_mode(self): + return self._intf.mode + + def _set_clock_mode(self, value): + self._intf.mode = value + + def _get_lsb_first(self): + return self._intf.lsbfirst + + def _set_lsb_first(self, value): + self._intf.lsbfirst = bool(value) + + def _get_select_high(self): + return self._intf.cshigh + + def _set_select_high(self, value): + self._intf.cshigh = bool(value) + + def _get_bits_per_word(self): + return self._intf.bits_per_word + + def _set_bits_per_word(self, value): + self._intf.bits_per_word = value + + +class LocalPiSoftwareSPI(SPI, OutputDevice): + def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin): + self._bus = None + self._address = factory.address + ( + 'SPI(clock_pin=%d, mosi_pin=%d, miso_pin=%d, select_pin=%d)' % ( + clock_pin, mosi_pin, miso_pin, select_pin), + ) + super(LocalPiSoftwareSPI, self).__init__(select_pin, active_high=False) + try: + self._clock_phase = False + self._lsb_first = False + self._bits_per_word = 8 + self._bus = SPISoftwareBus(clock_pin, mosi_pin, miso_pin) + except: + self.close() + raise + + def close(self): + if self._bus: + self._bus.close() + self._bus = None + super(LocalPiSoftwareSPI, self).close() + + @property + def closed(self): + return self._bus is None + + def __repr__(self): + try: + self._check_open() + return 'SPI(clock_pin=%d, mosi_pin=%d, miso_pin=%d, select_pin=%d)' % ( + self._bus.clock.pin.number, + self._bus.mosi.pin.number, + self._bus.miso.pin.number, + self.pin.number) + except DeviceClosed: + return 'SPI(closed)' + + def transfer(self, data): + with self._bus.lock: + self.on() + try: + return self._bus.transfer( + data, self._clock_phase, self._lsb_first, self._bits_per_word) + finally: + self.off() + + def _get_clock_mode(self): + with self._bus.lock: + return (not self._bus.clock.active_high) << 1 | self._clock_phase + + def _set_clock_mode(self, value): + if not (0 <= value < 4): + raise SPIInvalidClockMode("%d is not a valid clock mode" % value) + with self._bus.lock: + self._bus.clock.active_high = not (value & 2) + self._clock_phase = bool(value & 1) + + def _get_lsb_first(self): + return self._lsb_first + + def _set_lsb_first(self, value): + self._lsb_first = bool(value) + + def _get_bits_per_word(self): + return self._bits_per_word + + def _set_bits_per_word(self, value): + if value < 1: + raise ValueError('bits_per_word must be positive') + self._bits_per_word = int(value) + + def _get_select_high(self): + return self.active_high + + def _set_select_high(self, value): + with self._bus.lock: + self.active_high = value + self.off() + + +class LocalPiHardwareSPIShared(SharedMixin, LocalPiHardwareSPI): + @classmethod + def _shared_key(cls, factory, port, device): + return (port, device) + + +class LocalPiSoftwareSPIShared(SharedMixin, LocalPiSoftwareSPI): + @classmethod + def _shared_key(cls, factory, clock_pin, mosi_pin, miso_pin, select_pin): + return (select_pin,) + diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index f12c8cc..8cced75 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -15,56 +15,28 @@ try: except ImportError: from ..compat import isclose -from . import Pin -from .data import pi_info -from ..exc import PinSetInput, PinPWMUnsupported, PinFixedPull +from ..exc import PinPWMUnsupported, PinSetInput, PinFixedPull +from ..devices import Device +from .pi import PiPin +from .local import LocalPiFactory PinState = namedtuple('PinState', ('timestamp', 'state')) -class MockPin(Pin): +class MockPin(PiPin): """ A mock pin used primarily for testing. This class does *not* support PWM. """ - _PINS = {} - - @classmethod - def clear_pins(cls): - cls._PINS.clear() - - @classmethod - def pi_info(cls): - return pi_info('a21041') # Pretend we're a Pi 2B - - def __new__(cls, number): - if not (0 <= number < 54): - raise ValueError('invalid pin %d specified (must be 0..53)' % number) - try: - old_pin = cls._PINS[number] - except KeyError: - self = super(MockPin, cls).__new__(cls) - cls._PINS[number] = self - self._number = number - self._function = 'input' - self._state = False - self._pull = 'floating' - self._bounce = None - self._edges = 'both' - self._when_changed = None - self.clear_states() - return self - # Ensure the pin class expected supports PWM (or not) - if issubclass(cls, MockPWMPin) != isinstance(old_pin, MockPWMPin): - raise ValueError('pin %d is already in use as a %s' % (number, old_pin.__class__.__name__)) - return old_pin - - def __repr__(self): - return 'MOCK%d' % self._number - - @property - def number(self): - return self._number + def __init__(self, factory, number): + super(MockPin, self).__init__(factory, number) + self._function = 'input' + self._state = False + self._pull = 'floating' + self._bounce = None + self._edges = 'both' + self._when_changed = None + self.clear_states() def close(self): self.when_changed = None @@ -186,8 +158,8 @@ class MockChargingPin(MockPin): (as if attached to, e.g. a typical circuit using an LDR and a capacitor to time the charging rate). """ - def __init__(self, number): - super(MockChargingPin, self).__init__() + def __init__(self, factory, number): + super(MockChargingPin, self).__init__(factory, number) self.charge_time = 0.01 # dark charging time self._charge_stop = Event() self._charge_thread = None @@ -225,8 +197,8 @@ class MockTriggerPin(MockPin): corresponding pin instance. When this pin is driven high it will trigger the echo pin to drive high for the echo time. """ - def __init__(self, number): - super(MockTriggerPin, self).__init__() + def __init__(self, factory, number): + super(MockTriggerPin, self).__init__(factory, number) self.echo_pin = None self.echo_time = 0.04 # longest echo time self._echo_thread = None @@ -250,8 +222,8 @@ class MockPWMPin(MockPin): """ This derivative of :class:`MockPin` adds PWM support. """ - def __init__(self, number): - super(MockPWMPin, self).__init__() + def __init__(self, factory, number): + super(MockPWMPin, self).__init__(factory, number) self._frequency = None def close(self): @@ -283,8 +255,8 @@ class MockSPIClockPin(MockPin): rather, construct a :class:`MockSPIDevice` with various pin numbers, and this class will be used for the clock pin. """ - def __init__(self, number): - super(MockSPIClockPin, self).__init__() + def __init__(self, factory, number): + super(MockSPIClockPin, self).__init__(factory, number) if not hasattr(self, 'spi_devices'): self.spi_devices = [] @@ -301,8 +273,8 @@ class MockSPISelectPin(MockPin): tests; rather, construct a :class:`MockSPIDevice` with various pin numbers, and this class will be used for the select pin. """ - def __init__(self, number): - super(MockSPISelectPin, self).__init__() + def __init__(self, factory, number): + super(MockSPISelectPin, self).__init__(factory, number) if not hasattr(self, 'spi_device'): self.spi_device = None @@ -314,13 +286,13 @@ class MockSPISelectPin(MockPin): class MockSPIDevice(object): def __init__( - self, clock_pin, mosi_pin, miso_pin, select_pin=None, + self, clock_pin, mosi_pin=None, miso_pin=None, select_pin=None, clock_polarity=False, clock_phase=False, lsb_first=False, bits_per_word=8, select_high=False): - self.clock_pin = MockSPIClockPin(clock_pin) - self.mosi_pin = None if mosi_pin is None else MockPin(mosi_pin) - self.miso_pin = None if miso_pin is None else MockPin(miso_pin) - self.select_pin = None if select_pin is None else MockSPISelectPin(select_pin) + self.clock_pin = Device._pin_factory.pin(clock_pin, pin_class=MockSPIClockPin) + self.mosi_pin = None if mosi_pin is None else Device._pin_factory.pin(mosi_pin) + self.miso_pin = None if miso_pin is None else Device._pin_factory.pin(miso_pin) + self.select_pin = None if select_pin is None else Device._pin_factory.pin(select_pin, pin_class=MockSPISelectPin) self.clock_polarity = clock_polarity self.clock_phase = clock_phase self.lsb_first = lsb_first @@ -413,3 +385,34 @@ class MockSPIDevice(object): bits = reversed(bits) self.tx_buf.extend(bits) + +class MockFactory(LocalPiFactory): + def __init__(self, revision='a21041', pin_class=MockPin): + super(MockFactory, self).__init__() + self._revision = revision + self.pin_class = pin_class + + def _get_address(self): + return ('mock',) + + def _get_revision(self): + return self._revision + + def reset(self): + self.pins.clear() + + def pin(self, spec, pin_class=None): + if pin_class is None: + pin_class = self.pin_class + n = self._to_gpio(spec) + try: + pin = self.pins[n] + except KeyError: + pin = pin_class(self, n) + self.pins[n] = pin + else: + # Ensure the pin class expected supports PWM (or not) + if issubclass(pin_class, MockPWMPin) != isinstance(pin, MockPWMPin): + raise ValueError('pin %d is already in use as a %s' % (n, pin.__class__.__name__)) + return pin + diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index 290ea9a..12bc5a9 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -13,20 +13,18 @@ import mmap import errno import struct import warnings +import weakref from time import sleep from threading import Thread, Event, Lock from collections import Counter -from . import LocalPin, PINS_CLEANUP -from .data import pi_info +from .local import LocalPiPin, LocalPiFactory from ..exc import ( PinInvalidPull, PinInvalidEdges, PinInvalidFunction, PinFixedPull, PinSetInput, - PinNonPhysical, - PinNoPins, ) @@ -149,7 +147,7 @@ class GPIOFS(object): f.write(str(pin).encode('ascii')) -class NativePin(LocalPin): +class NativeFactory(LocalPiFactory): """ Uses a built-in pure Python implementation to interface to the Pi's GPIO pins. This is the default pin implementation if no third-party libraries @@ -169,10 +167,17 @@ class NativePin(LocalPin): led = LED(NativePin(12)) """ + def __init__(self): + super(NativeFactory, self).__init__() + self.mem = GPIOMemory() + self.pin_class = NativePin - _MEM = None - _PINS = {} + def close(self): + super(NativeFactory, self).close() + self.mem.close() + +class NativePin(LocalPiPin): GPIO_FUNCTIONS = { 'input': 0b000, 'output': 0b001, @@ -202,89 +207,62 @@ class NativePin(LocalPin): GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()} GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()} - PI_INFO = None - - def __new__(cls, number): - if not cls._PINS: - cls._MEM = GPIOMemory() - PINS_CLEANUP.append(cls._MEM.close) - if cls.PI_INFO is None: - cls.PI_INFO = pi_info() - if not (0 <= number < 54): - raise ValueError('invalid pin %d specified (must be 0..53)' % number) - try: - return cls._PINS[number] - except KeyError: - self = super(NativePin, cls).__new__(cls) - try: - cls.PI_INFO.physical_pin('GPIO%d' % number) - except PinNoPins: - warnings.warn( - PinNonPhysical( - 'no physical pins exist for GPIO%d' % number)) - self._number = number - self._func_offset = self._MEM.GPFSEL_OFFSET + (number // 10) - self._func_shift = (number % 10) * 3 - self._set_offset = self._MEM.GPSET_OFFSET + (number // 32) - self._set_shift = number % 32 - self._clear_offset = self._MEM.GPCLR_OFFSET + (number // 32) - self._clear_shift = number % 32 - self._level_offset = self._MEM.GPLEV_OFFSET + (number // 32) - self._level_shift = number % 32 - self._pull_offset = self._MEM.GPPUDCLK_OFFSET + (number // 32) - self._pull_shift = number % 32 - self._edge_offset = self._MEM.GPEDS_OFFSET + (number // 32) - self._edge_shift = number % 32 - self._rising_offset = self._MEM.GPREN_OFFSET + (number // 32) - self._rising_shift = number % 32 - self._falling_offset = self._MEM.GPFEN_OFFSET + (number // 32) - self._falling_shift = number % 32 - self._when_changed = None - self._change_thread = None - self._change_event = Event() - self.function = 'input' - self.pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' - self.bounce = None - self.edges = 'both' - cls._PINS[number] = self - return self - - def __repr__(self): - return "GPIO%d" % self._number - - @property - def number(self): - return self._number + def __init__(self, factory, number): + super(NativePin, self).__init__(factory, number) + self._func_offset = self.factory.mem.GPFSEL_OFFSET + (number // 10) + self._func_shift = (number % 10) * 3 + self._set_offset = self.factory.mem.GPSET_OFFSET + (number // 32) + self._set_shift = number % 32 + self._clear_offset = self.factory.mem.GPCLR_OFFSET + (number // 32) + self._clear_shift = number % 32 + self._level_offset = self.factory.mem.GPLEV_OFFSET + (number // 32) + self._level_shift = number % 32 + self._pull_offset = self.factory.mem.GPPUDCLK_OFFSET + (number // 32) + self._pull_shift = number % 32 + self._edge_offset = self.factory.mem.GPEDS_OFFSET + (number // 32) + self._edge_shift = number % 32 + self._rising_offset = self.factory.mem.GPREN_OFFSET + (number // 32) + self._rising_shift = number % 32 + self._falling_offset = self.factory.mem.GPFEN_OFFSET + (number // 32) + self._falling_shift = number % 32 + self._when_changed = None + self._change_thread = None + self._change_event = Event() + self.function = 'input' + self.pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self.bounce = None + self.edges = 'both' def close(self): + self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self.PI_INFO.pulled_up('GPIO%d' % self.number) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up('GPIO%d' % self.number) else 'floating' def _get_function(self): - return self.GPIO_FUNCTION_NAMES[(self._MEM[self._func_offset] >> self._func_shift) & 7] + return self.GPIO_FUNCTION_NAMES[(self.factory.mem[self._func_offset] >> self._func_shift) & 7] def _set_function(self, value): try: value = self.GPIO_FUNCTIONS[value] except KeyError: raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) - self._MEM[self._func_offset] = ( - self._MEM[self._func_offset] + self.factory.mem[self._func_offset] = ( + self.factory.mem[self._func_offset] & ~(7 << self._func_shift) | (value << self._func_shift) ) def _get_state(self): - return bool(self._MEM[self._level_offset] & (1 << self._level_shift)) + return bool(self.factory.mem[self._level_offset] & (1 << self._level_shift)) def _set_state(self, value): if self.function == 'input': raise PinSetInput('cannot set state of pin %r' % self) if value: - self._MEM[self._set_offset] = 1 << self._set_shift + self.factory.mem[self._set_offset] = 1 << self._set_shift else: - self._MEM[self._clear_offset] = 1 << self._clear_shift + self.factory.mem[self._clear_offset] = 1 << self._clear_shift def _get_pull(self): return self.GPIO_PULL_UP_NAMES[self._pull] @@ -292,23 +270,23 @@ class NativePin(LocalPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self.number): + if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: value = self.GPIO_PULL_UPS[value] except KeyError: raise PinInvalidPull('invalid pull direction "%s" for pin %r' % (value, self)) - self._MEM[self._MEM.GPPUD_OFFSET] = value + self.factory.mem[self.factory.mem.GPPUD_OFFSET] = value sleep(0.000000214) - self._MEM[self._pull_offset] = 1 << self._pull_shift + self.factory.mem[self._pull_offset] = 1 << self._pull_shift sleep(0.000000214) - self._MEM[self._MEM.GPPUD_OFFSET] = 0 - self._MEM[self._pull_offset] = 0 + self.factory.mem[self.factory.mem.GPPUD_OFFSET] = 0 + self.factory.mem[self._pull_offset] = 0 self._pull = value def _get_edges(self): - rising = bool(self._MEM[self._rising_offset] & (1 << self._rising_shift)) - falling = bool(self._MEM[self._falling_offset] & (1 << self._falling_shift)) + rising = bool(self.factory.mem[self._rising_offset] & (1 << self._rising_shift)) + falling = bool(self.factory.mem[self._falling_offset] & (1 << self._falling_shift)) return self.GPIO_EDGES_NAMES[(rising, falling)] def _set_edges(self, value): @@ -319,13 +297,13 @@ class NativePin(LocalPin): f = self.when_changed self.when_changed = None try: - self._MEM[self._rising_offset] = ( - self._MEM[self._rising_offset] + self.factory.mem[self._rising_offset] = ( + self.factory.mem[self._rising_offset] & ~(1 << self._rising_shift) | (rising << self._rising_shift) ) - self._MEM[self._falling_offset] = ( - self._MEM[self._falling_offset] + self.factory.mem[self._falling_offset] = ( + self.factory.mem[self._falling_offset] & ~(1 << self._falling_shift) | (falling << self._falling_shift) ) @@ -353,9 +331,9 @@ class NativePin(LocalPin): def _change_watch(self): offset = self._edge_offset mask = 1 << self._edge_shift - self._MEM[offset] = mask # clear any existing detection bit + self.factory.mem[offset] = mask # clear any existing detection bit while not self._change_event.wait(0.001): - if self._MEM[offset] & mask: - self._MEM[offset] = mask + if self.factory.mem[offset] & mask: + self.factory.mem[offset] = mask self._when_changed() diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py new file mode 100644 index 0000000..622ba79 --- /dev/null +++ b/gpiozero/pins/pi.py @@ -0,0 +1,214 @@ +from __future__ import ( + unicode_literals, + absolute_import, + print_function, + division, + ) +str = type('') + +import io +import weakref +import warnings + +try: + from spidev import SpiDev +except ImportError: + SpiDev = None + +from . import Factory, Pin +from .data import pi_info +from ..exc import ( + PinNoPins, + PinNonPhysical, + PinInvalidPin, + SPIBadArgs, + SPISoftwareFallback, + ) + + +class PiFactory(Factory): + """ + Abstract base class representing hardware attached to a Raspberry Pi. This + forms the base of :class:`LocalPiFactory`. + """ + def __init__(self): + self._info = None + self.pins = {} + self.pin_class = None + self.spi_hardware_class = None + self.spi_software_class = None + self.shared_spi_hardware_class = None + self.shared_spi_software_class = None + + def close(self): + for pin in self.pins.values(): + pin.close() + self.pins.clear() + + def pin(self, spec): + n = self._to_gpio(spec) + try: + pin = self.pins[n] + except KeyError: + pin = self.pin_class(self, n) + self.pins[n] = pin + return pin + + def pin_address(self, spec): + n = self._to_gpio(spec) + return self.address + ('GPIO%d' % n,) + + def _to_gpio(self, spec): + """ + Converts the pin *spec* to a GPIO port number. + """ + if not 0 <= spec < 54: + raise PinInvalidPin('invalid GPIO port %d specified (range 0..53) ' % spec) + return spec + + def _get_revision(self): + raise NotImplementedError + + def _get_pi_info(self): + if self._info is None: + self._info = pi_info(self._get_revision()) + return self._info + + def spi(self, **spi_args): + """ + Returns an SPI interface, for the specified SPI *port* and *device*, or + for the specified pins (*clock_pin*, *mosi_pin*, *miso_pin*, and + *select_pin*). Only one of the schemes can be used; attempting to mix + *port* and *device* with pin numbers will raise :exc:`SPIBadArgs`. + + If the pins specified match the hardware SPI pins (clock on GPIO11, + MOSI on GPIO10, MISO on GPIO9, and chip select on GPIO8 or GPIO7), and + the spidev module can be imported, a :class:`SPIHardwareInterface` + instance will be returned. Otherwise, a :class:`SPISoftwareInterface` + will be returned which will use simple bit-banging to communicate. + + Both interfaces have the same API, support clock polarity and phase + attributes, and can handle half and full duplex communications, but the + hardware interface is significantly faster (though for many things this + doesn't matter). + """ + spi_args, kwargs = self._extract_spi_args(**spi_args) + shared = kwargs.pop('shared', False) + if kwargs: + raise SPIBadArgs( + 'unrecognized keyword argument %s' % kwargs.popitem()[0]) + if all(( + spi_args['clock_pin'] == 11, + spi_args['mosi_pin'] == 10, + spi_args['miso_pin'] == 9, + spi_args['select_pin'] in (7, 8), + )): + try: + hardware_spi_args = { + 'port': 0, + 'device': {8: 0, 7: 1}[spi_args['select_pin']], + } + if shared: + return self.shared_spi_hardware_class(self, **hardware_spi_args) + else: + return self.spi_hardware_class(self, **hardware_spi_args) + except Exception as e: + warnings.warn( + SPISoftwareFallback( + 'failed to initialize hardware SPI, falling back to ' + 'software (error was: %s)' % str(e))) + # Convert all pin arguments to integer GPIO numbers. This is necessary + # to ensure the shared-key for shared implementations get matched + # correctly, and is a bit of a hack for the pigpio bit-bang + # implementation which just wants the pin numbers too. + spi_args = { + key: pin.number if isinstance(pin, Pin) else pin + for key, pin in spi_args.items() + } + if shared: + return self.shared_spi_software_class(self, **spi_args) + else: + return self.spi_software_class(self, **spi_args) + + def _extract_spi_args(self, **kwargs): + """ + Given a set of keyword arguments, splits it into those relevant to SPI + implementations and all the rest. SPI arguments are augmented with + defaults and converted into the pin format (from the port/device + format) if necessary. + + Returns a tuple of ``(spi_args, other_args)``. + """ + pin_defaults = { + 'clock_pin': 11, + 'mosi_pin': 10, + 'miso_pin': 9, + 'select_pin': 8, + } + dev_defaults = { + 'port': 0, + 'device': 0, + } + spi_args = { + key: value for (key, value) in kwargs.items() + if key in pin_defaults or key in dev_defaults + } + kwargs = { + key: value for (key, value) in kwargs.items() + if key not in spi_args + } + if not spi_args: + spi_args = pin_defaults + elif set(spi_args) <= set(pin_defaults): + spi_args = { + key: self._to_gpio(spi_args.get(key, default)) + for key, default in pin_defaults.items() + } + elif set(spi_args) <= set(dev_defaults): + spi_args = { + key: spi_args.get(key, default) + for key, default in dev_defaults.items() + } + if spi_args['port'] != 0: + raise SPIBadArgs('port 0 is the only valid SPI port') + if spi_args['device'] not in (0, 1): + raise SPIBadArgs('device must be 0 or 1') + spi_args = { + key: value if key != 'select_pin' else (8, 7)[spi_args['device']] + for key, value in pin_defaults.items() + } + else: + raise SPIBadArgs( + 'you must either specify port and device, or clock_pin, ' + 'mosi_pin, miso_pin, and select_pin; combinations of the two ' + 'schemes (e.g. port and clock_pin) are not permitted') + return spi_args, kwargs + + +class PiPin(Pin): + """ + Abstract base class representing a multi-function GPIO pin attached to a + Raspberry Pi. + """ + def __init__(self, factory, number): + super(PiPin, self).__init__() + try: + factory.pi_info.physical_pin('GPIO%d' % number) + except PinNoPins: + warnings.warn( + PinNonPhysical( + 'no physical pins exist for GPIO%d' % number)) + self._factory = weakref.proxy(factory) + self._number = number + + @property + def number(self): + return self._number + + @property + def factory(self): + return self._factory + + def _get_address(self): + return self.factory.address + ('GPIO%d' % self.number,) + diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 537eb48..d36b059 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -6,12 +6,15 @@ from __future__ import ( ) str = type('') -import warnings +import weakref import pigpio import os -from . import Pin +from . import SPI +from .pi import PiPin, PiFactory from .data import pi_info +from ..devices import Device +from ..mixins import SharedMixin from ..exc import ( PinInvalidFunction, PinSetInput, @@ -19,12 +22,12 @@ from ..exc import ( PinInvalidPull, PinInvalidBounce, PinInvalidState, - PinNonPhysical, - PinNoPins, + SPIBadArgs, + SPIInvalidClockMode, ) -class PiGPIOPin(Pin): +class PiGPIOFactory(PiFactory): """ Uses the `pigpio`_ library to interface to the Pi's GPIO pins. The pigpio library relies on a daemon (``pigpiod``) to be running as root to provide @@ -68,10 +71,65 @@ class PiGPIOPin(Pin): .. _pigpio: http://abyz.co.uk/rpi/pigpio/ """ + def __init__( + self, host=os.getenv('PIGPIO_ADDR', 'localhost'), + port=int(os.getenv('PIGPIO_PORT', 8888))): + super(PiGPIOFactory, self).__init__() + self.pin_class = PiGPIOPin + self.spi_hardware_class = PiGPIOHardwareSPI + self.spi_software_class = PiGPIOSoftwareSPI + self.shared_spi_hardware_class = PiGPIOHardwareSPIShared + self.shared_spi_software_class = PiGPIOSoftwareSPIShared + self._connection = pigpio.pi(host, port) + self._host = host + self._port = port + self._spis = [] + def close(self): + super(PiGPIOFactory, self).close() + # We *have* to keep track of SPI interfaces constructed with pigpio; + # if we fail to close them they prevent future interfaces from using + # the same pins + if self.connection: + while self._spis: + self._spis[0].close() + self.connection.stop() + self._connection = None + + @property + def connection(self): + # If we're shutting down, the connection may have disconnected itself + # already. Unfortunately, the connection's "connected" property is + # rather buggy - disconnecting doesn't set it to False! So we're + # naughty and check an internal variable instead... + try: + if self._connection.sl.s is not None: + return self._connection + except AttributeError: + pass + + @property + def host(self): + return self._host + + @property + def port(self): + return self._port + + def _get_revision(self): + return self.connection.get_hardware_revision() + + def _get_address(self): + return ("%s:%d" % (self.host, self.port),) + + def spi(self, **spi_args): + intf = super(PiGPIOFactory, self).spi(**spi_args) + self._spis.append(intf) + return intf + + +class PiGPIOPin(PiPin): _CONNECTIONS = {} # maps (host, port) to (connection, pi_info) - _PINS = {} - GPIO_FUNCTIONS = { 'input': pigpio.INPUT, 'output': pigpio.OUTPUT, @@ -99,101 +157,64 @@ class PiGPIOPin(Pin): GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()} GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()} - def __new__( - cls, number, host=os.getenv('PIGPIO_ADDR', 'localhost'), - port=int(os.getenv('PIGPIO_PORT', 8888))): + def __init__(self, factory, number): + super(PiGPIOPin, self).__init__(factory, number) + self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pwm = False + self._bounce = None + self._when_changed = None + self._callback = None + self._edges = pigpio.EITHER_EDGE try: - return cls._PINS[(host, port, number)] - except KeyError: - self = super(PiGPIOPin, cls).__new__(cls) - cls.pi_info(host, port) # implicitly creates connection - self._connection, self._pi_info = cls._CONNECTIONS[(host, port)] - try: - self._pi_info.physical_pin('GPIO%d' % number) - except PinNoPins: - warnings.warn( - PinNonPhysical( - 'no physical pins exist for GPIO%d' % number)) - self._host = host - self._port = port - self._number = number - self._pull = 'up' if self._pi_info.pulled_up('GPIO%d' % number) else 'floating' - self._pwm = False - self._bounce = None - self._when_changed = None - self._callback = None - self._edges = pigpio.EITHER_EDGE - try: - self._connection.set_mode(self._number, pigpio.INPUT) - except pigpio.error as e: - raise ValueError(e) - self._connection.set_pull_up_down(self._number, self.GPIO_PULL_UPS[self._pull]) - self._connection.set_glitch_filter(self._number, 0) - cls._PINS[(host, port, number)] = self - return self - - def __repr__(self): - if self._host == 'localhost': - return "GPIO%d" % self._number - else: - return "GPIO%d on %s:%d" % (self._number, self._host, self._port) - - @property - def host(self): - return self._host - - @property - def port(self): - return self._port - - @property - def number(self): - return self._number + self.factory.connection.set_mode(self.number, pigpio.INPUT) + except pigpio.error as e: + raise ValueError(e) + self.factory.connection.set_pull_up_down(self.number, self.GPIO_PULL_UPS[self._pull]) + self.factory.connection.set_glitch_filter(self.number, 0) def close(self): - # If we're shutting down, the connection may have disconnected itself - # already. Unfortunately, the connection's "connected" property is - # rather buggy - disconnecting doesn't set it to False! So we're - # naughty and check an internal variable instead... - if self._connection.sl.s is not None: + if self.factory.connection: self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self._pi_info.pulled_up('GPIO%d' % self.number) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up('GPIO%d' % self.number) else 'floating' + + def _get_address(self): + return self.factory.address + ('GPIO%d' % self.number,) def _get_function(self): - return self.GPIO_FUNCTION_NAMES[self._connection.get_mode(self._number)] + return self.GPIO_FUNCTION_NAMES[self.factory.connection.get_mode(self.number)] def _set_function(self, value): if value != 'input': self._pull = 'floating' try: - self._connection.set_mode(self._number, self.GPIO_FUNCTIONS[value]) + self.factory.connection.set_mode(self.number, self.GPIO_FUNCTIONS[value]) except KeyError: raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) def _get_state(self): if self._pwm: return ( - self._connection.get_PWM_dutycycle(self._number) / - self._connection.get_PWM_range(self._number) + self.factory.connection.get_PWM_dutycycle(self.number) / + self.factory.connection.get_PWM_range(self.number) ) else: - return bool(self._connection.read(self._number)) + return bool(self.factory.connection.read(self.number)) def _set_state(self, value): if self._pwm: try: - value = int(value * self._connection.get_PWM_range(self._number)) - if value != self._connection.get_PWM_dutycycle(self._number): - self._connection.set_PWM_dutycycle(self._number, value) + value = int(value * self.factory.connection.get_PWM_range(self.number)) + if value != self.factory.connection.get_PWM_dutycycle(self.number): + self.factory.connection.set_PWM_dutycycle(self.number, value) except pigpio.error: raise PinInvalidState('invalid state "%s" for pin %r' % (value, self)) elif self.function == 'input': raise PinSetInput('cannot set state of pin %r' % self) else: # write forces pin to OUTPUT, hence the check above - self._connection.write(self._number, bool(value)) + self.factory.connection.write(self.number, bool(value)) def _get_pull(self): return self._pull @@ -201,31 +222,31 @@ class PiGPIOPin(Pin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self._pi_info.pulled_up('GPIO%d' % self._number): + if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: - self._connection.set_pull_up_down(self._number, self.GPIO_PULL_UPS[value]) + self.factory.connection.set_pull_up_down(self.number, self.GPIO_PULL_UPS[value]) self._pull = value except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self)) def _get_frequency(self): if self._pwm: - return self._connection.get_PWM_frequency(self._number) + return self.factory.connection.get_PWM_frequency(self.number) return None def _set_frequency(self, value): if not self._pwm and value is not None: - self._connection.set_PWM_frequency(self._number, value) - self._connection.set_PWM_range(self._number, 10000) - self._connection.set_PWM_dutycycle(self._number, 0) + self.factory.connection.set_PWM_frequency(self.number, value) + self.factory.connection.set_PWM_range(self.number, 10000) + self.factory.connection.set_PWM_dutycycle(self.number, 0) self._pwm = True elif self._pwm and value is not None: - if value != self._connection.get_PWM_frequency(self._number): - self._connection.set_PWM_frequency(self._number, value) - self._connection.set_PWM_range(self._number, 10000) + if value != self.factory.connection.get_PWM_frequency(self.number): + self.factory.connection.set_PWM_frequency(self.number, value) + self.factory.connection.set_PWM_range(self.number, 10000) elif self._pwm and value is None: - self._connection.write(self._number, 0) + self.factory.connection.write(self.number, 0) self._pwm = False def _get_bounce(self): @@ -236,7 +257,7 @@ class PiGPIOPin(Pin): value = 0 elif value < 0: raise PinInvalidBounce('bounce must be 0 or greater') - self._connection.set_glitch_filter(self._number, int(value * 1000000)) + self.factory.connection.set_glitch_filter(self.number, int(value * 1000000)) def _get_edges(self): return self.GPIO_EDGES_NAMES[self._edges] @@ -259,20 +280,224 @@ class PiGPIOPin(Pin): self._callback.cancel() self._callback = None if value is not None: - self._callback = self._connection.callback( - self._number, self._edges, + self._callback = self.factory.connection.callback( + self.number, self._edges, lambda gpio, level, tick: value()) - @classmethod - def pi_info( - cls, host=os.getenv('PIGPIO_ADDR', 'localhost'), - port=int(os.getenv('PIGPIO_PORT', 8888))): - try: - connection, info = cls._CONNECTIONS[(host, port)] - except KeyError: - connection = pigpio.pi(host, port) - revision = '%04x' % connection.get_hardware_revision() - info = pi_info(revision) - cls._CONNECTIONS[(host, port)] = (connection, info) - return info + +class PiGPIOHardwareSPI(SPI, Device): + def __init__(self, factory, port, device): + self._port = port + self._device = device + self._factory = weakref.proxy(factory) + super(PiGPIOHardwareSPI, self).__init__() + self._reserve_pins(*( + factory.address + ('GPIO%d' % pin,) + for pin in (11, 10, 9, (8, 7)[device]) + )) + self._mode = 0 + self._select_high = False + self._bits_per_word = 8 + self._baud = 500000 + self._handle = self._factory.connection.spi_open( + device, self._baud, self._spi_flags()) + + def close(self): + try: + self._factory._spis.remove(self) + except (ReferenceError, ValueError): + # If the factory has died already or we're not present in its + # internal list, ignore the error + pass + if not self.closed: + self._factory.connection.spi_close(self._handle) + self._handle = None + self._release_all() + super(PiGPIOHardwareSPI, self).close() + + @property + def closed(self): + return self._handle is None or self._factory.connection is None + + @property + def factory(self): + return self._factory + + def __repr__(self): + try: + self._check_open() + return 'SPI(port=%d, device=%d)' % (self._port, self._device) + except DeviceClosed: + return 'SPI(closed)' + + def _spi_flags(self): + return ( + self._mode << 0 | + self._select_high << (2 + self._device) | + self._bits_per_word << 16 + ) + + def _get_clock_mode(self): + return self._clock_mode + + def _set_clock_mode(self, value): + self._check_open() + if not 0 <= value < 4: + raise SPIInvalidClockmode("%d is not a valid SPI clock mode" % value) + self._factory.connection.spi_close(self._handle) + self._clock_mode = value + self._handle = self._factory.connection.spi_open( + self._device, self._baud, self._spi_flags()) + + def _get_select_high(self): + return self._select_high + + def _set_select_high(self, value): + self._check_open() + self._factory.connection.spi_close(self._handle) + self._select_high = bool(value) + self._handle = self._factory.connection.spi_open( + self._device, self._baud, self._spi_flags()) + + def _get_bits_per_word(self): + return self._bits_per_word + + def _set_bits_per_word(self, value): + self._check_open() + self._factory.connection.spi_close(self._handle) + self._bits_per_word = value + self._handle = self._factory.connection.spi_open( + self._device, self._baud, self._spi_flags()) + + def transfer(self, data): + self._check_open() + count, data = self._factory.connection.spi_xfer(self._handle, data) + if count < 0: + raise IOError('SPI transfer error %d' % count) + # Convert returned bytearray to list of ints. XXX Not sure how non-byte + # sized words (aux intf only) are returned ... padded to 16/32-bits? + return [int(b) for b in data] + + +class PiGPIOSoftwareSPI(SPI, Device): + def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin): + self._select_pin = None + self._factory = weakref.proxy(factory) + self._address = factory.address + ( + ) + super(PiGPIOSoftwareSPI, self).__init__() + self._reserve_pins( + factory.pin_address(clock_pin), + factory.pin_address(mosi_pin), + factory.pin_address(miso_pin), + factory.pin_address(select_pin), + ) + self._mode = 0 + self._select_high = False + self._lsb_first = False + self._baud = 100000 + try: + self._factory.connection.bb_spi_open( + select_pin, miso_pin, mosi_pin, clock_pin, + self._baud, self._spi_flags()) + # Only set after opening bb_spi; if that fails then close() will + # also fail if bb_spi_close is attempted on an un-open interface + self._select_pin = select_pin + self._clock_pin = clock_pin + self._mosi_pin = mosi_pin + self._miso_pin = miso_pin + except: + self.close() + raise + + def close(self): + try: + self._factory._spis.remove(self) + except (ReferenceError, ValueError): + # If the factory has died already or we're not present in its + # internal list, ignore the error + pass + if not self.closed: + self._factory.connection.bb_spi_close(self._select_pin) + self._select_pin = None + self._release_all() + super(PiGPIOSoftwareSPI, self).close() + + @property + def closed(self): + return self._select_pin is None or self._factory.connection is None + + def __repr__(self): + try: + self._check_open() + return ( + 'SPI(clock_pin=%d, mosi_pin=%d, miso_pin=%d, select_pin=%d)' % ( + self._clock_pin, self._mosi_pin, self._miso_pin, self._select_pin + )) + except DeviceClosed: + return 'SPI(closed)' + + def _spi_flags(self): + return ( + self._mode << 0 | + self._select_high << 2 | + self._lsb_first << 14 | + self._lsb_first << 15 + ) + + def _get_clock_mode(self): + return self._clock_mode + + def _set_clock_mode(self, value): + self._check_open() + if not 0 <= value < 4: + raise SPIInvalidClockmode("%d is not a valid SPI clock mode" % value) + self._factory.connection.bb_spi_close(self._select_pin) + self._clock_mode = value + self._factory.connection.bb_spi_open( + self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, + self._baud, self._spi_flags()) + + def _get_select_high(self): + return self._select_high + + def _set_select_high(self, value): + self._check_open() + self._factory.connection.bb_spi_close(self._select_pin) + self._select_high = bool(value) + self._factory.connection.bb_spi_open( + self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, + self._baud, self._spi_flags()) + + def _get_lsb_first(self): + return self._lsb_first + + def _set_lsb_first(self, value): + self._check_open() + self._factory.connection.bb_spi_close(self._select_pin) + self._lsb_first = bool(value) + self._factory.connection.bb_spi_open( + self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, + self._baud, self._spi_flags()) + + def transfer(self, data): + self._check_open() + count, data = self._factory.connection.bb_spi_xfer(self._select_pin, data) + if count < 0: + raise IOError('SPI transfer error %d' % count) + # Convert returned bytearray to list of ints. bb_spi only supports + # byte-sized words so no issues here + return [int(b) for b in data] + + +class PiGPIOHardwareSPIShared(SharedMixin, PiGPIOHardwareSPI): + @classmethod + def _shared_key(cls, factory, port, device): + return (factory, port, device) + + +class PiGPIOSoftwareSPIShared(SharedMixin, PiGPIOSoftwareSPI): + @classmethod + def _shared_key(cls, factory, clock_pin, mosi_pin, miso_pin, select_pin): + return (factory, select_pin) diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index 1597fb0..679b8c2 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -7,10 +7,10 @@ from __future__ import ( str = type('') import warnings +import weakref from RPi import GPIO -from . import LocalPin -from .data import pi_info +from .local import LocalPiFactory, LocalPiPin from ..exc import ( PinInvalidFunction, PinSetInput, @@ -19,12 +19,10 @@ from ..exc import ( PinInvalidState, PinInvalidBounce, PinPWMFixedValue, - PinNonPhysical, - PinNoPins, ) -class RPiGPIOPin(LocalPin): +class RPiGPIOFactory(LocalPiFactory): """ Uses the `RPi.GPIO`_ library to interface to the Pi's GPIO pins. This is the default pin implementation if the RPi.GPIO library is installed. @@ -39,7 +37,7 @@ class RPiGPIOPin(LocalPin): However, you can also construct RPi.GPIO pins manually if you wish:: - from gpiozero.pins.rpigpio import RPiGPIOPin + from gpiozero.pins.rpigpio import RPiGPIOFactory from gpiozero import LED led = LED(RPiGPIOPin(12)) @@ -47,8 +45,18 @@ class RPiGPIOPin(LocalPin): .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO """ - _PINS = {} + def __init__(self): + super(RPiGPIOFactory, self).__init__() + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + self.pin_class = RPiGPIOPin + def close(self): + super(RPiGPIOFactory, self).close() + GPIO.cleanup() + + +class RPiGPIOPin(LocalPiPin): GPIO_FUNCTIONS = { 'input': GPIO.IN, 'output': GPIO.OUT, @@ -75,69 +83,43 @@ class RPiGPIOPin(LocalPin): GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()} GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()} - PI_INFO = None - - def __new__(cls, number): - if not cls._PINS: - GPIO.setmode(GPIO.BCM) - GPIO.setwarnings(False) - if cls.PI_INFO is None: - cls.PI_INFO = pi_info() - try: - return cls._PINS[number] - except KeyError: - self = super(RPiGPIOPin, cls).__new__(cls) - try: - cls.PI_INFO.physical_pin('GPIO%d' % number) - except PinNoPins: - warnings.warn( - PinNonPhysical( - 'no physical pins exist for GPIO%d' % number)) - self._number = number - self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' - self._pwm = None - self._frequency = None - self._duty_cycle = None - self._bounce = -666 - self._when_changed = None - self._edges = GPIO.BOTH - GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) - cls._PINS[number] = self - return self - - def __repr__(self): - return "GPIO%d" % self._number - - @property - def number(self): - return self._number + def __init__(self, factory, number): + super(RPiGPIOPin, self).__init__(factory, number) + self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pwm = None + self._frequency = None + self._duty_cycle = None + self._bounce = -666 + self._when_changed = None + self._edges = GPIO.BOTH + GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) def close(self): self.frequency = None self.when_changed = None - GPIO.cleanup(self._number) + GPIO.cleanup(self.number) def output_with_state(self, state): self._pull = 'floating' - GPIO.setup(self._number, GPIO.OUT, initial=state) + GPIO.setup(self.number, GPIO.OUT, initial=state) def input_with_pull(self, pull): - if pull != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self._number): + if pull != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: - GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[pull]) + GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[pull]) self._pull = pull except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (pull, self)) def _get_function(self): - return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self._number)] + return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self.number)] def _set_function(self, value): if value != 'input': self._pull = 'floating' if value in ('input', 'output') and value in self.GPIO_FUNCTIONS: - GPIO.setup(self._number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull]) + GPIO.setup(self.number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull]) else: raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) @@ -145,7 +127,7 @@ class RPiGPIOPin(LocalPin): if self._pwm: return self._duty_cycle else: - return GPIO.input(self._number) + return GPIO.input(self.number) def _set_state(self, value): if self._pwm: @@ -156,7 +138,7 @@ class RPiGPIOPin(LocalPin): self._duty_cycle = value else: try: - GPIO.output(self._number, value) + GPIO.output(self.number, value) except ValueError: raise PinInvalidState('invalid state "%s" for pin %r' % (value, self)) except RuntimeError: @@ -168,10 +150,10 @@ class RPiGPIOPin(LocalPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self._number): + if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: - GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[value]) + GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[value]) self._pull = value except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self)) @@ -182,7 +164,7 @@ class RPiGPIOPin(LocalPin): def _set_frequency(self, value): if self._frequency is None and value is not None: try: - self._pwm = GPIO.PWM(self._number, value) + self._pwm = GPIO.PWM(self.number, value) except RuntimeError: raise PinPWMFixedValue('cannot start PWM on pin %r' % self) self._pwm.start(0) @@ -228,11 +210,11 @@ class RPiGPIOPin(LocalPin): if self._when_changed is None and value is not None: self._when_changed = value GPIO.add_event_detect( - self._number, self._edges, + self.number, self._edges, callback=lambda channel: self._when_changed(), bouncetime=self._bounce) elif self._when_changed is not None and value is None: - GPIO.remove_event_detect(self._number) + GPIO.remove_event_detect(self.number) self._when_changed = None else: self._when_changed = value diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 58d5893..2413b57 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -8,11 +8,12 @@ str = type('') import warnings +import weakref import RPIO import RPIO.PWM from RPIO.Exceptions import InvalidChannelException -from . import LocalPin, PINS_CLEANUP +from .local import LocalPiPin, LocalPiFactory from .data import pi_info from ..exc import ( PinInvalidFunction, @@ -22,12 +23,10 @@ from ..exc import ( PinInvalidBounce, PinInvalidState, PinPWMError, - PinNonPhysical, - PinNoPins, ) -class RPIOPin(LocalPin): +class RPIOFactory(LocalPiFactory): """ Uses the `RPIO`_ library to interface to the Pi's GPIO pins. This is the default pin implementation if the RPi.GPIO library is not installed, @@ -48,9 +47,22 @@ class RPIOPin(LocalPin): .. _RPIO: https://pythonhosted.org/RPIO/ """ + def __init__(self): + super(RPIOFactory, self).__init__() + RPIO.setmode(RPIO.BCM) + RPIO.setwarnings(False) + RPIO.wait_for_interrupts(threaded=True) + RPIO.PWM.setup() + RPIO.PWM.init_channel(0, 10000) + self.pin_class = RPIOPin - _PINS = {} + def close(self): + RPIO.PWM.cleanup() + RPIO.stop_waiting_for_interrupts() + RPIO.cleanup() + +class RPIOPin(LocalPiPin): GPIO_FUNCTIONS = { 'input': RPIO.IN, 'output': RPIO.OUT, @@ -66,64 +78,32 @@ class RPIOPin(LocalPin): GPIO_FUNCTION_NAMES = {v: k for (k, v) in GPIO_FUNCTIONS.items()} GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()} - PI_INFO = None - - def __new__(cls, number): - if not cls._PINS: - RPIO.setmode(RPIO.BCM) - RPIO.setwarnings(False) - RPIO.wait_for_interrupts(threaded=True) - RPIO.PWM.setup() - RPIO.PWM.init_channel(0, 10000) - PINS_CLEANUP.append(RPIO.PWM.cleanup) - PINS_CLEANUP.append(RPIO.stop_waiting_for_interrupts) - PINS_CLEANUP.append(RPIO.cleanup) - if cls.PI_INFO is None: - cls.PI_INFO = pi_info() + def __init__(self, factory, number): + super(RPIOPin, self).__init__(factory, number) + self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pwm = False + self._duty_cycle = None + self._bounce = None + self._when_changed = None + self._edges = 'both' try: - return cls._PINS[number] - except KeyError: - self = super(RPIOPin, cls).__new__(cls) - try: - cls.PI_INFO.physical_pin('GPIO%d' % number) - except PinNoPins: - warnings.warn( - PinNonPhysical( - 'no physical pins exist for GPIO%d' % number)) - self._number = number - self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating' - self._pwm = False - self._duty_cycle = None - self._bounce = None - self._when_changed = None - self._edges = 'both' - try: - RPIO.setup(self._number, RPIO.IN, self.GPIO_PULL_UPS[self._pull]) - except InvalidChannelException as e: - raise ValueError(e) - cls._PINS[number] = self - return self - - def __repr__(self): - return "GPIO%d" % self._number - - @property - def number(self): - return self._number + RPIO.setup(self.number, RPIO.IN, self.GPIO_PULL_UPS[self._pull]) + except InvalidChannelException as e: + raise ValueError(e) def close(self): self.frequency = None self.when_changed = None - RPIO.setup(self._number, RPIO.IN, RPIO.PUD_OFF) + RPIO.setup(self.number, RPIO.IN, RPIO.PUD_OFF) def _get_function(self): - return self.GPIO_FUNCTION_NAMES[RPIO.gpio_function(self._number)] + return self.GPIO_FUNCTION_NAMES[RPIO.gpio_function(self.number)] def _set_function(self, value): if value != 'input': self._pull = 'floating' try: - RPIO.setup(self._number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull]) + RPIO.setup(self.number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull]) except KeyError: raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) @@ -131,23 +111,23 @@ class RPIOPin(LocalPin): if self._pwm: return self._duty_cycle else: - return RPIO.input(self._number) + return RPIO.input(self.number) def _set_state(self, value): if not 0 <= value <= 1: raise PinInvalidState('invalid state "%s" for pin %r' % (value, self)) if self._pwm: - RPIO.PWM.clear_channel_gpio(0, self._number) + RPIO.PWM.clear_channel_gpio(0, self.number) if value == 0: - RPIO.output(self._number, False) + RPIO.output(self.number, False) elif value == 1: - RPIO.output(self._number, True) + RPIO.output(self.number, True) else: - RPIO.PWM.add_channel_pulse(0, self._number, start=0, width=int(1000 * value)) + RPIO.PWM.add_channel_pulse(0, self.number, start=0, width=int(1000 * value)) self._duty_cycle = value else: try: - RPIO.output(self._number, value) + RPIO.output(self.number, value) except ValueError: raise PinInvalidState('invalid state "%s" for pin %r' % (value, self)) except RuntimeError: @@ -159,10 +139,10 @@ class RPIOPin(LocalPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self._number): + if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: - RPIO.setup(self._number, RPIO.IN, self.GPIO_PULL_UPS[value]) + RPIO.setup(self.number, RPIO.IN, self.GPIO_PULL_UPS[value]) self._pull = value except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self)) @@ -182,10 +162,10 @@ class RPIOPin(LocalPin): self._pwm = True # Dirty hack to get RPIO's PWM support to setup, but do nothing, # for a given GPIO pin - RPIO.PWM.add_channel_pulse(0, self._number, start=0, width=0) - RPIO.PWM.clear_channel_gpio(0, self._number) + RPIO.PWM.add_channel_pulse(0, self.number, start=0, width=0) + RPIO.PWM.clear_channel_gpio(0, self.number) elif self._pwm and value is None: - RPIO.PWM.clear_channel_gpio(0, self._number) + RPIO.PWM.clear_channel_gpio(0, self.number) self._pwm = False def _get_bounce(self): @@ -219,12 +199,12 @@ class RPIOPin(LocalPin): if self._when_changed is None and value is not None: self._when_changed = value RPIO.add_interrupt_callback( - self._number, + self.number, lambda channel, value: self._when_changed(), self._edges, self.GPIO_PULL_UPS[self._pull], self._bounce) elif self._when_changed is not None and value is None: try: - RPIO.del_interrupt_callback(self._number) + RPIO.del_interrupt_callback(self.number) except KeyError: # Ignore this exception which occurs during shutdown; this # simply means RPIO's built-in cleanup has already run and diff --git a/gpiozero/pins/spi.py b/gpiozero/pins/spi.py new file mode 100644 index 0000000..a92ff5c --- /dev/null +++ b/gpiozero/pins/spi.py @@ -0,0 +1,86 @@ +from __future__ import ( + unicode_literals, + print_function, + absolute_import, + division, + ) +str = type('') + + +import operator +from threading import RLock + +from ..devices import Device, SharedMixin +from ..input_devices import InputDevice +from ..output_devices import OutputDevice + + +class SPISoftwareBus(SharedMixin, Device): + def __init__(self, clock_pin, mosi_pin, miso_pin): + self.lock = None + self.clock = None + self.mosi = None + self.miso = None + super(SPISoftwareBus, self).__init__() + self.lock = RLock() + try: + self.clock = OutputDevice(clock_pin, active_high=True) + if mosi_pin is not None: + self.mosi = OutputDevice(mosi_pin) + if miso_pin is not None: + self.miso = InputDevice(miso_pin) + except: + self.close() + raise + + def close(self): + super(SPISoftwareBus, self).close() + if self.lock: + with self.lock: + if self.miso is not None: + self.miso.close() + self.miso = None + if self.mosi is not None: + self.mosi.close() + self.mosi = None + if self.clock is not None: + self.clock.close() + self.clock = None + self.lock = None + + @property + def closed(self): + return self.lock is None + + @classmethod + def _shared_key(cls, clock_pin, mosi_pin, miso_pin): + return (clock_pin, mosi_pin, miso_pin) + + def transfer(self, data, clock_phase=False, lsb_first=False, bits_per_word=8): + """ + Writes data (a list of integer words where each word is assumed to have + :attr:`bits_per_word` bits or less) to the SPI interface, and reads an + equivalent number of words, returning them as a list of integers. + """ + result = [] + with self.lock: + shift = operator.lshift if lsb_first else operator.rshift + for write_word in data: + mask = 1 if lsb_first else 1 << (bits_per_word - 1) + read_word = 0 + for _ in range(bits_per_word): + if self.mosi is not None: + self.mosi.value = bool(write_word & mask) + self.clock.on() + if self.miso is not None and not clock_phase: + if self.miso.value: + read_word |= mask + self.clock.off() + if self.miso is not None and clock_phase: + if self.miso.value: + read_word |= mask + mask = shift(mask, 1) + result.append(read_word) + return result + + diff --git a/gpiozero/spi.py b/gpiozero/spi.py deleted file mode 100644 index e89ab98..0000000 --- a/gpiozero/spi.py +++ /dev/null @@ -1,419 +0,0 @@ -from __future__ import ( - unicode_literals, - print_function, - absolute_import, - division, - ) -str = type('') - - -import warnings -import operator -from threading import RLock - -try: - from spidev import SpiDev -except ImportError: - SpiDev = None - -from .devices import Device, SharedMixin, _PINS, _PINS_LOCK -from .input_devices import InputDevice -from .output_devices import OutputDevice -from .exc import SPIBadArgs, SPISoftwareFallback, GPIOPinInUse, DeviceClosed - - -class SPIHardwareInterface(Device): - def __init__(self, port, device): - self._device = None - super(SPIHardwareInterface, self).__init__() - # XXX How can we detect conflicts with existing GPIO instances? This - # isn't ideal ... in fact, it's downright crap and doesn't guard - # against conflicts created *after* this instance, but it's all I can - # come up with right now ... - conflicts = (11, 10, 9, (8, 7)[device]) - with _PINS_LOCK: - for pin in _PINS: - if pin.number in conflicts: - raise GPIOPinInUse( - 'pin %r is already in use by another gpiozero object' % pin - ) - self._device_num = device - self._device = SpiDev() - self._device.open(port, device) - self._device.max_speed_hz = 500000 - - def close(self): - if self._device: - try: - self._device.close() - finally: - self._device = None - super(SPIHardwareInterface, self).close() - - @property - def closed(self): - return self._device is None - - def __repr__(self): - try: - self._check_open() - return ( - "hardware SPI on clock_pin=11, mosi_pin=10, miso_pin=9, " - "select_pin=%d" % ( - 8 if self._device_num == 0 else 7)) - except DeviceClosed: - return "hardware SPI closed" - - def read(self, n): - return self.transfer((0,) * n) - - def write(self, data): - return len(self.transfer(data)) - - def transfer(self, data): - """ - Writes data (a list of integer words where each word is assumed to have - :attr:`bits_per_word` bits or less) to the SPI interface, and reads an - equivalent number of words, returning them as a list of integers. - """ - return self._device.xfer2(data) - - def _get_clock_mode(self): - return self._device.mode - - def _set_clock_mode(self, value): - self._device.mode = value - - def _get_clock_polarity(self): - return bool(self.clock_mode & 2) - - def _set_clock_polarity(self, value): - self.clock_mode = self.clock_mode & (~2) | (bool(value) << 1) - - def _get_clock_phase(self): - return bool(self.clock_mode & 1) - - def _set_clock_phase(self, value): - self.clock_mode = self.clock_mode & (~1) | bool(value) - - def _get_lsb_first(self): - return self._device.lsbfirst - - def _set_lsb_first(self, value): - self._device.lsbfirst = bool(value) - - def _get_select_high(self): - return self._device.cshigh - - def _set_select_high(self, value): - self._device.cshigh = bool(value) - - def _get_bits_per_word(self): - return self._device.bits_per_word - - def _set_bits_per_word(self, value): - self._device.bits_per_word = value - - clock_polarity = property(_get_clock_polarity, _set_clock_polarity) - clock_phase = property(_get_clock_phase, _set_clock_phase) - clock_mode = property(_get_clock_mode, _set_clock_mode) - lsb_first = property(_get_lsb_first, _set_lsb_first) - select_high = property(_get_select_high, _set_select_high) - bits_per_word = property(_get_bits_per_word, _set_bits_per_word) - - -class SPISoftwareBus(SharedMixin, Device): - def __init__(self, clock_pin, mosi_pin, miso_pin): - self.lock = None - self.clock = None - self.mosi = None - self.miso = None - super(SPISoftwareBus, self).__init__() - self.lock = RLock() - try: - self.clock = OutputDevice(clock_pin, active_high=True) - if mosi_pin is not None: - self.mosi = OutputDevice(mosi_pin) - if miso_pin is not None: - self.miso = InputDevice(miso_pin) - except: - self.close() - raise - - def close(self): - super(SPISoftwareBus, self).close() - if self.lock: - with self.lock: - if self.miso is not None: - self.miso.close() - self.miso = None - if self.mosi is not None: - self.mosi.close() - self.mosi = None - if self.clock is not None: - self.clock.close() - self.clock = None - self.lock = None - - @property - def closed(self): - return self.lock is None - - @classmethod - def _shared_key(cls, clock_pin, mosi_pin, miso_pin): - return (clock_pin, mosi_pin, miso_pin) - - def transfer(self, data, clock_phase=False, lsb_first=False, bits_per_word=8): - """ - Writes data (a list of integer words where each word is assumed to have - :attr:`bits_per_word` bits or less) to the SPI interface, and reads an - equivalent number of words, returning them as a list of integers. - """ - result = [] - with self.lock: - shift = operator.lshift if lsb_first else operator.rshift - for write_word in data: - mask = 1 if lsb_first else 1 << (bits_per_word - 1) - read_word = 0 - for _ in range(bits_per_word): - if self.mosi is not None: - self.mosi.value = bool(write_word & mask) - self.clock.on() - if self.miso is not None and not clock_phase: - if self.miso.value: - read_word |= mask - self.clock.off() - if self.miso is not None and clock_phase: - if self.miso.value: - read_word |= mask - mask = shift(mask, 1) - result.append(read_word) - return result - - -class SPISoftwareInterface(OutputDevice): - def __init__(self, clock_pin, mosi_pin, miso_pin, select_pin): - self._bus = None - super(SPISoftwareInterface, self).__init__(select_pin, active_high=False) - try: - self._clock_phase = False - self._lsb_first = False - self._bits_per_word = 8 - self._bus = SPISoftwareBus(clock_pin, mosi_pin, miso_pin) - except: - self.close() - raise - - def close(self): - if self._bus: - self._bus.close() - self._bus = None - super(SPISoftwareInterface, self).close() - - def __repr__(self): - try: - self._check_open() - return ( - "software SPI on clock_pin=%d, mosi_pin=%d, miso_pin=%d, " - "select_pin=%d" % ( - self._bus.clock.pin.number, - self._bus.mosi.pin.number, - self._bus.miso.pin.number, - self.pin.number)) - except DeviceClosed: - return "software SPI closed" - - def read(self, n): - return self.transfer((0,) * n) - - def write(self, data): - return len(self.transfer(data)) - - def transfer(self, data): - with self._bus.lock: - self.on() - try: - return self._bus.transfer( - data, self._clock_phase, self._lsb_first, self._bits_per_word) - finally: - self.off() - - def _get_clock_mode(self): - return (self.clock_polarity << 1) | self.clock_phase - - def _set_clock_mode(self, value): - value = int(value) - if not 0 <= value <= 3: - raise ValueError('clock_mode must be a value between 0 and 3 inclusive') - self.clock_polarity = bool(value & 2) - self.clock_phase = bool(value & 1) - - def _get_clock_polarity(self): - with self._bus.lock: - return not self._bus.clock.active_high - - def _set_clock_polarity(self, value): - with self._bus.lock: - self._bus.clock.active_high = not value - self._bus.clock.off() - - def _get_clock_phase(self): - return self._clock_phase - - def _set_clock_phase(self, value): - self._clock_phase = bool(value) - - def _get_lsb_first(self): - return self._lsb_first - - def _set_lsb_first(self, value): - self._lsb_first = bool(value) - - def _get_bits_per_word(self): - return self._bits_per_word - - def _set_bits_per_word(self, value): - if value < 1: - raise ValueError('bits_per_word must be positive') - self._bits_per_word = int(value) - - def _get_select_high(self): - return self.active_high - - def _set_select_high(self, value): - with self._bus.lock: - self.active_high = value - self.off() - - clock_polarity = property(_get_clock_polarity, _set_clock_polarity) - clock_phase = property(_get_clock_phase, _set_clock_phase) - clock_mode = property(_get_clock_mode, _set_clock_mode) - lsb_first = property(_get_lsb_first, _set_lsb_first) - bits_per_word = property(_get_bits_per_word, _set_bits_per_word) - select_high = property(_get_select_high, _set_select_high) - - -class SharedSPIHardwareInterface(SharedMixin, SPIHardwareInterface): - @classmethod - def _shared_key(cls, port, device): - return (port, device) - - -class SharedSPISoftwareInterface(SharedMixin, SPISoftwareInterface): - @classmethod - def _shared_key(cls, clock_pin, mosi_pin, miso_pin, select_pin): - return (clock_pin, mosi_pin, miso_pin, select_pin) - - -def extract_spi_args(**kwargs): - """ - Given a set of keyword arguments, splits it into those relevant to SPI - implementations and all the rest. SPI arguments are augmented with defaults - and converted into the pin format (from the port/device format) if - necessary. - - Returns a tuple of ``(spi_args, other_args)``. - """ - pin_defaults = { - 'clock_pin': 11, - 'mosi_pin': 10, - 'miso_pin': 9, - 'select_pin': 8, - } - dev_defaults = { - 'port': 0, - 'device': 0, - } - spi_args = { - key: value for (key, value) in kwargs.items() - if key in pin_defaults or key in dev_defaults - } - kwargs = { - key: value for (key, value) in kwargs.items() - if key not in spi_args - } - if not spi_args: - spi_args = pin_defaults - elif set(spi_args) <= set(pin_defaults): - spi_args = { - key: spi_args.get(key, default) - for key, default in pin_defaults.items() - } - elif set(spi_args) <= set(dev_defaults): - spi_args = { - key: spi_args.get(key, default) - for key, default in dev_defaults.items() - } - if spi_args['port'] != 0: - raise SPIBadArgs('port 0 is the only valid SPI port') - if spi_args['device'] not in (0, 1): - raise SPIBadArgs('device must be 0 or 1') - spi_args = { - key: value if key != 'select_pin' else (8, 7)[spi_args['device']] - for key, value in pin_defaults.items() - } - else: - raise SPIBadArgs( - 'you must either specify port and device, or clock_pin, mosi_pin, ' - 'miso_pin, and select_pin; combinations of the two schemes (e.g. ' - 'port and clock_pin) are not permitted') - return spi_args, kwargs - - -def SPI(**spi_args): - """ - Returns an SPI interface, for the specified SPI *port* and *device*, or for - the specified pins (*clock_pin*, *mosi_pin*, *miso_pin*, and *select_pin*). - Only one of the schemes can be used; attempting to mix *port* and *device* - with pin numbers will raise :exc:`SPIBadArgs`. - - If the pins specified match the hardware SPI pins (clock on GPIO11, MOSI on - GPIO10, MISO on GPIO9, and chip select on GPIO8 or GPIO7), and the spidev - module can be imported, a :class:`SPIHardwareInterface` instance will be - returned. Otherwise, a :class:`SPISoftwareInterface` will be returned which - will use simple bit-banging to communicate. - - Both interfaces have the same API, support clock polarity and phase - attributes, and can handle half and full duplex communications, but the - hardware interface is significantly faster (though for many things this - doesn't matter). - - Finally, the *shared* keyword argument specifies whether the resulting - SPI interface can be repeatedly created and used by multiple devices - (useful with multi-channel devices like numerous ADCs). - """ - spi_args, kwargs = extract_spi_args(**spi_args) - shared = kwargs.pop('shared', False) - if kwargs: - raise SPIBadArgs( - 'unrecognized keyword argument %s' % kwargs.popitem()[0]) - if all(( - spi_args['clock_pin'] == 11, - spi_args['mosi_pin'] == 10, - spi_args['miso_pin'] == 9, - spi_args['select_pin'] in (7, 8), - )): - if SpiDev is None: - warnings.warn( - SPISoftwareFallback( - 'failed to import spidev, falling back to software SPI')) - else: - try: - hardware_spi_args = { - 'port': 0, - 'device': {8: 0, 7: 1}[spi_args['select_pin']], - } - if shared: - return SharedSPIHardwareInterface(**hardware_spi_args) - else: - return SPIHardwareInterface(**hardware_spi_args) - except Exception as e: - warnings.warn( - SPISoftwareFallback( - 'failed to initialize hardware SPI, falling back to ' - 'software (error was: %s)' % str(e))) - if shared: - return SharedSPISoftwareInterface(**spi_args) - else: - return SPISoftwareInterface(**spi_args) - diff --git a/gpiozero/spi_devices.py b/gpiozero/spi_devices.py index 7aff666..3840583 100644 --- a/gpiozero/spi_devices.py +++ b/gpiozero/spi_devices.py @@ -16,7 +16,6 @@ except ImportError: from .exc import DeviceClosed, SPIBadChannel from .devices import Device -from .spi import SPI class SPIDevice(Device): @@ -28,13 +27,12 @@ class SPIDevice(Device): specified with the constructor. """ def __init__(self, **spi_args): - self._spi = SPI(**spi_args) + self._spi = self._pin_factory.spi(**spi_args) def close(self): if self._spi: - s = self._spi + self._spi.close() self._spi = None - s.close() super(SPIDevice, self).close() @property diff --git a/setup.py b/setup.py index 0cd18c1..3540700 100644 --- a/setup.py +++ b/setup.py @@ -68,12 +68,12 @@ if sys.version_info[:2] == (3, 2): __entry_points__ = { 'gpiozero_pin_factories': [ - 'PiGPIOPin = gpiozero.pins.pigpiod:PiGPIOPin', - 'RPiGPIOPin = gpiozero.pins.rpigpio:RPiGPIOPin', - 'RPIOPin = gpiozero.pins.rpio:RPIOPin', - 'NativePin = gpiozero.pins.native:NativePin', - 'MockPin = gpiozero.pins.mock:MockPin', - 'MockPWMPin = gpiozero.pins.mock:MockPWMPin', + 'pigpio = gpiozero.pins.pigpiod:PiGPIOFactory', + 'rpigpio = gpiozero.pins.rpigpio:RPiGPIOFactory', + 'rpio = gpiozero.pins.rpio:RPIOFactory', + 'native = gpiozero.pins.native:NativeFactory', + 'mock = gpiozero.pins.mock:MockFactory', + 'mockpwm = gpiozero.pins.mock:MockPWMFactory', ], 'console_scripts': [ 'pinout = gpiozero.cli.pinout:main', diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..79b6d4c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +from __future__ import ( + unicode_literals, + print_function, + absolute_import, + division, + ) +str = type('') + +import os +os.environ['GPIOZERO_PIN_FACTORY'] = 'mock' diff --git a/tests/test_boards.py b/tests/test_boards.py index 8152f66..c0f34e0 100644 --- a/tests/test_boards.py +++ b/tests/test_boards.py @@ -11,26 +11,39 @@ import sys import pytest from time import sleep -from gpiozero.pins.mock import MockPin, MockPWMPin from gpiozero import * +from gpiozero.pins.mock import MockPWMPin, MockPin def setup_function(function): - import gpiozero.devices # dirty, but it does the job - if function.__name__ in ('test_robot', 'test_ryanteck_robot', 'test_camjam_kit_robot', 'test_led_borg', 'test_snow_pi_initial_value_pwm'): - gpiozero.devices.pin_factory = MockPWMPin - else: - gpiozero.devices.pin_factory = MockPin + Device._pin_factory.pin_class = MockPWMPin if function.__name__ in ( + 'test_robot', + 'test_ryanteck_robot', + 'test_camjam_kit_robot', + 'test_led_borg', + 'test_led_board_pwm_value', + 'test_led_board_pwm_bad_value', + 'test_snow_pi_initial_value_pwm', + 'test_led_board_pwm_initial_value', + 'test_led_board_pwm_bad_initial_value', + 'test_led_board_fade_background', + 'test_led_bar_graph_pwm_value', + 'test_led_bar_graph_pwm_initial_value', + ) else MockPin def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() + +def teardown_module(module): + # make sure we reset the default + Device._pin_factory.pwm = False def test_composite_output_on_off(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: device.on() assert all((pin1.state, pin2.state, pin3.state)) @@ -38,9 +51,9 @@ def test_composite_output_on_off(): assert not any((pin1.state, pin2.state, pin3.state)) def test_composite_output_toggle(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: device.toggle() assert all((pin1.state, pin2.state, pin3.state)) @@ -51,9 +64,9 @@ def test_composite_output_toggle(): assert not pin3.state def test_composite_output_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: assert device.value == (0, 0, 0) device.toggle() @@ -64,9 +77,9 @@ def test_composite_output_value(): assert device[2].is_active def test_led_board_on_off(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3) as board: assert isinstance(board[0], LED) assert isinstance(board[1], LED) @@ -121,9 +134,9 @@ def test_led_board_on_off(): assert pin3.state def test_led_board_active_low(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, active_high=False) as board: assert not board.active_high assert not board[0].active_high @@ -145,9 +158,9 @@ def test_led_board_active_low(): assert not pin3.state def test_led_board_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) @@ -156,9 +169,9 @@ def test_led_board_value(): assert board.value == (1, 0, 1) def test_led_board_pwm_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) @@ -167,9 +180,9 @@ def test_led_board_pwm_value(): assert board.value == (0.5, 0, 0.75) def test_led_board_pwm_bad_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: with pytest.raises(ValueError): board.value = (-1, 0, 0) @@ -177,18 +190,18 @@ def test_led_board_pwm_bad_value(): board.value = (0, 2, 0) def test_led_board_initial_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, initial_value=0) as board: assert board.value == (0, 0, 0) with LEDBoard(pin1, pin2, foo=pin3, initial_value=1) as board: assert board.value == (1, 1, 1) def test_led_board_pwm_initial_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=0) as board: assert board.value == (0, 0, 0) with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=1) as board: @@ -197,18 +210,18 @@ def test_led_board_pwm_initial_value(): assert board.value == (0.5, 0.5, 0.5) def test_led_board_pwm_bad_initial_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with pytest.raises(ValueError): LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=-1) with pytest.raises(ValueError): LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=2) def test_led_board_nested(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: assert list(led.pin for led in board.leds) == [pin1, pin2, pin3] assert board.value == (0, (0, 0)) @@ -218,9 +231,9 @@ def test_led_board_nested(): assert pin3.state def test_led_board_bad_blink(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: with pytest.raises(ValueError): board.blink(fade_in_time=1, fade_out_time=1) @@ -232,9 +245,9 @@ def test_led_board_bad_blink(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_background(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(0.1, 0.1, n=2) board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test @@ -252,9 +265,9 @@ def test_led_board_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_foreground(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(0.1, 0.1, n=2, background=False) test = [ @@ -271,9 +284,9 @@ def test_led_board_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(0.1, 0.1, n=2) # make sure the blink thread's started @@ -296,9 +309,9 @@ def test_led_board_blink_control(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_take_over(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board[1].blink(0.1, 0.1, n=2) board.blink(0.1, 0.1, n=2) # immediately take over blinking @@ -318,9 +331,9 @@ def test_led_board_blink_take_over(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control_all(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(0.1, 0.1, n=2) # make sure the blink thread's started @@ -340,9 +353,9 @@ def test_led_board_blink_control_all(): pin3.assert_states_and_times(test) def test_led_board_blink_interrupt_on(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(1, 0.1) sleep(0.2) @@ -352,9 +365,9 @@ def test_led_board_blink_interrupt_on(): pin3.assert_states([False, True, False]) def test_led_board_blink_interrupt_off(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(0.1, 1) sleep(0.2) @@ -366,9 +379,9 @@ def test_led_board_blink_interrupt_off(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_fade_background(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) as board: board.blink(0, 0, 0.2, 0.2, n=2) board._blink_thread.join() @@ -400,9 +413,9 @@ def test_led_board_fade_background(): pin3.assert_states_and_times(test) def test_led_bar_graph_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3) as graph: assert isinstance(graph[0], LED) assert isinstance(graph[1], LED) @@ -433,9 +446,9 @@ def test_led_bar_graph_value(): assert graph.value == -2/3 def test_led_bar_graph_active_low(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, active_high=False) as graph: assert not graph.active_high assert not graph[0].active_high @@ -455,9 +468,9 @@ def test_led_bar_graph_active_low(): assert not pin3.state and pin1.state and pin2.state def test_led_bar_graph_pwm_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, pwm=True) as graph: assert isinstance(graph[0], PWMLED) assert isinstance(graph[1], PWMLED) @@ -482,9 +495,9 @@ def test_led_bar_graph_pwm_value(): assert graph.value == -1/2 def test_led_bar_graph_bad_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3) as graph: with pytest.raises(ValueError): graph.value = -2 @@ -492,9 +505,9 @@ def test_led_bar_graph_bad_value(): graph.value = 2 def test_led_bar_graph_bad_init(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with pytest.raises(TypeError): LEDBarGraph(pin1, pin2, foo=pin3) with pytest.raises(ValueError): @@ -503,9 +516,9 @@ def test_led_bar_graph_bad_init(): LEDBarGraph(pin1, pin2, pin3, initial_value=2) def test_led_bar_graph_initial_value(): - pin1 = MockPin(2) - pin2 = MockPin(3) - pin3 = MockPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, initial_value=1/3) as graph: assert graph.value == 1/3 assert pin1.state and not (pin2.state or pin3.state) @@ -514,9 +527,9 @@ def test_led_bar_graph_initial_value(): assert pin3.state and not (pin1.state or pin2.state) def test_led_bar_graph_pwm_initial_value(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(3) - pin3 = MockPWMPin(4) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(3) + pin3 = Device._pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, pwm=True, initial_value=0.5) as graph: assert graph.value == 0.5 assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0) @@ -525,17 +538,17 @@ def test_led_bar_graph_pwm_initial_value(): assert (pin1.state, pin2.state, pin3.state) == (0, 0.5, 1) def test_led_borg(): - pins = [MockPWMPin(n) for n in (17, 27, 22)] + pins = [Device._pin_factory.pin(n) for n in (17, 27, 22)] with LedBorg() as board: assert [device.pin for device in board._leds] == pins def test_pi_liter(): - pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] + pins = [Device._pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] with PiLiter() as board: assert [device.pin for device in board] == pins def test_pi_liter_graph(): - pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] + pins = [Device._pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] with PiLiterBarGraph() as board: board.value = 0.5 assert [pin.state for pin in pins] == [1, 1, 1, 1, 0, 0, 0, 0] @@ -543,9 +556,9 @@ def test_pi_liter_graph(): assert board.value == 5/8 def test_traffic_lights(): - red_pin = MockPin(2) - amber_pin = MockPin(3) - green_pin = MockPin(4) + red_pin = Device._pin_factory.pin(2) + amber_pin = Device._pin_factory.pin(3) + green_pin = Device._pin_factory.pin(4) with TrafficLights(red_pin, amber_pin, green_pin) as board: board.red.on() assert board.red.value @@ -574,15 +587,15 @@ def test_traffic_lights(): def test_traffic_lights_bad_init(): with pytest.raises(ValueError): TrafficLights() - red_pin = MockPin(2) - amber_pin = MockPin(3) - green_pin = MockPin(4) - yellow_pin = MockPin(5) + red_pin = Device._pin_factory.pin(2) + amber_pin = Device._pin_factory.pin(3) + green_pin = Device._pin_factory.pin(4) + yellow_pin = Device._pin_factory.pin(5) with pytest.raises(ValueError): TrafficLights(red=red_pin, amber=amber_pin, yellow=yellow_pin, green=green_pin) def test_pi_traffic(): - pins = [MockPin(n) for n in (9, 10, 11)] + pins = [Device._pin_factory.pin(n) for n in (9, 10, 11)] with PiTraffic() as board: assert [device.pin for device in board] == pins @@ -591,27 +604,27 @@ def test_pi_stop(): PiStop() with pytest.raises(ValueError): PiStop('E') - pins_a = [MockPin(n) for n in (7, 8, 25)] + pins_a = [Device._pin_factory.pin(n) for n in (7, 8, 25)] with PiStop('A') as board: assert [device.pin for device in board] == pins_a - pins_aplus = [MockPin(n) for n in (21, 20, 16)] + pins_aplus = [Device._pin_factory.pin(n) for n in (21, 20, 16)] with PiStop('A+') as board: assert [device.pin for device in board] == pins_aplus - pins_b = [MockPin(n) for n in (10, 9, 11)] + pins_b = [Device._pin_factory.pin(n) for n in (10, 9, 11)] with PiStop('B') as board: assert [device.pin for device in board] == pins_b - pins_bplus = [MockPin(n) for n in (13, 19, 26)] + pins_bplus = [Device._pin_factory.pin(n) for n in (13, 19, 26)] with PiStop('B+') as board: assert [device.pin for device in board] == pins_bplus - pins_c = [MockPin(n) for n in (18, 15, 14)] + pins_c = [Device._pin_factory.pin(n) for n in (18, 15, 14)] with PiStop('C') as board: assert [device.pin for device in board] == pins_c - pins_d = [MockPin(n) for n in (2, 3, 4)] + pins_d = [Device._pin_factory.pin(n) for n in (2, 3, 4)] with PiStop('D') as board: assert [device.pin for device in board] == pins_d def test_snow_pi(): - pins = [MockPin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] + pins = [Device._pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] with SnowPi() as board: assert [device.pin for device in board.leds] == pins @@ -626,17 +639,17 @@ def test_snow_pi_initial_value(): assert all(device.pin.state == True for device in board.leds) def test_snow_pi_initial_value_pwm(): - pins = [MockPWMPin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] + pins = [Device._pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] with SnowPi(pwm=True, initial_value=0.5) as board: assert [device.pin for device in board.leds] == pins assert all(device.pin.state == 0.5 for device in board.leds) def test_traffic_lights_buzzer(): - red_pin = MockPin(2) - amber_pin = MockPin(3) - green_pin = MockPin(4) - buzzer_pin = MockPin(5) - button_pin = MockPin(6) + red_pin = Device._pin_factory.pin(2) + amber_pin = Device._pin_factory.pin(3) + green_pin = Device._pin_factory.pin(4) + buzzer_pin = Device._pin_factory.pin(5) + button_pin = Device._pin_factory.pin(6) with TrafficLightsBuzzer( TrafficLights(red_pin, amber_pin, green_pin), Buzzer(buzzer_pin), @@ -651,17 +664,17 @@ def test_traffic_lights_buzzer(): assert board.button.is_active def test_fish_dish(): - pins = [MockPin(n) for n in (9, 22, 4, 8, 7)] + pins = [Device._pin_factory.pin(n) for n in (9, 22, 4, 8, 7)] with FishDish() as board: assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins def test_traffic_hat(): - pins = [MockPin(n) for n in (24, 23, 22, 5, 25)] + pins = [Device._pin_factory.pin(n) for n in (24, 23, 22, 5, 25)] with TrafficHat() as board: assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins def test_robot(): - pins = [MockPWMPin(n) for n in (2, 3, 4, 5)] + pins = [Device._pin_factory.pin(n) for n in (2, 3, 4, 5)] with Robot((2, 3), (4, 5)) as robot: assert ( [device.pin for device in robot.left_motor] + @@ -696,12 +709,12 @@ def test_robot(): assert robot.value == (0, -0.5) def test_ryanteck_robot(): - pins = [MockPWMPin(n) for n in (17, 18, 22, 23)] + pins = [Device._pin_factory.pin(n) for n in (17, 18, 22, 23)] with RyanteckRobot() as board: assert [device.pin for motor in board for device in motor] == pins def test_camjam_kit_robot(): - pins = [MockPWMPin(n) for n in (9, 10, 7, 8)] + pins = [Device._pin_factory.pin(n) for n in (9, 10, 7, 8)] with CamJamKitRobot() as board: assert [device.pin for motor in board for device in motor] == pins @@ -714,7 +727,7 @@ def test_energenie_bad_init(): Energenie(5) def test_energenie(): - pins = [MockPin(n) for n in (17, 22, 23, 27, 24, 25)] + pins = [Device._pin_factory.pin(n) for n in (17, 22, 23, 27, 24, 25)] with Energenie(1, initial_value=True) as device1, \ Energenie(2, initial_value=False) as device2: assert repr(device1) == '' diff --git a/tests/test_devices.py b/tests/test_devices.py index e46a735..01b714a 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -6,86 +6,87 @@ from __future__ import ( ) str = type('') +import warnings import pytest -from gpiozero.pins.mock import MockPin from gpiozero import * def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() + # TODO add more devices tests! -def test_device_no_pin(): +def test_device_bad_pin(): with pytest.raises(GPIOPinMissing): device = GPIODevice() + with pytest.raises(PinInvalidPin): + device = GPIODevice(60) + +def test_device_non_physical(): + with warnings.catch_warnings(record=True) as w: + device = GPIODevice(37) + assert len(w) == 1 + assert w[0].category == PinNonPhysical def test_device_init(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with GPIODevice(pin) as device: assert not device.closed assert device.pin == pin def test_device_init_twice_same_pin(): - pin = MockPin(2) - with GPIODevice(pin) as device: + with GPIODevice(2) as device: with pytest.raises(GPIOPinInUse): - device2 = GPIODevice(pin) + GPIODevice(2) def test_device_init_twice_different_pin(): - pin = MockPin(2) - pin2 = MockPin(3) - with GPIODevice(pin) as device: - with GPIODevice(pin2) as device2: + with GPIODevice(2) as device: + with GPIODevice(3) as device2: pass def test_device_close(): - pin = MockPin(2) - device = GPIODevice(pin) + device = GPIODevice(2) device.close() assert device.closed assert device.pin is None def test_device_reopen_same_pin(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) device = GPIODevice(pin) device.close() device2 = GPIODevice(pin) assert not device2.closed - assert device2.pin == pin + assert device2.pin is pin assert device.closed assert device.pin is None device2.close() def test_device_repr(): - pin = MockPin(2) - with GPIODevice(pin) as device: - assert repr(device) == '' % pin + with GPIODevice(2) as device: + assert repr(device) == '' % device.pin def test_device_repr_after_close(): - pin = MockPin(2) - device = GPIODevice(pin) + device = GPIODevice(2) device.close() assert repr(device) == '' def test_device_unknown_attr(): - pin = MockPin(2) - with GPIODevice(pin) as device: + with GPIODevice(2) as device: with pytest.raises(AttributeError): device.foo = 1 def test_device_context_manager(): - pin = MockPin(2) - with GPIODevice(pin) as device: + with GPIODevice(2) as device: assert not device.closed assert device.closed def test_composite_device_sequence(): with CompositeDevice( - InputDevice(MockPin(2)), - InputDevice(MockPin(3)) + InputDevice(2), + InputDevice(3) ) as device: assert len(device) == 2 assert device[0].pin.number == 2 @@ -94,8 +95,8 @@ def test_composite_device_sequence(): def test_composite_device_values(): with CompositeDevice( - InputDevice(MockPin(2)), - InputDevice(MockPin(3)) + InputDevice(2), + InputDevice(3) ) as device: assert device.value == (0, 0) assert not device.is_active @@ -105,8 +106,8 @@ def test_composite_device_values(): def test_composite_device_named(): with CompositeDevice( - foo=InputDevice(MockPin(2)), - bar=InputDevice(MockPin(3)), + foo=InputDevice(2), + bar=InputDevice(3), _order=('foo', 'bar') ) as device: assert device.namedtuple._fields == ('foo', 'bar') @@ -121,13 +122,13 @@ def test_composite_device_bad_init(): with pytest.raises(ValueError): CompositeDevice(2) with pytest.raises(ValueError): - CompositeDevice(MockPin(2)) + CompositeDevice(Device._pin_factory.pin(2)) def test_composite_device_read_only(): - device = CompositeDevice( - foo=InputDevice(MockPin(2)), - bar=InputDevice(MockPin(3)) - ) - with pytest.raises(AttributeError): - device.foo = 1 + with CompositeDevice( + foo=InputDevice(2), + bar=InputDevice(3) + ) as device: + with pytest.raises(AttributeError): + device.foo = 1 diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 85e26a5..faf5894 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -12,57 +12,52 @@ import pytest from threading import Event from functools import partial -from gpiozero.pins.mock import ( - MockPin, - MockPulledUpPin, - MockChargingPin, - MockTriggerPin, - ) +from gpiozero.pins.mock import MockPulledUpPin, MockChargingPin, MockTriggerPin from gpiozero import * def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() + def test_input_initial_values(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with InputDevice(pin, pull_up=True) as device: assert pin.function == 'input' assert pin.pull == 'up' assert device.pull_up - device.close() - device = InputDevice(pin, pull_up=False) + with InputDevice(pin, pull_up=False) as device: assert pin.pull == 'down' assert not device.pull_up def test_input_is_active_low(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with InputDevice(pin, pull_up=True) as device: pin.drive_high() assert not device.is_active - assert repr(device) == '' + assert repr(device) == '' pin.drive_low() assert device.is_active - assert repr(device) == '' + assert repr(device) == '' def test_input_is_active_high(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with InputDevice(pin, pull_up=False) as device: pin.drive_high() assert device.is_active - assert repr(device) == '' + assert repr(device) == '' pin.drive_low() assert not device.is_active - assert repr(device) == '' + assert repr(device) == '' def test_input_pulled_up(): - pin = MockPulledUpPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPulledUpPin) with pytest.raises(PinFixedPull): InputDevice(pin, pull_up=False) def test_input_event_activated(): event = Event() - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalInputDevice(pin) as device: device.when_activated = lambda: event.set() assert not event.is_set() @@ -71,7 +66,7 @@ def test_input_event_activated(): def test_input_event_deactivated(): event = Event() - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalInputDevice(pin) as device: device.when_deactivated = lambda: event.set() assert not event.is_set() @@ -82,7 +77,7 @@ def test_input_event_deactivated(): def test_input_partial_callback(): event = Event() - pin = MockPin(2) + pin = Device._pin_factory.pin(2) def foo(a, b): event.set() return a + b @@ -95,22 +90,22 @@ def test_input_partial_callback(): assert event.is_set() def test_input_wait_active(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalInputDevice(pin) as device: pin.drive_high() assert device.wait_for_active(1) assert not device.wait_for_inactive(0) def test_input_wait_inactive(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalInputDevice(pin) as device: assert device.wait_for_inactive(1) assert not device.wait_for_active(0) def test_input_smoothed_attrib(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) as device: - assert repr(device) == '' + assert repr(device) == '' assert device.threshold == 0.5 assert device.queue_len == 5 assert not device.partial @@ -120,7 +115,7 @@ def test_input_smoothed_attrib(): device.threshold = 1 def test_input_smoothed_values(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with SmoothedInputDevice(pin) as device: device._queue.start() assert not device.is_active @@ -130,7 +125,7 @@ def test_input_smoothed_values(): assert device.wait_for_inactive(1) def test_input_button(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with Button(pin) as button: assert pin.pull == 'up' assert not button.is_pressed @@ -142,7 +137,7 @@ def test_input_button(): assert button.wait_for_release(1) def test_input_line_sensor(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with LineSensor(pin) as sensor: pin.drive_low() # logic is inverted for line sensor assert sensor.wait_for_line(1) @@ -152,7 +147,7 @@ def test_input_line_sensor(): assert not sensor.line_detected def test_input_motion_sensor(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with MotionSensor(pin) as sensor: pin.drive_high() assert sensor.wait_for_motion(1) @@ -164,7 +159,7 @@ def test_input_motion_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_light_sensor(): - pin = MockChargingPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockChargingPin) with LightSensor(pin) as sensor: pin.charge_time = 0.1 assert sensor.wait_for_dark(1) @@ -174,8 +169,8 @@ def test_input_light_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_distance_sensor(): - echo_pin = MockPin(2) - trig_pin = MockTriggerPin(3) + echo_pin = Device._pin_factory.pin(2) + trig_pin = Device._pin_factory.pin(3, pin_class=MockTriggerPin) trig_pin.echo_pin = echo_pin trig_pin.echo_time = 0.02 with pytest.raises(ValueError): diff --git a/tests/test_mock_pin.py b/tests/test_mock_pin.py index c8bdb95..4d5414e 100644 --- a/tests/test_mock_pin.py +++ b/tests/test_mock_pin.py @@ -11,25 +11,24 @@ from threading import Event import pytest -from gpiozero.pins.mock import MockPin, MockPWMPin +from gpiozero.pins.mock import MockPWMPin, MockPin from gpiozero import * def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() + # Some rough tests to make sure our MockPin is up to snuff. This is just # enough to get reasonable coverage but it's by no means comprehensive... def test_mock_pin_init(): - with pytest.raises(TypeError): - MockPin() with pytest.raises(ValueError): - MockPin(60) - assert MockPin(2).number == 2 + Device._pin_factory.pin(60) + assert Device._pin_factory.pin(2).number == 2 def test_mock_pin_defaults(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -39,30 +38,23 @@ def test_mock_pin_defaults(): assert pin.when_changed == None def test_mock_pin_open_close(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) pin.close() def test_mock_pin_init_twice_same_pin(): - pin1 = MockPin(2) - pin2 = MockPin(pin1.number) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(pin1.number) assert pin1 is pin2 def test_mock_pin_init_twice_different_pin(): - pin1 = MockPin(2) - pin2 = MockPin(pin1.number+1) + pin1 = Device._pin_factory.pin(2) + pin2 = Device._pin_factory.pin(pin1.number+1) assert pin1 != pin2 assert pin1.number == 2 assert pin2.number == pin1.number+1 -def test_mock_pwm_pin_init(): - with pytest.raises(TypeError): - MockPWMPin() - with pytest.raises(ValueError): - MockPWMPin(60) - assert MockPWMPin(2).number == 2 - def test_mock_pwm_pin_defaults(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -72,38 +64,38 @@ def test_mock_pwm_pin_defaults(): assert pin.when_changed == None def test_mock_pwm_pin_open_close(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) pin.close() def test_mock_pwm_pin_init_twice_same_pin(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(pin1.number) + pin1 = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin2 = Device._pin_factory.pin(pin1.number, pin_class=MockPWMPin) assert pin1 is pin2 def test_mock_pwm_pin_init_twice_different_pin(): - pin1 = MockPWMPin(2) - pin2 = MockPWMPin(pin1.number+1) + pin1 = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin2 = Device._pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) assert pin1 != pin2 assert pin1.number == 2 assert pin2.number == pin1.number+1 def test_mock_pin_init_twice_different_modes(): - pin1 = MockPin(2) - pin2 = MockPWMPin(pin1.number+1) + pin1 = Device._pin_factory.pin(2, pin_class=MockPin) + pin2 = Device._pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) assert pin1 != pin2 with pytest.raises(ValueError): - pin3 = MockPWMPin(pin1.number) + Device._pin_factory.pin(pin1.number, pin_class=MockPWMPin) with pytest.raises(ValueError): - pin4 = MockPin(pin2.number) + Device._pin_factory.pin(pin2.number, pin_class=MockPin) def test_mock_pin_frequency_unsupported(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) pin.frequency = None with pytest.raises(PinPWMUnsupported): pin.frequency = 100 def test_mock_pin_frequency_supported(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) pin.function = 'output' assert pin.frequency is None pin.frequency = 100 @@ -112,7 +104,7 @@ def test_mock_pin_frequency_supported(): assert not pin.state def test_mock_pin_pull(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) pin.function = 'input' assert pin.pull == 'floating' pin.pull = 'up' @@ -121,7 +113,7 @@ def test_mock_pin_pull(): assert not pin.state def test_mock_pin_state(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' @@ -134,7 +126,7 @@ def test_mock_pin_state(): assert pin.state == 1 def test_mock_pwm_pin_state(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' @@ -147,7 +139,7 @@ def test_mock_pwm_pin_state(): assert pin.state == 0.5 def test_mock_pin_edges(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) assert pin.when_changed is None fired = Event() pin.function = 'input' diff --git a/tests/test_outputs.py b/tests/test_outputs.py index eabc414..3816226 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -16,15 +16,16 @@ except ImportError: import pytest -from gpiozero.pins.mock import MockPin, MockPWMPin +from gpiozero.pins.mock import MockPWMPin from gpiozero import * def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() + def test_output_initial_values(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with OutputDevice(pin, initial_value=False) as device: assert pin.function == 'output' assert not pin.state @@ -35,7 +36,7 @@ def test_output_initial_values(): assert state == pin.state def test_output_write_active_high(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with OutputDevice(pin) as device: device.on() assert pin.state @@ -43,7 +44,7 @@ def test_output_write_active_high(): assert not pin.state def test_output_write_active_low(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with OutputDevice(pin, active_high=False) as device: device.on() assert not pin.state @@ -51,7 +52,7 @@ def test_output_write_active_low(): assert pin.state def test_output_write_closed(): - with OutputDevice(MockPin(2)) as device: + with OutputDevice(Device._pin_factory.pin(2)) as device: device.close() assert device.closed device.close() @@ -60,14 +61,14 @@ def test_output_write_closed(): device.on() def test_output_write_silly(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with OutputDevice(pin) as device: pin.function = 'input' with pytest.raises(AttributeError): device.on() def test_output_value(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with OutputDevice(pin) as device: assert not device.value assert not pin.state @@ -79,7 +80,7 @@ def test_output_value(): assert not pin.state def test_output_digital_toggle(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalOutputDevice(pin) as device: assert not device.value assert not pin.state @@ -93,7 +94,7 @@ def test_output_digital_toggle(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_background(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -111,7 +112,7 @@ def test_output_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_foreground(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -125,7 +126,7 @@ def test_output_blink_foreground(): ]) def test_output_blink_interrupt_on(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -133,7 +134,7 @@ def test_output_blink_interrupt_on(): pin.assert_states([False, True, False]) def test_output_blink_interrupt_off(): - pin = MockPin(2) + pin = Device._pin_factory.pin(2) with DigitalOutputDevice(pin) as device: device.blink(0.1, 1) sleep(0.2) @@ -142,14 +143,14 @@ def test_output_blink_interrupt_off(): def test_output_pwm_bad_initial_value(): with pytest.raises(ValueError): - PWMOutputDevice(MockPin(2), initial_value=2) + PWMOutputDevice(Device._pin_factory.pin(2), initial_value=2) def test_output_pwm_not_supported(): with pytest.raises(AttributeError): - PWMOutputDevice(MockPin(2)) + PWMOutputDevice(Device._pin_factory.pin(2)) def test_output_pwm_states(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.value = 0.1 device.value = 0.2 @@ -157,7 +158,7 @@ def test_output_pwm_states(): pin.assert_states([0.0, 0.1, 0.2, 0.0]) def test_output_pwm_read(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin, frequency=100) as device: assert device.frequency == 100 device.value = 0.1 @@ -170,14 +171,14 @@ def test_output_pwm_read(): assert device.frequency is None def test_output_pwm_write(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.on() device.off() pin.assert_states([False, True, False]) def test_output_pwm_toggle(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.toggle() device.value = 0.5 @@ -187,7 +188,7 @@ def test_output_pwm_toggle(): pin.assert_states([False, True, 0.5, 0.1, 0.9, False]) def test_output_pwm_active_high_read(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin, active_high=False) as device: device.value = 0.1 assert isclose(device.value, 0.1) @@ -196,17 +197,18 @@ def test_output_pwm_active_high_read(): assert device.value def test_output_pwm_bad_value(): - with pytest.raises(ValueError): - PWMOutputDevice(MockPWMPin(2)).value = 2 + with PWMOutputDevice(Device._pin_factory.pin(2, pin_class=MockPWMPin)) as device: + with pytest.raises(ValueError): + device.value = 2 def test_output_pwm_write_closed(): - device = PWMOutputDevice(MockPWMPin(2)) - device.close() - with pytest.raises(GPIODeviceClosed): - device.on() + with PWMOutputDevice(Device._pin_factory.pin(2, pin_class=MockPWMPin)) as device: + device.close() + with pytest.raises(GPIODeviceClosed): + device.on() def test_output_pwm_write_silly(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: pin.function = 'input' with pytest.raises(AttributeError): @@ -215,7 +217,7 @@ def test_output_pwm_write_silly(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_background(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -233,7 +235,7 @@ def test_output_pwm_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_foreground(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -249,7 +251,7 @@ def test_output_pwm_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_background(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -283,7 +285,7 @@ def test_output_pwm_fade_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_foreground(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -315,7 +317,7 @@ def test_output_pwm_fade_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_background(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -349,7 +351,7 @@ def test_output_pwm_pulse_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_foreground(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -379,7 +381,7 @@ def test_output_pwm_pulse_foreground(): ]) def test_output_pwm_blink_interrupt(): - pin = MockPWMPin(2) + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -391,7 +393,7 @@ def test_rgbled_missing_pins(): RGBLED() def test_rgbled_initial_value(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) as device: assert r.frequency assert g.frequency @@ -401,24 +403,24 @@ def test_rgbled_initial_value(): assert isclose(b.state, 0.0) def test_rgbled_initial_value_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) 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)) + r, g, b = (Device._pin_factory.pin(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)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) 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) @@ -436,7 +438,7 @@ def test_rgbled_value(): 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)) + r, g, b = (Device._pin_factory.pin(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) @@ -451,7 +453,7 @@ def test_rgbled_value_nonpwm(): assert device.value == (0, 0, 0) def test_rgbled_bad_value(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: with pytest.raises(ValueError): device.value = (2, 0, 0) @@ -460,7 +462,7 @@ def test_rgbled_bad_value(): device.value = (0, -1, 0) def test_rgbled_bad_value_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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) @@ -478,7 +480,7 @@ def test_rgbled_bad_value_nonpwm(): device.value = (0, 0, 0.5) def test_rgbled_toggle(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: assert not device.is_active assert device.value == (0, 0, 0) @@ -490,7 +492,7 @@ def test_rgbled_toggle(): assert device.value == (0, 0, 0) def test_rgbled_toggle_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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) @@ -501,10 +503,18 @@ def test_rgbled_toggle_nonpwm(): assert not device.is_active assert device.value == (0, 0, 0) +def test_rgbled_blink_nonpwm(): + r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + with RGBLED(r, g, b, pwm=False) as device: + with pytest.raises(ValueError): + device.blink(fade_in_time=1) + with pytest.raises(ValueError): + device.blink(fade_out_time=1) + @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -525,7 +535,7 @@ def test_rgbled_blink_background(): @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)) + r, g, b = (Device._pin_factory.pin(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) @@ -546,7 +556,7 @@ def test_rgbled_blink_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -565,7 +575,7 @@ def test_rgbled_blink_foreground(): @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)) + r, g, b = (Device._pin_factory.pin(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) @@ -584,7 +594,7 @@ def test_rgbled_blink_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_background(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -619,7 +629,7 @@ def test_rgbled_fade_background(): b.assert_states_and_times(expected) def test_rgbled_fade_background_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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) @@ -627,7 +637,7 @@ def test_rgbled_fade_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_foreground(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -660,7 +670,7 @@ def test_rgbled_fade_foreground(): b.assert_states_and_times(expected) def test_rgbled_fade_foreground_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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) @@ -668,7 +678,7 @@ def test_rgbled_fade_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_background(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -703,7 +713,7 @@ def test_rgbled_pulse_background(): b.assert_states_and_times(expected) def test_rgbled_pulse_background_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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) @@ -711,7 +721,7 @@ def test_rgbled_pulse_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_foreground(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -744,13 +754,13 @@ def test_rgbled_pulse_foreground(): b.assert_states_and_times(expected) def test_rgbled_pulse_foreground_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(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)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: device.blink(1, 0.1) sleep(0.2) @@ -760,7 +770,7 @@ def test_rgbled_blink_interrupt(): b.assert_states([0, 1, 0]) def test_rgbled_blink_interrupt_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) with RGBLED(r, g, b, pwm=False) as device: device.blink(1, 0.1) sleep(0.2) @@ -770,7 +780,7 @@ def test_rgbled_blink_interrupt_nonpwm(): b.assert_states([0, 1, 0]) def test_rgbled_close(): - r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: assert not device.closed device.close() @@ -779,7 +789,7 @@ def test_rgbled_close(): assert device.closed def test_rgbled_close_nonpwm(): - r, g, b = (MockPin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) with RGBLED(r, g, b, pwm=False) as device: assert not device.closed device.close() @@ -792,8 +802,8 @@ def test_motor_missing_pins(): Motor() def test_motor_pins(): - f = MockPWMPin(1) - b = MockPWMPin(2) + f = Device._pin_factory.pin(1, pin_class=MockPWMPin) + b = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, PWMOutputDevice) @@ -801,8 +811,8 @@ def test_motor_pins(): assert isinstance(device.backward_device, PWMOutputDevice) def test_motor_pins_nonpwm(): - f = MockPin(1) - b = MockPin(2) + f = Device._pin_factory.pin(1) + b = Device._pin_factory.pin(2) with Motor(f, b, pwm=False) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, DigitalOutputDevice) @@ -810,8 +820,8 @@ def test_motor_pins_nonpwm(): assert isinstance(device.backward_device, DigitalOutputDevice) def test_motor_close(): - f = MockPWMPin(1) - b = MockPWMPin(2) + f = Device._pin_factory.pin(1, pin_class=MockPWMPin) + b = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.close() assert device.closed @@ -821,8 +831,8 @@ def test_motor_close(): assert device.closed def test_motor_close_nonpwm(): - f = MockPin(1) - b = MockPin(2) + f = Device._pin_factory.pin(1) + b = Device._pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.close() assert device.closed @@ -830,8 +840,8 @@ def test_motor_close_nonpwm(): assert device.backward_device.pin is None def test_motor_value(): - f = MockPWMPin(1) - b = MockPWMPin(2) + f = Device._pin_factory.pin(1, pin_class=MockPWMPin) + b = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.value = -1 assert device.is_active @@ -855,8 +865,8 @@ def test_motor_value(): assert b.state == 0 and f.state == 0 def test_motor_value_nonpwm(): - f = MockPin(1) - b = MockPin(2) + f = Device._pin_factory.pin(1) + b = Device._pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.value = -1 assert device.is_active @@ -872,17 +882,21 @@ def test_motor_value_nonpwm(): assert b.state == 0 and f.state == 0 def test_motor_bad_value(): - f = MockPWMPin(1) - b = MockPWMPin(2) + f = Device._pin_factory.pin(1, pin_class=MockPWMPin) + b = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: with pytest.raises(ValueError): device.value = -2 with pytest.raises(ValueError): device.value = 2 + with pytest.raises(ValueError): + device.forward(2) + with pytest.raises(ValueError): + device.backward(2) def test_motor_bad_value_nonpwm(): - f = MockPin(1) - b = MockPin(2) + f = Device._pin_factory.pin(1) + b = Device._pin_factory.pin(2) with Motor(f, b, pwm=False) as device: with pytest.raises(ValueError): device.value = -2 @@ -894,8 +908,8 @@ def test_motor_bad_value_nonpwm(): device.value = -0.5 def test_motor_reverse(): - f = MockPWMPin(1) - b = MockPWMPin(2) + f = Device._pin_factory.pin(1, pin_class=MockPWMPin) + b = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.forward() assert device.value == 1 @@ -911,8 +925,8 @@ def test_motor_reverse(): assert b.state == 0 and f.state == 0.5 def test_motor_reverse_nonpwm(): - f = MockPin(1) - b = MockPin(2) + f = Device._pin_factory.pin(1) + b = Device._pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.forward() assert device.value == 1 @@ -922,13 +936,13 @@ def test_motor_reverse_nonpwm(): assert b.state == 1 and f.state == 0 def test_servo_pins(): - p = MockPWMPin(1) + p = Device._pin_factory.pin(1, pin_class=MockPWMPin) with Servo(p) as device: assert device.pwm_device.pin is p assert isinstance(device.pwm_device, PWMOutputDevice) def test_servo_bad_value(): - p = MockPWMPin(1) + p = Device._pin_factory.pin(1, pin_class=MockPWMPin) with pytest.raises(ValueError): Servo(p, initial_value=2) with pytest.raises(ValueError): @@ -937,12 +951,12 @@ def test_servo_bad_value(): Servo(p, max_pulse_width=30/1000) def test_servo_pins_nonpwm(): - p = MockPin(2) + p = Device._pin_factory.pin(2) with pytest.raises(PinPWMUnsupported): Servo(p) def test_servo_close(): - p = MockPWMPin(2) + p = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Servo(p) as device: device.close() assert device.closed @@ -951,7 +965,7 @@ def test_servo_close(): assert device.closed def test_servo_pulse_width(): - p = MockPWMPin(2) + p = Device._pin_factory.pin(2, pin_class=MockPWMPin) with Servo(p, min_pulse_width=5/10000, max_pulse_width=25/10000) as device: assert isclose(device.min_pulse_width, 5/10000) assert isclose(device.max_pulse_width, 25/10000) @@ -965,7 +979,7 @@ def test_servo_pulse_width(): assert device.pulse_width is None def test_servo_values(): - p = MockPWMPin(1) + p = Device._pin_factory.pin(1, pin_class=MockPWMPin) with Servo(p) as device: device.min() assert device.is_active @@ -992,13 +1006,13 @@ def test_servo_values(): assert device.value is None def test_angular_servo_range(): - p = MockPWMPin(1) + p = Device._pin_factory.pin(1, pin_class=MockPWMPin) with AngularServo(p, initial_angle=15, min_angle=0, max_angle=90) as device: assert device.min_angle == 0 assert device.max_angle == 90 def test_angular_servo_angles(): - p = MockPWMPin(1) + p = Device._pin_factory.pin(1, pin_class=MockPWMPin) with AngularServo(p) as device: device.angle = 0 assert device.angle == 0 diff --git a/tests/test_pins_data.py b/tests/test_pins_data.py index ea43e8f..2a9af16 100644 --- a/tests/test_pins_data.py +++ b/tests/test_pins_data.py @@ -11,44 +11,44 @@ import re import pytest from mock import patch, MagicMock -import gpiozero.devices import gpiozero.pins.data -import gpiozero.pins.native -from gpiozero.pins.data import pi_info, Style, HeaderInfo, PinInfo -from gpiozero import PinMultiplePins, PinNoPins, PinUnknownPi +import gpiozero.pins.local +from gpiozero.pins.local import LocalPiFactory +from gpiozero.pins.data import Style, HeaderInfo, PinInfo +from gpiozero import * def test_pi_revision(): - save_factory = gpiozero.devices.pin_factory - try: + # We're not using _set_pin_factory here because we don't want to implicitly + # close the old instance, just replace it while we test stuff + with patch('gpiozero.devices.Device._pin_factory', LocalPiFactory()): # Can't use MockPin for this as we want something that'll actually try # and read /proc/cpuinfo (MockPin simply parrots the 2B's data); - # NativePin is used as we're guaranteed to be able to import it - gpiozero.devices.pin_factory = gpiozero.pins.native.NativePin + # LocalPiFactory is used as we can definitely instantiate it (strictly + # speaking it's abstract but we're only interested in the pi_info + # stuff) with patch('io.open') as m: m.return_value.__enter__.return_value = ['lots of irrelevant', 'lines', 'followed by', 'Revision: 0002', 'Serial: xxxxxxxxxxx'] assert pi_info().revision == '0002' - # LocalPin caches the revision (because realistically it isn't going to - # change at runtime); we need to wipe it here though - gpiozero.pins.native.NativePin._PI_REVISION = None + # LocalPiFactory caches the revision (because realistically it + # isn't going to change at runtime); we need to wipe it here though + Device._pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: a21042'] assert pi_info().revision == 'a21042' # Check over-volting result (some argument over whether this is 7 or # 8 character result; make sure both work) - gpiozero.pins.native.NativePin._PI_REVISION = None + Device._pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: 1000003'] assert pi_info().revision == '0003' - gpiozero.pins.native.NativePin._PI_REVISION = None + Device._pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: 100003'] assert pi_info().revision == '0003' with pytest.raises(PinUnknownPi): m.return_value.__enter__.return_value = ['nothing', 'relevant', 'at all'] - gpiozero.pins.native.NativePin._PI_REVISION = None + Device._pin_factory._info = None pi_info() with pytest.raises(PinUnknownPi): pi_info('0fff') - finally: - gpiozero.devices.pin_factory = save_factory def test_pi_info(): r = pi_info('900011') @@ -73,14 +73,14 @@ def test_pi_info_other_types(): def test_physical_pins(): # Assert physical pins for some well-known Pi's; a21041 is a Pi2B - assert pi_info('a21041').physical_pins('3V3') == {('P1', 1), ('P1', 17)} - assert pi_info('a21041').physical_pins('GPIO2') == {('P1', 3)} + assert pi_info('a21041').physical_pins('3V3') == {('J8', 1), ('J8', 17)} + assert pi_info('a21041').physical_pins('GPIO2') == {('J8', 3)} assert pi_info('a21041').physical_pins('GPIO47') == set() def test_physical_pin(): with pytest.raises(PinMultiplePins): assert pi_info('a21041').physical_pin('GND') - assert pi_info('a21041').physical_pin('GPIO3') == ('P1', 5) + assert pi_info('a21041').physical_pin('GPIO3') == ('J8', 5) with pytest.raises(PinNoPins): assert pi_info('a21041').physical_pin('GPIO47') @@ -114,6 +114,18 @@ def test_pprint_content(): pi_info('0014').headers['SODIMM'].pprint(color=False) assert len(''.join(stdout.output).splitlines()) == 100 +def test_format_content(): + with patch('sys.stdout') as stdout: + stdout.output = [] + stdout.write = lambda buf: stdout.output.append(buf) + pi_info('900092').pprint(color=False) + s = ''.join(stdout.output) + assert '{0:mono}\n'.format(pi_info('900092')) == s + stdout.output = [] + pi_info('900092').pprint(color=True) + s = ''.join(stdout.output) + assert '{0:color full}\n'.format(pi_info('900092')) == s + def test_pprint_headers(): assert len(pi_info('0002').headers) == 1 assert len(pi_info('000e').headers) == 2 @@ -133,7 +145,8 @@ def test_pprint_headers(): stdout.output = [] pi_info('900092').pprint() s = ''.join(stdout.output) - assert 'P1:\n' in s + assert 'J8:\n' in s + assert 'P1:\n' not in s assert 'P5:\n' not in s def test_pprint_color(): @@ -194,11 +207,12 @@ def test_pprint_missing_pin(): assert ('(%d)' % i) def test_pprint_rows_cols(): - assert '{0:row1}'.format(pi_info('900092').headers['P1']) == '1o' - assert '{0:row2}'.format(pi_info('900092').headers['P1']) == 'oo' + assert '{0:row1}'.format(pi_info('900092').headers['J8']) == '1o' + assert '{0:row2}'.format(pi_info('900092').headers['J8']) == 'oo' assert '{0:col1}'.format(pi_info('0002').headers['P1']) == '1oooooooooooo' assert '{0:col2}'.format(pi_info('0002').headers['P1']) == 'ooooooooooooo' with pytest.raises(ValueError): '{0:row16}'.format(pi_info('0002').headers['P1']) with pytest.raises(ValueError): '{0:col3}'.format(pi_info('0002').headers['P1']) + diff --git a/tests/test_spi.py b/tests/test_spi.py index f035bde..5159109 100644 --- a/tests/test_spi.py +++ b/tests/test_spi.py @@ -4,93 +4,113 @@ from __future__ import ( print_function, division, ) +nstr = str str = type('') import sys -import mock import pytest +from array import array +from mock import patch from collections import namedtuple +from gpiozero.pins.native import NativeFactory +from gpiozero.pins.local import ( + LocalPiHardwareSPI, + LocalPiSoftwareSPI, + LocalPiHardwareSPIShared, + LocalPiSoftwareSPIShared, + ) +from gpiozero.pins.mock import MockSPIDevice from gpiozero import * -from gpiozero.pins.mock import MockPin, MockSPIDevice -from gpiozero.spi import * -def setup_function(function): - import gpiozero.devices - gpiozero.devices.pin_factory = MockPin - def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() def test_spi_hardware_params(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: - with SPI() as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(port=0, device=0) as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(port=0, device=1) as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(clock_pin=11) as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(clock_pin=11, mosi_pin=10, select_pin=8) as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(clock_pin=11, mosi_pin=10, select_pin=7) as device: - assert isinstance(device, SPIHardwareInterface) - with SPI(shared=True) as device: - assert isinstance(device, SharedSPIHardwareInterface) - with pytest.raises(ValueError): - SPI(port=1) - with pytest.raises(ValueError): - SPI(device=2) - with pytest.raises(ValueError): - SPI(port=0, clock_pin=12) - with pytest.raises(ValueError): - SPI(foo='bar') + with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: + mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) + io_open.return_value.__enter__.return_value = ['Revision: a21042'] + with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + patch('gpiozero.pins.local.SpiDev'): + with Device._pin_factory.spi() as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(port=0, device=0) as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(port=0, device=1) as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(clock_pin=11) as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device: + assert isinstance(device, LocalPiHardwareSPI) + with Device._pin_factory.spi(shared=True) as device: + assert isinstance(device, LocalPiHardwareSPIShared) + with pytest.raises(ValueError): + Device._pin_factory.spi(port=1) + with pytest.raises(ValueError): + Device._pin_factory.spi(device=2) + with pytest.raises(ValueError): + Device._pin_factory.spi(port=0, clock_pin=12) + with pytest.raises(ValueError): + Device._pin_factory.spi(foo='bar') def test_spi_software_params(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: - with SPI(select_pin=6) as device: - assert isinstance(device, SPISoftwareInterface) - with SPI(clock_pin=11, mosi_pin=9, miso_pin=10) as device: - assert isinstance(device, SPISoftwareInterface) - with SPI(select_pin=6, shared=True) as device: - assert isinstance(device, SharedSPISoftwareInterface) - # Ensure software fallback works when SpiDev isn't present - with SPI() as device: - assert isinstance(device, SPISoftwareInterface) + with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: + mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) + io_open.return_value.__enter__.return_value = ['Revision: a21042'] + with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + patch('gpiozero.pins.local.SpiDev'): + with Device._pin_factory.spi(select_pin=6) as device: + assert isinstance(device, LocalPiSoftwareSPI) + with Device._pin_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device: + assert isinstance(device, LocalPiSoftwareSPI) + with Device._pin_factory.spi(select_pin=6, shared=True) as device: + assert isinstance(device, LocalPiSoftwareSPIShared) + with patch('gpiozero.devices.Device._pin_factory', NativeFactory()): + # Clear out the old factory's pins cache (this is only necessary + # because we're being very naughty switching out pin factories) + Device._pin_factory.pins.clear() + # Ensure software fallback works when SpiDev isn't present + with Device._pin_factory.spi() as device: + assert isinstance(device, LocalPiSoftwareSPI) def test_spi_hardware_conflict(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: + with patch('gpiozero.pins.local.SpiDev') as spidev: with LED(11) as led: with pytest.raises(GPIOPinInUse): - SPI(port=0, device=0) + Device._pin_factory.spi(port=0, device=0) + with patch('gpiozero.pins.local.SpiDev') as spidev: + with Device._pin_factory.spi(port=0, device=0) as spi: + with pytest.raises(GPIOPinInUse): + LED(11) def test_spi_hardware_read(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: + with patch('gpiozero.pins.local.SpiDev') as spidev: spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)] - with SPI() as device: + with Device._pin_factory.spi() as device: assert device.read(3) == [0, 1, 2] assert device.read(6) == list(range(6)) def test_spi_hardware_write(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: + with patch('gpiozero.pins.local.SpiDev') as spidev: spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)] - with SPI() as device: + with Device._pin_factory.spi() as device: assert device.write([0, 1, 2]) == 3 assert spidev.return_value.xfer2.called_with([0, 1, 2]) assert device.write(list(range(6))) == 6 assert spidev.return_value.xfer2.called_with(list(range(6))) def test_spi_hardware_modes(): - with mock.patch('gpiozero.spi.SpiDev') as spidev: + with patch('gpiozero.pins.local.SpiDev') as spidev: spidev.return_value.mode = 0 spidev.return_value.lsbfirst = False spidev.return_value.cshigh = True spidev.return_value.bits_per_word = 8 - with SPI() as device: + with Device._pin_factory.spi() as device: assert device.clock_mode == 0 assert not device.clock_polarity assert not device.clock_phase @@ -116,7 +136,7 @@ def test_spi_software_read(): super(SPISlave, self).on_start() for i in range(10): self.tx_word(i) - with SPISlave(11, 10, 9, 8) as slave, SPI() as master: + with SPISlave(11, 10, 9, 8) as slave, Device._pin_factory.spi() as master: assert master.read(3) == [0, 1, 2] assert master.read(6) == [0, 1, 2, 3, 4, 5] slave.clock_phase = True @@ -125,7 +145,7 @@ def test_spi_software_read(): assert master.read(6) == [0, 1, 2, 3, 4, 5] def test_spi_software_write(): - with MockSPIDevice(11, 10, 9, 8) as test_device, SPI() as master: + with MockSPIDevice(11, 10, 9, 8) as test_device, Device._pin_factory.spi() as master: master.write([0]) assert test_device.rx_word() == 0 master.write([2, 0]) @@ -134,7 +154,7 @@ def test_spi_software_write(): assert test_device.rx_word() == 257 def test_spi_software_clock_mode(): - with SPI() as master: + with Device._pin_factory.spi() as master: assert master.clock_mode == 0 assert not master.clock_polarity assert not master.clock_phase @@ -151,7 +171,7 @@ def test_spi_software_clock_mode(): master.clock_mode = 5 def test_spi_software_attr(): - with SPI() as master: + with Device._pin_factory.spi() as master: assert not master.lsb_first assert not master.select_high assert master.bits_per_word == 8 diff --git a/tests/test_spi_devices.py b/tests/test_spi_devices.py index ecf0ca8..6c876ad 100644 --- a/tests/test_spi_devices.py +++ b/tests/test_spi_devices.py @@ -15,16 +15,12 @@ try: except ImportError: from gpiozero.compat import isclose -from gpiozero import * from gpiozero.pins.mock import MockSPIDevice, MockPin +from gpiozero import * -def setup_function(function): - import gpiozero.devices - gpiozero.devices.pin_factory = MockPin - def teardown_function(function): - MockPin.clear_pins() + Device._pin_factory.reset() def clamp(v, min_value, max_value): return min(max_value, max(min_value, v)) From 4d79dc74dba6e48738d024d725a8d48fed731546 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 10:43:58 +0100 Subject: [PATCH 30/62] Removed redundant weakref references Also tweaked a couple of minor bits (SPI bus init mask) and unused _get_address override --- gpiozero/pins/local.py | 1 - gpiozero/pins/native.py | 1 - gpiozero/pins/pigpiod.py | 3 --- gpiozero/pins/rpigpio.py | 1 - gpiozero/pins/rpio.py | 1 - gpiozero/pins/spi.py | 9 +++++++-- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index f61f4eb..17310c6 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -7,7 +7,6 @@ from __future__ import ( str = type('') import io -import weakref import warnings try: diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index 12bc5a9..2fd14ec 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -13,7 +13,6 @@ import mmap import errno import struct import warnings -import weakref from time import sleep from threading import Thread, Event, Lock from collections import Counter diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index d36b059..5418e2c 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -179,9 +179,6 @@ class PiGPIOPin(PiPin): self.function = 'input' self.pull = 'up' if self.factory.pi_info.pulled_up('GPIO%d' % self.number) else 'floating' - def _get_address(self): - return self.factory.address + ('GPIO%d' % self.number,) - def _get_function(self): return self.GPIO_FUNCTION_NAMES[self.factory.connection.get_mode(self.number)] diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index 679b8c2..1b073a4 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -7,7 +7,6 @@ from __future__ import ( str = type('') import warnings -import weakref from RPi import GPIO from .local import LocalPiFactory, LocalPiPin diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 2413b57..5f8d740 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -8,7 +8,6 @@ str = type('') import warnings -import weakref import RPIO import RPIO.PWM from RPIO.Exceptions import InvalidChannelException diff --git a/gpiozero/pins/spi.py b/gpiozero/pins/spi.py index a92ff5c..fff2a85 100644 --- a/gpiozero/pins/spi.py +++ b/gpiozero/pins/spi.py @@ -64,9 +64,14 @@ class SPISoftwareBus(SharedMixin, Device): """ result = [] with self.lock: - shift = operator.lshift if lsb_first else operator.rshift + if lsb_first: + shift = operator.lshift + init_mask = 1 + else: + shift = operator.rshift + init_mask = 1 << (bits_per_word - 1) for write_word in data: - mask = 1 if lsb_first else 1 << (bits_per_word - 1) + mask = init_mask read_word = 0 for _ in range(bits_per_word): if self.mosi is not None: From c570b8f09b1ecf6a04e9975a6091e920f7bc6b11 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 11:07:48 +0100 Subject: [PATCH 31/62] Clean up repeated string substitutions --- gpiozero/pins/native.py | 6 +++--- gpiozero/pins/pi.py | 8 ++++---- gpiozero/pins/pigpiod.py | 6 +++--- gpiozero/pins/rpigpio.py | 6 +++--- gpiozero/pins/rpio.py | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index 2fd14ec..e8a521c 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -228,7 +228,7 @@ class NativePin(LocalPiPin): self._change_thread = None self._change_event = Event() self.function = 'input' - self.pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self.pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self.bounce = None self.edges = 'both' @@ -236,7 +236,7 @@ class NativePin(LocalPiPin): self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self.factory.pi_info.pulled_up('GPIO%d' % self.number) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[(self.factory.mem[self._func_offset] >> self._func_shift) & 7] @@ -269,7 +269,7 @@ class NativePin(LocalPiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): + if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: value = self.GPIO_PULL_UPS[value] diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 622ba79..d7a0bbe 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -192,14 +192,14 @@ class PiPin(Pin): """ def __init__(self, factory, number): super(PiPin, self).__init__() + self._factory = weakref.proxy(factory) + self._number = number try: - factory.pi_info.physical_pin('GPIO%d' % number) + factory.pi_info.physical_pin(self.address[-1]) except PinNoPins: warnings.warn( PinNonPhysical( - 'no physical pins exist for GPIO%d' % number)) - self._factory = weakref.proxy(factory) - self._number = number + 'no physical pins exist for %s' % self.address[-1])) @property def number(self): diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 5418e2c..01e8948 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -159,7 +159,7 @@ class PiGPIOPin(PiPin): def __init__(self, factory, number): super(PiGPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = False self._bounce = None self._when_changed = None @@ -177,7 +177,7 @@ class PiGPIOPin(PiPin): self.frequency = None self.when_changed = None self.function = 'input' - self.pull = 'up' if self.factory.pi_info.pulled_up('GPIO%d' % self.number) else 'floating' + self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating' def _get_function(self): return self.GPIO_FUNCTION_NAMES[self.factory.connection.get_mode(self.number)] @@ -219,7 +219,7 @@ class PiGPIOPin(PiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): + if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: self.factory.connection.set_pull_up_down(self.number, self.GPIO_PULL_UPS[value]) diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index 1b073a4..dcc2744 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -84,7 +84,7 @@ class RPiGPIOPin(LocalPiPin): def __init__(self, factory, number): super(RPiGPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = None self._frequency = None self._duty_cycle = None @@ -103,7 +103,7 @@ class RPiGPIOPin(LocalPiPin): GPIO.setup(self.number, GPIO.OUT, initial=state) def input_with_pull(self, pull): - if pull != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): + if pull != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[pull]) @@ -149,7 +149,7 @@ class RPiGPIOPin(LocalPiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): + if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[value]) diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 5f8d740..58ca12e 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -79,7 +79,7 @@ class RPIOPin(LocalPiPin): def __init__(self, factory, number): super(RPIOPin, self).__init__(factory, number) - self._pull = 'up' if factory.pi_info.pulled_up('GPIO%d' % number) else 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = False self._duty_cycle = None self._bounce = None @@ -138,7 +138,7 @@ class RPIOPin(LocalPiPin): def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) - if value != 'up' and self.factory.pi_info.pulled_up('GPIO%d' % self.number): + if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: RPIO.setup(self.number, RPIO.IN, self.GPIO_PULL_UPS[value]) From b0c807da190fdd950badced83a849e8712babbb1 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 14:54:34 +0100 Subject: [PATCH 32/62] More tidying up Ensure LEDCollection cleans up upon construction failure, rename some internals to be a bit more obvious, rename PinGPIOUnsupported to PinUnsupported, and some other stuff I've forgotten! --- docs/api_exc.rst | 2 +- gpiozero/boards.py | 32 +++++++++++++++------------- gpiozero/devices.py | 19 +++++++---------- gpiozero/exc.py | 4 ++-- gpiozero/mixins.py | 2 +- gpiozero/pins/__init__.py | 3 ++- gpiozero/pins/local.py | 44 ++++++++++++++++++++------------------- gpiozero/pins/pi.py | 22 ++++++++------------ gpiozero/pins/pigpiod.py | 10 +++++---- 9 files changed, 69 insertions(+), 69 deletions(-) diff --git a/docs/api_exc.rst b/docs/api_exc.rst index f68ed72..5d67aa1 100644 --- a/docs/api_exc.rst +++ b/docs/api_exc.rst @@ -105,7 +105,7 @@ Errors .. autoexception:: PinEdgeDetectUnsupported -.. autoexception:: PinGPIOUnsupported +.. autoexception:: PinUnsupported .. autoexception:: PinSPIUnsupported diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 7809fea..90074f4 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -211,20 +211,24 @@ class LEDCollection(CompositeOutputDevice): initial_value = kwargs.pop('initial_value', False) order = kwargs.pop('_order', None) LEDClass = PWMLED if pwm else LED - super(LEDCollection, self).__init__( - *( - pin_or_collection - if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) - for pin_or_collection in args - ), - _order=order, - **{ - name: pin_or_collection - if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) - for name, pin_or_collection in kwargs.items() - }) + try: + super(LEDCollection, self).__init__( + *( + pin_or_collection + if isinstance(pin_or_collection, LEDCollection) else + LEDClass(pin_or_collection, active_high, initial_value) + for pin_or_collection in args + ), + _order=order, + **{ + name: pin_or_collection + if isinstance(pin_or_collection, LEDCollection) else + LEDClass(pin_or_collection, active_high, initial_value) + for name, pin_or_collection in kwargs.items() + }) + except: + self.close() + raise leds = [] for item in self: if isinstance(item, LEDCollection): diff --git a/gpiozero/devices.py b/gpiozero/devices.py index c8c5b49..9b587b3 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -11,7 +11,7 @@ import os import atexit import weakref import warnings -from collections import namedtuple +from collections import namedtuple, defaultdict from itertools import chain from types import FunctionType from threading import Lock @@ -194,7 +194,7 @@ class Device(ValuesMixin, GPIOBase): property, the :attr:`value` property, and the :meth:`close` method). """ _pin_factory = None # instance of a Factory sub-class - _reservations = {} # maps pin addresses to lists of devices + _reservations = defaultdict(list) # maps pin addresses to lists of devices _res_lock = Lock() def __repr__(self): @@ -226,19 +226,14 @@ class Device(ValuesMixin, GPIOBase): ) with self._res_lock: for address in addresses: - try: - conflictors = self._reservations[address] - except KeyError: - conflictors = [] - self._reservations[address] = conflictors - for device_ref in conflictors: + for device_ref in Device._reservations[address]: device = device_ref() if device is not None and self._conflicts_with(device): raise GPIOPinInUse( 'pin %s is already in use by %r' % ( '/'.join(address), device) ) - conflictors.append(weakref.ref(self)) + Device._reservations[address].append(weakref.ref(self)) def _release_pins(self, *pins_or_addresses): """ @@ -254,7 +249,7 @@ class Device(ValuesMixin, GPIOBase): ) with self._res_lock: for address in addresses: - self._reservations[address] = [ + Device._reservations[address] = [ ref for ref in self._reservations[address] if ref() not in (self, None) # may as well clean up dead refs ] @@ -265,13 +260,13 @@ class Device(ValuesMixin, GPIOBase): :meth:`_release_pins` for further information). """ with self._res_lock: - Device._reservations = { + Device._reservations = defaultdict(list, { address: [ ref for ref in conflictors if ref() not in (self, None) ] for address, conflictors in self._reservations.items() - } + }) def _conflicts_with(self, other): """ diff --git a/gpiozero/exc.py b/gpiozero/exc.py index 9ed9361..416f1a6 100644 --- a/gpiozero/exc.py +++ b/gpiozero/exc.py @@ -118,8 +118,8 @@ class PinFixedPull(PinError, AttributeError): class PinEdgeDetectUnsupported(PinError, AttributeError): "Error raised when attempting to use edge detection on unsupported pins" -class PinGPIOUnsupported(PinError, NotImplementedError): - "Error raised when attempting to obtain a GPIO interface on unsupported pins" +class PinUnsupported(PinError, NotImplementedError): + "Error raised when attempting to obtain a pin interface on unsupported pins" class PinSPIUnsupported(PinError, NotImplementedError): "Error raised when attempting to obtain an SPI interface on unsupported pins" diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index 669617f..25c2012 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -71,9 +71,9 @@ class SourceMixin(object): def close(self): try: super(SourceMixin, self).close() + self.source = None except AttributeError: pass - self.source = None def _copy_values(self, source): for v in source: diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index f88cb11..71d3939 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -12,6 +12,7 @@ from ..exc import ( PinInvalidFunction, PinSetInput, PinFixedPull, + PinUnsupported, PinSPIUnsupported, PinPWMUnsupported, PinEdgeDetectUnsupported, @@ -58,7 +59,7 @@ class Factory(object): :meth:`pin` for the same pin specification must return the same object. """ - raise PinGPIOUnsupported("GPIO not supported by this pin factory") + raise PinUnsupported("Individual pins are not supported by this pin factory") def pin_address(self, spec): """ diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index 17310c6..3fb6820 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -32,10 +32,12 @@ class LocalPiFactory(PiFactory): def __init__(self): super(LocalPiFactory, self).__init__() - self.spi_hardware_class = LocalPiHardwareSPI - self.spi_software_class = LocalPiSoftwareSPI - self.shared_spi_hardware_class = LocalPiHardwareSPIShared - self.shared_spi_software_class = LocalPiSoftwareSPIShared + self.spi_classes = { + ('hardware', 'exclusive'): LocalPiHardwareSPI, + ('hardware', 'shared'): LocalPiHardwareSPIShared, + ('software', 'exclusive'): LocalPiSoftwareSPI, + ('software', 'shared'): LocalPiSoftwareSPIShared, + } # Override the pins dict to be this class' pins dict. This is a bit of # a dirty hack, but ensures that anyone evil enough to mix pin # implementations doesn't try and control the same pin with different @@ -74,7 +76,7 @@ class LocalPiHardwareSPI(SPI, Device): raise ImportError('failed to import spidev') self._port = port self._device = device - self._intf = None + self._interface = None self._address = factory.address + ('SPI(port=%d, device=%d)' % (port, device),) super(LocalPiHardwareSPI, self).__init__() self._reserve_pins( @@ -83,9 +85,9 @@ class LocalPiHardwareSPI(SPI, Device): factory.pin_address(9), factory.pin_address((8, 7)[device]) ) - self._intf = SpiDev() - self._intf.open(port, device) - self._intf.max_speed_hz = 500000 + self._interface = SpiDev() + self._interface.open(port, device) + self._interface.max_speed_hz = 500000 def _conflicts_with(self, other): return not ( @@ -94,17 +96,17 @@ class LocalPiHardwareSPI(SPI, Device): ) def close(self): - if self._intf: + if self._interface: try: - self._intf.close() + self._interface.close() finally: - self._intf = None + self._interface = None self._release_all() super(LocalPiHardwareSPI, self).close() @property def closed(self): - return self._intf is None + return self._interface is None def __repr__(self): try: @@ -119,31 +121,31 @@ class LocalPiHardwareSPI(SPI, Device): :attr:`bits_per_word` bits or less) to the SPI interface, and reads an equivalent number of words, returning them as a list of integers. """ - return self._intf.xfer2(data) + return self._interface.xfer2(data) def _get_clock_mode(self): - return self._intf.mode + return self._interface.mode def _set_clock_mode(self, value): - self._intf.mode = value + self._interface.mode = value def _get_lsb_first(self): - return self._intf.lsbfirst + return self._interface.lsbfirst def _set_lsb_first(self, value): - self._intf.lsbfirst = bool(value) + self._interface.lsbfirst = bool(value) def _get_select_high(self): - return self._intf.cshigh + return self._interface.cshigh def _set_select_high(self, value): - self._intf.cshigh = bool(value) + self._interface.cshigh = bool(value) def _get_bits_per_word(self): - return self._intf.bits_per_word + return self._interface.bits_per_word def _set_bits_per_word(self, value): - self._intf.bits_per_word = value + self._interface.bits_per_word = value class LocalPiSoftwareSPI(SPI, OutputDevice): diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index d7a0bbe..0d40efb 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -35,10 +35,12 @@ class PiFactory(Factory): self._info = None self.pins = {} self.pin_class = None - self.spi_hardware_class = None - self.spi_software_class = None - self.shared_spi_hardware_class = None - self.shared_spi_software_class = None + self.spi_classes = { + ('hardware', 'exclusive'): None, + ('hardware', 'shared'): None, + ('software', 'exclusive'): None, + ('software', 'shared'): None, + } def close(self): for pin in self.pins.values(): @@ -93,7 +95,7 @@ class PiFactory(Factory): doesn't matter). """ spi_args, kwargs = self._extract_spi_args(**spi_args) - shared = kwargs.pop('shared', False) + shared = 'shared' if kwargs.pop('shared', False) else 'exclusive' if kwargs: raise SPIBadArgs( 'unrecognized keyword argument %s' % kwargs.popitem()[0]) @@ -108,10 +110,7 @@ class PiFactory(Factory): 'port': 0, 'device': {8: 0, 7: 1}[spi_args['select_pin']], } - if shared: - return self.shared_spi_hardware_class(self, **hardware_spi_args) - else: - return self.spi_hardware_class(self, **hardware_spi_args) + return self.spi_classes[('hardware', shared)](self, **hardware_spi_args) except Exception as e: warnings.warn( SPISoftwareFallback( @@ -125,10 +124,7 @@ class PiFactory(Factory): key: pin.number if isinstance(pin, Pin) else pin for key, pin in spi_args.items() } - if shared: - return self.shared_spi_software_class(self, **spi_args) - else: - return self.spi_software_class(self, **spi_args) + return self.spi_classes[('software', shared)](self, **spi_args) def _extract_spi_args(self, **kwargs): """ diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 01e8948..e507a9d 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -76,10 +76,12 @@ class PiGPIOFactory(PiFactory): port=int(os.getenv('PIGPIO_PORT', 8888))): super(PiGPIOFactory, self).__init__() self.pin_class = PiGPIOPin - self.spi_hardware_class = PiGPIOHardwareSPI - self.spi_software_class = PiGPIOSoftwareSPI - self.shared_spi_hardware_class = PiGPIOHardwareSPIShared - self.shared_spi_software_class = PiGPIOSoftwareSPIShared + self.spi_classes = { + ('hardware', 'exclusive'): PiGPIOHardwareSPI, + ('hardware', 'shared'): PiGPIOHardwareSPIShared, + ('software', 'exclusive'): PiGPIOSoftwareSPI, + ('software', 'shared'): PiGPIOSoftwareSPIShared, + } self._connection = pigpio.pi(host, port) self._host = host self._port = port From ba1a7e6497d0e3d48db29cfb6f61abcb0b71cb96 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 20:49:31 +0100 Subject: [PATCH 33/62] Add configuration of mock factory via env-vars Also tidied up some docs --- docs/api_pins.rst | 31 +++++++++++++++++++++++++++++-- gpiozero/pins/__init__.py | 19 +++++++++++-------- gpiozero/pins/mock.py | 13 ++++++++++++- setup.py | 8 +++++++- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/docs/api_pins.rst b/docs/api_pins.rst index fd8e0e6..fda62cf 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -32,6 +32,31 @@ The default pin factory can be replaced by specifying a value for the >>> gpiozero.Device._pin_factory +To set the ``GPIOZERO_PIN_FACTORY`` for the rest of your session you can +export this value: + +.. code-block:: console + + pi@raspberrypi $ export GPIOZERO_PIN_FACTORY=native + pi@raspberrypi $ python + Python 3.4.2 (default, Oct 19 2014, 13:31:11) + [GCC 4.9.1] on linux + Type "help", "copyright", "credits" or "license" for more information. + >>> import gpiozero + >>> gpiozero.Device._pin_factory + + >>> quit() + pi@raspberrypi $ python + Python 3.4.2 (default, Oct 19 2014, 13:31:11) + [GCC 4.9.1] on linux + Type "help", "copyright", "credits" or "license" for more information. + >>> import gpiozero + >>> gpiozero.Device._pin_factory + + +If you add the ``export`` command to your :file:`~/.bashrc` file, you'll set +the default pin factory for all future sessions too. + The following values, and the corresponding :class:`Factory` and :class:`Pin` classes are listed in the table below. Factories are listed in the order that they are tried by default. @@ -71,8 +96,10 @@ script: .. code-block:: console - $ export GPIOZERO_PIN_FACTORY=pigpio - $ PIGPIO_ADDR=remote-pi python3 my_script.py + $ GPIOZERO_PIN_FACTORY=pigpio PIGPIO_ADDR=remote-pi python3 my_script.py + +Like the ``GPIOZERO_PIN_FACTORY`` value, these can be exported from your +:file:`~/.bashrc` script too. .. warning:: diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index 71d3939..df30f61 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -26,12 +26,14 @@ from ..exc import ( class Factory(object): """ Generates pins, SPI, and I2C interfaces for devices. This is an abstract - base class for pin factories. Descendents must override: + base class for pin factories. Descendents *must* override the following + methods: * :meth:`_get_address` * :meth:`pin_address` - Descendents may override: + Descendents *may* additionally override the following methods, if + applicable: * :meth:`close` * :meth:`pin` @@ -123,15 +125,16 @@ class Pin(object): be it GPIO, SPI, ADC, etc. Descendents should override property getters and setters to accurately - represent the capabilities of pins. The following functions *must* be - overridden: + represent the capabilities of pins. Descendents *must* override the + following methods: * :meth:`_get_address` * :meth:`_get_function` * :meth:`_set_function` * :meth:`_get_state` - The following functions *may* be overridden if applicable: + Descendents *may* additionally override the following methods, if + applicable: * :meth:`close` * :meth:`output_with_state` @@ -389,13 +392,13 @@ class Pin(object): class SPI(object): """ - Abstract interface for `Serial Peripheral Interface`_ (SPI) implementations. - Descendents *must* override the following: + Abstract interface for `Serial Peripheral Interface`_ (SPI) + implementations. Descendents *must* override the following methods: * :meth:`transfer` * :meth:`_get_clock_mode` - Descendents *may* override the following methods: + Descendents *may* override the following methods, if applicable: * :meth:`read` * :meth:`write` diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 8cced75..4b97647 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -7,6 +7,7 @@ from __future__ import ( str = type('') +import os from collections import namedtuple from time import time, sleep from threading import Thread, Event @@ -15,6 +16,8 @@ try: except ImportError: from ..compat import isclose +import pkg_resources + from ..exc import PinPWMUnsupported, PinSetInput, PinFixedPull from ..devices import Device from .pi import PiPin @@ -387,9 +390,17 @@ class MockSPIDevice(object): class MockFactory(LocalPiFactory): - def __init__(self, revision='a21041', pin_class=MockPin): + def __init__( + self, revision=os.getenv('GPIOZERO_MOCK_REVISION', 'a21041'), + pin_class=os.getenv('GPIOZERO_MOCK_PIN_CLASS', MockPin)): super(MockFactory, self).__init__() self._revision = revision + if not issubclass(pin_class, MockPin): + if isinstance(pin_class, bytes): + pin_class = pin_class.decode('ascii') + dist = pkg_resources.get_distribution('gpiozero') + group = 'gpiozero_mock_pin_classes' + pin_class = pkg_resources.load_entry_point(dist, group, pin_class.lower()) self.pin_class = pin_class def _get_address(self): diff --git a/setup.py b/setup.py index 3540700..9801fb8 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,13 @@ __entry_points__ = { 'rpio = gpiozero.pins.rpio:RPIOFactory', 'native = gpiozero.pins.native:NativeFactory', 'mock = gpiozero.pins.mock:MockFactory', - 'mockpwm = gpiozero.pins.mock:MockPWMFactory', + ], + 'gpiozero_mock_pin_classes': [ + 'mockpin = gpiozero.pins.mock:MockPin', + 'mockpwmpin = gpiozero.pins.mock:MockPWMPin', + 'mockpulleduppin = gpiozero.pins.mock:MockPulledUpPin', + 'mockchargingpin = gpiozero.pins.mock:MockChargingPin', + 'mocktriggerpin = gpiozero.pins.mock:MockTriggerPin', ], 'console_scripts': [ 'pinout = gpiozero.cli.pinout:main', From a9f9aa4a3e9d7eae148eb9fa96944045b2d95a5f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 21:51:10 +0100 Subject: [PATCH 34/62] Catch SPI conflicts properly Also handle SPI flags in pigpio implementation more elegantly (just store the flags and manipulate them instead of keeping separate fields) --- gpiozero/pins/local.py | 12 +++--- gpiozero/pins/pigpiod.py | 88 +++++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index 3fb6820..13b961b 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -89,12 +89,6 @@ class LocalPiHardwareSPI(SPI, Device): self._interface.open(port, device) self._interface.max_speed_hz = 500000 - def _conflicts_with(self, other): - return not ( - isinstance(other, LocalPiHardwareSPI) and - (self._port, self._device) != (other._port, other._device) - ) - def close(self): if self._interface: try: @@ -165,6 +159,12 @@ class LocalPiSoftwareSPI(SPI, OutputDevice): self.close() raise + def _conflicts_with(self, other): + return not ( + isinstance(other, LocalPiSoftwareSPI) and + (self.pin.number != other.pin.number) + ) + def close(self): if self._bus: self._bus.close() diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index e507a9d..2b6d655 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -294,13 +294,17 @@ class PiGPIOHardwareSPI(SPI, Device): factory.address + ('GPIO%d' % pin,) for pin in (11, 10, 9, (8, 7)[device]) )) - self._mode = 0 - self._select_high = False - self._bits_per_word = 8 + self._spi_flags = 8 << 16 self._baud = 500000 self._handle = self._factory.connection.spi_open( device, self._baud, self._spi_flags()) + def _conflicts_with(self, other): + return not ( + isinstance(other, PiGPIOHardwareSPI) and + (self._port, self._device) != (other._port, other._device) + ) + def close(self): try: self._factory._spis.remove(self) @@ -329,44 +333,37 @@ class PiGPIOHardwareSPI(SPI, Device): except DeviceClosed: return 'SPI(closed)' - def _spi_flags(self): - return ( - self._mode << 0 | - self._select_high << (2 + self._device) | - self._bits_per_word << 16 - ) - def _get_clock_mode(self): - return self._clock_mode + return self._spi_flags & 0x3 def _set_clock_mode(self, value): self._check_open() if not 0 <= value < 4: - raise SPIInvalidClockmode("%d is not a valid SPI clock mode" % value) + raise SPIInvalidClockMode("%d is not a valid SPI clock mode" % value) self._factory.connection.spi_close(self._handle) - self._clock_mode = value + self._spi_flags = (self._spi_flags & ~0x3) | value self._handle = self._factory.connection.spi_open( - self._device, self._baud, self._spi_flags()) + self._device, self._baud, self._spi_flags) def _get_select_high(self): - return self._select_high + return bool((self._spi_flags >> (2 + self._device)) & 0x1) def _set_select_high(self, value): self._check_open() self._factory.connection.spi_close(self._handle) - self._select_high = bool(value) + self._spi_flags = (self._spi_flags & ~0x1c) | (bool(value) << (2 + self._device)) self._handle = self._factory.connection.spi_open( - self._device, self._baud, self._spi_flags()) + self._device, self._baud, self._spi_flags) def _get_bits_per_word(self): - return self._bits_per_word + return (self._spi_flags >> 16) & 0x3f def _set_bits_per_word(self, value): self._check_open() self._factory.connection.spi_close(self._handle) - self._bits_per_word = value + self._spi_flags = (self._spi_flags & ~0x3f0000) | ((value & 0x3f) << 16) self._handle = self._factory.connection.spi_open( - self._device, self._baud, self._spi_flags()) + self._device, self._baud, self._spi_flags) def transfer(self, data): self._check_open() @@ -380,10 +377,12 @@ class PiGPIOHardwareSPI(SPI, Device): class PiGPIOSoftwareSPI(SPI, Device): def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin): - self._select_pin = None + self._closed = True + self._select_pin = select_pin + self._clock_pin = clock_pin + self._mosi_pin = mosi_pin + self._miso_pin = miso_pin self._factory = weakref.proxy(factory) - self._address = factory.address + ( - ) super(PiGPIOSoftwareSPI, self).__init__() self._reserve_pins( factory.pin_address(clock_pin), @@ -391,24 +390,25 @@ class PiGPIOSoftwareSPI(SPI, Device): factory.pin_address(miso_pin), factory.pin_address(select_pin), ) - self._mode = 0 - self._select_high = False - self._lsb_first = False + self._spi_flags = 0 self._baud = 100000 try: self._factory.connection.bb_spi_open( select_pin, miso_pin, mosi_pin, clock_pin, - self._baud, self._spi_flags()) + self._baud, self._spi_flags) # Only set after opening bb_spi; if that fails then close() will # also fail if bb_spi_close is attempted on an un-open interface - self._select_pin = select_pin - self._clock_pin = clock_pin - self._mosi_pin = mosi_pin - self._miso_pin = miso_pin + self._closed = False except: self.close() raise + def _conflicts_with(self, other): + return not ( + isinstance(other, PiGPIOHardwareSPI) and + (self._select_pin) != (other._select_pin) + ) + def close(self): try: self._factory._spis.remove(self) @@ -417,14 +417,14 @@ class PiGPIOSoftwareSPI(SPI, Device): # internal list, ignore the error pass if not self.closed: + self._closed = True self._factory.connection.bb_spi_close(self._select_pin) - self._select_pin = None self._release_all() super(PiGPIOSoftwareSPI, self).close() @property def closed(self): - return self._select_pin is None or self._factory.connection is None + return self._closed def __repr__(self): try: @@ -445,39 +445,43 @@ class PiGPIOSoftwareSPI(SPI, Device): ) def _get_clock_mode(self): - return self._clock_mode + return self._spi_flags & 0x3 def _set_clock_mode(self, value): self._check_open() if not 0 <= value < 4: raise SPIInvalidClockmode("%d is not a valid SPI clock mode" % value) self._factory.connection.bb_spi_close(self._select_pin) - self._clock_mode = value + self._spi_flags = (self._spi_flags & ~0x3) | value self._factory.connection.bb_spi_open( self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, - self._baud, self._spi_flags()) + self._baud, self._spi_flags) def _get_select_high(self): - return self._select_high + return bool(self._spi_flags & 0x4) def _set_select_high(self, value): self._check_open() self._factory.connection.bb_spi_close(self._select_pin) - self._select_high = bool(value) + self._spi_flags = (self._spi_flags & ~0x4) | (bool(value) << 2) self._factory.connection.bb_spi_open( self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, - self._baud, self._spi_flags()) + self._baud, self._spi_flags) def _get_lsb_first(self): - return self._lsb_first + return bool(self._spi_flags & 0xc000) def _set_lsb_first(self, value): self._check_open() self._factory.connection.bb_spi_close(self._select_pin) - self._lsb_first = bool(value) + self._spi_flags = ( + (self._spi_flags & ~0xc000) + | (bool(value) << 14) + | (bool(value) << 15) + ) self._factory.connection.bb_spi_open( self._select_pin, self._miso_pin, self._mosi_pin, self._clock_pin, - self._baud, self._spi_flags()) + self._baud, self._spi_flags) def transfer(self, data): self._check_open() From cbff81f3a182c2a1418edd571923b8d04bc7961f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 22:12:55 +0100 Subject: [PATCH 35/62] Simplify SPI bit-banging implementation And add some comments to make stuff clearer --- gpiozero/pins/spi.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gpiozero/pins/spi.py b/gpiozero/pins/spi.py index fff2a85..c118e18 100644 --- a/gpiozero/pins/spi.py +++ b/gpiozero/pins/spi.py @@ -64,6 +64,11 @@ class SPISoftwareBus(SharedMixin, Device): """ result = [] with self.lock: + # See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + # (specifically the section "Example of bit-banging the master + # protocol") for a simpler C implementation of this which ignores + # clock polarity, phase, variable word-size, and multiple input + # words if lsb_first: shift = operator.lshift init_mask = 1 @@ -76,13 +81,15 @@ class SPISoftwareBus(SharedMixin, Device): for _ in range(bits_per_word): if self.mosi is not None: self.mosi.value = bool(write_word & mask) + # read bit on clock activation self.clock.on() - if self.miso is not None and not clock_phase: - if self.miso.value: + if not clock_phase: + if self.miso is not None and self.miso.value: read_word |= mask + # read bit on clock deactivation self.clock.off() - if self.miso is not None and clock_phase: - if self.miso.value: + if clock_phase: + if self.miso is not None and self.miso.value: read_word |= mask mask = shift(mask, 1) result.append(read_word) From 15d2c860d3357ba4f81722e751e0b9528f3a5818 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 22:30:40 +0100 Subject: [PATCH 36/62] Use with in a few more tests --- tests/test_devices.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/test_devices.py b/tests/test_devices.py index 01b714a..858b388 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -49,28 +49,28 @@ def test_device_init_twice_different_pin(): def test_device_close(): device = GPIODevice(2) + # Don't use "with" here; we're testing close explicitly device.close() assert device.closed assert device.pin is None def test_device_reopen_same_pin(): pin = Device._pin_factory.pin(2) - device = GPIODevice(pin) - device.close() - device2 = GPIODevice(pin) - assert not device2.closed - assert device2.pin is pin - assert device.closed - assert device.pin is None - device2.close() + with GPIODevice(pin) as device: + pass + with GPIODevice(pin) as device2: + assert not device2.closed + assert device2.pin is pin + assert device.closed + assert device.pin is None def test_device_repr(): with GPIODevice(2) as device: assert repr(device) == '' % device.pin def test_device_repr_after_close(): - device = GPIODevice(2) - device.close() + with GPIODevice(2) as device: + pass assert repr(device) == '' def test_device_unknown_attr(): From 08076e8d0edfd11fe7e77f5c41552630060b9827 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 21 Oct 2016 22:30:47 +0100 Subject: [PATCH 37/62] Inline the SPI hardware args (neater code) --- gpiozero/pins/pi.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 0d40efb..d663b08 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -106,11 +106,9 @@ class PiFactory(Factory): spi_args['select_pin'] in (7, 8), )): try: - hardware_spi_args = { - 'port': 0, - 'device': {8: 0, 7: 1}[spi_args['select_pin']], - } - return self.spi_classes[('hardware', shared)](self, **hardware_spi_args) + return self.spi_classes[('hardware', shared)]( + self, port=0, device=0 if spi_args['select_pin'] == 8 else 1 + ) except Exception as e: warnings.warn( SPISoftwareFallback( From cab6cc80862e0ac95c36a46ea9a2fcc6b9d50c55 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 13:55:31 +0100 Subject: [PATCH 38/62] Rework when_changed attribute to use weakrefs Some fairly major changes to ensure that the Pin.when_changed property doesn't keep references to the objects owning the callbacks that are assigned. This is vaguely tricky given that ordinary weakref's can't be used with bound methods (which are ephemeral), so I've back-ported weakref.WeakMethod from Py3.4. This solves a whole pile of things like Button instances not disappearing when they're deleted, and makes composite devices containing Buttons much easier to construct as we don't need to worry about partially constructed things not getting deleted. --- gpiozero/boards.py | 32 ++++++++++------------ gpiozero/compat.py | 57 ++++++++++++++++++++++++++++++++++++++++ gpiozero/mixins.py | 31 +++++++++++++--------- gpiozero/pins/pi.py | 47 +++++++++++++++++++++++++++++++-- gpiozero/pins/pigpiod.py | 31 +++++++++++++--------- gpiozero/pins/rpigpio.py | 33 +++++++++++++---------- gpiozero/pins/rpio.py | 42 +++++++++++++++-------------- 7 files changed, 193 insertions(+), 80 deletions(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 90074f4..7809fea 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -211,24 +211,20 @@ class LEDCollection(CompositeOutputDevice): initial_value = kwargs.pop('initial_value', False) order = kwargs.pop('_order', None) LEDClass = PWMLED if pwm else LED - try: - super(LEDCollection, self).__init__( - *( - pin_or_collection - if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) - for pin_or_collection in args - ), - _order=order, - **{ - name: pin_or_collection - if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) - for name, pin_or_collection in kwargs.items() - }) - except: - self.close() - raise + super(LEDCollection, self).__init__( + *( + pin_or_collection + if isinstance(pin_or_collection, LEDCollection) else + LEDClass(pin_or_collection, active_high, initial_value) + for pin_or_collection in args + ), + _order=order, + **{ + name: pin_or_collection + if isinstance(pin_or_collection, LEDCollection) else + LEDClass(pin_or_collection, active_high, initial_value) + for name, pin_or_collection in kwargs.items() + }) leds = [] for item in self: if isinstance(item, LEDCollection): diff --git a/gpiozero/compat.py b/gpiozero/compat.py index 31e5f35..c8c01a2 100644 --- a/gpiozero/compat.py +++ b/gpiozero/compat.py @@ -9,6 +9,7 @@ from __future__ import ( str = type('') import cmath +import weakref import collections import operator import functools @@ -81,3 +82,59 @@ class frozendict(collections.Mapping): hashes = map(hash, self.items()) self.__hash = functools.reduce(operator.xor, hashes, 0) return self.__hash + + +# Backported from py3.4 +class WeakMethod(weakref.ref): + """ + A custom `weakref.ref` subclass which simulates a weak reference to + a bound method, working around the lifetime problem of bound methods. + """ + + __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__" + + def __new__(cls, meth, callback=None): + try: + obj = meth.__self__ + func = meth.__func__ + except AttributeError: + raise TypeError("argument should be a bound method, not {0}" + .format(type(meth))) from None + def _cb(arg): + # The self-weakref trick is needed to avoid creating a reference + # cycle. + self = self_wr() + if self._alive: + self._alive = False + if callback is not None: + callback(self) + self = weakref.ref.__new__(cls, obj, _cb) + self._func_ref = weakref.ref(func, _cb) + self._meth_type = type(meth) + self._alive = True + self_wr = weakref.ref(self) + return self + + def __call__(self): + obj = super(WeakMethod, self).__call__() + func = self._func_ref() + if obj is None or func is None: + return None + return self._meth_type(func, obj) + + def __eq__(self, other): + if isinstance(other, WeakMethod): + if not self._alive or not other._alive: + return self is other + return weakref.ref.__eq__(self, other) and self._func_ref == other._func_ref + return False + + def __ne__(self, other): + if isinstance(other, WeakMethod): + if not self._alive or not other._alive: + return self is not other + return weakref.ref.__ne__(self, other) or self._func_ref != other._func_ref + return True + + __hash__ = weakref.ref.__hash__ + diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index 25c2012..794a850 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -438,23 +438,28 @@ class HoldThread(GPIOThread): device is active. """ def __init__(self, parent): - super(HoldThread, self).__init__(target=self.held, args=(parent,)) + super(HoldThread, self).__init__( + target=self.held, args=(weakref.proxy(parent),)) self.holding = Event() self.start() def held(self, parent): - while not self.stopping.is_set(): - if self.holding.wait(0.1): - self.holding.clear() - while not ( - self.stopping.is_set() or - parent._inactive_event.wait(parent.hold_time) - ): - if parent._held_from is None: - parent._held_from = time() - parent._fire_held() - if not parent.hold_repeat: - break + try: + while not self.stopping.is_set(): + if self.holding.wait(0.1): + self.holding.clear() + while not ( + self.stopping.is_set() or + parent._inactive_event.wait(parent.hold_time) + ): + if parent._held_from is None: + parent._held_from = time() + parent._fire_held() + if not parent.hold_repeat: + break + except ReferenceError: + # Parent is dead; time to die! + pass class GPIOQueue(GPIOThread): diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index d663b08..e7aba58 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -7,7 +7,12 @@ from __future__ import ( str = type('') import io -import weakref +from threading import RLock +from weakref import ref, proxy +try: + from weakref import WeakMethod +except ImportError: + from .compat import WeakMethod import warnings try: @@ -186,7 +191,9 @@ class PiPin(Pin): """ def __init__(self, factory, number): super(PiPin, self).__init__() - self._factory = weakref.proxy(factory) + self._factory = proxy(factory) + self._when_changed_lock = RLock() + self._when_changed = None self._number = number try: factory.pi_info.physical_pin(self.address[-1]) @@ -206,3 +213,39 @@ class PiPin(Pin): def _get_address(self): return self.factory.address + ('GPIO%d' % self.number,) + def _call_when_changed(self): + method = self.when_changed() + if method is None: + self.when_changed = None + else: + method() + + def _get_when_changed(self): + return self._when_changed + + def _set_when_changed(self, value): + # Have to take care, if value is either a closure or a bound method, + # not to keep a strong reference to the containing object + with self._when_changed_lock: + if self._when_changed is None and value is not None: + if isinstance(value, MethodType): + self._when_changed = WeakMethod(value) + else: + self._when_changed = ref(value) + self._enable_event_detect() + elif self._when_changed is not None and value is None: + self._disable_event_detect() + self._when_changed = None + elif value is None: + self._when_changed = None + elif isinstance(value, MethodType): + self._when_changed = WeakMethod(value) + else: + self._when_changed = ref(value) + + def _enable_event_detect(self): + raise NotImplementedError + + def _disable_event_detect(self): + raise NotImplementedError + diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 2b6d655..a739512 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -6,9 +6,15 @@ from __future__ import ( ) str = type('') -import weakref -import pigpio import os +from weakref import proxy +from threading import RLock +try: + from weakref import WeakMethod +except ImportError: + from .compat import WeakMethod + +import pigpio from . import SPI from .pi import PiPin, PiFactory @@ -164,6 +170,7 @@ class PiGPIOPin(PiPin): self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = False self._bounce = None + self._when_changed_lock = RLock() self._when_changed = None self._callback = None self._edges = pigpio.EITHER_EDGE @@ -269,26 +276,24 @@ class PiGPIOPin(PiPin): finally: self.when_changed = f - def _get_when_changed(self): - if self._callback is None: - return None - return self._callback.callb.func + def _call_when_changed(self, gpio, level, tick): + super(PiGPIOPin, self)._call_when_changed() - def _set_when_changed(self, value): + def _enable_event_detect(self): + self._callback = self.factory.connection.callback( + self.number, self._edges, self._call_when_changed) + + def _disable_event_detect(self): if self._callback is not None: self._callback.cancel() self._callback = None - if value is not None: - self._callback = self.factory.connection.callback( - self.number, self._edges, - lambda gpio, level, tick: value()) class PiGPIOHardwareSPI(SPI, Device): def __init__(self, factory, port, device): self._port = port self._device = device - self._factory = weakref.proxy(factory) + self._factory = proxy(factory) super(PiGPIOHardwareSPI, self).__init__() self._reserve_pins(*( factory.address + ('GPIO%d' % pin,) @@ -382,7 +387,7 @@ class PiGPIOSoftwareSPI(SPI, Device): self._clock_pin = clock_pin self._mosi_pin = mosi_pin self._miso_pin = miso_pin - self._factory = weakref.proxy(factory) + self._factory = proxy(factory) super(PiGPIOSoftwareSPI, self).__init__() self._reserve_pins( factory.pin_address(clock_pin), diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index dcc2744..4cad33a 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -7,6 +7,14 @@ from __future__ import ( str = type('') import warnings +from types import MethodType +from threading import RLock +from weakref import ref +try: + from weakref import WeakMethod +except ImportError: + from .compat import WeakMethod + from RPi import GPIO from .local import LocalPiFactory, LocalPiPin @@ -89,6 +97,7 @@ class RPiGPIOPin(LocalPiPin): self._frequency = None self._duty_cycle = None self._bounce = -666 + self._when_changed_lock = RLock() self._when_changed = None self._edges = GPIO.BOTH GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) @@ -202,19 +211,15 @@ class RPiGPIOPin(LocalPiPin): finally: self.when_changed = f - def _get_when_changed(self): - return self._when_changed + def _call_when_changed(self, channel): + super(RPiGPIOPin, self)._call_when_changed() - def _set_when_changed(self, value): - if self._when_changed is None and value is not None: - self._when_changed = value - GPIO.add_event_detect( - self.number, self._edges, - callback=lambda channel: self._when_changed(), - bouncetime=self._bounce) - elif self._when_changed is not None and value is None: - GPIO.remove_event_detect(self.number) - self._when_changed = None - else: - self._when_changed = value + def _enable_event_detect(self): + GPIO.add_event_detect( + self.number, self._edges, + callback=self._call_when_changed, + bouncetime=self._bounce) + + def _disable_event_detect(self): + GPIO.remove_event_detect(self.number) diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 58ca12e..d0d2d4b 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -8,6 +8,12 @@ str = type('') import warnings +from threading import RLock +try: + from weakref import WeakMethod +except ImportError: + from .compat import WeakMethod + import RPIO import RPIO.PWM from RPIO.Exceptions import InvalidChannelException @@ -83,6 +89,7 @@ class RPIOPin(LocalPiPin): self._pwm = False self._duty_cycle = None self._bounce = None + self._when_changed_lock = RLock() self._when_changed = None self._edges = 'both' try: @@ -191,25 +198,20 @@ class RPIOPin(LocalPiPin): finally: self.when_changed = f - def _get_when_changed(self): - return self._when_changed + def _call_when_changed(self, channel, value): + super(RPIOPin, self)._call_when_changed() - def _set_when_changed(self, value): - if self._when_changed is None and value is not None: - self._when_changed = value - RPIO.add_interrupt_callback( - self.number, - lambda channel, value: self._when_changed(), - self._edges, self.GPIO_PULL_UPS[self._pull], self._bounce) - elif self._when_changed is not None and value is None: - try: - RPIO.del_interrupt_callback(self.number) - except KeyError: - # Ignore this exception which occurs during shutdown; this - # simply means RPIO's built-in cleanup has already run and - # removed the handler - pass - self._when_changed = None - else: - self._when_changed = value + def _enable_event_detect(self): + RPIO.add_interrupt_callback( + self.number, self._call_when_changed, self._edges, + self.GPIO_PULL_UPS[self._pull], self._bounce) + + def _disable_event_detect(self): + try: + RPIO.del_interrupt_callback(self.number) + except KeyError: + # Ignore this exception which occurs during shutdown; this + # simply means RPIO's built-in cleanup has already run and + # removed the handler + pass From 73c0516a28133c07700eed9b48226b243440ec94 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 15:25:20 +0100 Subject: [PATCH 39/62] Try and import the right compat... And remove all the nonsense you re-factored into PiPin... --- gpiozero/pins/native.py | 27 ++++++++++----------------- gpiozero/pins/pi.py | 2 +- gpiozero/pins/pigpiod.py | 7 ------- gpiozero/pins/rpigpio.py | 9 --------- gpiozero/pins/rpio.py | 7 ------- 5 files changed, 11 insertions(+), 41 deletions(-) diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index e8a521c..eebf0b3 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -309,23 +309,16 @@ class NativePin(LocalPiPin): finally: self.when_changed = f - def _get_when_changed(self): - return self._when_changed + def _enable_event_detect(self): + self._change_thread = Thread(target=self._change_watch) + self._change_thread.daemon = True + self._change_event.clear() + self._change_thread.start() - def _set_when_changed(self, value): - if self._when_changed is None and value is not None: - self._when_changed = value - self._change_thread = Thread(target=self._change_watch) - self._change_thread.daemon = True - self._change_event.clear() - self._change_thread.start() - elif self._when_changed is not None and value is None: - self._change_event.set() - self._change_thread.join() - self._change_thread = None - self._when_changed = None - else: - self._when_changed = value + def _disable_event_detect(self): + self._change_event.set() + self._change_thread.join() + self._change_thread = None def _change_watch(self): offset = self._edge_offset @@ -334,5 +327,5 @@ class NativePin(LocalPiPin): while not self._change_event.wait(0.001): if self.factory.mem[offset] & mask: self.factory.mem[offset] = mask - self._when_changed() + self._call_when_changed() diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index e7aba58..3df6ec9 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -12,7 +12,7 @@ from weakref import ref, proxy try: from weakref import WeakMethod except ImportError: - from .compat import WeakMethod + from ..compat import WeakMethod import warnings try: diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index a739512..dd3fcd0 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -8,11 +8,6 @@ str = type('') import os from weakref import proxy -from threading import RLock -try: - from weakref import WeakMethod -except ImportError: - from .compat import WeakMethod import pigpio @@ -170,8 +165,6 @@ class PiGPIOPin(PiPin): self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' self._pwm = False self._bounce = None - self._when_changed_lock = RLock() - self._when_changed = None self._callback = None self._edges = pigpio.EITHER_EDGE try: diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index 4cad33a..e0274b6 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -7,13 +7,6 @@ from __future__ import ( str = type('') import warnings -from types import MethodType -from threading import RLock -from weakref import ref -try: - from weakref import WeakMethod -except ImportError: - from .compat import WeakMethod from RPi import GPIO @@ -97,8 +90,6 @@ class RPiGPIOPin(LocalPiPin): self._frequency = None self._duty_cycle = None self._bounce = -666 - self._when_changed_lock = RLock() - self._when_changed = None self._edges = GPIO.BOTH GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index d0d2d4b..12fced2 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -8,11 +8,6 @@ str = type('') import warnings -from threading import RLock -try: - from weakref import WeakMethod -except ImportError: - from .compat import WeakMethod import RPIO import RPIO.PWM @@ -89,8 +84,6 @@ class RPIOPin(LocalPiPin): self._pwm = False self._duty_cycle = None self._bounce = None - self._when_changed_lock = RLock() - self._when_changed = None self._edges = 'both' try: RPIO.setup(self.number, RPIO.IN, self.GPIO_PULL_UPS[self._pull]) From b59af7a08f21e4367d999ed5c3e7fe68c9e4324a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 15:48:12 +0100 Subject: [PATCH 40/62] Remove py2 incompatible raise in WeakMethod backport --- gpiozero/compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/compat.py b/gpiozero/compat.py index c8c01a2..0549c77 100644 --- a/gpiozero/compat.py +++ b/gpiozero/compat.py @@ -99,7 +99,7 @@ class WeakMethod(weakref.ref): func = meth.__func__ except AttributeError: raise TypeError("argument should be a bound method, not {0}" - .format(type(meth))) from None + .format(type(meth))) def _cb(arg): # The self-weakref trick is needed to avoid creating a reference # cycle. From d3c55d25a4455e5da4d834aece3549d6c511e2dd Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 16:02:27 +0100 Subject: [PATCH 41/62] Tidying up... Dunno how many commits this PR is now! --- gpiozero/output_devices.py | 8 ++------ gpiozero/pins/pi.py | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 9c24ba6..b570f3b 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -562,12 +562,8 @@ class RGBLED(SourceMixin, Device): raise GPIOPinMissing('red, green, and blue pins must be provided') LEDClass = PWMLED if pwm else LED super(RGBLED, self).__init__() - try: - self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) - self.value = initial_value - except: - self.close() - raise + self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) + self.value = initial_value red = _led_property(0) green = _led_property(1) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 3df6ec9..b5f11ef 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -224,24 +224,22 @@ class PiPin(Pin): return self._when_changed def _set_when_changed(self, value): - # Have to take care, if value is either a closure or a bound method, - # not to keep a strong reference to the containing object with self._when_changed_lock: - if self._when_changed is None and value is not None: + if value is None: + if self._when_changed is not None: + self._disable_event_detect() + self._when_changed = None + else: + enabled = self._when_changed is not None + # Have to take care, if value is either a closure or a bound + # method, not to keep a strong reference to the containing + # object if isinstance(value, MethodType): self._when_changed = WeakMethod(value) else: self._when_changed = ref(value) - self._enable_event_detect() - elif self._when_changed is not None and value is None: - self._disable_event_detect() - self._when_changed = None - elif value is None: - self._when_changed = None - elif isinstance(value, MethodType): - self._when_changed = WeakMethod(value) - else: - self._when_changed = ref(value) + if not enabled: + self._enable_event_detect() def _enable_event_detect(self): raise NotImplementedError From 4049ef5094557457144a8807f93fae851e2e7ec2 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 16:19:06 +0100 Subject: [PATCH 42/62] Work around for longer object lifetimes on pypy On pypy the subordinate LED objects in RGBLED composite objects do die on failed construction ... eventually. Unfortunately it's not quick enough to prevent the following tests from failing. As we can't know for certain exactly which test is going to follow, it's best to simply clear down the reservation table before each test. --- tests/test_boards.py | 1 + tests/test_inputs.py | 1 + tests/test_outputs.py | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/test_boards.py b/tests/test_boards.py index c0f34e0..4cc69e1 100644 --- a/tests/test_boards.py +++ b/tests/test_boards.py @@ -34,6 +34,7 @@ def setup_function(function): def teardown_function(function): Device._pin_factory.reset() + Device._reservations.clear() def teardown_module(module): # make sure we reset the default diff --git a/tests/test_inputs.py b/tests/test_inputs.py index faf5894..dbfd7dc 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -18,6 +18,7 @@ from gpiozero import * def teardown_function(function): Device._pin_factory.reset() + Device._reservations.clear() def test_input_initial_values(): diff --git a/tests/test_outputs.py b/tests/test_outputs.py index 3816226..4fbcbf4 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -22,6 +22,7 @@ from gpiozero import * def teardown_function(function): Device._pin_factory.reset() + Device._reservations.clear() def test_output_initial_values(): From 2495939603753415467ccb492925b283dd56606e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 22:28:33 +0100 Subject: [PATCH 43/62] Fix real pin tests ... and some other bits The real pin tests were broken by the new factory stuff. This commit fixes them up, and fixes up a few other bits besides (like why the pigpio PWM tests were failing, why RPi.GPIO sometimes segfaulted on PWM tests, etc.) It also causes the real pin tests to run against MockPin (thanks to @lurch for the suggestion!). This required some tweaks to MockPin to make it emulate physically pulled up pins itself (which in turn necessitated changing quite a few pin numbers in the main test suite because we were using 2 and 3 everywhere), and to allow one MockPin to drive another. Anyway, everything's working now including all the tests on a Pi (haven't tried RPIO yet, but only because I'm on a Pi3 - everything else works with overall coverage of 88% :). --- gpiozero/pins/mock.py | 58 +++++++++++--- gpiozero/pins/pigpiod.py | 6 ++ setup.py | 1 - tests/test_boards.py | 71 +++++++++++------ tests/test_devices.py | 22 +++--- tests/test_inputs.py | 38 +++++----- tests/test_mock_pin.py | 20 +++-- tests/test_outputs.py | 48 ++++++------ tests/test_real_pins.py | 160 +++++++++++++++++++++++---------------- 9 files changed, 265 insertions(+), 159 deletions(-) diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 4b97647..046fdce 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -18,7 +18,13 @@ except ImportError: import pkg_resources -from ..exc import PinPWMUnsupported, PinSetInput, PinFixedPull +from ..exc import ( + PinPWMUnsupported, + PinSetInput, + PinFixedPull, + PinInvalidFunction, + PinInvalidPull, + ) from ..devices import Device from .pi import PiPin from .local import LocalPiFactory @@ -34,8 +40,8 @@ class MockPin(PiPin): def __init__(self, factory, number): super(MockPin, self).__init__(factory, number) self._function = 'input' - self._state = False - self._pull = 'floating' + self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating' + self._state = self._pull == 'up' self._bounce = None self._edges = 'both' self._when_changed = None @@ -49,7 +55,8 @@ class MockPin(PiPin): return self._function def _set_function(self, value): - assert value in ('input', 'output') + if value not in ('input', 'output'): + raise PinInvalidFunction('function must be input or output') self._function = value if value == 'input': # Drive the input to the pull @@ -85,8 +92,12 @@ class MockPin(PiPin): return self._pull def _set_pull(self, value): - assert self._function == 'input' - assert value in ('floating', 'up', 'down') + if self.function != 'input': + raise PinFixedPull('cannot set pull on non-input pin %r' % self) + if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]): + raise PinFixedPull('%r has a physical pull-up resistor' % self) + if value not in ('floating', 'up', 'down'): + raise PinInvalidPull('pull must be floating, up, or down') self._pull = value if value == 'up': self.drive_high() @@ -132,7 +143,12 @@ class MockPin(PiPin): def assert_states(self, expected_states): # Tests that the pin went through the expected states (a list of values) for actual, expected in zip(self.states, expected_states): - assert actual.state == expected + try: + assert actual.state == expected + except AssertionError: + print('Actual states', self.states) + print('Expected states', expected_states) + raise def assert_states_and_times(self, expected_states): # Tests that the pin went through the expected states at the expected @@ -140,8 +156,32 @@ class MockPin(PiPin): # that's about all we can reasonably expect in a non-realtime # environment on a Pi 1) for actual, expected in zip(self.states, expected_states): - assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05) - assert isclose(actual.state, expected[1]) + try: + assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05) + assert isclose(actual.state, expected[1]) + except AssertionError: + print('Actual states', self.states) + print('Expected states', expected_states) + raise + + +class MockConnectedPin(MockPin): + """ + This derivative of :class:`MockPin` emulates a pin connected to another + mock pin. This is used in the "real pins" portion of the test suite to + check that one pin can influence another. + """ + def __init__(self, factory, number): + super(MockConnectedPin, self).__init__(factory, number) + self.input_pin = None + + def _change_state(self, value): + if self.input_pin: + if value: + self.input_pin.drive_high() + else: + self.input_pin.drive_low() + return super(MockConnectedPin, self)._change_state(value) class MockPulledUpPin(MockPin): diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index dd3fcd0..beba9d7 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -236,6 +236,12 @@ class PiGPIOPin(PiPin): def _set_frequency(self, value): if not self._pwm and value is not None: + if self.function != 'output': + raise PinPWMFixedValue('cannot start PWM on pin %r' % self) + # NOTE: the pin's state *must* be set to zero; if it's currently + # high, starting PWM and setting a 0 duty-cycle *doesn't* bring + # the pin low; it stays high! + self.factory.connection.write(self.number, 0) self.factory.connection.set_PWM_frequency(self.number, value) self.factory.connection.set_PWM_range(self.number, 10000) self.factory.connection.set_PWM_dutycycle(self.number, 0) diff --git a/setup.py b/setup.py index 9801fb8..4647fdc 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,6 @@ __entry_points__ = { 'gpiozero_mock_pin_classes': [ 'mockpin = gpiozero.pins.mock:MockPin', 'mockpwmpin = gpiozero.pins.mock:MockPWMPin', - 'mockpulleduppin = gpiozero.pins.mock:MockPulledUpPin', 'mockchargingpin = gpiozero.pins.mock:MockChargingPin', 'mocktriggerpin = gpiozero.pins.mock:MockTriggerPin', ], diff --git a/tests/test_boards.py b/tests/test_boards.py index 4cc69e1..36e3277 100644 --- a/tests/test_boards.py +++ b/tests/test_boards.py @@ -246,10 +246,15 @@ def test_led_board_bad_blink(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_background(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + # Instantiation takes a long enough time that it throws off our timing + # here! + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0.1, 0.1, n=2) board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test test = [ @@ -266,10 +271,13 @@ def test_led_board_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_foreground(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0.1, 0.1, n=2, background=False) test = [ (0.0, False), @@ -285,10 +293,13 @@ def test_led_board_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0.1, 0.1, n=2) # make sure the blink thread's started while not board._blink_leds: @@ -310,10 +321,13 @@ def test_led_board_blink_control(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_take_over(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board[1].blink(0.1, 0.1, n=2) board.blink(0.1, 0.1, n=2) # immediately take over blinking board[1]._blink_thread.join() @@ -332,10 +346,13 @@ def test_led_board_blink_take_over(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control_all(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0.1, 0.1, n=2) # make sure the blink thread's started while not board._blink_leds: @@ -354,9 +371,9 @@ def test_led_board_blink_control_all(): pin3.assert_states_and_times(test) def test_led_board_blink_interrupt_on(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(1, 0.1) sleep(0.2) @@ -366,10 +383,13 @@ def test_led_board_blink_interrupt_on(): pin3.assert_states([False, True, False]) def test_led_board_blink_interrupt_off(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0.1, 1) sleep(0.2) board.off() # should interrupt while off @@ -380,10 +400,13 @@ def test_led_board_blink_interrupt_off(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_fade_background(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device._pin_factory.pin(4) + pin2 = Device._pin_factory.pin(5) + pin3 = Device._pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) as board: + pin1.clear_states() + pin2.clear_states() + pin3.clear_states() board.blink(0, 0, 0.2, 0.2, n=2) board._blink_thread.join() test = [ diff --git a/tests/test_devices.py b/tests/test_devices.py index 858b388..cd28f4a 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -65,7 +65,7 @@ def test_device_reopen_same_pin(): assert device.pin is None def test_device_repr(): - with GPIODevice(2) as device: + with GPIODevice(4) as device: assert repr(device) == '' % device.pin def test_device_repr_after_close(): @@ -85,18 +85,18 @@ def test_device_context_manager(): def test_composite_device_sequence(): with CompositeDevice( - InputDevice(2), - InputDevice(3) + InputDevice(4), + InputDevice(5) ) as device: assert len(device) == 2 - assert device[0].pin.number == 2 - assert device[1].pin.number == 3 + assert device[0].pin.number == 4 + assert device[1].pin.number == 5 assert device.namedtuple._fields == ('_0', '_1') def test_composite_device_values(): with CompositeDevice( - InputDevice(2), - InputDevice(3) + InputDevice(4), + InputDevice(5) ) as device: assert device.value == (0, 0) assert not device.is_active @@ -106,8 +106,8 @@ def test_composite_device_values(): def test_composite_device_named(): with CompositeDevice( - foo=InputDevice(2), - bar=InputDevice(3), + foo=InputDevice(4), + bar=InputDevice(5), _order=('foo', 'bar') ) as device: assert device.namedtuple._fields == ('foo', 'bar') @@ -126,8 +126,8 @@ def test_composite_device_bad_init(): def test_composite_device_read_only(): with CompositeDevice( - foo=InputDevice(2), - bar=InputDevice(3) + foo=InputDevice(4), + bar=InputDevice(5) ) as device: with pytest.raises(AttributeError): device.foo = 1 diff --git a/tests/test_inputs.py b/tests/test_inputs.py index dbfd7dc..0b61ddd 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -12,7 +12,7 @@ import pytest from threading import Event from functools import partial -from gpiozero.pins.mock import MockPulledUpPin, MockChargingPin, MockTriggerPin +from gpiozero.pins.mock import MockChargingPin, MockTriggerPin from gpiozero import * @@ -22,7 +22,7 @@ def teardown_function(function): def test_input_initial_values(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with InputDevice(pin, pull_up=True) as device: assert pin.function == 'input' assert pin.pull == 'up' @@ -42,23 +42,23 @@ def test_input_is_active_low(): assert repr(device) == '' def test_input_is_active_high(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with InputDevice(pin, pull_up=False) as device: pin.drive_high() assert device.is_active - assert repr(device) == '' + assert repr(device) == '' pin.drive_low() assert not device.is_active - assert repr(device) == '' + assert repr(device) == '' def test_input_pulled_up(): - pin = Device._pin_factory.pin(2, pin_class=MockPulledUpPin) + pin = Device._pin_factory.pin(2) with pytest.raises(PinFixedPull): InputDevice(pin, pull_up=False) def test_input_event_activated(): event = Event() - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalInputDevice(pin) as device: device.when_activated = lambda: event.set() assert not event.is_set() @@ -67,7 +67,7 @@ def test_input_event_activated(): def test_input_event_deactivated(): event = Event() - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalInputDevice(pin) as device: device.when_deactivated = lambda: event.set() assert not event.is_set() @@ -78,7 +78,7 @@ def test_input_event_deactivated(): def test_input_partial_callback(): event = Event() - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) def foo(a, b): event.set() return a + b @@ -91,22 +91,22 @@ def test_input_partial_callback(): assert event.is_set() def test_input_wait_active(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalInputDevice(pin) as device: pin.drive_high() assert device.wait_for_active(1) assert not device.wait_for_inactive(0) def test_input_wait_inactive(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalInputDevice(pin) as device: assert device.wait_for_inactive(1) assert not device.wait_for_active(0) def test_input_smoothed_attrib(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) as device: - assert repr(device) == '' + assert repr(device) == '' assert device.threshold == 0.5 assert device.queue_len == 5 assert not device.partial @@ -116,7 +116,7 @@ def test_input_smoothed_attrib(): device.threshold = 1 def test_input_smoothed_values(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with SmoothedInputDevice(pin) as device: device._queue.start() assert not device.is_active @@ -138,7 +138,7 @@ def test_input_button(): assert button.wait_for_release(1) def test_input_line_sensor(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with LineSensor(pin) as sensor: pin.drive_low() # logic is inverted for line sensor assert sensor.wait_for_line(1) @@ -148,7 +148,7 @@ def test_input_line_sensor(): assert not sensor.line_detected def test_input_motion_sensor(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with MotionSensor(pin) as sensor: pin.drive_high() assert sensor.wait_for_motion(1) @@ -160,7 +160,7 @@ def test_input_motion_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_light_sensor(): - pin = Device._pin_factory.pin(2, pin_class=MockChargingPin) + pin = Device._pin_factory.pin(4, pin_class=MockChargingPin) with LightSensor(pin) as sensor: pin.charge_time = 0.1 assert sensor.wait_for_dark(1) @@ -170,8 +170,8 @@ def test_input_light_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_distance_sensor(): - echo_pin = Device._pin_factory.pin(2) - trig_pin = Device._pin_factory.pin(3, pin_class=MockTriggerPin) + echo_pin = Device._pin_factory.pin(4) + trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin) trig_pin.echo_pin = echo_pin trig_pin.echo_time = 0.02 with pytest.raises(ValueError): diff --git a/tests/test_mock_pin.py b/tests/test_mock_pin.py index 4d5414e..880f859 100644 --- a/tests/test_mock_pin.py +++ b/tests/test_mock_pin.py @@ -28,7 +28,7 @@ def test_mock_pin_init(): assert Device._pin_factory.pin(2).number == 2 def test_mock_pin_defaults(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -36,6 +36,9 @@ def test_mock_pin_defaults(): assert pin.pull == 'floating' assert pin.state == 0 assert pin.when_changed == None + pin.close() + pin = Device._pin_factory.pin(2) + assert pin.pull == 'up' def test_mock_pin_open_close(): pin = Device._pin_factory.pin(2) @@ -54,7 +57,7 @@ def test_mock_pin_init_twice_different_pin(): assert pin2.number == pin1.number+1 def test_mock_pwm_pin_defaults(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -62,6 +65,9 @@ def test_mock_pwm_pin_defaults(): assert pin.pull == 'floating' assert pin.state == 0 assert pin.when_changed == None + pin.close() + pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + assert pin.pull == 'up' def test_mock_pwm_pin_open_close(): pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) @@ -104,20 +110,25 @@ def test_mock_pin_frequency_supported(): assert not pin.state def test_mock_pin_pull(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) pin.function = 'input' assert pin.pull == 'floating' pin.pull = 'up' assert pin.state pin.pull = 'down' assert not pin.state + pin.close() + pin = Device._pin_factory.pin(2) + pin.function = 'input' + assert pin.pull == 'up' + with pytest.raises(PinFixedPull): + pin.pull = 'floating' def test_mock_pin_state(): pin = Device._pin_factory.pin(2) with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' - assert pin.state == 0 pin.state = 1 assert pin.state == 1 pin.state = 0 @@ -130,7 +141,6 @@ def test_mock_pwm_pin_state(): with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' - assert pin.state == 0 pin.state = 1 assert pin.state == 1 pin.state = 0 diff --git a/tests/test_outputs.py b/tests/test_outputs.py index 4fbcbf4..6908270 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -95,7 +95,7 @@ def test_output_digital_toggle(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_background(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -113,7 +113,7 @@ def test_output_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_foreground(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -127,7 +127,7 @@ def test_output_blink_foreground(): ]) def test_output_blink_interrupt_on(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -135,7 +135,7 @@ def test_output_blink_interrupt_on(): pin.assert_states([False, True, False]) def test_output_blink_interrupt_off(): - pin = Device._pin_factory.pin(2) + pin = Device._pin_factory.pin(4) with DigitalOutputDevice(pin) as device: device.blink(0.1, 1) sleep(0.2) @@ -151,7 +151,7 @@ def test_output_pwm_not_supported(): PWMOutputDevice(Device._pin_factory.pin(2)) def test_output_pwm_states(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.value = 0.1 device.value = 0.2 @@ -172,14 +172,14 @@ def test_output_pwm_read(): assert device.frequency is None def test_output_pwm_write(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.on() device.off() pin.assert_states([False, True, False]) def test_output_pwm_toggle(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.toggle() device.value = 0.5 @@ -218,7 +218,7 @@ def test_output_pwm_write_silly(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_background(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -236,7 +236,7 @@ def test_output_pwm_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_foreground(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -252,7 +252,7 @@ def test_output_pwm_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_background(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -286,7 +286,7 @@ def test_output_pwm_fade_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_foreground(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -318,7 +318,7 @@ def test_output_pwm_fade_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_background(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -352,7 +352,7 @@ def test_output_pwm_pulse_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_foreground(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -382,7 +382,7 @@ def test_output_pwm_pulse_foreground(): ]) def test_output_pwm_blink_interrupt(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -515,7 +515,7 @@ def test_rgbled_blink_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -536,7 +536,7 @@ def test_rgbled_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -557,7 +557,7 @@ def test_rgbled_blink_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -576,7 +576,7 @@ def test_rgbled_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -595,7 +595,7 @@ def test_rgbled_blink_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -638,7 +638,7 @@ def test_rgbled_fade_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -679,7 +679,7 @@ def test_rgbled_fade_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -722,7 +722,7 @@ def test_rgbled_pulse_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -761,7 +761,7 @@ def test_rgbled_pulse_foreground_nonpwm(): device.pulse(0.2, 0.2, n=2, background=False) def test_rgbled_blink_interrupt(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: device.blink(1, 0.1) sleep(0.2) @@ -771,7 +771,7 @@ def test_rgbled_blink_interrupt(): b.assert_states([0, 1, 0]) def test_rgbled_blink_interrupt_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: device.blink(1, 0.1) sleep(0.2) diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index 94d25ef..7fbe59e 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -11,20 +11,33 @@ except NameError: pass import io +import os import subprocess +from time import sleep import pytest +import pkg_resources -from gpiozero import PinFixedPull, PinInvalidPull, PinInvalidFunction +from gpiozero import ( + PinFixedPull, + PinInvalidPull, + PinInvalidFunction, + PinPWMUnsupported, + Device, + ) +from gpiozero.pins.mock import MockConnectedPin, MockFactory try: from math import isclose except ImportError: from gpiozero.compat import isclose -# This module assumes you've wired the following GPIO pins together -TEST_PIN = 22 -INPUT_PIN = 27 +# This module assumes you've wired the following GPIO pins together. The pins +# can be re-configured via the listed environment variables (useful for when +# your testing rig requires different pins because the defaults interfere with +# attached hardware). +TEST_PIN = int(os.getenv('GPIOZERO_TEST_PIN', '22')) +INPUT_PIN = int(os.getenv('GPIOZERO_INPUT_PIN', '27')) # Skip the entire module if we're not on a Pi @@ -40,51 +53,48 @@ pytestmark = pytest.mark.skipif(not is_a_pi(), reason='tests cannot run on non-P 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=('rpigpio',)) + #params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) +def pin_factory(request): + # Constructs each pin factory in turn with some extra logic to ensure + # the pigpiod daemon gets started and stopped around the pigpio factory + if request.param == 'pigpio': + try: + subprocess.check_call(['sudo', 'systemctl', 'start', 'pigpiod']) + except subprocess.CalledProcessError: + pytest.skip("skipped factory pigpio: failed to start pigpiod") + try: + factory = pkg_resources.load_entry_point('gpiozero', 'gpiozero_pin_factories', request.param)() + except Exception as e: + if request.param == 'pigpio': + subprocess.check_call(['sudo', 'systemctl', 'stop', 'pigpiod']) + pytest.skip("skipped factory %s: %s" % (request.param, str(e))) + else: + Device._set_pin_factory(factory) + def fin(): + Device._set_pin_factory(MockFactory()) + if request.param == 'pigpio': + subprocess.check_call(['sudo', 'systemctl', 'stop', 'pigpiod']) + request.addfinalizer(fin) + return factory -@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(scope='function') -def pins(request, pin_class): +def pins(request, pin_factory): # 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(TEST_PIN) - input_pin = pin_class(INPUT_PIN) + if pin_factory.__class__.__name__ == 'MockFactory': + test_pin = pin_factory.pin(TEST_PIN, pin_class=MockConnectedPin) + else: + test_pin = pin_factory.pin(TEST_PIN) + input_pin = pin_factory.pin(INPUT_PIN) input_pin.function = 'input' input_pin.pull = 'down' + if pin_factory.__class__.__name__ == 'MockFactory': + test_pin.input_pin = input_pin def fin(): test_pin.close() input_pin.close() @@ -134,17 +144,18 @@ def test_pull_bad(pins): with pytest.raises(PinInvalidPull): test_pin.input_with_pull('foo') -def test_pull_down_warning(pin_class): - # XXX This assumes we're on a vaguely modern Pi and not a compute module - # Might want to refine this with the pi-info database - pin = pin_class(2) - try: - with pytest.raises(PinFixedPull): - pin.pull = 'down' - with pytest.raises(PinFixedPull): - pin.input_with_pull('down') - finally: - pin.close() +def test_pull_down_warning(pin_factory): + if pin_factory.pi_info.pulled_up('GPIO2'): + pin = pin_factory.pin(2) + try: + with pytest.raises(PinFixedPull): + pin.pull = 'down' + with pytest.raises(PinFixedPull): + pin.input_with_pull('down') + finally: + pin.close() + else: + pytest.skip("GPIO2 isn't pulled up on this pi") def test_input_with_pull(pins): test_pin, input_pin = pins @@ -153,25 +164,42 @@ def test_input_with_pull(pins): test_pin.input_with_pull('down') assert input_pin.state == 0 -@pytest.mark.skipif(True, reason='causes segfaults') def test_bad_duty_cycle(pins): test_pin, input_pin = pins - if test_pin.__class__.__name__ == 'NativePin': - pytest.skip("native pin doesn't support PWM") test_pin.function = 'output' - test_pin.frequency = 100 - with pytest.raises(ValueError): - test_pin.state = 1.1 + try: + # NOTE: There's some race in RPi.GPIO that causes a segfault if we + # don't pause before starting PWM; only seems to happen when stopping + # and restarting PWM very rapidly (i.e. between test cases). + if Device._pin_factory.__class__.__name__ == 'RPiGPIOFactory': + sleep(0.1) + test_pin.frequency = 100 + except PinPWMUnsupported: + pytest.skip("%r doesn't support PWM" % test_pin.factory) + else: + try: + with pytest.raises(ValueError): + test_pin.state = 1.1 + finally: + test_pin.frequency = None def test_duty_cycles(pins): test_pin, input_pin = pins - if test_pin.__class__.__name__ == 'NativePin': - pytest.skip("native pin doesn't support PWM") test_pin.function = 'output' - test_pin.frequency = 100 - for duty_cycle in (0.0, 0.1, 0.5, 1.0): - test_pin.state = duty_cycle - assert test_pin.state == duty_cycle - total = sum(input_pin.state for i in range(20000)) - assert isclose(total / 20000, duty_cycle, rel_tol=0.1, abs_tol=0.1) + try: + # NOTE: see above + if Device._pin_factory.__class__.__name__ == 'RPiGPIOFactory': + sleep(0.1) + test_pin.frequency = 100 + except PinPWMUnsupported: + pytest.skip("%r doesn't support PWM" % test_pin.factory) + else: + try: + for duty_cycle in (0.0, 0.1, 0.5, 1.0): + test_pin.state = duty_cycle + assert test_pin.state == duty_cycle + total = sum(input_pin.state for i in range(20000)) + assert isclose(total / 20000, duty_cycle, rel_tol=0.1, abs_tol=0.1) + finally: + test_pin.frequency = None From f09b5c5c18ce673dde9d5ed62a044e1b71f5e02d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 22 Oct 2016 22:44:10 +0100 Subject: [PATCH 44/62] Remove some redundant testing bits --- gpiozero/pins/mock.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 046fdce..a874e4d 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -143,12 +143,7 @@ class MockPin(PiPin): def assert_states(self, expected_states): # Tests that the pin went through the expected states (a list of values) for actual, expected in zip(self.states, expected_states): - try: - assert actual.state == expected - except AssertionError: - print('Actual states', self.states) - print('Expected states', expected_states) - raise + assert actual.state == expected def assert_states_and_times(self, expected_states): # Tests that the pin went through the expected states at the expected @@ -156,13 +151,8 @@ class MockPin(PiPin): # that's about all we can reasonably expect in a non-realtime # environment on a Pi 1) for actual, expected in zip(self.states, expected_states): - try: - assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05) - assert isclose(actual.state, expected[1]) - except AssertionError: - print('Actual states', self.states) - print('Expected states', expected_states) - raise + assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05) + assert isclose(actual.state, expected[1]) class MockConnectedPin(MockPin): @@ -184,16 +174,6 @@ class MockConnectedPin(MockPin): return super(MockConnectedPin, self)._change_state(value) -class MockPulledUpPin(MockPin): - """ - This derivative of :class:`MockPin` emulates a pin with a physical pull-up - resistor. - """ - def _set_pull(self, value): - if value != 'up': - raise PinFixedPull('pin has a physical pull-up resistor') - - class MockChargingPin(MockPin): """ This derivative of :class:`MockPin` emulates a pin which, when set to From 2ecc25f9951c775f2fdd5bf9f0b94518113e439d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 23 Oct 2016 10:35:24 +0100 Subject: [PATCH 45/62] Enable all the factory tests Ooops ... --- tests/test_real_pins.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index 7fbe59e..2fc0fa7 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -55,8 +55,7 @@ del is_a_pi @pytest.fixture( scope='module', - params=('rpigpio',)) - #params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) + params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) def pin_factory(request): # Constructs each pin factory in turn with some extra logic to ensure # the pigpiod daemon gets started and stopped around the pigpio factory From 945bea4e5482b047f71082c2b0d3f40446701c16 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 23 Oct 2016 15:29:55 +0100 Subject: [PATCH 46/62] Added keyword args to MockFactory.pin And a few other last minute fixes --- docs/api_pins.rst | 18 +++++++++ docs/images/composite_device_hierarchy.pdf | Bin 14799 -> 14799 bytes docs/images/input_device_hierarchy.pdf | Bin 8581 -> 8581 bytes gpiozero/pins/local.py | 6 ++- gpiozero/pins/mock.py | 18 ++++----- gpiozero/pins/pi.py | 42 ++++++++++++++++++++- tests/test_inputs.py | 4 +- tests/test_real_pins.py | 8 ++-- 8 files changed, 75 insertions(+), 21 deletions(-) diff --git a/docs/api_pins.rst b/docs/api_pins.rst index fda62cf..467de4d 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -154,6 +154,22 @@ Base classes .. autoclass:: SPI :members: +.. currentmodule:: gpiozero.pins.pi + +.. autoclass:: PiFactory + :members: + +.. autoclass:: PiPin + :members: + +.. currentmodule:: gpiozero.pins.local + +.. autoclass:: LocalPiFactory + :members: + +.. autoclass:: LocalPiPin + :members: + Utilities ========= @@ -164,6 +180,8 @@ non-physical pins are used, or to raise exceptions when pull-downs are requested on pins with physical pull-up resistors attached. The following functions and classes can be used to query this database: +.. currentmodule:: gpiozero + .. autofunction:: pi_info .. autoclass:: PiBoardInfo diff --git a/docs/images/composite_device_hierarchy.pdf b/docs/images/composite_device_hierarchy.pdf index fe1482d9c97b27883d3d632c123ff61a7fd98a7f..6d032bd3cf97e6cf655441200d763a2a1dafa59e 100644 GIT binary patch delta 9295 zcmV-VB(U4hbI)@KB~V00Eio=Mu?YJKe|Qu{)^}B%uI`?mYfol!A-Bn85<-B)gaF}| zF>=RcgCGKm1PB4~LXbtkfC;!HL_n?yhzJn@5fCG?m|#R*!(DV&!ChB;y$~1O4an|` zmkpW9d%7n9cE9!gzW=`GeV(_Qn(nIZt~&LrbAIQX3WO3uG*V80_@+NRwd6waf3{PE zMBhgUn>78gU-`%bvAKlA))PWSammbw=k|JRHX-p?C;MhTw5YgZ^Y{$B-%m)Fx>+-( z7O4-e|Bet}5w`W7g$?%Y%0{ej#d`9rhkv#3=rM0ktiO%*tq;waK9$hF;8+P*NbSQ@ z7nVpH<+)gI!@95J(HSNEmA~O_e_{+Fd=_D(Sky?xd?!k)kS+n6be+i8smjZkL^7Jr zwcJKr=UUFSWQOSpx<5frD3(auJcw@lTGS|xpZ@-+oQ8ei{CFKdPgJ6lo&hhZwk)O9 zE|s}7!lUe2B*r4SU2QGbTJ&5zZX+3Zn|ZJ>jMB+e&-M}BMH2i8<~5Dde+}1Y4viOI ziZddgZl?!njhH10#8jSfeF2T6J!y9uv0H2s<>CoZgHvH-Zu>>4Oe!TF5=}}1$;3-7 z73vD^eTni08+{|P!Ch}#6%*}cs#hhWnA?(G&`$zAFqQZ znRCd_B1%u1lqf4wS=&L|+1F>Em^S@)4~lEz1WjxEiYoPN*NQC-4tD>fqbGXxI?$~< z?MpQpM(+@xHElX{U>m9i8Au4usgTIzdLR{aiAzkUj2jnVGLflHe~6sVfV{a=ka8W5B~--)B@JmW^ydB@#rG_=3ncVbh7iG5aX=BTj~6c@j&xYUlqFHcOQ zfv1PF*{qb6u?kks*0G&TH3qVPMe-u1U7(AULQ-fNq)9$Chvd+H&`-)#hmxUm1dNb| z^5Jqo9Z$y7i7-(re^84_F?|3YkY@5(a-lk({EC)BsWhKIE-xp`X%$pSRlGv3AvJUp z+X9=V&3u!*hrcM-sc);FtL^Hb$z*a^wuNTXq=E0!`|17fiu+on!nSd+|9Y*t?(ZN_ zi)4?fyXgUkd{lasG%`+Ai40X;Z39}eaK6oLEtvtU%M!2@e^?4FB^FMxS3OD3_9nek zkB3xvy;k;oYhaFg1eZ{cqDWpKnpDsglB2@DLTk{ahKPE7RTsr=C&N8My13e!vsyxm z;}X}dxW2!FBRHd7(dE%=qidtNp%kV9cs=2rnvrN~c~&@F8vR_sYsZhjR`A^DU+kJ3 z6d%(bRK9zMf0VO7J^kX@vlr9T_a-OPLDWIrv|kc2T>WFoQSW$M8>2aZ0EuCVaU{`*)l6lA(9Usj)#0lBit%{1`@YLc<%i4*!N?nvJ zyHq^;@~_3q;&EC*$5veC)6P%1Uz`ws6rYF__fPp~fB0~;$C-2%-9GGw-OWe5tR#Yr z41~!IZqi_@cdv@HxSeCb?Hv+nnpp=@2vSmBR4FNy%ak&;%u=S6SxaqY_A*DAv&>bd zm%3}Cu14u7Z6|O!y;4%M3_(Nav3VQ!@2lRhfB%N7)Ge-D{hRoX>hSrcQ>QL{bMnNu zTg6Gye#Q-d1zk~yCZ}su_$9AnG{Ho-Ihovkz*CFtuodJ_0f${E`{h$Rh0{L z)mab|sdgEfWZ>A=*4AROL&kss&DRDrwPfk;2;_#a%;bXPlH|3?wRpaj{CRSFvIQj` zgbWbwMXl(QOTO15psvv0i+tdt55%$&BEm^dF1Qwz}0%kD*7fg z#_DeCun38$Y-p?@dR7SW=H_cnEv_a+-BK7=9#0pb+t92vuQ@)O+OJbuzLyQz_NzF*hOPi8bmR6p&Hmx@8YFZ@H(%hT&9Z%z^*CQj6f2ld9 zA3&weKqr;ct2eGXtQ@^(QdQNojd@MGe*EL4cONP~K6Tlu8T$hJHh=Mc@gXViK-aG0 z#sx+sIJ!Mkwe@gP($SopiDO0;_?^ks%eL*03*p-bmEiAu8wn$Q15pmHI^iXv(?+#Y zvm(m4@-DYys0RtJ3IAnvcvw?se{*v)55D3x{cM6aLHC6Br(P5_M^DPh*69LTDwdC$ z_vV}DcT`sLZQ{3Ug0)qnw`~8A6|SL!Lb_*g&nL(|hK(nojaR!#wQZeY<5A9Ri1NA& z8*jU5<213u1>$dNh-J)QNWCC}6fRt#RJ329{pdomLL3*zL?vCs?-cdoe{1n)QBQ}{ zE;O1B-zn}D+r)NpFWpI};knC{F!pmL={U!~DTPrc1@5F|DBWc z1A2t*4o=;^{pe0sdcAgkfARFIu*X;njCG{h80&E257<~WSt`*O=tm?OM{F^MLvLfr zR0@=GD3>JD*C6tzPP0F>P2uNT&+qN%V|oor$h0g+tB z8fBnxb{7xu0$#{V_*E{4oFO_w+4GN<4!)F%OpJR6qHZEwZ)?;jB0Cx}wi>$DV$w{; zfaV+E7J5H0z@`6={E7^4_ct`;zc&A!<7}rvciXoabcZxIqv$)7)WD>rBZl;mI|4~j zq*}97yD^f~UXItTe<}-$is!@;6V9VzdRj<~TS_pA8VLirAf)srR;cpM#E{CH)|hnT z#*YpUZB;QWR!T~s8|dH{o_p>E(MZ!bu3NWJSebOGwR~~)E^+mG@Edk2_*v!3Rm)ki z7&Pb6xh1>bezj_c$9HD)$v>ekmZC29K%6w<4jLnS8jL-CCCS)e& zr3PXHae?@NFOU#OEQl?LD~K=f6(kfS7NnM>E|0B@tBkMoRVFM?T$@^(dNnn!^V80c zIzK3kD~vDne-$Q_#FfOC_(~GWE1>{_`r!E-sxm?~_AmcLta4EuQ+$jyKNiZS`Q_lzL?P(j%CFhiR{ zJbP1>B4A|vi0)foL{D{Od05XFIONvP91R{sMJk@o`Hi?_66(L3MR zryPbpb4aWion#pUw{$wo!y#V@W@gd>2QvvRoOZ?}C=l$ZukZKj;xp}}{mkN5gD22S z?%9K$e-aL}`~T6hr)Vl2OjSGwPZi!yR~d@qRw9?ilH7og@Mu~M(bcN^dHsO5+ObYu z6~{=7-b>1kjIz4o3|eh&Yq}B7iE~#BI```dISINfbw+Sf#I3QN^sYF}-1EhsYsC&R zpRT0$ucykKlD3uNinxqXk^8|t=jpoL!LqS;f755^!}JmQ%blT`vBa(MU$dFWxQ^@p9RImG13+gQD%|1tw2ZW0rorTY4a=m2|1&I0Hneg0 zy!WQ;dTqh($G`f6_)J`y{atx!f6JpUH&$*b{pvK0`2K-E@tw!|^e%sF`i%If^iK|d z@=xwkQGCrRLG~PW!7@*E7oWui%#%T)WRH^ zFc)SA?_`JCmas#?8B*b%wofr;2h8+KDAjhIApvgK&z;#K2 zd|4u1ki69vPqlriRpK(}7&C-BxE2*9>3JS4#wMBB5*ie0k{${me+C$I;?6bBTUR2a zYJoT-*T{c7jB>&$XEG?}zKDl~qf_w{KlQT|NR?BR6g9=-i|b8$v!Qe-o5kl#^ZA0X z74iyYv%Fb}#}z^Cj0j7Dp48wbJ;7&$B{ygbR^MJa=m)#RkP_-z+RN=5>~4*q5LRxpI;_qJ>SZp; z#UnJ2)nn`8f9T>&CCQj=`XnDuQ@dLHTCz3SmTK?j=;rk4eMkRjfEF3Y@QhmvzCU*!y-k!-TaoJz84WFOWLedwl*wKR8f zxpcYHf5MD=G%=UWFtI5T)6{U5%F=kcI-V7?nd&^YfG=ZJ{AqOqtKpl}7ns|^Ei$u$ zrgVi=sVh&H)0Kd278Kg5V7XMqSIcXZEwD-13or7+$}#0*T5vy0e+qtvF+q(erW;HS%MXNE8BwZv9a(Ba zZOQGRuu*lc8+)!T%^|uq&+umbEWGHD5Z?73MkQuJguC*tY9H2{ zfA>;{v7zWg?q)ODV~F&VYz1GVZe-7@mzY-u1LJ1KoA;J;luX<0 zsJ%l%+H0GJzGoJnsVv|nww17wKaH!f#_s>gQr}a{Dv<#$1zcMMwB)2^KB~p z)SAxY+lWM3zclk3m+`k7oI67;`EB5KqGO!Vp&dAF(1^|m;9BWil8r`-4w`B_$S0sw zQ&@^Csw%RCfDjAUtgdsRKMf3Me>S||4H!Cfhu=b(p?d_yXIg5$lRBBx00v{B$4CiT zMJx(c(KTA6a2mzN(+RA=Hj~a`3+ZEQF+3_QP!_6{bOkH7ZD!9vjTC_Z7;BzQlOO?- zSfjYY{G#-0miys~;FJ~Txg!__2U^oe^N%;=~z0I zE~HP;_3Svi;7jpk`uh3yCnUDF8-M#Ewe&7ph|iaFJP*U?xi_Bw{6TSy3v>(JO1I%z z+i@Pp^CUg_-+uZ3dZZ9HhJuthF*6J&#-?8qNya((&3Q)RZ#;=6Q9t{A7|xCpFX{s! zT}T8f3L%Mzi?NrYU_?iVf5F#QVn?KmBLU-s|2_WYpgE+ToWb)QvX^Y7yRlY`&2zD( zmK`L^$$V^im!6?jtOvI3CRfQv_+}+J1A8SxN0Mx8CFB#%$Td2S9Kt?wsfXsGoe^oY zbV#~Os+TTFXGtGvo^)0!l;%-P!1#E+8%r)6V{YWMcv4S4C-cY=fA|)%p-~zvImqX5 z7WR^_aTH@+&yY1_Cn-f)Jai5zW2NjaY&pTtk}Y`7!RKdDOFu&Cj?gE`d9oQKHk@pu z=W$+V$PeU67{|&mZ^>rGDE|rU>nwi1h0MbY`#jZ%VCmR~(&Jdu%->k(!OxrLRkX5F zGLGz&>t&CUgrgXUf9*0ZRw`7cVc*A$8R3|R*j+fIV$z6Zf$YLL^{30B3MDn3#*(wjNGSuq z#~zd=IBP=YKn|IWcctV2IY@dy4OxRdne&zV@E`EYtVOl5le_e{P=O}7{|np_M1m4YG|>XMovjBWUkam2C`i8j#NzM@*32UugP5H z3^~F*^_$dp1tbrdK@V$U*0{+tve|Ny&YT&9LzI*C+ z{+)m;HE_8GT3X?+t?(BC-}ZxV^5K$zKWD+$f6Zh0*EP_LFE)>bi(h5%i>>fg27D>t z3jv>J!GCz*vl_S{;8QpJX$gGt2K-UL$N2ikOW^#uVf_3OI5!MF`Y@V*B;dnn_`QJN z3HU(3`vT6^z5NQ3)tm`odRCi;ovW1!43yJ zUj()IN^K2n7qIO)8{a12IU8(!Hi~a8e}ZSXxcIYCu*C(>Xs}tprW!lnB%sC))%a0$ z4Q$-t;2XQb1_!Kfg>`G+;OhjeT{D@leFN5(OKYC?^EH!UO+b3u532>NTG^AY60ou- zJcZMI>UOAFVdYgGSYd@qY^W@P3Ph^H56gAHJ9n%XC;Opj<$ifI#~be@m9| zCj=~60*i~Fbexx$`r&Z_iv%omzycdQronsxziNeft?+0o%x#4d0doXABH*C}cu>G> zJ)h4W3l9jGwFG8jrC7iW0Yw6)3z#NgYCkA!h5KzVS-`ylCJC50LE{r!VS)ztgh%mv zvS7S`yK&^Z^I@D9#!?p_8wq!Le_+hWFg`{=ffar!VDv9se6)aHxZq9!qwvWn0V7Aa z_{cCA5o_loTrk`Y!vqYifgv?8Sil{u2fw2g^51~lM?pY9o`69E-F%P-1`crYfo>Sk z-_8dF+MUqf4*dk=3h3L%!~3>EpWZIs#{<1{th~1ia;(rR4zlf#b(@uEe+jtF3Yi&J zo@s{+EA;GP;XPf@!vfv2AibNPrx!uDG&k?&hcq{IP4)Axw?nEQQv6n);sn1Hk_99Q zNOVF1&NIOcz9NWkg*co-ToJ_DAqEkQ5fI%9UGgCcD^UU>iy#7#iVzTvAB9JOSAa)A zm;g7v;1;0cT=jf#Edgf{MmPl6ZQCn&A!(DDn`5@d1wLAP^N(BpBaR1tX-jMHxq8w5S*# zr9>N}MiPUGag2``Ypji!(up;SV$!5)9woFfh^uMRS`%$*OQT7RkCAS=2b0ycx>ozQ ztLNNv=6v6N?{(&oMnvJXhCpWJ@?|OXK+;Ge?R8n~TReZ!k`c=n5J7)19h|>#m9M>N z=`cC(5_x*nygA;m2cNz|WGoaew@L`x^VVv?`vj*~En2oRY9nnG{I=k*h1HdF#I8#4 zdxE1D%~`qFsJ1K-{E^_4#Y^Wc9&P^FRBpJZpHz6DXnZL-|f!qjTr zpsZ78JBO2bw)1S~uwH+TREI0ok?J$3s|E>Om)LK$-~3{!Ww7|jBC>Q@oHUr+bbmpg ztb2QBhGm!uv0;5P!l|DnEIm2A|9~k&&93}Yo>Q`!r#zv(D_`6f^iJrPb|BrMZ6Nn+ z884f(EzX*LB0ecKD?k6D$8*tht<&uE$mbcR#isSQT9UNXoDqL{xp}#xLpTH-X^yW~ zT26M(h}>+I9h;`#3{(yrpxv64IIwtaQ=oFHe&`rmLth}!^eS#0J7#fiA2g_{vbbet zVy}VQr&U$n-h(q;S$9@LamzvdvUEzzp=N58`35!8E^WUcpU_K$*`pt#b@Y%hC$&~> zqwW@NKV7AE(cFJPt!Okzn?%{d5`Ca_x~7%VVev6ib7~{47K4mpoN2W^`mC(Jk`)~Tt+rd7)6Gi&Z7;DbV;HZ;=h#|Xdl%| zE>5kQR_nF;3}N0=eFA^&);grFR=Q4WQL3+&dzh{J zB>%U>SDV=Hpc;czhZaGsX9{;XbT4Uc&z=Og>gbtQX|+TyrG1uWi_@AWQ9>QtubtF7 zEn8?0wd31Zf)BNIMw;=WF@YNHbO069Aij5mY%D%)mDC=ZwIT2N3Zp`6q{~Kyb*}h6 z9jZuT9@c+nNJTz6A!~)jl$u6s>#$KW4M~%z%{s}*5_|Drt&^&Ws*ytrK^iMFvYZ{1ZY~owkoB$yL(!hk)X;0DlvZmS6IMsrCs<>!VB&plc$xX1pYCu z=qs<|DvE?FDU)Le2`&7%q8?c&Xh6B-n^+M@sjNz=H|x_z)tmE1x#hA-#d`Vnru2ss zzZ;$ZCG`uV&^YtxjXq!h-Zmp7fvh$5|!Rhw$ulRorU2dq) zdLn=HU+)=3q4()dJd{!(4j;7Ow~TY5ey$E3XUD6KI-DJk_V*K1 zJLCNXoMF7j_zmONj5a^sZB171GFp@ID-Ygbyt&Sy-b}>lIGkdfWc-rx2IFe zUS*tMv@ni4aBRIx9b+^fZBfmPqeo_|qb)eP#yIkdOC6bA(2XMn#w#uyX8hcbLyUiy z83D%67)@UM)Q*=9y3|Wv9BhnH2VH24!2wD7KoBo7e!|$#_;C#OF<#hfS1)+5*Nz`~ zu}4()`0+er_j6HdH{-b|?AjTxc6qULhpBePV~2_D5qOrd&2LlN7=9bJiqTd-p4nno z&kVvAJDv{Wsm(3wDaPi8*=lnOHm`p%8lH5ihS_K+FrIW_6XS`;hpHzSj}Jw?lvzI( z8y|~Q8=ZJ85*vir;Kh3B)Or`zIq)cB?IRAgmhp%KKV+<7tY#E+KU`O*9%j_l;RjyS zmd2`D7rxI}#aL;_iYP3Pz(b5>LDU4XG>9cZEM`!^@~-%w^0Og^D1)6NTA~Z!zv?l$S-Q@*v70Fe@%z&GO(r#!QJkvk;}RDA7z+ z(g!n~m_DhOn$DOOiElEBr<$smG1bHr#$=I9W=xuBs!6>tG0CPTnwVh2c*ebcjPs+2 zagXj+_XJVcg0YiP!1xB^?lFHc>TV~-&4ic|xl;fh2$BaP8N8mUreY7A1m=odt?l#qYyMUoAP(!oSV zLJ)lm5icN~(Z`G4(y88zI5CQgM=Zn1=*5T;g&2lIYIPLCtV6UHc7`n~PT3eyq8$~7 zNJfN-a7LJ@g)yv7SiCSqXvhtSg|J|GMNOr7Rev z*rEz$Ze(+Ga%Ev{3T3n4GL!)ZQ&U4nNLrJ6G)xROG9WQGIWr(JGBYxhyC_5hGBYxh x88vzaQ&U4nNLrJbHQfeNQ$t5cT9bS>!UHreHj_a&Gy^m)Hj_a&9kZ1;Is!Zc4NU+5 delta 9295 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 diff --git a/docs/images/input_device_hierarchy.pdf b/docs/images/input_device_hierarchy.pdf index 994f7db4cb44439003d3c181074ad17adfe2d2a8..7b2e60bc12e42e4bc67c8eacddd4c34049cf80f9 100644 GIT binary patch delta 5428 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 diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index 13b961b..b9ec330 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -25,8 +25,10 @@ from ..exc import DeviceClosed, PinUnknownPi, SPIInvalidClockMode class LocalPiFactory(PiFactory): """ Abstract base class representing pins attached locally to a Pi. This forms - the base class for local-only pin interfaces (:class:`RPiGPIOPin`, - :class:`RPIOPin`, and :class:`NativePin`). + the base class for local-only pin interfaces + (:class:`~gpiozero.pins.rpigpio.RPiGPIOPin`, + :class:`~gpiozero.pins.rpio.RPIOPin`, and + :class:`~gpiozero.pins.native.NativePin`). """ pins = {} diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index a874e4d..7af2658 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -161,9 +161,9 @@ class MockConnectedPin(MockPin): mock pin. This is used in the "real pins" portion of the test suite to check that one pin can influence another. """ - def __init__(self, factory, number): + def __init__(self, factory, number, input_pin=None): super(MockConnectedPin, self).__init__(factory, number) - self.input_pin = None + self.input_pin = input_pin def _change_state(self, value): if self.input_pin: @@ -181,9 +181,9 @@ class MockChargingPin(MockPin): (as if attached to, e.g. a typical circuit using an LDR and a capacitor to time the charging rate). """ - def __init__(self, factory, number): + def __init__(self, factory, number, charge_time=0.01): super(MockChargingPin, self).__init__(factory, number) - self.charge_time = 0.01 # dark charging time + self.charge_time = charge_time # dark charging time self._charge_stop = Event() self._charge_thread = None @@ -220,10 +220,10 @@ class MockTriggerPin(MockPin): corresponding pin instance. When this pin is driven high it will trigger the echo pin to drive high for the echo time. """ - def __init__(self, factory, number): + def __init__(self, factory, number, echo_pin=None, echo_time=0.04): super(MockTriggerPin, self).__init__(factory, number) - self.echo_pin = None - self.echo_time = 0.04 # longest echo time + self.echo_pin = echo_pin + self.echo_time = echo_time # longest echo time self._echo_thread = None def _set_state(self, value): @@ -432,14 +432,14 @@ class MockFactory(LocalPiFactory): def reset(self): self.pins.clear() - def pin(self, spec, pin_class=None): + def pin(self, spec, pin_class=None, **kwargs): if pin_class is None: pin_class = self.pin_class n = self._to_gpio(spec) try: pin = self.pins[n] except KeyError: - pin = pin_class(self, n) + pin = pin_class(self, n, **kwargs) self.pins[n] = pin else: # Ensure the pin class expected supports PWM (or not) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index b5f11ef..6769607 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -34,7 +34,7 @@ from ..exc import ( class PiFactory(Factory): """ Abstract base class representing hardware attached to a Raspberry Pi. This - forms the base of :class:`LocalPiFactory`. + forms the base of :class:`~gpiozero.pins.local.LocalPiFactory`. """ def __init__(self): self._info = None @@ -187,7 +187,31 @@ class PiFactory(Factory): class PiPin(Pin): """ Abstract base class representing a multi-function GPIO pin attached to a - Raspberry Pi. + Raspberry Pi. This overrides several methods in the abstract base + :class:`~gpiozero.Pin`. Descendents must override the following methods: + + * :meth:`_get_function` + * :meth:`_set_function` + * :meth:`_get_state` + * :meth:`_call_when_changed` + * :meth:`_enable_event_detect` + * :meth:`_disable_event_detect` + + Descendents *may* additionally override the following methods, if + applicable: + + * :meth:`close` + * :meth:`output_with_state` + * :meth:`input_with_pull` + * :meth:`_set_state` + * :meth:`_get_frequency` + * :meth:`_set_frequency` + * :meth:`_get_pull` + * :meth:`_set_pull` + * :meth:`_get_bounce` + * :meth:`_set_bounce` + * :meth:`_get_edges` + * :meth:`_set_edges` """ def __init__(self, factory, number): super(PiPin, self).__init__() @@ -214,6 +238,11 @@ class PiPin(Pin): return self.factory.address + ('GPIO%d' % self.number,) def _call_when_changed(self): + """ + Called to fire the :attr:`when_changed` event handler; override this + in descendents if additional (currently redundant) parameters need + to be passed. + """ method = self.when_changed() if method is None: self.when_changed = None @@ -242,8 +271,17 @@ class PiPin(Pin): self._enable_event_detect() def _enable_event_detect(self): + """ + Enables event detection. This is called to activate event detection on + pin :attr:`number`, watching for the specified :attr:`edges`. In + response, :meth:`_call_when_changed` should be executed. + """ raise NotImplementedError def _disable_event_detect(self): + """ + Disables event detection. This is called to deactivate event detection + on pin :attr:`number`. + """ raise NotImplementedError diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 0b61ddd..d2bf447 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -171,9 +171,7 @@ def test_input_light_sensor(): reason='timing is too random on pypy') def test_input_distance_sensor(): echo_pin = Device._pin_factory.pin(4) - trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin) - trig_pin.echo_pin = echo_pin - trig_pin.echo_time = 0.02 + trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin, echo_pin=echo_pin, echo_time=0.02) with pytest.raises(ValueError): DistanceSensor(echo_pin, trig_pin, max_distance=-1) # normal queue len is large (because the sensor is *really* jittery) but diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index 2fc0fa7..7aee8ea 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -85,15 +85,13 @@ def pins(request, pin_factory): # 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 - if pin_factory.__class__.__name__ == 'MockFactory': - test_pin = pin_factory.pin(TEST_PIN, pin_class=MockConnectedPin) - else: - test_pin = pin_factory.pin(TEST_PIN) input_pin = pin_factory.pin(INPUT_PIN) input_pin.function = 'input' input_pin.pull = 'down' if pin_factory.__class__.__name__ == 'MockFactory': - test_pin.input_pin = input_pin + test_pin = pin_factory.pin(TEST_PIN, pin_class=MockConnectedPin, input_pin=input_pin) + else: + test_pin = pin_factory.pin(TEST_PIN) def fin(): test_pin.close() input_pin.close() From e5336c38ced86cab21f69bc7e3a39ddae4b46cf2 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 23 Oct 2016 21:27:38 +0100 Subject: [PATCH 47/62] Run all tests on all platforms Also renamed GPIOZERO_INPUT_PIN to GPIOZERO_TEST_INPUT_PIN, and fixed up the pigpio factory so it actually raises an exception if the connection fails and we don't try and control the daemon anymore. --- gpiozero/pins/pigpiod.py | 4 ++++ tests/test_real_pins.py | 28 ++++------------------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index beba9d7..07c8d9c 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -84,6 +84,10 @@ class PiGPIOFactory(PiFactory): ('software', 'shared'): PiGPIOSoftwareSPIShared, } self._connection = pigpio.pi(host, port) + # Annoyingly, pigpio doesn't raise an exception when it fails to make a + # connection; it returns a valid (but disconnected) pi object + if self.connection is None: + raise IOError('failed to connect to %s:%s' % (host, port)) self._host = host self._port = port self._spis = [] diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index 7aee8ea..e570eba 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -12,7 +12,6 @@ except NameError: import io import os -import subprocess from time import sleep import pytest @@ -37,20 +36,7 @@ except ImportError: # your testing rig requires different pins because the defaults interfere with # attached hardware). TEST_PIN = int(os.getenv('GPIOZERO_TEST_PIN', '22')) -INPUT_PIN = int(os.getenv('GPIOZERO_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 +INPUT_PIN = int(os.getenv('GPIOZERO_TEST_INPUT_PIN', '27')) @pytest.fixture( @@ -58,24 +44,18 @@ del is_a_pi params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) def pin_factory(request): # Constructs each pin factory in turn with some extra logic to ensure - # the pigpiod daemon gets started and stopped around the pigpio factory + # we skip tests if pigpio is set for remote operation if request.param == 'pigpio': - try: - subprocess.check_call(['sudo', 'systemctl', 'start', 'pigpiod']) - except subprocess.CalledProcessError: - pytest.skip("skipped factory pigpio: failed to start pigpiod") + if os.getenv('PIGPIO_ADDR', 'localhost') != 'localhost': + pytest.skip("skipped factory pigpio: remote host in PIGPIO_ADDR") try: factory = pkg_resources.load_entry_point('gpiozero', 'gpiozero_pin_factories', request.param)() except Exception as e: - if request.param == 'pigpio': - subprocess.check_call(['sudo', 'systemctl', 'stop', 'pigpiod']) pytest.skip("skipped factory %s: %s" % (request.param, str(e))) else: Device._set_pin_factory(factory) def fin(): Device._set_pin_factory(MockFactory()) - if request.param == 'pigpio': - subprocess.check_call(['sudo', 'systemctl', 'stop', 'pigpiod']) request.addfinalizer(fin) return factory From 4944849a3038747a102bb085287300cbde1f5aac Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 23 Oct 2016 22:11:52 +0100 Subject: [PATCH 48/62] Debug travis Mock pin tests aren't skipped locally, but are skipped on Travis; temporarily adding a reporting flag to find out why... --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9cf458f..dae7b25 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ develop: tags $(PIP) install -e .[doc,test] test: - $(COVERAGE) run -m $(PYTEST) tests -v + $(COVERAGE) run -m $(PYTEST) tests -v -r sx $(COVERAGE) report --rcfile coverage.cfg clean: From 5487124f748781dbfc2be437bab50396b6c99c7d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 1 Nov 2016 10:03:04 +0000 Subject: [PATCH 49/62] Fix pigpiod SPI conflicts Wrong classname in the software implementation and for some reason I'd reverted a change on spi_flags somewhere... Also removed the clause skipping remote pigpiod tests Tested this commit with hardware and software SPI remotely - working nicely --- gpiozero/pins/pigpiod.py | 5 +++-- gpiozero/spi_devices.py | 2 ++ tests/test_real_pins.py | 5 ----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 07c8d9c..564c376 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -297,6 +297,7 @@ class PiGPIOHardwareSPI(SPI, Device): self._port = port self._device = device self._factory = proxy(factory) + self._handle = None super(PiGPIOHardwareSPI, self).__init__() self._reserve_pins(*( factory.address + ('GPIO%d' % pin,) @@ -305,7 +306,7 @@ class PiGPIOHardwareSPI(SPI, Device): self._spi_flags = 8 << 16 self._baud = 500000 self._handle = self._factory.connection.spi_open( - device, self._baud, self._spi_flags()) + device, self._baud, self._spi_flags) def _conflicts_with(self, other): return not ( @@ -413,7 +414,7 @@ class PiGPIOSoftwareSPI(SPI, Device): def _conflicts_with(self, other): return not ( - isinstance(other, PiGPIOHardwareSPI) and + isinstance(other, PiGPIOSoftwareSPI) and (self._select_pin) != (other._select_pin) ) diff --git a/gpiozero/spi_devices.py b/gpiozero/spi_devices.py index 3840583..0a30de1 100644 --- a/gpiozero/spi_devices.py +++ b/gpiozero/spi_devices.py @@ -27,6 +27,8 @@ class SPIDevice(Device): specified with the constructor. """ def __init__(self, **spi_args): + self._spi = None + super(SPIDevice, self).__init__() self._spi = self._pin_factory.spi(**spi_args) def close(self): diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index e570eba..c266828 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -43,11 +43,6 @@ INPUT_PIN = int(os.getenv('GPIOZERO_TEST_INPUT_PIN', '27')) scope='module', params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) def pin_factory(request): - # Constructs each pin factory in turn with some extra logic to ensure - # we skip tests if pigpio is set for remote operation - if request.param == 'pigpio': - if os.getenv('PIGPIO_ADDR', 'localhost') != 'localhost': - pytest.skip("skipped factory pigpio: remote host in PIGPIO_ADDR") try: factory = pkg_resources.load_entry_point('gpiozero', 'gpiozero_pin_factories', request.param)() except Exception as e: From 6017e7d01d4c69673df7fab51f3af6eed7b3fc51 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 21 Nov 2016 15:35:11 +0000 Subject: [PATCH 50/62] Missing import... --- gpiozero/pins/pi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 6769607..8fa408c 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -8,6 +8,7 @@ str = type('') import io from threading import RLock +from types import MethodType from weakref import ref, proxy try: from weakref import WeakMethod From aa3aa21695441b23d8986907422b29f9d9eef263 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 16 Jun 2017 22:12:16 +0100 Subject: [PATCH 51/62] Reference Device directly Don't go via the instance dict (prevents anyone overriding the reservations dict or pin_factory at the instance level) --- gpiozero/devices.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 9b587b3..ed8d37c 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -224,7 +224,7 @@ class Device(ValuesMixin, GPIOBase): p.address if isinstance(p, Pin) else p for p in pins_or_addresses ) - with self._res_lock: + with Device._res_lock: for address in addresses: for device_ref in Device._reservations[address]: device = device_ref() @@ -247,10 +247,10 @@ class Device(ValuesMixin, GPIOBase): p.address if isinstance(p, Pin) else p for p in pins_or_addresses ) - with self._res_lock: + with Device._res_lock: for address in addresses: Device._reservations[address] = [ - ref for ref in self._reservations[address] + ref for ref in Device._reservations[address] if ref() not in (self, None) # may as well clean up dead refs ] @@ -259,13 +259,13 @@ class Device(ValuesMixin, GPIOBase): Releases all pin reservations taken out by this device. See :meth:`_release_pins` for further information). """ - with self._res_lock: + with Device._res_lock: Device._reservations = defaultdict(list, { address: [ ref for ref in conflictors if ref() not in (self, None) ] - for address, conflictors in self._reservations.items() + for address, conflictors in Device._reservations.items() }) def _conflicts_with(self, other): @@ -424,8 +424,8 @@ class GPIODevice(Device): self._reserve_pins(pin) else: # Check you can reserve *before* constructing the pin - self._reserve_pins(self._pin_factory.pin_address(pin)) - pin = self._pin_factory.pin(pin) + self._reserve_pins(Device._pin_factory.pin_address(pin)) + pin = Device._pin_factory.pin(pin) self._pin = pin self._active_state = True self._inactive_state = False From ab73e857fde9cf35e80870ba710528572f612345 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 19 Jun 2017 12:36:06 +0100 Subject: [PATCH 52/62] Add compatibility names for pin factories --- setup.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.py b/setup.py index 4647fdc..f1f76f8 100644 --- a/setup.py +++ b/setup.py @@ -73,6 +73,11 @@ __entry_points__ = { 'rpio = gpiozero.pins.rpio:RPIOFactory', 'native = gpiozero.pins.native:NativeFactory', 'mock = gpiozero.pins.mock:MockFactory', + # Backwards compatible names + 'PiGPIOPin = gpiozero.pins.pigpiod:PiGPIOFactory', + 'RPiGPIOPin = gpiozero.pins.rpigpio:RPiGPIOFactory', + 'RPIOPin = gpiozero.pins.rpio:RPIOFactory', + 'NativePin = gpiozero.pins.native:NativeFactory', ], 'gpiozero_mock_pin_classes': [ 'mockpin = gpiozero.pins.mock:MockPin', From bcc94354ea45d0a449d73ad5b9473837ad5a8cde Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 19 Jun 2017 22:22:39 +0100 Subject: [PATCH 53/62] Fix #553 Ensure SourceMixin descendents shut down the source prior to closing. Furthermore, make sure devices are closed before pin factory shuts down, and that pins have a strong reference to their owning factory (to prevent losing the factory before the pins). --- gpiozero/devices.py | 15 +++++++++++++++ gpiozero/exc.py | 3 +++ gpiozero/mixins.py | 5 ++++- gpiozero/pins/pi.py | 6 +++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/gpiozero/devices.py b/gpiozero/devices.py index ed8d37c..4b282d0 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -34,6 +34,7 @@ from .exc import ( GPIOPinInUse, GPIODeviceClosed, PinFactoryFallback, + PinReservationsExist, ) from .compat import frozendict @@ -202,6 +203,20 @@ class Device(ValuesMixin, GPIOBase): @classmethod def _set_pin_factory(cls, new_factory): + reserved_devices = { + dev + for ref_list in cls._reservations.values() + for ref in ref_list + for dev in (ref(),) + if dev is not None + } + if new_factory is None: + for dev in reserved_devices: + dev.close() + elif reserved_devices: + raise PinReservationsExist( + "can't change factory while devices still hold pin " + "reservations (%r)" % dev) if cls._pin_factory is not None: cls._pin_factory.close() cls._pin_factory = new_factory diff --git a/gpiozero/exc.py b/gpiozero/exc.py index 416f1a6..1a3182d 100644 --- a/gpiozero/exc.py +++ b/gpiozero/exc.py @@ -145,6 +145,9 @@ class PinNoPins(PinError, RuntimeError): class PinInvalidPin(PinError, ValueError): "Error raised when an invalid pin specification is provided" +class PinReservationsExist(PinError, RuntimeError): + "Error raised when pin factory is changed while reservations still exist" + class GPIOZeroWarning(Warning): "Base class for all warnings in GPIO Zero" diff --git a/gpiozero/mixins.py b/gpiozero/mixins.py index 794a850..56ed1d5 100644 --- a/gpiozero/mixins.py +++ b/gpiozero/mixins.py @@ -70,10 +70,13 @@ class SourceMixin(object): def close(self): try: - super(SourceMixin, self).close() self.source = None except AttributeError: pass + try: + super(SourceMixin, self).close() + except AttributeError: + pass def _copy_values(self, source): for v in source: diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 8fa408c..2f88ce3 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -9,10 +9,10 @@ str = type('') import io from threading import RLock from types import MethodType -from weakref import ref, proxy try: - from weakref import WeakMethod + from weakref import ref, WeakMethod except ImportError: + from ..compat import WeakMethod import warnings @@ -216,7 +216,7 @@ class PiPin(Pin): """ def __init__(self, factory, number): super(PiPin, self).__init__() - self._factory = proxy(factory) + self._factory = factory self._when_changed_lock = RLock() self._when_changed = None self._number = number From 1022b0b0dea9c07cc47947a5e3b4a8064c02e5fe Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 20 Jun 2017 23:16:59 +0100 Subject: [PATCH 54/62] Close #465 Factor out hardware SPI pin numbers; this is a effectively a rebase (and minor modification) of @lurch's original patch which conflicted after the merge of the remote-spi branch. --- gpiozero/pins/local.py | 11 ++++--- gpiozero/pins/pi.py | 67 ++++++++++++++++++++++++++-------------- gpiozero/pins/pigpiod.py | 12 +++++-- 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/gpiozero/pins/local.py b/gpiozero/pins/local.py index b9ec330..9121dac 100644 --- a/gpiozero/pins/local.py +++ b/gpiozero/pins/local.py @@ -15,7 +15,7 @@ except ImportError: SpiDev = None from . import SPI -from .pi import PiFactory, PiPin +from .pi import PiFactory, PiPin, SPI_HARDWARE_PINS from .spi import SPISoftwareBus from ..devices import Device, SharedMixin from ..output_devices import OutputDevice @@ -81,11 +81,12 @@ class LocalPiHardwareSPI(SPI, Device): self._interface = None self._address = factory.address + ('SPI(port=%d, device=%d)' % (port, device),) super(LocalPiHardwareSPI, self).__init__() + pins = SPI_HARDWARE_PINS[port] self._reserve_pins( - factory.pin_address(11), - factory.pin_address(10), - factory.pin_address(9), - factory.pin_address((8, 7)[device]) + factory.pin_address(pins['clock']), + factory.pin_address(pins['mosi']), + factory.pin_address(pins['miso']), + factory.pin_address(pins['select'][device]) ) self._interface = SpiDev() self._interface.open(port, device) diff --git a/gpiozero/pins/pi.py b/gpiozero/pins/pi.py index 2f88ce3..1ec024d 100644 --- a/gpiozero/pins/pi.py +++ b/gpiozero/pins/pi.py @@ -32,6 +32,16 @@ from ..exc import ( ) +SPI_HARDWARE_PINS = { + 0: { + 'clock': 11, + 'mosi': 10, + 'miso': 9, + 'select': (8, 7), + }, +} + + class PiFactory(Factory): """ Abstract base class representing hardware attached to a Raspberry Pi. This @@ -105,21 +115,24 @@ class PiFactory(Factory): if kwargs: raise SPIBadArgs( 'unrecognized keyword argument %s' % kwargs.popitem()[0]) - if all(( - spi_args['clock_pin'] == 11, - spi_args['mosi_pin'] == 10, - spi_args['miso_pin'] == 9, - spi_args['select_pin'] in (7, 8), - )): - try: - return self.spi_classes[('hardware', shared)]( - self, port=0, device=0 if spi_args['select_pin'] == 8 else 1 - ) - except Exception as e: - warnings.warn( - SPISoftwareFallback( - 'failed to initialize hardware SPI, falling back to ' - 'software (error was: %s)' % str(e))) + for port, pins in SPI_HARDWARE_PINS.items(): + if all(( + spi_args['clock_pin'] == pins['clock'], + spi_args['mosi_pin'] == pins['mosi'], + spi_args['miso_pin'] == pins['miso'], + spi_args['select_pin'] in pins['select'], + )): + try: + return self.spi_classes[('hardware', shared)]( + self, port=port, + device=pins['select'].index(spi_args['select_pin']) + ) + except Exception as e: + warnings.warn( + SPISoftwareFallback( + 'failed to initialize hardware SPI, falling back to ' + 'software (error was: %s)' % str(e))) + break # Convert all pin arguments to integer GPIO numbers. This is necessary # to ensure the shared-key for shared implementations get matched # correctly, and is a bit of a hack for the pigpio bit-bang @@ -139,16 +152,17 @@ class PiFactory(Factory): Returns a tuple of ``(spi_args, other_args)``. """ - pin_defaults = { - 'clock_pin': 11, - 'mosi_pin': 10, - 'miso_pin': 9, - 'select_pin': 8, - } dev_defaults = { 'port': 0, 'device': 0, } + default_hw = SPI_HARDWARE_PINS[dev_defaults['port']] + pin_defaults = { + 'clock_pin': default_hw['clock'], + 'mosi_pin': default_hw['mosi'], + 'miso_pin': default_hw['miso'], + 'select_pin': default_hw['select'][dev_defaults['device']], + } spi_args = { key: value for (key, value) in kwargs.items() if key in pin_defaults or key in dev_defaults @@ -171,10 +185,15 @@ class PiFactory(Factory): } if spi_args['port'] != 0: raise SPIBadArgs('port 0 is the only valid SPI port') - if spi_args['device'] not in (0, 1): - raise SPIBadArgs('device must be 0 or 1') + selected_hw = SPI_HARDWARE_PINS[spi_args['port']] + try: + selected_hw['select'][spi_args['device']] + except IndexError: + raise SPIBadArgs( + 'device must be in the range 0..%d' % + len(selected_hw['select'])) spi_args = { - key: value if key != 'select_pin' else (8, 7)[spi_args['device']] + key: value if key != 'select_pin' else selected_hw['select'][spi_args['device']] for key, value in pin_defaults.items() } else: diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpiod.py index 564c376..c6841be 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpiod.py @@ -12,7 +12,7 @@ from weakref import proxy import pigpio from . import SPI -from .pi import PiPin, PiFactory +from .pi import PiPin, PiFactory, SPI_HARDWARE_PINS from .data import pi_info from ..devices import Device from ..mixins import SharedMixin @@ -299,10 +299,16 @@ class PiGPIOHardwareSPI(SPI, Device): self._factory = proxy(factory) self._handle = None super(PiGPIOHardwareSPI, self).__init__() + pins = SPI_HARDWARE_PINS[port] self._reserve_pins(*( factory.address + ('GPIO%d' % pin,) - for pin in (11, 10, 9, (8, 7)[device]) - )) + for pin in ( + pins['clock'], + pins['mosi'], + pins['miso'], + pins['select'][device] + ) + )) self._spi_flags = 8 << 16 self._baud = 500000 self._handle = self._factory.connection.spi_open( From 35f1ff0623dc3e7e9fb7826f062665ef6d176bd0 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2017 14:40:30 +0100 Subject: [PATCH 55/62] Eliminate compatibility names from tests No need to run the same tests on the same backends --- tests/test_real_pins.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index c266828..bccf045 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -41,7 +41,11 @@ INPUT_PIN = int(os.getenv('GPIOZERO_TEST_INPUT_PIN', '27')) @pytest.fixture( scope='module', - params=pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys()) + params=[ + name + for name in pkg_resources.get_distribution('gpiozero').get_entry_map('gpiozero_pin_factories').keys() + if not name.endswith('Pin') # leave out compatibility names + ]) def pin_factory(request): try: factory = pkg_resources.load_entry_point('gpiozero', 'gpiozero_pin_factories', request.param)() From d2a7c1434adb95d253e59ea5f25832151f828257 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2017 14:40:52 +0100 Subject: [PATCH 56/62] Fix SPI tests when spidev is installed Doh! SPI tests fail when the spidev package is installed (which it normally isn't in my virtualenv) because hardware SPI always takes precedence and the mock SPI stuff only replaces software SPI. --- tests/test_spi.py | 17 +++-- tests/test_spi_devices.py | 142 +++++++++++++++++++++----------------- 2 files changed, 89 insertions(+), 70 deletions(-) diff --git a/tests/test_spi.py b/tests/test_spi.py index 5159109..7b514bf 100644 --- a/tests/test_spi.py +++ b/tests/test_spi.py @@ -70,7 +70,8 @@ def test_spi_software_params(): assert isinstance(device, LocalPiSoftwareSPI) with Device._pin_factory.spi(select_pin=6, shared=True) as device: assert isinstance(device, LocalPiSoftwareSPIShared) - with patch('gpiozero.devices.Device._pin_factory', NativeFactory()): + with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + patch('gpiozero.pins.local.SpiDev', None): # Clear out the old factory's pins cache (this is only necessary # because we're being very naughty switching out pin factories) Device._pin_factory.pins.clear() @@ -136,7 +137,9 @@ def test_spi_software_read(): super(SPISlave, self).on_start() for i in range(10): self.tx_word(i) - with SPISlave(11, 10, 9, 8) as slave, Device._pin_factory.spi() as master: + with patch('gpiozero.pins.local.SpiDev', None), \ + SPISlave(11, 10, 9, 8) as slave, \ + Device._pin_factory.spi() as master: assert master.read(3) == [0, 1, 2] assert master.read(6) == [0, 1, 2, 3, 4, 5] slave.clock_phase = True @@ -145,7 +148,9 @@ def test_spi_software_read(): assert master.read(6) == [0, 1, 2, 3, 4, 5] def test_spi_software_write(): - with MockSPIDevice(11, 10, 9, 8) as test_device, Device._pin_factory.spi() as master: + with patch('gpiozero.pins.local.SpiDev', None), \ + MockSPIDevice(11, 10, 9, 8) as test_device, \ + Device._pin_factory.spi() as master: master.write([0]) assert test_device.rx_word() == 0 master.write([2, 0]) @@ -154,7 +159,8 @@ def test_spi_software_write(): assert test_device.rx_word() == 257 def test_spi_software_clock_mode(): - with Device._pin_factory.spi() as master: + with patch('gpiozero.pins.local.SpiDev', None), \ + Device._pin_factory.spi() as master: assert master.clock_mode == 0 assert not master.clock_polarity assert not master.clock_phase @@ -171,7 +177,8 @@ def test_spi_software_clock_mode(): master.clock_mode = 5 def test_spi_software_attr(): - with Device._pin_factory.spi() as master: + with patch('gpiozero.pins.local.SpiDev', None), \ + Device._pin_factory.spi() as master: assert not master.lsb_first assert not master.select_high assert master.bits_per_word == 8 diff --git a/tests/test_spi_devices.py b/tests/test_spi_devices.py index 6c876ad..4f45171 100644 --- a/tests/test_spi_devices.py +++ b/tests/test_spi_devices.py @@ -9,6 +9,7 @@ str = type('') import sys import pytest +from mock import patch from collections import namedtuple try: from math import isclose @@ -247,89 +248,100 @@ def differential_mcp_test(mock, pot, pos_channel, neg_channel, bits, full=False) def test_MCP3001(): - mock = MockMCP3001(11, 10, 9, 8) - with MCP3001() as pot: - differential_mcp_test(mock, pot, 0, 1, 10) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3001(11, 10, 9, 8) + with MCP3001() as pot: + differential_mcp_test(mock, pot, 0, 1, 10) def test_MCP3002(): - mock = MockMCP3002(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3002(channel=5) - with MCP3002(channel=1) as pot: - single_mcp_test(mock, pot, 1, 10) - with MCP3002(channel=1, differential=True) as pot: - differential_mcp_test(mock, pot, 1, 0, 10) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3002(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3002(channel=5) + with MCP3002(channel=1) as pot: + single_mcp_test(mock, pot, 1, 10) + with MCP3002(channel=1, differential=True) as pot: + differential_mcp_test(mock, pot, 1, 0, 10) def test_MCP3004(): - mock = MockMCP3004(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3004(channel=5) - with MCP3004(channel=3) as pot: - single_mcp_test(mock, pot, 3, 10) - with MCP3004(channel=3, differential=True) as pot: - differential_mcp_test(mock, pot, 3, 2, 10) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3004(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3004(channel=5) + with MCP3004(channel=3) as pot: + single_mcp_test(mock, pot, 3, 10) + with MCP3004(channel=3, differential=True) as pot: + differential_mcp_test(mock, pot, 3, 2, 10) def test_MCP3008(): - mock = MockMCP3008(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3008(channel=9) - with MCP3008(channel=0) as pot: - single_mcp_test(mock, pot, 0, 10) - with MCP3008(channel=0, differential=True) as pot: - differential_mcp_test(mock, pot, 0, 1, 10) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3008(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3008(channel=9) + with MCP3008(channel=0) as pot: + single_mcp_test(mock, pot, 0, 10) + with MCP3008(channel=0, differential=True) as pot: + differential_mcp_test(mock, pot, 0, 1, 10) def test_MCP3201(): - mock = MockMCP3201(11, 10, 9, 8) - with MCP3201() as pot: - differential_mcp_test(mock, pot, 0, 1, 12) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3201(11, 10, 9, 8) + with MCP3201() as pot: + differential_mcp_test(mock, pot, 0, 1, 12) def test_MCP3202(): - mock = MockMCP3202(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3202(channel=5) - with MCP3202(channel=1) as pot: - single_mcp_test(mock, pot, 1, 12) - with MCP3202(channel=1, differential=True) as pot: - differential_mcp_test(mock, pot, 1, 0, 12) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3202(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3202(channel=5) + with MCP3202(channel=1) as pot: + single_mcp_test(mock, pot, 1, 12) + with MCP3202(channel=1, differential=True) as pot: + differential_mcp_test(mock, pot, 1, 0, 12) def test_MCP3204(): - mock = MockMCP3204(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3204(channel=5) - with MCP3204(channel=1) as pot: - single_mcp_test(mock, pot, 1, 12) - with MCP3204(channel=1, differential=True) as pot: - differential_mcp_test(mock, pot, 1, 0, 12) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3204(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3204(channel=5) + with MCP3204(channel=1) as pot: + single_mcp_test(mock, pot, 1, 12) + with MCP3204(channel=1, differential=True) as pot: + differential_mcp_test(mock, pot, 1, 0, 12) def test_MCP3208(): - mock = MockMCP3208(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3208(channel=9) - with MCP3208(channel=7) as pot: - single_mcp_test(mock, pot, 7, 12) - with MCP3208(channel=7, differential=True) as pot: - differential_mcp_test(mock, pot, 7, 6, 12) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3208(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3208(channel=9) + with MCP3208(channel=7) as pot: + single_mcp_test(mock, pot, 7, 12) + with MCP3208(channel=7, differential=True) as pot: + differential_mcp_test(mock, pot, 7, 6, 12) def test_MCP3301(): - mock = MockMCP3301(11, 10, 9, 8) - with MCP3301() as pot: - differential_mcp_test(mock, pot, 0, 1, 12, full=True) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3301(11, 10, 9, 8) + with MCP3301() as pot: + differential_mcp_test(mock, pot, 0, 1, 12, full=True) def test_MCP3302(): - mock = MockMCP3302(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3302(channel=4) - with MCP3302(channel=0) as pot: - single_mcp_test(mock, pot, 0, 12) - with MCP3302(channel=0, differential=True) as pot: - differential_mcp_test(mock, pot, 0, 1, 12, full=True) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3302(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3302(channel=4) + with MCP3302(channel=0) as pot: + single_mcp_test(mock, pot, 0, 12) + with MCP3302(channel=0, differential=True) as pot: + differential_mcp_test(mock, pot, 0, 1, 12, full=True) def test_MCP3304(): - mock = MockMCP3304(11, 10, 9, 8) - with pytest.raises(ValueError): - MCP3304(channel=9) - with MCP3304(channel=5) as pot: - single_mcp_test(mock, pot, 5, 12) - with MCP3304(channel=5, differential=True) as pot: - differential_mcp_test(mock, pot, 5, 4, 12, full=True) + with patch('gpiozero.pins.local.SpiDev', None): + mock = MockMCP3304(11, 10, 9, 8) + with pytest.raises(ValueError): + MCP3304(channel=9) + with MCP3304(channel=5) as pot: + single_mcp_test(mock, pot, 5, 12) + with MCP3304(channel=5, differential=True) as pot: + differential_mcp_test(mock, pot, 5, 4, 12, full=True) From ffe12362f5d98a9fd5487375a9016497162d5e7c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2017 15:39:50 +0100 Subject: [PATCH 57/62] Fix #521 Rename pigpiod module to pigpio --- gpiozero/pins/{pigpiod.py => pigpio.py} | 6 +++--- setup.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename gpiozero/pins/{pigpiod.py => pigpio.py} (99%) diff --git a/gpiozero/pins/pigpiod.py b/gpiozero/pins/pigpio.py similarity index 99% rename from gpiozero/pins/pigpiod.py rename to gpiozero/pins/pigpio.py index c6841be..fe5e59e 100644 --- a/gpiozero/pins/pigpiod.py +++ b/gpiozero/pins/pigpio.py @@ -45,9 +45,9 @@ class PiGPIOFactory(PiFactory): * Your script itself doesn't require root privileges; it just needs to be able to communicate with the daemon - You can construct pigpiod pins manually like so:: + You can construct pigpio pins manually like so:: - from gpiozero.pins.pigpiod import PiGPIOPin + from gpiozero.pins.pigpio import PiGPIOPin from gpiozero import LED led = LED(PiGPIOPin(12)) @@ -56,7 +56,7 @@ class PiGPIOFactory(PiFactory): accomplish this simply specify the host (and optionally port) when constructing the pin:: - from gpiozero.pins.pigpiod import PiGPIOPin + from gpiozero.pins.pigpio import PiGPIOPin from gpiozero import LED from signal import pause diff --git a/setup.py b/setup.py index f1f76f8..7bafc6a 100644 --- a/setup.py +++ b/setup.py @@ -68,13 +68,13 @@ if sys.version_info[:2] == (3, 2): __entry_points__ = { 'gpiozero_pin_factories': [ - 'pigpio = gpiozero.pins.pigpiod:PiGPIOFactory', + 'pigpio = gpiozero.pins.pigpio:PiGPIOFactory', 'rpigpio = gpiozero.pins.rpigpio:RPiGPIOFactory', 'rpio = gpiozero.pins.rpio:RPIOFactory', 'native = gpiozero.pins.native:NativeFactory', 'mock = gpiozero.pins.mock:MockFactory', # Backwards compatible names - 'PiGPIOPin = gpiozero.pins.pigpiod:PiGPIOFactory', + 'PiGPIOPin = gpiozero.pins.pigpio:PiGPIOFactory', 'RPiGPIOPin = gpiozero.pins.rpigpio:RPiGPIOFactory', 'RPIOPin = gpiozero.pins.rpio:RPIOFactory', 'NativePin = gpiozero.pins.native:NativeFactory', From a0e7b63b8f8922da2d511a9c35c7f9e3376a4cae Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2017 16:08:21 +0100 Subject: [PATCH 58/62] Fix docs for #521 --- docs/api_pins.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api_pins.rst b/docs/api_pins.rst index 467de4d..b052010 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -68,7 +68,7 @@ they are tried by default. +---------+-----------------------------------------------+-------------------------------------------+ | rpio | :class:`gpiozero.pins.rpio.RPIOFactory` | :class:`gpiozero.pins.rpio.RPIOPin` | +---------+-----------------------------------------------+-------------------------------------------+ -| pigpio | :class:`gpiozero.pins.pigpiod.PiGPIOFactory` | :class:`gpiozero.pins.pigpiod.PiGPIOPin` | +| pigpio | :class:`gpiozero.pins.pigpio.PiGPIOFactory` | :class:`gpiozero.pins.pigpio.PiGPIOPin` | +---------+-----------------------------------------------+-------------------------------------------+ | native | :class:`gpiozero.pins.native.NativeFactory` | :class:`gpiozero.pins.native.NativePin` | +---------+-----------------------------------------------+-------------------------------------------+ @@ -90,7 +90,7 @@ any devices using them):: Certain factories may take default information from additional sources. For example, to default to creating pins with -:class:`gpiozero.pins.pigpiod.PiGPIOPin` on a remote pi called ``remote-pi`` +:class:`gpiozero.pins.pigpio.PiGPIOPin` on a remote pi called ``remote-pi`` you can set the :envvar:`PIGPIO_ADDR` environment variable when running your script: @@ -129,9 +129,9 @@ RPIO PiGPIO ====== -.. autoclass:: gpiozero.pins.pigpiod.PiGPIOFactory +.. autoclass:: gpiozero.pins.pigpio.PiGPIOFactory -.. autoclass:: gpiozero.pins.pigpiod.PiGPIOPin +.. autoclass:: gpiozero.pins.pigpio.PiGPIOPin Native From 412ca72066bf18d1d2ef1b9b5af0ac699786b2ad Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 21 Jun 2017 16:12:25 +0100 Subject: [PATCH 59/62] First stab at #451 This is almost a straight copy'n'paste of picamera's development chapter with a few minor changes to make it read sensibly for GPIO Zero; it needs plenty more work to fulfil the goals of #451 but hopefully this'll act as a reasonable base for people to work on. --- docs/changelog.rst | 2 +- docs/development.rst | 130 +++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 3 +- 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 docs/development.rst diff --git a/docs/changelog.rst b/docs/changelog.rst index d8b935c..cab5024 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -61,7 +61,7 @@ Release 1.2.0 (2016-04-10) * Added support for lots of ADC chips (MCP3xxx family) (`#162`_) - many thanks to pcopa and lurch! * Added support for pigpiod as a pin implementation with - :class:`~gpiozero.pins.pigpiod.PiGPIOPin` (`#180`_) + :class:`~gpiozero.pins.pigpio.PiGPIOPin` (`#180`_) * Many refinements to the base classes mean more consistency in composite devices and several bugs squashed (`#164`_, `#175`_, `#182`_, `#189`_, `#193`_, `#229`_) diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 0000000..3dcc75c --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,130 @@ +=========== +Development +=========== + +.. currentmodule:: gpiozero + +The main GitHub repository for the project can be found at: + + https://github.com/RPi-Distro/python-gpiozero + +For anybody wishing to hack on the project, we recommend starting off by +getting to grips with some simple device classes. Pick something like +:class:`LED` and follow its heritage backward to :class:`DigitalOutputDevice`. +Follow that back to :class:`OutputDevice` and you should have a good +understanding of simple output devices along with a grasp of how GPIO Zero +relies fairly heavily upon inheritance to refine the functionality of devices. +The same can be done for input devices, and eventually more complex devices +(composites and SPI based). + + +.. _dev_install: + +Development installation +======================== + +If you wish to develop GPIO Zero itself, we recommend obtaining the source by +cloning the GitHub repository and then use the "develop" target of the Makefile +which will install the package as a link to the cloned repository allowing +in-place development (it also builds a tags file for use with vim/emacs with +Exuberant’s ctags utility). The following example demonstrates this method +within a virtual Python environment: + +.. code-block:: console + + $ sudo apt-get install lsb-release build-essential git git-core \ + > exuberant-ctags virtualenvwrapper python-virtualenv python3-virtualenv \ + > python-dev python3-dev + $ cd + $ mkvirtualenv -p /usr/bin/python3 python-gpiozero + $ workon python-gpiozero + (python-gpiozero) $ git clone https://github.com/RPi-Distro/python-gpiozero.git + (python-gpiozero) $ cd python-gpiozero + (python-gpiozero) $ make develop + +You will likely wish to install one or more pin implementations within the +virtual environment (if you don't, GPIO Zero will use the "native" pin +implementation which is largely experimental at this stage and not very +useful): + +.. code-block:: console + + (python-gpiozero) $ pip install rpi.gpio pigpio + +If you are working on SPI devices you may also wish to install the ``spidev`` +package to provide hardware SPI capabilities (again, GPIO Zero will work +without this, but a big-banging software SPI implementation will be used +instead): + +.. code-block:: console + + (python-gpiozero) $ pip install spidev + +To pull the latest changes from git into your clone and update your +installation: + +.. code-block:: console + + $ workon python-gpiozero + (python-gpiozero) $ cd ~/python-gpiozero + (python-gpiozero) $ git pull + (python-gpiozero) $ make develop + +To remove your installation, destroy the sandbox and the clone: + +.. code-block:: console + + (python-gpiozero) $ deactivate + $ rmvirtualenv python-gpiozero + $ rm -fr ~/python-gpiozero + + +Building the docs +================= + +If you wish to build the docs, you'll need a few more dependencies. Inkscape +is used for conversion of SVGs to other formats, Graphviz is used for rendering +certain charts, and TeX Live is required for building PDF output. The following +command should install all required dependencies: + +.. code-block:: console + + $ sudo apt-get install texlive-latex-recommended texlive-latex-extra \ + texlive-fonts-recommended graphviz inkscape + +Once these are installed, you can use the "doc" target to build the +documentation: + +.. code-block:: console + + $ workon python-gpiozero + (python-gpiozero) $ cd ~/python-gpiozero + (python-gpiozero) $ make doc + +The HTML output is written to :file:`docs/_build/html` while the PDF output +goes to :file:`docs/_build/latex`. + + +Test suite +========== + +If you wish to run the GPIO Zero test suite, follow the instructions in +:ref:`dev_install` above and then make the "test" target within the sandbox: + +.. code-block:: console + + $ workon python-gpiozero + (python-gpiozero) $ cd ~/python-gpiozero + (python-gpiozero) $ make test + +The test suite expects pins 22 and 27 (by default) to be wired together in +order to run the "real" pin tests. The pins used by the test suite can be +overridden with the environment variables ``GPIOZERO_TEST_PIN`` (defaults to +22) and ``GPIOZERO_TEST_INPUT_PIN`` (defaults to 27). + +.. warning:: + + When wiring GPIOs together, ensure a load (like a 330Ω resistor) is placed + between them. Failure to do so may lead to blown GPIO pins (your humble + author has a fried GPIO27 as a result of such laziness, although it did + take *many* runs of the test suite before this occurred!). diff --git a/docs/index.rst b/docs/index.rst index af73305..a0dcba8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,6 @@ Table of Contents recipes notes - contributing api_input api_output api_spi @@ -20,6 +19,8 @@ Table of Contents api_exc cli_tools source_values + contributing + development changelog license From 576fced6c429c1e42d4b62a2ed8a930f74e86a5f Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 26 Sep 2016 11:08:17 +0100 Subject: [PATCH 60/62] Update all hierarchy charts in the docs Added notes on how the abstracts are represented, ensured all the class hierarchies were up to date, and changed the orientation so the classes are actually readable in the big chart. --- README.rst | 20 +- docs/api_generic.rst | 3 +- docs/api_input.rst | 3 +- docs/api_other.rst | 3 +- docs/api_output.rst | 3 +- docs/api_spi.rst | 3 +- docs/images/composite_device_hierarchy.dot | 3 +- docs/images/composite_device_hierarchy.pdf | Bin 14799 -> 15382 bytes docs/images/composite_device_hierarchy.png | Bin 59369 -> 63091 bytes docs/images/composite_device_hierarchy.svg | 244 +++---- docs/images/device_hierarchy.dot | 29 +- docs/images/device_hierarchy.pdf | Bin 19780 -> 22132 bytes docs/images/device_hierarchy.png | Bin 168277 -> 252615 bytes docs/images/device_hierarchy.svg | 734 +++++++++++++-------- docs/images/input_device_hierarchy.dot | 2 +- docs/images/input_device_hierarchy.pdf | Bin 8581 -> 8642 bytes docs/images/input_device_hierarchy.png | Bin 28335 -> 28276 bytes docs/images/input_device_hierarchy.svg | 86 +-- docs/images/other_device_hierarchy.dot | 3 +- docs/images/other_device_hierarchy.pdf | Bin 7383 -> 7943 bytes docs/images/other_device_hierarchy.png | Bin 9007 -> 11476 bytes docs/images/other_device_hierarchy.svg | 48 +- docs/images/output_device_hierarchy.dot | 2 +- docs/images/output_device_hierarchy.pdf | Bin 8653 -> 8637 bytes docs/images/output_device_hierarchy.png | Bin 23066 -> 21826 bytes docs/images/output_device_hierarchy.svg | 86 +-- docs/images/spi_device_hierarchy.dot | 2 +- docs/images/spi_device_hierarchy.pdf | Bin 9455 -> 9550 bytes docs/images/spi_device_hierarchy.png | Bin 47072 -> 53994 bytes docs/images/spi_device_hierarchy.svg | 164 ++--- 30 files changed, 823 insertions(+), 615 deletions(-) diff --git a/README.rst b/README.rst index 8ecedd0..bf468d9 100644 --- a/README.rst +++ b/README.rst @@ -2,17 +2,19 @@ gpiozero ======== -.. image:: https://badge.fury.io/py/gpiozero.svg - :target: https://badge.fury.io/py/gpiozero - :alt: Latest Version +.. only:: builder_html -.. image:: https://travis-ci.org/RPi-Distro/python-gpiozero.svg?branch=master - :target: https://travis-ci.org/RPi-Distro/python-gpiozero - :alt: Build Tests + .. image:: https://badge.fury.io/py/gpiozero.svg + :target: https://badge.fury.io/py/gpiozero + :alt: Latest Version -.. image:: https://img.shields.io/codecov/c/github/RPi-Distro/python-gpiozero/master.svg?maxAge=2592000 - :target: https://codecov.io/github/RPi-Distro/python-gpiozero - :alt: Code Coverage + .. image:: https://travis-ci.org/RPi-Distro/python-gpiozero.svg?branch=master + :target: https://travis-ci.org/RPi-Distro/python-gpiozero + :alt: Build Tests + + .. image:: https://img.shields.io/codecov/c/github/RPi-Distro/python-gpiozero/master.svg?maxAge=2592000 + :target: https://codecov.io/github/RPi-Distro/python-gpiozero + :alt: Code Coverage A simple interface to GPIO devices with Raspberry Pi. diff --git a/docs/api_generic.rst b/docs/api_generic.rst index 2645561..5b3c6ae 100644 --- a/docs/api_generic.rst +++ b/docs/api_generic.rst @@ -23,7 +23,8 @@ classes (most of which are documented in their corresponding chapters): devices like HATs There are also several `mixin classes`_ for adding important functionality -at numerous points in the hierarchy, which is illustrated below: +at numerous points in the hierarchy, which is illustrated below (mixin classes +are represented in purple, while abstract classes are shaded lighter): .. image:: images/device_hierarchy.* diff --git a/docs/api_input.rst b/docs/api_input.rst index 898f603..4791c1c 100644 --- a/docs/api_input.rst +++ b/docs/api_input.rst @@ -52,7 +52,8 @@ Base Classes The classes in the sections above are derived from a series of base classes, some of which are effectively abstract. The classes form the (partial) -hierarchy displayed in the graph below: +hierarchy displayed in the graph below (abstract classes are shaded lighter +than concrete classes): .. image:: images/input_device_hierarchy.* diff --git a/docs/api_other.rst b/docs/api_other.rst index a8efaa4..35729dd 100644 --- a/docs/api_other.rst +++ b/docs/api_other.rst @@ -35,7 +35,8 @@ Base Classes The classes in the sections above are derived from a series of base classes, some of which are effectively abstract. The classes form the (partial) -hierarchy displayed in the graph below: +hierarchy displayed in the graph below (abstract classes are shaded lighter +than concrete classes): .. image:: images/other_device_hierarchy.* diff --git a/docs/api_output.rst b/docs/api_output.rst index 7bd888a..4a2a178 100644 --- a/docs/api_output.rst +++ b/docs/api_output.rst @@ -62,7 +62,8 @@ Base Classes The classes in the sections above are derived from a series of base classes, some of which are effectively abstract. The classes form the (partial) -hierarchy displayed in the graph below: +hierarchy displayed in the graph below (abstract classes are shaded lighter +than concrete classes): .. image:: images/output_device_hierarchy.* diff --git a/docs/api_spi.rst b/docs/api_spi.rst index 7fdc3bb..09338ac 100644 --- a/docs/api_spi.rst +++ b/docs/api_spi.rst @@ -121,7 +121,8 @@ Base Classes The classes in the sections above are derived from a series of base classes, some of which are effectively abstract. The classes form the (partial) -hierarchy displayed in the graph below: +hierarchy displayed in the graph below (abstract classes are shaded lighter +than concrete classes): .. image:: images/spi_device_hierarchy.* diff --git a/docs/images/composite_device_hierarchy.dot b/docs/images/composite_device_hierarchy.dot index 4fe7c50..ab4dd98 100644 --- a/docs/images/composite_device_hierarchy.dot +++ b/docs/images/composite_device_hierarchy.dot @@ -1,7 +1,7 @@ /* vim: set et sw=4 sts=4: */ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; @@ -24,6 +24,7 @@ digraph classes { PiLiter->LEDBoard; PiLiterBarGraph->LEDBarGraph; TrafficLights->LEDBoard; + SnowPi->LEDBoard; PiTraffic->TrafficLights; PiStop->TrafficLights; TrafficLightsBuzzer->CompositeOutputDevice; diff --git a/docs/images/composite_device_hierarchy.pdf b/docs/images/composite_device_hierarchy.pdf index 6d032bd3cf97e6cf655441200d763a2a1dafa59e..77942f841a40114700a137fcdcf9c3257be20514 100644 GIT binary patch delta 10803 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%0Dq}` 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 delta 10190 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 S@*RPLj{||4T0%h*;r{?kLU4Bg diff --git a/docs/images/composite_device_hierarchy.png b/docs/images/composite_device_hierarchy.png index 484f2c502d978e23b1a287b36c8cca40ba108f77..b4a167165e76c01dc64c2a4265688576f8822841 100644 GIT binary patch literal 63091 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 Wgya}b_BCMO*t7cp@edP9B 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 DWk*IR diff --git a/docs/images/composite_device_hierarchy.svg b/docs/images/composite_device_hierarchy.svg index 87b1d0b..dbd3962 100644 --- a/docs/images/composite_device_hierarchy.svg +++ b/docs/images/composite_device_hierarchy.svg @@ -1,228 +1,238 @@ - - - + + classes - + Device - -Device + +Device CompositeDevice - -CompositeDevice + +CompositeDevice CompositeDevice->Device - - + + CompositeOutputDevice - -CompositeOutputDevice + +CompositeOutputDevice CompositeOutputDevice->CompositeDevice - - + + LEDCollection - -LEDCollection + +LEDCollection LEDCollection->CompositeOutputDevice - - + + LEDBoard - -LEDBoard + +LEDBoard LEDBoard->LEDCollection - - + + LEDBarGraph - -LEDBarGraph + +LEDBarGraph LEDBarGraph->LEDCollection - - + + PiLiter - -PiLiter + +PiLiter PiLiter->LEDBoard - - + + PiLiterBarGraph - -PiLiterBarGraph + +PiLiterBarGraph PiLiterBarGraph->LEDBarGraph - - + + TrafficLights - -TrafficLights + +TrafficLights TrafficLights->LEDBoard - - + + + + +SnowPi + +SnowPi + + +SnowPi->LEDBoard + + -PiTraffic - -PiTraffic +PiTraffic + +PiTraffic -PiTraffic->TrafficLights - - +PiTraffic->TrafficLights + + -PiStop - -PiStop +PiStop + +PiStop -PiStop->TrafficLights - - +PiStop->TrafficLights + + -TrafficLightsBuzzer - -TrafficLightsBuzzer +TrafficLightsBuzzer + +TrafficLightsBuzzer -TrafficLightsBuzzer->CompositeOutputDevice - - +TrafficLightsBuzzer->CompositeOutputDevice + + -FishDish - -FishDish +FishDish + +FishDish -FishDish->TrafficLightsBuzzer - - +FishDish->TrafficLightsBuzzer + + -TrafficHat - -TrafficHat +TrafficHat + +TrafficHat -TrafficHat->TrafficLightsBuzzer - - +TrafficHat->TrafficLightsBuzzer + + -Robot - -Robot +Robot + +Robot -Robot->CompositeDevice - - +Robot->CompositeDevice + + -RyanteckRobot - -RyanteckRobot +RyanteckRobot + +RyanteckRobot -RyanteckRobot->Robot - - +RyanteckRobot->Robot + + -CamJamKitRobot - -CamJamKitRobot +CamJamKitRobot + +CamJamKitRobot -CamJamKitRobot->Robot - - +CamJamKitRobot->Robot + + -Motor - -Motor +Motor + +Motor -Motor->CompositeDevice - - +Motor->CompositeDevice + + -Servo - -Servo +Servo + +Servo -Servo->CompositeDevice - - +Servo->CompositeDevice + + -AngularServo - -AngularServo +AngularServo + +AngularServo -AngularServo->Servo - - +AngularServo->Servo + + -Energenie - -Energenie +Energenie + +Energenie -Energenie->Device - - +Energenie->Device + + -ButtonBoard - -ButtonBoard +ButtonBoard + +ButtonBoard -ButtonBoard->CompositeDevice - - +ButtonBoard->CompositeDevice + + diff --git a/docs/images/device_hierarchy.dot b/docs/images/device_hierarchy.dot index 2db340c..a794678 100644 --- a/docs/images/device_hierarchy.dot +++ b/docs/images/device_hierarchy.dot @@ -1,7 +1,7 @@ /* vim: set et sw=4 sts=4: */ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; @@ -60,11 +60,21 @@ digraph classes { SPIDevice->Device; AnalogInputDevice->SPIDevice; MCP3xxx->AnalogInputDevice; + MCP30xx->MCP3xxx; + MCP32xx->MCP3xxx; MCP33xx->MCP3xxx; - MCP3004->MCP3xxx; - MCP3008->MCP3xxx; - MCP3204->MCP3xxx; - MCP3208->MCP3xxx; + MCP3xx2->MCP3xxx; + + MCP3001->MCP30xx; + MCP3002->MCP30xx; + MCP3004->MCP30xx; + MCP3008->MCP30xx; + MCP3201->MCP32xx; + MCP3202->MCP32xx; + MCP3204->MCP32xx; + MCP3208->MCP32xx; + MCP3002->MCP3xx2; + MCP3202->MCP3xx2; MCP3301->MCP33xx; MCP3302->MCP33xx; MCP3304->MCP33xx; @@ -75,10 +85,15 @@ digraph classes { LEDCollection->CompositeOutputDevice; LEDBoard->LEDCollection; LEDBarGraph->LEDCollection; + LedBorg->RGBLED; + ButtonBoard->CompositeDevice; + ButtonBoard->HoldMixin; PiLiter->LEDBoard; PiLiterBarGraph->LEDBarGraph; TrafficLights->LEDBoard; + SnowPi->LEDBoard; PiTraffic->TrafficLights; + PiStop->TrafficLights; TrafficLightsBuzzer->CompositeOutputDevice; FishDish->TrafficLightsBuzzer; TrafficHat->TrafficLightsBuzzer; @@ -90,10 +105,14 @@ digraph classes { CamJamKitRobot->Robot; Motor->CompositeDevice; Motor->SourceMixin; + Servo->CompositeDevice; + Servo->SourceMixin; + AngularServo->Servo; InternalDevice->Device; InternalDevice->EventsMixin; TimeOfDay->InternalDevice; PingServer->InternalDevice; + CPUTemperature->InternalDevice; } diff --git a/docs/images/device_hierarchy.pdf b/docs/images/device_hierarchy.pdf index 6115eb4758a2572e81427e2c5d65f47ee0cee8d7..5aecea98c39aecf474a8bcf04dcfaa784ae584f0 100644 GIT binary patch delta 19590 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 X6r8?z94`b1wBSfV1qEYk6T$xg!0N9< delta 17159 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 MF_)^UtG^o;08+9kdH?_b diff --git a/docs/images/device_hierarchy.png b/docs/images/device_hierarchy.png index c46f5a0891007d9972d9c937561dcc6720fb9af9..42e1073b39c1cfe03d192572991372a78c3b9b19 100644 GIT binary patch literal 252615 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 literal 168277 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 - - - + + classes - + ValuesMixin - -ValuesMixin + +ValuesMixin SourceMixin - -SourceMixin + +SourceMixin SharedMixin - -SharedMixin + +SharedMixin EventsMixin - -EventsMixin + +EventsMixin HoldMixin - -HoldMixin + +HoldMixin Device - -Device + +Device Device->ValuesMixin - - + + GPIODevice - -GPIODevice + +GPIODevice GPIODevice->Device - - + + SmoothedInputDevice - -SmoothedInputDevice + +SmoothedInputDevice SmoothedInputDevice->EventsMixin - - + + InputDevice - -InputDevice + +InputDevice SmoothedInputDevice->InputDevice - - + + AnalogInputDevice - -AnalogInputDevice + +AnalogInputDevice SPIDevice - -SPIDevice + +SPIDevice AnalogInputDevice->SPIDevice - - + + MCP3xxx - -MCP3xxx + +MCP3xxx MCP3xxx->AnalogInputDevice - - + + MCP33xx - -MCP33xx + +MCP33xx -MCP33xx->MCP3xxx - - +MCP33xx->MCP3xxx + + CompositeDevice - -CompositeDevice + +CompositeDevice -CompositeDevice->Device - - +CompositeDevice->Device + + CompositeOutputDevice - -CompositeOutputDevice + +CompositeOutputDevice -CompositeOutputDevice->SourceMixin - - +CompositeOutputDevice->SourceMixin + + -CompositeOutputDevice->CompositeDevice - - +CompositeOutputDevice->CompositeDevice + + LEDCollection - -LEDCollection + +LEDCollection -LEDCollection->CompositeOutputDevice - - +LEDCollection->CompositeOutputDevice + + InternalDevice - -InternalDevice + +InternalDevice -InternalDevice->EventsMixin - - +InternalDevice->EventsMixin + + -InternalDevice->Device - - +InternalDevice->Device + + InputDevice->GPIODevice - - + + DigitalInputDevice - -DigitalInputDevice + +DigitalInputDevice DigitalInputDevice->EventsMixin - - + + DigitalInputDevice->InputDevice - - + + Button - -Button + +Button Button->HoldMixin - - + + Button->DigitalInputDevice - - + + MotionSensor - -MotionSensor + +MotionSensor MotionSensor->SmoothedInputDevice - - + + LightSensor - -LightSensor + +LightSensor LightSensor->SmoothedInputDevice - - + + LineSensor - -LineSensor + +LineSensor LineSensor->SmoothedInputDevice - - + + DistanceSensor - -DistanceSensor + +DistanceSensor DistanceSensor->SmoothedInputDevice - - + + OutputDevice - -OutputDevice + +OutputDevice OutputDevice->SourceMixin - - + + OutputDevice->GPIODevice - - + + DigitalOutputDevice - -DigitalOutputDevice + +DigitalOutputDevice DigitalOutputDevice->OutputDevice - - + + LED - -LED + +LED LED->DigitalOutputDevice - - + + Buzzer - -Buzzer + +Buzzer Buzzer->DigitalOutputDevice - - + + PWMOutputDevice - -PWMOutputDevice + +PWMOutputDevice PWMOutputDevice->OutputDevice - - + + PWMLED - -PWMLED + +PWMLED PWMLED->PWMOutputDevice - - + + RGBLED - -RGBLED + +RGBLED RGBLED->SourceMixin - - + + RGBLED->Device - - + + SPIDevice->Device - - + + + + +MCP30xx + +MCP30xx + + +MCP30xx->MCP3xxx + + + + +MCP32xx + +MCP32xx + + +MCP32xx->MCP3xxx + + + + +MCP3xx2 + +MCP3xx2 + + +MCP3xx2->MCP3xxx + + + + +MCP3001 + +MCP3001 + + +MCP3001->MCP30xx + + + + +MCP3002 + +MCP3002 + + +MCP3002->MCP30xx + + + + +MCP3002->MCP3xx2 + + -MCP3004 - -MCP3004 +MCP3004 + +MCP3004 - -MCP3004->MCP3xxx - - + +MCP3004->MCP30xx + + -MCP3008 - -MCP3008 +MCP3008 + +MCP3008 - -MCP3008->MCP3xxx - - + +MCP3008->MCP30xx + + + + +MCP3201 + +MCP3201 + + +MCP3201->MCP32xx + + + + +MCP3202 + +MCP3202 + + +MCP3202->MCP32xx + + + + +MCP3202->MCP3xx2 + + -MCP3204 - -MCP3204 +MCP3204 + +MCP3204 - -MCP3204->MCP3xxx - - + +MCP3204->MCP32xx + + -MCP3208 - -MCP3208 +MCP3208 + +MCP3208 - -MCP3208->MCP3xxx - - + +MCP3208->MCP32xx + + -MCP3301 - -MCP3301 +MCP3301 + +MCP3301 -MCP3301->MCP33xx - - +MCP3301->MCP33xx + + -MCP3302 - -MCP3302 +MCP3302 + +MCP3302 -MCP3302->MCP33xx - - +MCP3302->MCP33xx + + -MCP3304 - -MCP3304 +MCP3304 + +MCP3304 -MCP3304->MCP33xx - - +MCP3304->MCP33xx + + -LEDBoard - -LEDBoard +LEDBoard + +LEDBoard -LEDBoard->LEDCollection - - +LEDBoard->LEDCollection + + -LEDBarGraph - -LEDBarGraph +LEDBarGraph + +LEDBarGraph -LEDBarGraph->LEDCollection - - +LEDBarGraph->LEDCollection + + + + +LedBorg + +LedBorg + + +LedBorg->RGBLED + + + + +ButtonBoard + +ButtonBoard + + +ButtonBoard->HoldMixin + + + + +ButtonBoard->CompositeDevice + + -PiLiter - -PiLiter +PiLiter + +PiLiter -PiLiter->LEDBoard - - +PiLiter->LEDBoard + + -PiLiterBarGraph - -PiLiterBarGraph +PiLiterBarGraph + +PiLiterBarGraph -PiLiterBarGraph->LEDBarGraph - - +PiLiterBarGraph->LEDBarGraph + + -TrafficLights - -TrafficLights +TrafficLights + +TrafficLights -TrafficLights->LEDBoard - - +TrafficLights->LEDBoard + + + + +SnowPi + +SnowPi + + +SnowPi->LEDBoard + + -PiTraffic - -PiTraffic +PiTraffic + +PiTraffic -PiTraffic->TrafficLights - - +PiTraffic->TrafficLights + + + + +PiStop + +PiStop + + +PiStop->TrafficLights + + -TrafficLightsBuzzer - -TrafficLightsBuzzer +TrafficLightsBuzzer + +TrafficLightsBuzzer -TrafficLightsBuzzer->CompositeOutputDevice - - +TrafficLightsBuzzer->CompositeOutputDevice + + -FishDish - -FishDish +FishDish + +FishDish -FishDish->TrafficLightsBuzzer - - +FishDish->TrafficLightsBuzzer + + -TrafficHat - -TrafficHat +TrafficHat + +TrafficHat -TrafficHat->TrafficLightsBuzzer - - +TrafficHat->TrafficLightsBuzzer + + -Robot - -Robot +Robot + +Robot -Robot->SourceMixin - - +Robot->SourceMixin + + -Robot->CompositeDevice - - +Robot->CompositeDevice + + -Energenie - -Energenie +Energenie + +Energenie -Energenie->SourceMixin - - +Energenie->SourceMixin + + -Energenie->Device - - +Energenie->Device + + -RyanteckRobot - -RyanteckRobot +RyanteckRobot + +RyanteckRobot -RyanteckRobot->Robot - - +RyanteckRobot->Robot + + -CamJamKitRobot - -CamJamKitRobot +CamJamKitRobot + +CamJamKitRobot -CamJamKitRobot->Robot - - +CamJamKitRobot->Robot + + -Motor - -Motor +Motor + +Motor -Motor->SourceMixin - - +Motor->SourceMixin + + -Motor->CompositeDevice - - +Motor->CompositeDevice + + + + +Servo + +Servo + + +Servo->SourceMixin + + + + +Servo->CompositeDevice + + + + +AngularServo + +AngularServo + + +AngularServo->Servo + + -TimeOfDay - -TimeOfDay +TimeOfDay + +TimeOfDay -TimeOfDay->InternalDevice - - +TimeOfDay->InternalDevice + + -PingServer - -PingServer +PingServer + +PingServer -PingServer->InternalDevice - - +PingServer->InternalDevice + + + + +CPUTemperature + +CPUTemperature + + +CPUTemperature->InternalDevice + + diff --git a/docs/images/input_device_hierarchy.dot b/docs/images/input_device_hierarchy.dot index cbf8ea6..80dbdbc 100644 --- a/docs/images/input_device_hierarchy.dot +++ b/docs/images/input_device_hierarchy.dot @@ -1,7 +1,7 @@ /* vim: set et sw=4 sts=4: */ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; diff --git a/docs/images/input_device_hierarchy.pdf b/docs/images/input_device_hierarchy.pdf index 7b2e60bc12e42e4bc67c8eacddd4c34049cf80f9..6e47729eaee749dd23bbbde12485ab638bbdcc56 100644 GIT binary patch delta 1237 zcmZp5KIA;Xw?6E2UbH38-TUhw7{$7X%2(y~@^y*nJ`;T3q}O!CGe+f`&!cmH{>i+u z%6uDhom-hBCvu6)ykd`6^BYh8m&Kwqn~E-Q!+{Qzor7 z*mot!clUMuvj0{6&HoQK%76TyyW>yOT90`4#phFwYz#26y8h;R{h42TFZ$0p%PuGW zBY{`fE!W4i-Q{!p!?$NEZH}{@&2QUW-d#Wadbj!K{KNU5Co|ubjs93&B|>{^Is}Rfb3HvKP)OILN&8?Wwift$jBX`!c3_&hFa-I`Ya(O;qP+K%bLpju*_2;68a}`vtB^(p`tP(msUG8>W%y|)wDe8AR zW=_mx-63WA$#?31<$kS*Y36xrikoFuWz~K zac)CM%;CB`zFFSsKd0W#nQ&s^jGn4TlbW{_MFiv>ICS3X;hxxCe?Q;rUiPggU46n* z3$^lqzKKhlL`nsc6qRZ$%K@`<)MDc83FAx z3S3#YYqF%@H=q6Wm1tJj>kfC$iN=ezE^;iKzU6`d^D3D$Awj%L)r__tnC9WV!Fh#b z&e`0U)oNl(j54_&Ff;t*R1HmOeP-;Hcl@EsmM+CoPmQ08CvCpveS6O|Q(whzm3t%C zg^PDzy1p_fJd>*-|$E#t1qYTw^M!HR{2PbO8b z%gf~QzQU{SmMJ$yi(T~fgq0;bkNG|4=ke9DSfMPw*L`=w_d9;t9}7P?$+;^Y@i_cp zYjg4U%SBr)G$QU~9&lg$Jo8!3m#bec6maX;OuNJ0cs)11ynlM^ly}=YzQ6Gg4*g;t zIeBqMLd4cd!ftsNU+(-Eyk%!pthL5JzL_j)=4W{87v#3GGFDz(P?qF$-1v+0bNR)0 zpLf0Hiu~T*aIMHABEa|LrTgp(IjeQ#18R&tG&S=)0=`dPmQJj$^2t4U!3`V z@*QS5CUeutf0#G0o0^#^7?~Mt-ptY=En#6`Y@lEO0t$HwTwsQQp@D_vTl@$tP>h zJ(K;;|3f(I%Ty07>xFM7&$chkf3NpaXmwuQ_1GBQf3f%U?w#3R`u*im3efIF9*X>uo z&(GI;nzY&VOX|Ok=Vi4YX1Gk?aE#QjToUoy;<#A!Galw-)Az2H8ow3F-()}Wcop$9 zWQN$i#Ekuy1cjO>OH9h;YJS9^^i9{ry0>tzHj|ytCeEqMcy!@O?+&(gVfn?3 ztapo@=l#JXrzHX|sO9~fJ^C%W# zKCZK)N6KP%{Vn~83nr>uyXMAicx*zugWCZ^hM6`W-5)a96}B*N#f9`eII^?i%ErsL zHYGji>p91G{K|o+o_n`Oo%S*9oA5ii^8W@&#^X}am3)gfTdQy=-r8Ca)9B4Jr)8CE zGDpi!@i*ry^%QXbsFI#>lesIkhOH&RHumzirMLgd_I_(zoGHP;KKs05Vtk`R;9(W6l0UOd z9rr8`jM0rZGhZEjI5A#q`2-FtPraN7i!aJzldYz!sct$L8+A}K@r>A+(k<3&vgZGs zxO1)9(#^qJ?6g;WOFeFDE4FD7_qBhkYJ=bXkiBtc*Z$rA8F#s-tez~%BFAKCGTD-4 z1G|Z-v4XL&(dG{<9nuo!mS&a;1|Xo2r@#ef7#JEDSxlawpjK~ShAw4pYHWZmW@u<^ zjv;1jYKSgoW^RFDm6?U15xP2aBV&lY=16WbH!{W0Y++z*g09)Z(9CFZj-oH8p(&TD Js;j>n7Xa?X{8#`0 diff --git a/docs/images/input_device_hierarchy.png b/docs/images/input_device_hierarchy.png index 9ea75698fe4ad3f98b32d86c8c0a9d4ea38ebb63..49910133f9905454f5de2b2ec8b4b6635719ad80 100644 GIT binary patch literal 28276 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 literal 28335 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 S3BFv8MCGOWi(+}xkN*eK2sVcR diff --git a/docs/images/input_device_hierarchy.svg b/docs/images/input_device_hierarchy.svg index 3f41742..7126887 100644 --- a/docs/images/input_device_hierarchy.svg +++ b/docs/images/input_device_hierarchy.svg @@ -1,108 +1,108 @@ - - - + + classes - + Device - -Device + +Device GPIODevice - -GPIODevice + +GPIODevice GPIODevice->Device - - + + SmoothedInputDevice - -SmoothedInputDevice + +SmoothedInputDevice InputDevice - -InputDevice + +InputDevice SmoothedInputDevice->InputDevice - - + + InputDevice->GPIODevice - - + + DigitalInputDevice - -DigitalInputDevice + +DigitalInputDevice DigitalInputDevice->InputDevice - - + + Button - -Button + +Button Button->DigitalInputDevice - - + + MotionSensor - -MotionSensor + +MotionSensor MotionSensor->SmoothedInputDevice - - + + LightSensor - -LightSensor + +LightSensor LightSensor->SmoothedInputDevice - - + + LineSensor - -LineSensor + +LineSensor LineSensor->SmoothedInputDevice - - + + DistanceSensor - -DistanceSensor + +DistanceSensor DistanceSensor->SmoothedInputDevice - - + + diff --git a/docs/images/other_device_hierarchy.dot b/docs/images/other_device_hierarchy.dot index c8654d7..b0e5796 100644 --- a/docs/images/other_device_hierarchy.dot +++ b/docs/images/other_device_hierarchy.dot @@ -1,7 +1,7 @@ /* vim: set et sw=4 sts=4: */ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; @@ -16,4 +16,5 @@ digraph classes { InternalDevice->Device; TimeOfDay->InternalDevice; PingServer->InternalDevice; + CPUTemperature->InternalDevice; } diff --git a/docs/images/other_device_hierarchy.pdf b/docs/images/other_device_hierarchy.pdf index dcfa7dede2edcbe48d4978ba67d470d65ffaa937..d87d5f3cf169dbf8342a132a0954de2113116223 100644 GIT binary patch delta 6451 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 Jvg&eJ{{yedUc3MR delta 5911 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 diff --git a/docs/images/other_device_hierarchy.png b/docs/images/other_device_hierarchy.png index 52da6f1eb9ea1cb66a11ea34256c86b1a2c37bfa..c43215e6c019cc3bbd471521a69b6261a495281c 100644 GIT binary patch literal 11476 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 X_X_D&Mj6n743d>rk}8uh{{BAz14urh literal 9007 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 an(TJ?=~)ZiJ>YN)NI_QhZLze;m;V8NWT;&L diff --git a/docs/images/other_device_hierarchy.svg b/docs/images/other_device_hierarchy.svg index 275484c..1063e8c 100644 --- a/docs/images/other_device_hierarchy.svg +++ b/docs/images/other_device_hierarchy.svg @@ -1,48 +1,58 @@ - - - + + classes - + Device - -Device + +Device InternalDevice - -InternalDevice + +InternalDevice InternalDevice->Device - - + + TimeOfDay - -TimeOfDay + +TimeOfDay TimeOfDay->InternalDevice - - + + PingServer - -PingServer + +PingServer PingServer->InternalDevice - - + + + + +CPUTemperature + +CPUTemperature + + +CPUTemperature->InternalDevice + + diff --git a/docs/images/output_device_hierarchy.dot b/docs/images/output_device_hierarchy.dot index 6a92a52..a678408 100644 --- a/docs/images/output_device_hierarchy.dot +++ b/docs/images/output_device_hierarchy.dot @@ -1,7 +1,7 @@ /* vim: set et sw=4 sts=4: */ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; diff --git a/docs/images/output_device_hierarchy.pdf b/docs/images/output_device_hierarchy.pdf index b7ffe954af8490ca234b62f9bb51599bc5451f79..03741082dc1b19a25db72e6c1714e9785af917b1 100644 GIT binary patch delta 6664 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

  • NajZwp&PZg;14428fZMt7!2|qSvUds=CSDq8KR>|97GzX{L1@(-v?-J>| z2*ZuRr2w_p=fdFUp!1@!q1k_lX4}KJ(_-8b8Os$K-wj$6rskwvYHy}YTeVRST&+5P zO9v*sI^4}3plL$SxX5uykuSxsEe-DT@8psnN&f`UZvS&Np*aeC*)5&!)lOb=4X2i{ zl+@6;4N$5ePz$=qOcryA4JhmQ=gO8U(W(XnzhO!D$!ZW7v@gJS<*?zkm|~)NAkes^ z8Bo4qHl&qkB%8I2I3FNnze>l^vb-_FWQmMdVVX+CnRN$HH3g$t&*RLsN5#SKRO4z2 z(nWe?q(<0MYdaQLI85*%ZsFL&Zu6&Av;qkl(#%%0w zS{z=8lZ9|xG{dAZE-1-fs;GI;E|N7ZcwSg9tRzFsl23s5(Rk1Ju@)qoXYuD>VH>-f znfu@4c#bY4yd|VbW`aSwc}G8Zq7eIF0GQ*Vh3eUtC&W0}jwuB3b3+#~qIj_gkS;l; z(X(2~rj$2fD(E7Vex_9pV!a4wd@hGsC_Q({9 zLO~pD8`XWGrS#xHfUgo%M~$zv%G0Eckctgdz0e~&^=D$eO+#=%B@yYgr?;CEjMo#u zPE~{|z*l8;>*oo;Vs#I|v$rWk_EJVnS*a>3>5|^Li}rnq{sN6f>eckCUmtPd$}#B- z)26MkRLwSXEag!tOd4al-9p%1WyE!9XL;7i?kM#vgu!Kj^y1jjVs4|KpyY_*pFUu!v~VMoaQYfz47~H0Fd3@N zpN@Rth@2x3f6P0X=+T(rB9tdpwag_R3Y0RtAK@=LYDYhGb?DlNKbG)jb7paZs!)jH zdBfPT0NbjdBu)|*PzL%CbCG6=fmMPWzW2G3fRaHe=2|+rSsZt)_Ou}(({JV8{HDJt zmC)bZ+NB_u9JySwc^%!qr5~s_WxvQPe-AY||2evf2{4LCU#PV;dL;uqyW*Vld>jWO z3)?12Lux2!k@#9BDddoGL4vd(ArW3$5J*S}LIspV`5$eu2I?cD@N0q5tB9 xL_`GslN09W<@;Yx`2Xu9%+L2lGjwg{yzb4*JA(x diff --git a/docs/images/output_device_hierarchy.png b/docs/images/output_device_hierarchy.png index 7afa368b55b747b95a56a1f1fa8e544479e20b46..28699f16b8043f05f868cb34e5ce245e8984e57e 100644 GIT binary patch literal 21826 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
    )22c;Xs?#mmX!^t4RddUE$~eR%lHc1jr{rx676 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 O8FE+4KobSGef2*9ll3wH diff --git a/docs/images/output_device_hierarchy.svg b/docs/images/output_device_hierarchy.svg index 4f1cad2..f896bb9 100644 --- a/docs/images/output_device_hierarchy.svg +++ b/docs/images/output_device_hierarchy.svg @@ -1,108 +1,108 @@ - - - + + classes - + Device - -Device + +Device GPIODevice - -GPIODevice + +GPIODevice GPIODevice->Device - - + + OutputDevice - -OutputDevice + +OutputDevice OutputDevice->GPIODevice - - + + DigitalOutputDevice - -DigitalOutputDevice + +DigitalOutputDevice DigitalOutputDevice->OutputDevice - - + + LED - -LED + +LED LED->DigitalOutputDevice - - + + Buzzer - -Buzzer + +Buzzer Buzzer->DigitalOutputDevice - - + + PWMOutputDevice - -PWMOutputDevice + +PWMOutputDevice PWMOutputDevice->OutputDevice - - + + PWMLED - -PWMLED + +PWMLED PWMLED->PWMOutputDevice - - + + RGBLED - -RGBLED + +RGBLED RGBLED->Device - - + + LedBorg - -LedBorg + +LedBorg LedBorg->RGBLED - - + + diff --git a/docs/images/spi_device_hierarchy.dot b/docs/images/spi_device_hierarchy.dot index a205b03..80c0e0b 100644 --- a/docs/images/spi_device_hierarchy.dot +++ b/docs/images/spi_device_hierarchy.dot @@ -1,5 +1,5 @@ digraph classes { - graph [rankdir=BT]; + graph [rankdir=RL]; node [shape=rect, style=filled, fontname=Sans, fontsize=10]; edge []; diff --git a/docs/images/spi_device_hierarchy.pdf b/docs/images/spi_device_hierarchy.pdf index 65ba0cd34c218cd71ed78c0a7258defd6d8c5f31..214894282aed4a49fdb0af04443c2ac94cd18891 100644 GIT binary patch delta 1742 zcmZY3X*Ao38V2yH*dn%RGHN;^25nPYB8mK?#!|#mYU#vUlyS9Jq{|3e8X?wNZV9!7 zjM7$X8x$#{D6K6jC8#AS9aKe`=xACo$~|*G-J|cP_xzscyyq1=^IURW>Gj2Km%qnD z(!`sFRH~}CK6BgR6~$BECb4CvG|w(~_EK{6Y*p~ClvXXBX8V!x$w#{5^(kZ*X)g0Ad;xV0Kv^>mi7nkL9*%#$BBORRK)=LGcwUZ@d2gb(3U(p@>VmmFZA@5rYy`R4ewpt;}< za(3}+TCC*tYwPZWC-F^xPtdvrE#rLg@u0c9%|c%wwZCw#lZKlowN4luR>st2UdN&X zG+k&jrLpO)RWlYzl4%*TWv}+LTAt2828x64re+P{1!d-q8+4PP6wk~Yw1rN2`qg;J z$UC*a=ix!L-7n&9`4i&Uh6}!yZDE@7CUD0;)Om?xS_OQnuTFn#YccVd`LI;*29-E5 zYFsqkn49w(R`%_u)se@Sr6Q3iMKP*zC?~IX&QE6rqQU-y>3S>--&Na(wb1b6%@gf) zn1lAQHx-%v^kpL?QLpE5Mw{l;4G9F67e-RF7uno_N5B2faKYApgBqFqbo^%BQY4`8 z-fYmhvE-3-%d)d9lIsLdiso`nVW;P6%Z*QarCMfx;s6xq2?oA1g?Bo5dGLlw=gm^&IVgMvJGsYu%DH@OLS+k ztj`j=8M40Jsig>kYvY}!aif#wnZz66b5!9EgZU=xAETNQB zTiS|VkACtp07gSOy=Lm?Sd?QcLk)T>8g42KVdgWNS9+(L3Zn;S2Us(#2Q@2xciiRX zZ$;7*C(;gdS7o0)a$*kr(40>|lG$(7!$_+69}VQ!qe$_bAiu)wYw5m2Q`pkM?96qoAD$1TvqDbr<8Mp}GP>-dKy>)3 zmPy^E->=gB8^GQt*W9BVnh732o?LPwfj%#40X?>z zoN|B48Dys6S#Ij4RUzk=E+{IExtLuM-jBA+*%^l5OqU^YgW(Wd$hQzR@6t{C_*NXm zR1#tGSSyXIcH!X;18d>S_H+i(eNOUky0!w@RTasBym{`uPl4p(bE_S{=C39x!7M^6 zFTX4C;9-t-_F?^d8AAXab7;NNTlDXatV-oLZb4C;gV~hfPC}K>#ip)P4K4j667YQK z``dFP-^Stmw2?K>^%_Ki>kXoH@ie)!FQmoji8*h66$dtiG25zhskU@oWQqe!pNbkF z<%SlMY#IE(I!1~Yww3`3Wc%2{1-~A8l|+-SQ3HeT*U6w*YsL7 z2{Hx4T+YbZX38R6nP2Op0?pGse~5KXoF##(`@X5~@Wefh!H%9AyGj_}Sv8U{)7?WW z@8(L{7XCtD6W QS1=mDf(;BD+=<}-0&$EP8UO$Q delta 1666 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 diff --git a/docs/images/spi_device_hierarchy.svg b/docs/images/spi_device_hierarchy.svg index b801f8e..fcf33a6 100644 --- a/docs/images/spi_device_hierarchy.svg +++ b/docs/images/spi_device_hierarchy.svg @@ -4,205 +4,205 @@ - - + + classes - + Device - -Device + +Device SPIDevice - -SPIDevice + +SPIDevice SPIDevice->Device - - + + AnalogInputDevice - -AnalogInputDevice + +AnalogInputDevice AnalogInputDevice->SPIDevice - - + + MCP3xxx - -MCP3xxx + +MCP3xxx MCP3xxx->AnalogInputDevice - - + + MCP30xx - -MCP30xx + +MCP30xx MCP30xx->MCP3xxx - - + + MCP32xx - -MCP32xx + +MCP32xx MCP32xx->MCP3xxx - - + + MCP3xx2 - -MCP3xx2 + +MCP3xx2 MCP3xx2->MCP3xxx - - + + MCP33xx - -MCP33xx + +MCP33xx MCP33xx->MCP3xxx - - + + MCP3001 - -MCP3001 + +MCP3001 MCP3001->MCP30xx - - + + MCP3002 - -MCP3002 + +MCP3002 MCP3002->MCP30xx - - + + MCP3002->MCP3xx2 - - + + MCP3004 - -MCP3004 + +MCP3004 MCP3004->MCP30xx - - + + MCP3008 - -MCP3008 + +MCP3008 MCP3008->MCP30xx - - + + MCP3201 - -MCP3201 + +MCP3201 MCP3201->MCP32xx - - + + MCP3202 - -MCP3202 + +MCP3202 MCP3202->MCP32xx - - + + MCP3202->MCP3xx2 - - + + MCP3204 - -MCP3204 + +MCP3204 MCP3204->MCP32xx - - + + MCP3208 - -MCP3208 + +MCP3208 MCP3208->MCP32xx - - + + MCP3301 - -MCP3301 + +MCP3301 MCP3301->MCP33xx - - + + MCP3302 - -MCP3302 + +MCP3302 MCP3302->MCP33xx - - + + MCP3304 - -MCP3304 + +MCP3304 MCP3304->MCP33xx - - + + From f8f810a91218945ef4c30231e91bfc5e10a330bb Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 22 Jun 2017 10:56:29 +0100 Subject: [PATCH 61/62] Add a little script to generate class graphs Heavily based on @lurch's efforts in #469 but with some additional filtering capabilities. --- docs/images/class_graph | 173 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100755 docs/images/class_graph diff --git a/docs/images/class_graph b/docs/images/class_graph new file mode 100755 index 0000000..6780167 --- /dev/null +++ b/docs/images/class_graph @@ -0,0 +1,173 @@ +#!/usr/bin/python3 + +import re +import sys +import argparse +from pathlib import Path + + +ABSTRACT_CLASSES = { + 'Device', + 'GPIODevice', + 'SmoothedInputDevice', + 'AnalogInputDevice', + 'MCP3xxx', + 'MCP33xx', + 'CompositeDevice', + 'CompositeOutputDevice', + 'LEDCollection', + 'InternalDevice', +} + +OMIT_CLASSES = { + 'object', + 'GPIOBase', + 'GPIOMeta', + 'frozendict', + 'WeakMethod', + '_EnergenieMaster', +} + + +def main(args=None): + """ + A simple application for generating GPIO Zero's charts. Specify the root + class to generate with -i (multiple roots can be specified). Specify parts + of the hierarchy to exclude with -x. Output is in a format suitable for + feeding to graphviz's dot application. + """ + if args is None: + args = sys.argv[1:] + my_path = Path(__file__).parent + # XXX make this relative to repo root rather than this script + default_path = my_path / '..' / '..' / 'gpiozero' + default_path = default_path.resolve() + parser = argparse.ArgumentParser(description=main.__doc__) + parser.add_argument('-p', '--path', action='append', metavar='PATH', + default=[], help= + "search under PATH for Python source files; can be " + "specified multiple times, defaults to %s" % default_path) + parser.add_argument('-i', '--include', action='append', metavar='BASE', + default=[], help= + "only include classes which have BASE somewhere in " + "their ancestry; can be specified multiple times") + parser.add_argument('-x', '--exclude', action='append', metavar='BASE', + default=[], help= + "exclude any classes which have BASE somewhere in " + "their ancestry; can be specified multiple times") + parser.add_argument('output', nargs='?', type=argparse.FileType('w'), + default=sys.stdout, help= + "the file to write the output to; defaults to stdout") + args = parser.parse_args(args) + if not args.path: + args.path = [str(default_path)] + + m = make_class_map(args.path, OMIT_CLASSES) + if args.include or args.exclude: + m = filter_map(m, include_roots=set(args.include), exclude_roots=set(args.exclude)) + args.output.write(render_map(m, ABSTRACT_CLASSES)) + + +def make_class_map(search_paths, omit): + """ + Find all Python source files under *search_paths*, extract (via a crude + regex) all class definitions and return a mapping of class-name to the list + of base classes. + + All classes listed in *omit* will be excluded from the result, but not + their descendents (useful for excluding "object" etc.) + """ + def find_classes(): + class_re = re.compile(r'^class (?P\w+)(?:\((?P.*)\))?:', re.MULTILINE) + for path in search_paths: + for py_file in Path(path).rglob('*.py'): + with py_file.open() as f: + for match in class_re.finditer(f.read()): + if match.group('name') not in omit: + yield match.group('name'), [ + base.strip() + for base in (match.group('bases') or '').split(',') + if base.strip() not in omit + ] + return { + name: bases + for name, bases in find_classes() + } + + +def filter_map(class_map, include_roots, exclude_roots): + """ + Returns *class_map* (which is a mapping such as that returned by + :func:`make_class_map`), with only those classes which have at least one + of the *include_roots* in their ancestry, and none of the *exclude_roots*. + """ + def has_parent(cls, parent): + return cls == parent or any( + has_parent(base, parent) for base in class_map.get(cls, ())) + + return { + name: bases + for name, bases in class_map.items() + if (not include_roots or any(has_parent(name, root) for root in include_roots)) + and not any(has_parent(name, root) for root in exclude_roots) + } + + +def render_map(class_map, abstract): + """ + Renders *class_map* (which is a mapping such as that returned by + :func:`make_class_map`) to graphviz's dot language. + + The *abstract* sequence determines which classes will be rendered lighter + to indicate their abstract nature. All classes with names ending "Mixin" + will be implicitly rendered in a different style. + """ + def all_names(class_map): + for name, bases in class_map.items(): + yield name + for base in bases: + yield base + + template = """\ +digraph classes {{ + graph [rankdir=RL]; + node [shape=rect, style=filled, fontname=Sans, fontsize=10]; + edge []; + + /* Mixin classes */ + node [color="#c69ee0", fontcolor="#000000"] + + {mixin_nodes} + + /* Abstract classes */ + node [color="#9ec6e0", fontcolor="#000000"] + + {abstract_nodes} + + /* Concrete classes */ + node [color="#2980b9", fontcolor="#ffffff"]; + + {edges} +}} +""" + + return template.format( + mixin_nodes='\n '.join( + '{name};'.format(name=name) + for name in set(all_names(class_map)) + if name.endswith('Mixin') + ), + abstract_nodes='\n '.join( + '{name};'.format(name=name) + for name in abstract & set(all_names(class_map)) + ), + edges='\n '.join( + '{name}->{base};'.format(name=name, base=base) + for name, bases in class_map.items() + for base in bases + ), + ) + + +if __name__ == '__main__': + main() From a99e0746c3e9ce80cd6bb310da10b7b67c5f30ce Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 22 Jun 2017 22:45:00 +0100 Subject: [PATCH 62/62] Fix #279 Permit replacement of pin_factory without closing old factory. However, continue closing devices associated with extant pin factory at script termination. --- docs/api_pins.rst | 17 ++- gpiozero/devices.py | 49 ++++---- gpiozero/exc.py | 3 - gpiozero/pins/__init__.py | 3 + gpiozero/pins/data.py | 2 +- gpiozero/pins/mock.py | 8 +- gpiozero/spi_devices.py | 2 +- tests/test_boards.py | 234 +++++++++++++++++++------------------- tests/test_devices.py | 8 +- tests/test_inputs.py | 36 +++--- tests/test_mock_pin.py | 56 ++++----- tests/test_outputs.py | 168 +++++++++++++-------------- tests/test_pins_data.py | 12 +- tests/test_real_pins.py | 8 +- tests/test_spi.py | 58 +++++----- tests/test_spi_devices.py | 2 +- 16 files changed, 328 insertions(+), 338 deletions(-) diff --git a/docs/api_pins.rst b/docs/api_pins.rst index b052010..6a34a72 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -13,7 +13,7 @@ extender chips. This is the purpose of the pins portion of the library. When you construct a device, you pass in a pin specification. However, what the library actually expects is a :class:`Pin` implementation. If it finds anything -else, it uses the existing ``Device._pin_factory`` to construct a :class:`Pin` +else, it uses the existing ``Device.pin_factory`` to construct a :class:`Pin` implementation based on the specification. Changing the pin factory @@ -29,7 +29,7 @@ The default pin factory can be replaced by specifying a value for the [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gpiozero - >>> gpiozero.Device._pin_factory + >>> gpiozero.Device.pin_factory To set the ``GPIOZERO_PIN_FACTORY`` for the rest of your session you can @@ -43,7 +43,7 @@ export this value: [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gpiozero - >>> gpiozero.Device._pin_factory + >>> gpiozero.Device.pin_factory >>> quit() pi@raspberrypi $ python @@ -51,7 +51,7 @@ export this value: [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import gpiozero - >>> gpiozero.Device._pin_factory + >>> gpiozero.Device.pin_factory If you add the ``export`` command to your :file:`~/.bashrc` file, you'll set @@ -73,15 +73,12 @@ they are tried by default. | native | :class:`gpiozero.pins.native.NativeFactory` | :class:`gpiozero.pins.native.NativePin` | +---------+-----------------------------------------------+-------------------------------------------+ -If you need to change the default pin factory from within a script, use the -``Device._set_pin_factory`` class method, passing in the instance of the new -factory to use. This is only supported at script startup (replacing the factory -closes all existing pin instances which can have interesting consequences for -any devices using them):: +If you need to change the default pin factory from within a script, set +``Device.pin_factory`` to the new factory instance to use:: from gpiozero.pins.native import NativeFactory from gpiozero import * - Device._set_pin_factory(NativeFactory()) + Device.pin_factory = NativeFactory() from gpiozero import LED diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 4b282d0..e993b0d 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -34,7 +34,6 @@ from .exc import ( GPIOPinInUse, GPIODeviceClosed, PinFactoryFallback, - PinReservationsExist, ) from .compat import frozendict @@ -194,33 +193,13 @@ class Device(ValuesMixin, GPIOBase): services applicable to all devices (specifically the :attr:`is_active` property, the :attr:`value` property, and the :meth:`close` method). """ - _pin_factory = None # instance of a Factory sub-class + pin_factory = None # instance of a Factory sub-class _reservations = defaultdict(list) # maps pin addresses to lists of devices _res_lock = Lock() def __repr__(self): return "" % (self.__class__.__name__) - @classmethod - def _set_pin_factory(cls, new_factory): - reserved_devices = { - dev - for ref_list in cls._reservations.values() - for ref in ref_list - for dev in (ref(),) - if dev is not None - } - if new_factory is None: - for dev in reserved_devices: - dev.close() - elif reserved_devices: - raise PinReservationsExist( - "can't change factory while devices still hold pin " - "reservations (%r)" % dev) - if cls._pin_factory is not None: - cls._pin_factory.close() - cls._pin_factory = new_factory - def _reserve_pins(self, *pins_or_addresses): """ Called to indicate that the device reserves the right to use the @@ -439,8 +418,8 @@ class GPIODevice(Device): self._reserve_pins(pin) else: # Check you can reserve *before* constructing the pin - self._reserve_pins(Device._pin_factory.pin_address(pin)) - pin = Device._pin_factory.pin(pin) + self._reserve_pins(Device.pin_factory.pin_address(pin)) + pin = Device.pin_factory.pin(pin) self._pin = pin self._active_state = True self._inactive_state = False @@ -524,11 +503,27 @@ def _default_pin_factory(name=os.getenv('GPIOZERO_PIN_FACTORY', None)): return factory.load()() raise BadPinFactory('Unable to find pin factory "%s"' % name) -Device._set_pin_factory(_default_pin_factory()) + +def _devices_shutdown(): + if Device.pin_factory: + with Device._res_lock: + reserved_devices = { + dev + for ref_list in Device._reservations.values() + for ref in ref_list + for dev in (ref(),) + if dev is not None + } + for dev in reserved_devices: + dev.close() + Device.pin_factory.close() + Device.pin_factory = None + def _shutdown(): _threads_shutdown() - Device._set_pin_factory(None) + _devices_shutdown() + +Device.pin_factory = _default_pin_factory() atexit.register(_shutdown) - diff --git a/gpiozero/exc.py b/gpiozero/exc.py index 1a3182d..416f1a6 100644 --- a/gpiozero/exc.py +++ b/gpiozero/exc.py @@ -145,9 +145,6 @@ class PinNoPins(PinError, RuntimeError): class PinInvalidPin(PinError, ValueError): "Error raised when an invalid pin specification is provided" -class PinReservationsExist(PinError, RuntimeError): - "Error raised when pin factory is changed while reservations still exist" - class GPIOZeroWarning(Warning): "Base class for all warnings in GPIO Zero" diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index df30f61..60d325c 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -562,8 +562,11 @@ class SPI(object): | mode | polarity (CPOL) | phase (CPHA) | +======+=================+==============+ | 0 | False | False | + +------+-----------------+--------------+ | 1 | False | True | + +------+-----------------+--------------+ | 2 | True | False | + +------+-----------------+--------------+ | 3 | True | True | +------+-----------------+--------------+ diff --git a/gpiozero/pins/data.py b/gpiozero/pins/data.py index 4dbbda3..54fa7fa 100644 --- a/gpiozero/pins/data.py +++ b/gpiozero/pins/data.py @@ -1140,7 +1140,7 @@ def pi_info(revision=None): # The reason this import is located here is to avoid a circular # dependency; devices->pins.local->pins.data->devices from ..devices import Device - result = Device._pin_factory.pi_info + result = Device.pin_factory.pi_info if result is None: raise PinUnknownPi('The default pin_factory is not attached to a Pi') else: diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 7af2658..4d974c3 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -312,10 +312,10 @@ class MockSPIDevice(object): self, clock_pin, mosi_pin=None, miso_pin=None, select_pin=None, clock_polarity=False, clock_phase=False, lsb_first=False, bits_per_word=8, select_high=False): - self.clock_pin = Device._pin_factory.pin(clock_pin, pin_class=MockSPIClockPin) - self.mosi_pin = None if mosi_pin is None else Device._pin_factory.pin(mosi_pin) - self.miso_pin = None if miso_pin is None else Device._pin_factory.pin(miso_pin) - self.select_pin = None if select_pin is None else Device._pin_factory.pin(select_pin, pin_class=MockSPISelectPin) + self.clock_pin = Device.pin_factory.pin(clock_pin, pin_class=MockSPIClockPin) + self.mosi_pin = None if mosi_pin is None else Device.pin_factory.pin(mosi_pin) + self.miso_pin = None if miso_pin is None else Device.pin_factory.pin(miso_pin) + self.select_pin = None if select_pin is None else Device.pin_factory.pin(select_pin, pin_class=MockSPISelectPin) self.clock_polarity = clock_polarity self.clock_phase = clock_phase self.lsb_first = lsb_first diff --git a/gpiozero/spi_devices.py b/gpiozero/spi_devices.py index 0a30de1..621828a 100644 --- a/gpiozero/spi_devices.py +++ b/gpiozero/spi_devices.py @@ -29,7 +29,7 @@ class SPIDevice(Device): def __init__(self, **spi_args): self._spi = None super(SPIDevice, self).__init__() - self._spi = self._pin_factory.spi(**spi_args) + self._spi = self.pin_factory.spi(**spi_args) def close(self): if self._spi: diff --git a/tests/test_boards.py b/tests/test_boards.py index 36e3277..1ba4879 100644 --- a/tests/test_boards.py +++ b/tests/test_boards.py @@ -17,7 +17,7 @@ from gpiozero.pins.mock import MockPWMPin, MockPin def setup_function(function): # dirty, but it does the job - Device._pin_factory.pin_class = MockPWMPin if function.__name__ in ( + Device.pin_factory.pin_class = MockPWMPin if function.__name__ in ( 'test_robot', 'test_ryanteck_robot', 'test_camjam_kit_robot', @@ -33,18 +33,18 @@ def setup_function(function): ) else MockPin def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() Device._reservations.clear() def teardown_module(module): # make sure we reset the default - Device._pin_factory.pwm = False + Device.pin_factory.pwm = False def test_composite_output_on_off(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: device.on() assert all((pin1.state, pin2.state, pin3.state)) @@ -52,9 +52,9 @@ def test_composite_output_on_off(): assert not any((pin1.state, pin2.state, pin3.state)) def test_composite_output_toggle(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: device.toggle() assert all((pin1.state, pin2.state, pin3.state)) @@ -65,9 +65,9 @@ def test_composite_output_toggle(): assert not pin3.state def test_composite_output_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device: assert device.value == (0, 0, 0) device.toggle() @@ -78,9 +78,9 @@ def test_composite_output_value(): assert device[2].is_active def test_led_board_on_off(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3) as board: assert isinstance(board[0], LED) assert isinstance(board[1], LED) @@ -135,9 +135,9 @@ def test_led_board_on_off(): assert pin3.state def test_led_board_active_low(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, active_high=False) as board: assert not board.active_high assert not board[0].active_high @@ -159,9 +159,9 @@ def test_led_board_active_low(): assert not pin3.state def test_led_board_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) @@ -170,9 +170,9 @@ def test_led_board_value(): assert board.value == (1, 0, 1) def test_led_board_pwm_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: assert board.value == (0, 0, 0) board.value = (0, 1, 0) @@ -181,9 +181,9 @@ def test_led_board_pwm_value(): assert board.value == (0.5, 0, 0.75) def test_led_board_pwm_bad_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True) as board: with pytest.raises(ValueError): board.value = (-1, 0, 0) @@ -191,18 +191,18 @@ def test_led_board_pwm_bad_value(): board.value = (0, 2, 0) def test_led_board_initial_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, initial_value=0) as board: assert board.value == (0, 0, 0) with LEDBoard(pin1, pin2, foo=pin3, initial_value=1) as board: assert board.value == (1, 1, 1) def test_led_board_pwm_initial_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=0) as board: assert board.value == (0, 0, 0) with LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=1) as board: @@ -211,18 +211,18 @@ def test_led_board_pwm_initial_value(): assert board.value == (0.5, 0.5, 0.5) def test_led_board_pwm_bad_initial_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with pytest.raises(ValueError): LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=-1) with pytest.raises(ValueError): LEDBoard(pin1, pin2, foo=pin3, pwm=True, initial_value=2) def test_led_board_nested(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: assert list(led.pin for led in board.leds) == [pin1, pin2, pin3] assert board.value == (0, (0, 0)) @@ -232,9 +232,9 @@ def test_led_board_nested(): assert pin3.state def test_led_board_bad_blink(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: with pytest.raises(ValueError): board.blink(fade_in_time=1, fade_out_time=1) @@ -246,9 +246,9 @@ def test_led_board_bad_blink(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_background(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: # Instantiation takes a long enough time that it throws off our timing # here! @@ -271,9 +271,9 @@ def test_led_board_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_foreground(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: pin1.clear_states() pin2.clear_states() @@ -293,9 +293,9 @@ def test_led_board_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: pin1.clear_states() pin2.clear_states() @@ -321,9 +321,9 @@ def test_led_board_blink_control(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_take_over(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: pin1.clear_states() pin2.clear_states() @@ -346,9 +346,9 @@ def test_led_board_blink_take_over(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_blink_control_all(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: pin1.clear_states() pin2.clear_states() @@ -371,9 +371,9 @@ def test_led_board_blink_control_all(): pin3.assert_states_and_times(test) def test_led_board_blink_interrupt_on(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: board.blink(1, 0.1) sleep(0.2) @@ -383,9 +383,9 @@ def test_led_board_blink_interrupt_on(): pin3.assert_states([False, True, False]) def test_led_board_blink_interrupt_off(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board: pin1.clear_states() pin2.clear_states() @@ -400,9 +400,9 @@ def test_led_board_blink_interrupt_off(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_led_board_fade_background(): - pin1 = Device._pin_factory.pin(4) - pin2 = Device._pin_factory.pin(5) - pin3 = Device._pin_factory.pin(6) + pin1 = Device.pin_factory.pin(4) + pin2 = Device.pin_factory.pin(5) + pin3 = Device.pin_factory.pin(6) with LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) as board: pin1.clear_states() pin2.clear_states() @@ -437,9 +437,9 @@ def test_led_board_fade_background(): pin3.assert_states_and_times(test) def test_led_bar_graph_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3) as graph: assert isinstance(graph[0], LED) assert isinstance(graph[1], LED) @@ -470,9 +470,9 @@ def test_led_bar_graph_value(): assert graph.value == -2/3 def test_led_bar_graph_active_low(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, active_high=False) as graph: assert not graph.active_high assert not graph[0].active_high @@ -492,9 +492,9 @@ def test_led_bar_graph_active_low(): assert not pin3.state and pin1.state and pin2.state def test_led_bar_graph_pwm_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, pwm=True) as graph: assert isinstance(graph[0], PWMLED) assert isinstance(graph[1], PWMLED) @@ -519,9 +519,9 @@ def test_led_bar_graph_pwm_value(): assert graph.value == -1/2 def test_led_bar_graph_bad_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3) as graph: with pytest.raises(ValueError): graph.value = -2 @@ -529,9 +529,9 @@ def test_led_bar_graph_bad_value(): graph.value = 2 def test_led_bar_graph_bad_init(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with pytest.raises(TypeError): LEDBarGraph(pin1, pin2, foo=pin3) with pytest.raises(ValueError): @@ -540,9 +540,9 @@ def test_led_bar_graph_bad_init(): LEDBarGraph(pin1, pin2, pin3, initial_value=2) def test_led_bar_graph_initial_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, initial_value=1/3) as graph: assert graph.value == 1/3 assert pin1.state and not (pin2.state or pin3.state) @@ -551,9 +551,9 @@ def test_led_bar_graph_initial_value(): assert pin3.state and not (pin1.state or pin2.state) def test_led_bar_graph_pwm_initial_value(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(3) - pin3 = Device._pin_factory.pin(4) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(3) + pin3 = Device.pin_factory.pin(4) with LEDBarGraph(pin1, pin2, pin3, pwm=True, initial_value=0.5) as graph: assert graph.value == 0.5 assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0) @@ -562,17 +562,17 @@ def test_led_bar_graph_pwm_initial_value(): assert (pin1.state, pin2.state, pin3.state) == (0, 0.5, 1) def test_led_borg(): - pins = [Device._pin_factory.pin(n) for n in (17, 27, 22)] + pins = [Device.pin_factory.pin(n) for n in (17, 27, 22)] with LedBorg() as board: assert [device.pin for device in board._leds] == pins def test_pi_liter(): - pins = [Device._pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] + pins = [Device.pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] with PiLiter() as board: assert [device.pin for device in board] == pins def test_pi_liter_graph(): - pins = [Device._pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] + pins = [Device.pin_factory.pin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] with PiLiterBarGraph() as board: board.value = 0.5 assert [pin.state for pin in pins] == [1, 1, 1, 1, 0, 0, 0, 0] @@ -580,9 +580,9 @@ def test_pi_liter_graph(): assert board.value == 5/8 def test_traffic_lights(): - red_pin = Device._pin_factory.pin(2) - amber_pin = Device._pin_factory.pin(3) - green_pin = Device._pin_factory.pin(4) + red_pin = Device.pin_factory.pin(2) + amber_pin = Device.pin_factory.pin(3) + green_pin = Device.pin_factory.pin(4) with TrafficLights(red_pin, amber_pin, green_pin) as board: board.red.on() assert board.red.value @@ -611,15 +611,15 @@ def test_traffic_lights(): def test_traffic_lights_bad_init(): with pytest.raises(ValueError): TrafficLights() - red_pin = Device._pin_factory.pin(2) - amber_pin = Device._pin_factory.pin(3) - green_pin = Device._pin_factory.pin(4) - yellow_pin = Device._pin_factory.pin(5) + red_pin = Device.pin_factory.pin(2) + amber_pin = Device.pin_factory.pin(3) + green_pin = Device.pin_factory.pin(4) + yellow_pin = Device.pin_factory.pin(5) with pytest.raises(ValueError): TrafficLights(red=red_pin, amber=amber_pin, yellow=yellow_pin, green=green_pin) def test_pi_traffic(): - pins = [Device._pin_factory.pin(n) for n in (9, 10, 11)] + pins = [Device.pin_factory.pin(n) for n in (9, 10, 11)] with PiTraffic() as board: assert [device.pin for device in board] == pins @@ -628,27 +628,27 @@ def test_pi_stop(): PiStop() with pytest.raises(ValueError): PiStop('E') - pins_a = [Device._pin_factory.pin(n) for n in (7, 8, 25)] + pins_a = [Device.pin_factory.pin(n) for n in (7, 8, 25)] with PiStop('A') as board: assert [device.pin for device in board] == pins_a - pins_aplus = [Device._pin_factory.pin(n) for n in (21, 20, 16)] + pins_aplus = [Device.pin_factory.pin(n) for n in (21, 20, 16)] with PiStop('A+') as board: assert [device.pin for device in board] == pins_aplus - pins_b = [Device._pin_factory.pin(n) for n in (10, 9, 11)] + pins_b = [Device.pin_factory.pin(n) for n in (10, 9, 11)] with PiStop('B') as board: assert [device.pin for device in board] == pins_b - pins_bplus = [Device._pin_factory.pin(n) for n in (13, 19, 26)] + pins_bplus = [Device.pin_factory.pin(n) for n in (13, 19, 26)] with PiStop('B+') as board: assert [device.pin for device in board] == pins_bplus - pins_c = [Device._pin_factory.pin(n) for n in (18, 15, 14)] + pins_c = [Device.pin_factory.pin(n) for n in (18, 15, 14)] with PiStop('C') as board: assert [device.pin for device in board] == pins_c - pins_d = [Device._pin_factory.pin(n) for n in (2, 3, 4)] + pins_d = [Device.pin_factory.pin(n) for n in (2, 3, 4)] with PiStop('D') as board: assert [device.pin for device in board] == pins_d def test_snow_pi(): - pins = [Device._pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] + pins = [Device.pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] with SnowPi() as board: assert [device.pin for device in board.leds] == pins @@ -663,17 +663,17 @@ def test_snow_pi_initial_value(): assert all(device.pin.state == True for device in board.leds) def test_snow_pi_initial_value_pwm(): - pins = [Device._pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] + pins = [Device.pin_factory.pin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] with SnowPi(pwm=True, initial_value=0.5) as board: assert [device.pin for device in board.leds] == pins assert all(device.pin.state == 0.5 for device in board.leds) def test_traffic_lights_buzzer(): - red_pin = Device._pin_factory.pin(2) - amber_pin = Device._pin_factory.pin(3) - green_pin = Device._pin_factory.pin(4) - buzzer_pin = Device._pin_factory.pin(5) - button_pin = Device._pin_factory.pin(6) + red_pin = Device.pin_factory.pin(2) + amber_pin = Device.pin_factory.pin(3) + green_pin = Device.pin_factory.pin(4) + buzzer_pin = Device.pin_factory.pin(5) + button_pin = Device.pin_factory.pin(6) with TrafficLightsBuzzer( TrafficLights(red_pin, amber_pin, green_pin), Buzzer(buzzer_pin), @@ -688,17 +688,17 @@ def test_traffic_lights_buzzer(): assert board.button.is_active def test_fish_dish(): - pins = [Device._pin_factory.pin(n) for n in (9, 22, 4, 8, 7)] + pins = [Device.pin_factory.pin(n) for n in (9, 22, 4, 8, 7)] with FishDish() as board: assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins def test_traffic_hat(): - pins = [Device._pin_factory.pin(n) for n in (24, 23, 22, 5, 25)] + pins = [Device.pin_factory.pin(n) for n in (24, 23, 22, 5, 25)] with TrafficHat() as board: assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins def test_robot(): - pins = [Device._pin_factory.pin(n) for n in (2, 3, 4, 5)] + pins = [Device.pin_factory.pin(n) for n in (2, 3, 4, 5)] with Robot((2, 3), (4, 5)) as robot: assert ( [device.pin for device in robot.left_motor] + @@ -733,12 +733,12 @@ def test_robot(): assert robot.value == (0, -0.5) def test_ryanteck_robot(): - pins = [Device._pin_factory.pin(n) for n in (17, 18, 22, 23)] + pins = [Device.pin_factory.pin(n) for n in (17, 18, 22, 23)] with RyanteckRobot() as board: assert [device.pin for motor in board for device in motor] == pins def test_camjam_kit_robot(): - pins = [Device._pin_factory.pin(n) for n in (9, 10, 7, 8)] + pins = [Device.pin_factory.pin(n) for n in (9, 10, 7, 8)] with CamJamKitRobot() as board: assert [device.pin for motor in board for device in motor] == pins @@ -751,7 +751,7 @@ def test_energenie_bad_init(): Energenie(5) def test_energenie(): - pins = [Device._pin_factory.pin(n) for n in (17, 22, 23, 27, 24, 25)] + pins = [Device.pin_factory.pin(n) for n in (17, 22, 23, 27, 24, 25)] with Energenie(1, initial_value=True) as device1, \ Energenie(2, initial_value=False) as device2: assert repr(device1) == '' diff --git a/tests/test_devices.py b/tests/test_devices.py index cd28f4a..de5fcd0 100644 --- a/tests/test_devices.py +++ b/tests/test_devices.py @@ -14,7 +14,7 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() # TODO add more devices tests! @@ -32,7 +32,7 @@ def test_device_non_physical(): assert w[0].category == PinNonPhysical def test_device_init(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with GPIODevice(pin) as device: assert not device.closed assert device.pin == pin @@ -55,7 +55,7 @@ def test_device_close(): assert device.pin is None def test_device_reopen_same_pin(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with GPIODevice(pin) as device: pass with GPIODevice(pin) as device2: @@ -122,7 +122,7 @@ def test_composite_device_bad_init(): with pytest.raises(ValueError): CompositeDevice(2) with pytest.raises(ValueError): - CompositeDevice(Device._pin_factory.pin(2)) + CompositeDevice(Device.pin_factory.pin(2)) def test_composite_device_read_only(): with CompositeDevice( diff --git a/tests/test_inputs.py b/tests/test_inputs.py index d2bf447..d05940c 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -17,12 +17,12 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() Device._reservations.clear() def test_input_initial_values(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with InputDevice(pin, pull_up=True) as device: assert pin.function == 'input' assert pin.pull == 'up' @@ -32,7 +32,7 @@ def test_input_initial_values(): assert not device.pull_up def test_input_is_active_low(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with InputDevice(pin, pull_up=True) as device: pin.drive_high() assert not device.is_active @@ -42,7 +42,7 @@ def test_input_is_active_low(): assert repr(device) == '' def test_input_is_active_high(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with InputDevice(pin, pull_up=False) as device: pin.drive_high() assert device.is_active @@ -52,13 +52,13 @@ def test_input_is_active_high(): assert repr(device) == '' def test_input_pulled_up(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with pytest.raises(PinFixedPull): InputDevice(pin, pull_up=False) def test_input_event_activated(): event = Event() - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalInputDevice(pin) as device: device.when_activated = lambda: event.set() assert not event.is_set() @@ -67,7 +67,7 @@ def test_input_event_activated(): def test_input_event_deactivated(): event = Event() - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalInputDevice(pin) as device: device.when_deactivated = lambda: event.set() assert not event.is_set() @@ -78,7 +78,7 @@ def test_input_event_deactivated(): def test_input_partial_callback(): event = Event() - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) def foo(a, b): event.set() return a + b @@ -91,20 +91,20 @@ def test_input_partial_callback(): assert event.is_set() def test_input_wait_active(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalInputDevice(pin) as device: pin.drive_high() assert device.wait_for_active(1) assert not device.wait_for_inactive(0) def test_input_wait_inactive(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalInputDevice(pin) as device: assert device.wait_for_inactive(1) assert not device.wait_for_active(0) def test_input_smoothed_attrib(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) as device: assert repr(device) == '' assert device.threshold == 0.5 @@ -116,7 +116,7 @@ def test_input_smoothed_attrib(): device.threshold = 1 def test_input_smoothed_values(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with SmoothedInputDevice(pin) as device: device._queue.start() assert not device.is_active @@ -126,7 +126,7 @@ def test_input_smoothed_values(): assert device.wait_for_inactive(1) def test_input_button(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with Button(pin) as button: assert pin.pull == 'up' assert not button.is_pressed @@ -138,7 +138,7 @@ def test_input_button(): assert button.wait_for_release(1) def test_input_line_sensor(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with LineSensor(pin) as sensor: pin.drive_low() # logic is inverted for line sensor assert sensor.wait_for_line(1) @@ -148,7 +148,7 @@ def test_input_line_sensor(): assert not sensor.line_detected def test_input_motion_sensor(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with MotionSensor(pin) as sensor: pin.drive_high() assert sensor.wait_for_motion(1) @@ -160,7 +160,7 @@ def test_input_motion_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_light_sensor(): - pin = Device._pin_factory.pin(4, pin_class=MockChargingPin) + pin = Device.pin_factory.pin(4, pin_class=MockChargingPin) with LightSensor(pin) as sensor: pin.charge_time = 0.1 assert sensor.wait_for_dark(1) @@ -170,8 +170,8 @@ def test_input_light_sensor(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_input_distance_sensor(): - echo_pin = Device._pin_factory.pin(4) - trig_pin = Device._pin_factory.pin(5, pin_class=MockTriggerPin, echo_pin=echo_pin, echo_time=0.02) + echo_pin = Device.pin_factory.pin(4) + trig_pin = Device.pin_factory.pin(5, pin_class=MockTriggerPin, echo_pin=echo_pin, echo_time=0.02) with pytest.raises(ValueError): DistanceSensor(echo_pin, trig_pin, max_distance=-1) # normal queue len is large (because the sensor is *really* jittery) but diff --git a/tests/test_mock_pin.py b/tests/test_mock_pin.py index 880f859..e4c3124 100644 --- a/tests/test_mock_pin.py +++ b/tests/test_mock_pin.py @@ -16,7 +16,7 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() # Some rough tests to make sure our MockPin is up to snuff. This is just @@ -24,11 +24,11 @@ def teardown_function(function): def test_mock_pin_init(): with pytest.raises(ValueError): - Device._pin_factory.pin(60) - assert Device._pin_factory.pin(2).number == 2 + Device.pin_factory.pin(60) + assert Device.pin_factory.pin(2).number == 2 def test_mock_pin_defaults(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -37,27 +37,27 @@ def test_mock_pin_defaults(): assert pin.state == 0 assert pin.when_changed == None pin.close() - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) assert pin.pull == 'up' def test_mock_pin_open_close(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) pin.close() def test_mock_pin_init_twice_same_pin(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(pin1.number) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(pin1.number) assert pin1 is pin2 def test_mock_pin_init_twice_different_pin(): - pin1 = Device._pin_factory.pin(2) - pin2 = Device._pin_factory.pin(pin1.number+1) + pin1 = Device.pin_factory.pin(2) + pin2 = Device.pin_factory.pin(pin1.number+1) assert pin1 != pin2 assert pin1.number == 2 assert pin2.number == pin1.number+1 def test_mock_pwm_pin_defaults(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) assert pin.bounce == None assert pin.edges == 'both' assert pin.frequency == None @@ -66,42 +66,42 @@ def test_mock_pwm_pin_defaults(): assert pin.state == 0 assert pin.when_changed == None pin.close() - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) assert pin.pull == 'up' def test_mock_pwm_pin_open_close(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) pin.close() def test_mock_pwm_pin_init_twice_same_pin(): - pin1 = Device._pin_factory.pin(2, pin_class=MockPWMPin) - pin2 = Device._pin_factory.pin(pin1.number, pin_class=MockPWMPin) + pin1 = Device.pin_factory.pin(2, pin_class=MockPWMPin) + pin2 = Device.pin_factory.pin(pin1.number, pin_class=MockPWMPin) assert pin1 is pin2 def test_mock_pwm_pin_init_twice_different_pin(): - pin1 = Device._pin_factory.pin(2, pin_class=MockPWMPin) - pin2 = Device._pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) + pin1 = Device.pin_factory.pin(2, pin_class=MockPWMPin) + pin2 = Device.pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) assert pin1 != pin2 assert pin1.number == 2 assert pin2.number == pin1.number+1 def test_mock_pin_init_twice_different_modes(): - pin1 = Device._pin_factory.pin(2, pin_class=MockPin) - pin2 = Device._pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) + pin1 = Device.pin_factory.pin(2, pin_class=MockPin) + pin2 = Device.pin_factory.pin(pin1.number + 1, pin_class=MockPWMPin) assert pin1 != pin2 with pytest.raises(ValueError): - Device._pin_factory.pin(pin1.number, pin_class=MockPWMPin) + Device.pin_factory.pin(pin1.number, pin_class=MockPWMPin) with pytest.raises(ValueError): - Device._pin_factory.pin(pin2.number, pin_class=MockPin) + Device.pin_factory.pin(pin2.number, pin_class=MockPin) def test_mock_pin_frequency_unsupported(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) pin.frequency = None with pytest.raises(PinPWMUnsupported): pin.frequency = 100 def test_mock_pin_frequency_supported(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) pin.function = 'output' assert pin.frequency is None pin.frequency = 100 @@ -110,7 +110,7 @@ def test_mock_pin_frequency_supported(): assert not pin.state def test_mock_pin_pull(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) pin.function = 'input' assert pin.pull == 'floating' pin.pull = 'up' @@ -118,14 +118,14 @@ def test_mock_pin_pull(): pin.pull = 'down' assert not pin.state pin.close() - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) pin.function = 'input' assert pin.pull == 'up' with pytest.raises(PinFixedPull): pin.pull = 'floating' def test_mock_pin_state(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' @@ -137,7 +137,7 @@ def test_mock_pin_state(): assert pin.state == 1 def test_mock_pwm_pin_state(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) with pytest.raises(PinSetInput): pin.state = 1 pin.function = 'output' @@ -149,7 +149,7 @@ def test_mock_pwm_pin_state(): assert pin.state == 0.5 def test_mock_pin_edges(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) assert pin.when_changed is None fired = Event() pin.function = 'input' diff --git a/tests/test_outputs.py b/tests/test_outputs.py index 6908270..b50dda5 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -21,12 +21,12 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() Device._reservations.clear() def test_output_initial_values(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with OutputDevice(pin, initial_value=False) as device: assert pin.function == 'output' assert not pin.state @@ -37,7 +37,7 @@ def test_output_initial_values(): assert state == pin.state def test_output_write_active_high(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with OutputDevice(pin) as device: device.on() assert pin.state @@ -45,7 +45,7 @@ def test_output_write_active_high(): assert not pin.state def test_output_write_active_low(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with OutputDevice(pin, active_high=False) as device: device.on() assert not pin.state @@ -53,7 +53,7 @@ def test_output_write_active_low(): assert pin.state def test_output_write_closed(): - with OutputDevice(Device._pin_factory.pin(2)) as device: + with OutputDevice(Device.pin_factory.pin(2)) as device: device.close() assert device.closed device.close() @@ -62,14 +62,14 @@ def test_output_write_closed(): device.on() def test_output_write_silly(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with OutputDevice(pin) as device: pin.function = 'input' with pytest.raises(AttributeError): device.on() def test_output_value(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with OutputDevice(pin) as device: assert not device.value assert not pin.state @@ -81,7 +81,7 @@ def test_output_value(): assert not pin.state def test_output_digital_toggle(): - pin = Device._pin_factory.pin(2) + pin = Device.pin_factory.pin(2) with DigitalOutputDevice(pin) as device: assert not device.value assert not pin.state @@ -95,7 +95,7 @@ def test_output_digital_toggle(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_background(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -113,7 +113,7 @@ def test_output_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_blink_foreground(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -127,7 +127,7 @@ def test_output_blink_foreground(): ]) def test_output_blink_interrupt_on(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -135,7 +135,7 @@ def test_output_blink_interrupt_on(): pin.assert_states([False, True, False]) def test_output_blink_interrupt_off(): - pin = Device._pin_factory.pin(4) + pin = Device.pin_factory.pin(4) with DigitalOutputDevice(pin) as device: device.blink(0.1, 1) sleep(0.2) @@ -144,14 +144,14 @@ def test_output_blink_interrupt_off(): def test_output_pwm_bad_initial_value(): with pytest.raises(ValueError): - PWMOutputDevice(Device._pin_factory.pin(2), initial_value=2) + PWMOutputDevice(Device.pin_factory.pin(2), initial_value=2) def test_output_pwm_not_supported(): with pytest.raises(AttributeError): - PWMOutputDevice(Device._pin_factory.pin(2)) + PWMOutputDevice(Device.pin_factory.pin(2)) def test_output_pwm_states(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.value = 0.1 device.value = 0.2 @@ -159,7 +159,7 @@ def test_output_pwm_states(): pin.assert_states([0.0, 0.1, 0.2, 0.0]) def test_output_pwm_read(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin, frequency=100) as device: assert device.frequency == 100 device.value = 0.1 @@ -172,14 +172,14 @@ def test_output_pwm_read(): assert device.frequency is None def test_output_pwm_write(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.on() device.off() pin.assert_states([False, True, False]) def test_output_pwm_toggle(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.toggle() device.value = 0.5 @@ -189,7 +189,7 @@ def test_output_pwm_toggle(): pin.assert_states([False, True, 0.5, 0.1, 0.9, False]) def test_output_pwm_active_high_read(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin, active_high=False) as device: device.value = 0.1 assert isclose(device.value, 0.1) @@ -198,18 +198,18 @@ def test_output_pwm_active_high_read(): assert device.value def test_output_pwm_bad_value(): - with PWMOutputDevice(Device._pin_factory.pin(2, pin_class=MockPWMPin)) as device: + with PWMOutputDevice(Device.pin_factory.pin(2, pin_class=MockPWMPin)) as device: with pytest.raises(ValueError): device.value = 2 def test_output_pwm_write_closed(): - with PWMOutputDevice(Device._pin_factory.pin(2, pin_class=MockPWMPin)) as device: + with PWMOutputDevice(Device.pin_factory.pin(2, pin_class=MockPWMPin)) as device: device.close() with pytest.raises(GPIODeviceClosed): device.on() def test_output_pwm_write_silly(): - pin = Device._pin_factory.pin(2, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(2, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: pin.function = 'input' with pytest.raises(AttributeError): @@ -218,7 +218,7 @@ def test_output_pwm_write_silly(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_background(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -236,7 +236,7 @@ def test_output_pwm_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_blink_foreground(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -252,7 +252,7 @@ def test_output_pwm_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_background(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -286,7 +286,7 @@ def test_output_pwm_fade_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_fade_foreground(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -318,7 +318,7 @@ def test_output_pwm_fade_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_background(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -352,7 +352,7 @@ def test_output_pwm_pulse_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_output_pwm_pulse_foreground(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -382,7 +382,7 @@ def test_output_pwm_pulse_foreground(): ]) def test_output_pwm_blink_interrupt(): - pin = Device._pin_factory.pin(4, pin_class=MockPWMPin) + pin = Device.pin_factory.pin(4, pin_class=MockPWMPin) with PWMOutputDevice(pin) as device: device.blink(1, 0.1) sleep(0.2) @@ -394,7 +394,7 @@ def test_rgbled_missing_pins(): RGBLED() def test_rgbled_initial_value(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) as device: assert r.frequency assert g.frequency @@ -404,24 +404,24 @@ def test_rgbled_initial_value(): assert isclose(b.state, 0.0) def test_rgbled_initial_value_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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 = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) 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 = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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 = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) 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) @@ -439,7 +439,7 @@ def test_rgbled_value(): assert device.value == (0.5, 0.5, 0.5) def test_rgbled_value_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -454,7 +454,7 @@ def test_rgbled_value_nonpwm(): assert device.value == (0, 0, 0) def test_rgbled_bad_value(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: with pytest.raises(ValueError): device.value = (2, 0, 0) @@ -463,7 +463,7 @@ def test_rgbled_bad_value(): device.value = (0, -1, 0) def test_rgbled_bad_value_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -481,7 +481,7 @@ def test_rgbled_bad_value_nonpwm(): device.value = (0, 0, 0.5) def test_rgbled_toggle(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: assert not device.is_active assert device.value == (0, 0, 0) @@ -493,7 +493,7 @@ def test_rgbled_toggle(): assert device.value == (0, 0, 0) def test_rgbled_toggle_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -505,7 +505,7 @@ def test_rgbled_toggle_nonpwm(): assert device.value == (0, 0, 0) def test_rgbled_blink_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) with RGBLED(r, g, b, pwm=False) as device: with pytest.raises(ValueError): device.blink(fade_in_time=1) @@ -515,7 +515,7 @@ def test_rgbled_blink_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -536,7 +536,7 @@ def test_rgbled_blink_background(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_background_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2) @@ -557,7 +557,7 @@ def test_rgbled_blink_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -576,7 +576,7 @@ def test_rgbled_blink_foreground(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_blink_foreground_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: start = time() device.blink(0.1, 0.1, n=2, background=False) @@ -595,7 +595,7 @@ def test_rgbled_blink_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2) @@ -630,7 +630,7 @@ def test_rgbled_fade_background(): b.assert_states_and_times(expected) def test_rgbled_fade_background_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -638,7 +638,7 @@ def test_rgbled_fade_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_fade_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.blink(0, 0, 0.2, 0.2, n=2, background=False) @@ -671,7 +671,7 @@ def test_rgbled_fade_foreground(): b.assert_states_and_times(expected) def test_rgbled_fade_foreground_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -679,7 +679,7 @@ def test_rgbled_fade_foreground_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_background(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2) @@ -714,7 +714,7 @@ def test_rgbled_pulse_background(): b.assert_states_and_times(expected) def test_rgbled_pulse_background_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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) @@ -722,7 +722,7 @@ def test_rgbled_pulse_background_nonpwm(): @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), reason='timing is too random on pypy') def test_rgbled_pulse_foreground(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: start = time() device.pulse(0.2, 0.2, n=2, background=False) @@ -755,13 +755,13 @@ def test_rgbled_pulse_foreground(): b.assert_states_and_times(expected) def test_rgbled_pulse_foreground_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(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 = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (4, 5, 6)) with RGBLED(r, g, b) as device: device.blink(1, 0.1) sleep(0.2) @@ -771,7 +771,7 @@ def test_rgbled_blink_interrupt(): b.assert_states([0, 1, 0]) def test_rgbled_blink_interrupt_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (4, 5, 6)) + r, g, b = (Device.pin_factory.pin(i) for i in (4, 5, 6)) with RGBLED(r, g, b, pwm=False) as device: device.blink(1, 0.1) sleep(0.2) @@ -781,7 +781,7 @@ def test_rgbled_blink_interrupt_nonpwm(): b.assert_states([0, 1, 0]) def test_rgbled_close(): - r, g, b = (Device._pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i, pin_class=MockPWMPin) for i in (1, 2, 3)) with RGBLED(r, g, b) as device: assert not device.closed device.close() @@ -790,7 +790,7 @@ def test_rgbled_close(): assert device.closed def test_rgbled_close_nonpwm(): - r, g, b = (Device._pin_factory.pin(i) for i in (1, 2, 3)) + r, g, b = (Device.pin_factory.pin(i) for i in (1, 2, 3)) with RGBLED(r, g, b, pwm=False) as device: assert not device.closed device.close() @@ -803,8 +803,8 @@ def test_motor_missing_pins(): Motor() def test_motor_pins(): - f = Device._pin_factory.pin(1, pin_class=MockPWMPin) - b = Device._pin_factory.pin(2, pin_class=MockPWMPin) + f = Device.pin_factory.pin(1, pin_class=MockPWMPin) + b = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, PWMOutputDevice) @@ -812,8 +812,8 @@ def test_motor_pins(): assert isinstance(device.backward_device, PWMOutputDevice) def test_motor_pins_nonpwm(): - f = Device._pin_factory.pin(1) - b = Device._pin_factory.pin(2) + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) with Motor(f, b, pwm=False) as device: assert device.forward_device.pin is f assert isinstance(device.forward_device, DigitalOutputDevice) @@ -821,8 +821,8 @@ def test_motor_pins_nonpwm(): assert isinstance(device.backward_device, DigitalOutputDevice) def test_motor_close(): - f = Device._pin_factory.pin(1, pin_class=MockPWMPin) - b = Device._pin_factory.pin(2, pin_class=MockPWMPin) + f = Device.pin_factory.pin(1, pin_class=MockPWMPin) + b = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.close() assert device.closed @@ -832,8 +832,8 @@ def test_motor_close(): assert device.closed def test_motor_close_nonpwm(): - f = Device._pin_factory.pin(1) - b = Device._pin_factory.pin(2) + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.close() assert device.closed @@ -841,8 +841,8 @@ def test_motor_close_nonpwm(): assert device.backward_device.pin is None def test_motor_value(): - f = Device._pin_factory.pin(1, pin_class=MockPWMPin) - b = Device._pin_factory.pin(2, pin_class=MockPWMPin) + f = Device.pin_factory.pin(1, pin_class=MockPWMPin) + b = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.value = -1 assert device.is_active @@ -866,8 +866,8 @@ def test_motor_value(): assert b.state == 0 and f.state == 0 def test_motor_value_nonpwm(): - f = Device._pin_factory.pin(1) - b = Device._pin_factory.pin(2) + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.value = -1 assert device.is_active @@ -883,8 +883,8 @@ def test_motor_value_nonpwm(): assert b.state == 0 and f.state == 0 def test_motor_bad_value(): - f = Device._pin_factory.pin(1, pin_class=MockPWMPin) - b = Device._pin_factory.pin(2, pin_class=MockPWMPin) + f = Device.pin_factory.pin(1, pin_class=MockPWMPin) + b = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: with pytest.raises(ValueError): device.value = -2 @@ -896,8 +896,8 @@ def test_motor_bad_value(): device.backward(2) def test_motor_bad_value_nonpwm(): - f = Device._pin_factory.pin(1) - b = Device._pin_factory.pin(2) + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) with Motor(f, b, pwm=False) as device: with pytest.raises(ValueError): device.value = -2 @@ -909,8 +909,8 @@ def test_motor_bad_value_nonpwm(): device.value = -0.5 def test_motor_reverse(): - f = Device._pin_factory.pin(1, pin_class=MockPWMPin) - b = Device._pin_factory.pin(2, pin_class=MockPWMPin) + f = Device.pin_factory.pin(1, pin_class=MockPWMPin) + b = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Motor(f, b) as device: device.forward() assert device.value == 1 @@ -926,8 +926,8 @@ def test_motor_reverse(): assert b.state == 0 and f.state == 0.5 def test_motor_reverse_nonpwm(): - f = Device._pin_factory.pin(1) - b = Device._pin_factory.pin(2) + f = Device.pin_factory.pin(1) + b = Device.pin_factory.pin(2) with Motor(f, b, pwm=False) as device: device.forward() assert device.value == 1 @@ -937,13 +937,13 @@ def test_motor_reverse_nonpwm(): assert b.state == 1 and f.state == 0 def test_servo_pins(): - p = Device._pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1, pin_class=MockPWMPin) with Servo(p) as device: assert device.pwm_device.pin is p assert isinstance(device.pwm_device, PWMOutputDevice) def test_servo_bad_value(): - p = Device._pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1, pin_class=MockPWMPin) with pytest.raises(ValueError): Servo(p, initial_value=2) with pytest.raises(ValueError): @@ -952,12 +952,12 @@ def test_servo_bad_value(): Servo(p, max_pulse_width=30/1000) def test_servo_pins_nonpwm(): - p = Device._pin_factory.pin(2) + p = Device.pin_factory.pin(2) with pytest.raises(PinPWMUnsupported): Servo(p) def test_servo_close(): - p = Device._pin_factory.pin(2, pin_class=MockPWMPin) + p = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Servo(p) as device: device.close() assert device.closed @@ -966,7 +966,7 @@ def test_servo_close(): assert device.closed def test_servo_pulse_width(): - p = Device._pin_factory.pin(2, pin_class=MockPWMPin) + p = Device.pin_factory.pin(2, pin_class=MockPWMPin) with Servo(p, min_pulse_width=5/10000, max_pulse_width=25/10000) as device: assert isclose(device.min_pulse_width, 5/10000) assert isclose(device.max_pulse_width, 25/10000) @@ -980,7 +980,7 @@ def test_servo_pulse_width(): assert device.pulse_width is None def test_servo_values(): - p = Device._pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1, pin_class=MockPWMPin) with Servo(p) as device: device.min() assert device.is_active @@ -1007,13 +1007,13 @@ def test_servo_values(): assert device.value is None def test_angular_servo_range(): - p = Device._pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1, pin_class=MockPWMPin) with AngularServo(p, initial_angle=15, min_angle=0, max_angle=90) as device: assert device.min_angle == 0 assert device.max_angle == 90 def test_angular_servo_angles(): - p = Device._pin_factory.pin(1, pin_class=MockPWMPin) + p = Device.pin_factory.pin(1, pin_class=MockPWMPin) with AngularServo(p) as device: device.angle = 0 assert device.angle == 0 diff --git a/tests/test_pins_data.py b/tests/test_pins_data.py index 2a9af16..109257b 100644 --- a/tests/test_pins_data.py +++ b/tests/test_pins_data.py @@ -19,9 +19,7 @@ from gpiozero import * def test_pi_revision(): - # We're not using _set_pin_factory here because we don't want to implicitly - # close the old instance, just replace it while we test stuff - with patch('gpiozero.devices.Device._pin_factory', LocalPiFactory()): + with patch('gpiozero.devices.Device.pin_factory', LocalPiFactory()): # Can't use MockPin for this as we want something that'll actually try # and read /proc/cpuinfo (MockPin simply parrots the 2B's data); # LocalPiFactory is used as we can definitely instantiate it (strictly @@ -32,20 +30,20 @@ def test_pi_revision(): assert pi_info().revision == '0002' # LocalPiFactory caches the revision (because realistically it # isn't going to change at runtime); we need to wipe it here though - Device._pin_factory._info = None + Device.pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: a21042'] assert pi_info().revision == 'a21042' # Check over-volting result (some argument over whether this is 7 or # 8 character result; make sure both work) - Device._pin_factory._info = None + Device.pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: 1000003'] assert pi_info().revision == '0003' - Device._pin_factory._info = None + Device.pin_factory._info = None m.return_value.__enter__.return_value = ['Revision: 100003'] assert pi_info().revision == '0003' with pytest.raises(PinUnknownPi): m.return_value.__enter__.return_value = ['nothing', 'relevant', 'at all'] - Device._pin_factory._info = None + Device.pin_factory._info = None pi_info() with pytest.raises(PinUnknownPi): pi_info('0fff') diff --git a/tests/test_real_pins.py b/tests/test_real_pins.py index bccf045..8b9b7da 100644 --- a/tests/test_real_pins.py +++ b/tests/test_real_pins.py @@ -52,9 +52,9 @@ def pin_factory(request): except Exception as e: pytest.skip("skipped factory %s: %s" % (request.param, str(e))) else: - Device._set_pin_factory(factory) + Device.pin_factory = factory def fin(): - Device._set_pin_factory(MockFactory()) + Device.pin_factory = MockFactory() request.addfinalizer(fin) return factory @@ -147,7 +147,7 @@ def test_bad_duty_cycle(pins): # NOTE: There's some race in RPi.GPIO that causes a segfault if we # don't pause before starting PWM; only seems to happen when stopping # and restarting PWM very rapidly (i.e. between test cases). - if Device._pin_factory.__class__.__name__ == 'RPiGPIOFactory': + if Device.pin_factory.__class__.__name__ == 'RPiGPIOFactory': sleep(0.1) test_pin.frequency = 100 except PinPWMUnsupported: @@ -164,7 +164,7 @@ def test_duty_cycles(pins): test_pin.function = 'output' try: # NOTE: see above - if Device._pin_factory.__class__.__name__ == 'RPiGPIOFactory': + if Device.pin_factory.__class__.__name__ == 'RPiGPIOFactory': sleep(0.1) test_pin.frequency = 100 except PinPWMUnsupported: diff --git a/tests/test_spi.py b/tests/test_spi.py index 7b514bf..6ae6967 100644 --- a/tests/test_spi.py +++ b/tests/test_spi.py @@ -26,80 +26,80 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() def test_spi_hardware_params(): with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) io_open.return_value.__enter__.return_value = ['Revision: a21042'] - with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ patch('gpiozero.pins.local.SpiDev'): - with Device._pin_factory.spi() as device: + with Device.pin_factory.spi() as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(port=0, device=0) as device: + with Device.pin_factory.spi(port=0, device=0) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(port=0, device=1) as device: + with Device.pin_factory.spi(port=0, device=1) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(clock_pin=11) as device: + with Device.pin_factory.spi(clock_pin=11) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device: + with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device: + with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device: assert isinstance(device, LocalPiHardwareSPI) - with Device._pin_factory.spi(shared=True) as device: + with Device.pin_factory.spi(shared=True) as device: assert isinstance(device, LocalPiHardwareSPIShared) with pytest.raises(ValueError): - Device._pin_factory.spi(port=1) + Device.pin_factory.spi(port=1) with pytest.raises(ValueError): - Device._pin_factory.spi(device=2) + Device.pin_factory.spi(device=2) with pytest.raises(ValueError): - Device._pin_factory.spi(port=0, clock_pin=12) + Device.pin_factory.spi(port=0, clock_pin=12) with pytest.raises(ValueError): - Device._pin_factory.spi(foo='bar') + Device.pin_factory.spi(foo='bar') def test_spi_software_params(): with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open: mmap_mmap.return_value = array(nstr('B'), (0,) * 4096) io_open.return_value.__enter__.return_value = ['Revision: a21042'] - with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ patch('gpiozero.pins.local.SpiDev'): - with Device._pin_factory.spi(select_pin=6) as device: + with Device.pin_factory.spi(select_pin=6) as device: assert isinstance(device, LocalPiSoftwareSPI) - with Device._pin_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device: + with Device.pin_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device: assert isinstance(device, LocalPiSoftwareSPI) - with Device._pin_factory.spi(select_pin=6, shared=True) as device: + with Device.pin_factory.spi(select_pin=6, shared=True) as device: assert isinstance(device, LocalPiSoftwareSPIShared) - with patch('gpiozero.devices.Device._pin_factory', NativeFactory()), \ + with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \ patch('gpiozero.pins.local.SpiDev', None): # Clear out the old factory's pins cache (this is only necessary # because we're being very naughty switching out pin factories) - Device._pin_factory.pins.clear() + Device.pin_factory.pins.clear() # Ensure software fallback works when SpiDev isn't present - with Device._pin_factory.spi() as device: + with Device.pin_factory.spi() as device: assert isinstance(device, LocalPiSoftwareSPI) def test_spi_hardware_conflict(): with patch('gpiozero.pins.local.SpiDev') as spidev: with LED(11) as led: with pytest.raises(GPIOPinInUse): - Device._pin_factory.spi(port=0, device=0) + Device.pin_factory.spi(port=0, device=0) with patch('gpiozero.pins.local.SpiDev') as spidev: - with Device._pin_factory.spi(port=0, device=0) as spi: + with Device.pin_factory.spi(port=0, device=0) as spi: with pytest.raises(GPIOPinInUse): LED(11) def test_spi_hardware_read(): with patch('gpiozero.pins.local.SpiDev') as spidev: spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)] - with Device._pin_factory.spi() as device: + with Device.pin_factory.spi() as device: assert device.read(3) == [0, 1, 2] assert device.read(6) == list(range(6)) def test_spi_hardware_write(): with patch('gpiozero.pins.local.SpiDev') as spidev: spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)] - with Device._pin_factory.spi() as device: + with Device.pin_factory.spi() as device: assert device.write([0, 1, 2]) == 3 assert spidev.return_value.xfer2.called_with([0, 1, 2]) assert device.write(list(range(6))) == 6 @@ -111,7 +111,7 @@ def test_spi_hardware_modes(): spidev.return_value.lsbfirst = False spidev.return_value.cshigh = True spidev.return_value.bits_per_word = 8 - with Device._pin_factory.spi() as device: + with Device.pin_factory.spi() as device: assert device.clock_mode == 0 assert not device.clock_polarity assert not device.clock_phase @@ -139,7 +139,7 @@ def test_spi_software_read(): self.tx_word(i) with patch('gpiozero.pins.local.SpiDev', None), \ SPISlave(11, 10, 9, 8) as slave, \ - Device._pin_factory.spi() as master: + Device.pin_factory.spi() as master: assert master.read(3) == [0, 1, 2] assert master.read(6) == [0, 1, 2, 3, 4, 5] slave.clock_phase = True @@ -150,7 +150,7 @@ def test_spi_software_read(): def test_spi_software_write(): with patch('gpiozero.pins.local.SpiDev', None), \ MockSPIDevice(11, 10, 9, 8) as test_device, \ - Device._pin_factory.spi() as master: + Device.pin_factory.spi() as master: master.write([0]) assert test_device.rx_word() == 0 master.write([2, 0]) @@ -160,7 +160,7 @@ def test_spi_software_write(): def test_spi_software_clock_mode(): with patch('gpiozero.pins.local.SpiDev', None), \ - Device._pin_factory.spi() as master: + Device.pin_factory.spi() as master: assert master.clock_mode == 0 assert not master.clock_polarity assert not master.clock_phase @@ -178,7 +178,7 @@ def test_spi_software_clock_mode(): def test_spi_software_attr(): with patch('gpiozero.pins.local.SpiDev', None), \ - Device._pin_factory.spi() as master: + Device.pin_factory.spi() as master: assert not master.lsb_first assert not master.select_high assert master.bits_per_word == 8 diff --git a/tests/test_spi_devices.py b/tests/test_spi_devices.py index 4f45171..e6ae140 100644 --- a/tests/test_spi_devices.py +++ b/tests/test_spi_devices.py @@ -21,7 +21,7 @@ from gpiozero import * def teardown_function(function): - Device._pin_factory.reset() + Device.pin_factory.reset() def clamp(v, min_value, max_value): return min(max_value, max(min_value, v))