Merge pull request #246 from waveform80/pin-database

Add pins database
This commit is contained in:
Dave Jones
2016-04-05 00:51:27 +01:00
9 changed files with 775 additions and 26 deletions

View File

@@ -8,6 +8,11 @@ from __future__ import (
from .pins import (
Pin,
)
from .pins.data import (
PiBoardInfo,
PinInfo,
pi_info,
)
from .exc import (
GPIOZeroError,
DeviceClosed,
@@ -38,6 +43,9 @@ from .exc import (
PinPWMError,
PinPWMUnsupported,
PinPWMFixedValue,
PinUnknownPi,
PinMultiplePins,
PinNoPins,
GPIOZeroWarning,
SPIWarning,
SPISoftwareFallback,

View File

@@ -100,6 +100,15 @@ class PinPWMUnsupported(PinPWMError, AttributeError):
class PinPWMFixedValue(PinPWMError, AttributeError):
"Error raised when attempting to initialize PWM on an input pin"
class PinUnknownPi(PinError, RuntimeError):
"Error raised when gpiozero doesn't recognize a revision of the Pi"
class PinMultiplePins(PinError, RuntimeError):
"Error raised when multiple pins support the requested function"
class PinNoPins(PinError, RuntimeError):
"Error raised when no pins support the requested function"
class GPIOZeroWarning(Warning):
"Base class for all warnings in GPIO Zero"

696
gpiozero/pins/data.py Normal file
View File

@@ -0,0 +1,696 @@
from __future__ import (
unicode_literals,
absolute_import,
print_function,
division,
)
str = type('')
import io
from collections import namedtuple
from ..exc import PinUnknownPi, PinMultiplePins
# Some useful constants for describing pins
V1_8 = '1V8'
V3_3 = '3V3'
V5 = '5V'
GND = 'GND'
NC = 'NC' # not connected
GPIO0 = 'GPIO0'
GPIO1 = 'GPIO1'
GPIO2 = 'GPIO2'
GPIO3 = 'GPIO3'
GPIO4 = 'GPIO4'
GPIO5 = 'GPIO5'
GPIO6 = 'GPIO6'
GPIO7 = 'GPIO7'
GPIO8 = 'GPIO8'
GPIO9 = 'GPIO9'
GPIO10 = 'GPIO10'
GPIO11 = 'GPIO11'
GPIO12 = 'GPIO12'
GPIO13 = 'GPIO13'
GPIO14 = 'GPIO14'
GPIO15 = 'GPIO15'
GPIO16 = 'GPIO16'
GPIO17 = 'GPIO17'
GPIO18 = 'GPIO18'
GPIO19 = 'GPIO19'
GPIO20 = 'GPIO20'
GPIO21 = 'GPIO21'
GPIO22 = 'GPIO22'
GPIO23 = 'GPIO23'
GPIO24 = 'GPIO24'
GPIO25 = 'GPIO25'
GPIO26 = 'GPIO26'
GPIO27 = 'GPIO27'
GPIO28 = 'GPIO28'
GPIO29 = 'GPIO29'
GPIO30 = 'GPIO30'
GPIO31 = 'GPIO31'
GPIO32 = 'GPIO32'
GPIO33 = 'GPIO33'
GPIO34 = 'GPIO34'
GPIO35 = 'GPIO35'
GPIO36 = 'GPIO36'
GPIO37 = 'GPIO37'
GPIO38 = 'GPIO38'
GPIO39 = 'GPIO39'
GPIO40 = 'GPIO40'
GPIO41 = 'GPIO41'
GPIO42 = 'GPIO42'
GPIO43 = 'GPIO43'
GPIO44 = 'GPIO44'
GPIO45 = 'GPIO45'
# Pin maps for various board revisions and headers
REV1_P1 = {
# pin func pullup pin func pullup
1: (V3_3, False), 2: (V5, False),
3: (GPIO0, True), 4: (V5, False),
5: (GPIO1, True), 6: (GND, False),
7: (GPIO4, False), 8: (GPIO14, False),
9: (GND, False), 10: (GPIO15, False),
11: (GPIO17, False), 12: (GPIO18, False),
13: (GPIO21, False), 14: (GND, False),
15: (GPIO22, False), 16: (GPIO23, False),
17: (V3_3, False), 18: (GPIO24, False),
19: (GPIO10, False), 20: (GND, False),
21: (GPIO9, False), 22: (GPIO25, False),
23: (GPIO11, False), 24: (GPIO8, False),
25: (GND, False), 26: (GPIO7, False),
}
REV2_P1 = {
1: (V3_3, False), 2: (V5, False),
3: (GPIO2, True), 4: (V5, False),
5: (GPIO3, True), 6: (GND, False),
7: (GPIO4, False), 8: (GPIO14, False),
9: (GND, False), 10: (GPIO15, False),
11: (GPIO17, False), 12: (GPIO18, False),
13: (GPIO27, False), 14: (GND, False),
15: (GPIO22, False), 16: (GPIO23, False),
17: (V3_3, False), 18: (GPIO24, False),
19: (GPIO10, False), 20: (GND, False),
21: (GPIO9, False), 22: (GPIO25, False),
23: (GPIO11, False), 24: (GPIO8, False),
25: (GND, False), 26: (GPIO7, False),
}
REV2_P5 = {
1: (V5, False), 2: (V3_3, False),
3: (GPIO28, False), 4: (GPIO29, False),
5: (GPIO30, False), 6: (GPIO31, False),
7: (GND, False), 8: (GND, False),
}
PLUS_P1 = {
1: (V3_3, False), 2: (V5, False),
3: (GPIO2, True), 4: (V5, False),
5: (GPIO3, True), 6: (GND, False),
7: (GPIO4, False), 8: (GPIO14, False),
9: (GND, False), 10: (GPIO15, False),
11: (GPIO17, False), 12: (GPIO18, False),
13: (GPIO27, False), 14: (GND, False),
15: (GPIO22, False), 16: (GPIO23, False),
17: (V3_3, False), 18: (GPIO24, False),
19: (GPIO10, False), 20: (GND, False),
21: (GPIO9, False), 22: (GPIO25, False),
23: (GPIO11, False), 24: (GPIO8, False),
25: (GND, False), 26: (GPIO7, False),
27: (GPIO0, False), 28: (GPIO1, False),
29: (GPIO5, False), 30: (GND, False),
31: (GPIO6, False), 32: (GPIO12, False),
33: (GPIO13, False), 34: (GND, False),
35: (GPIO19, False), 36: (GPIO16, False),
37: (GPIO26, False), 38: (GPIO20, False),
39: (GND, False), 40: (GPIO21, False),
}
CM_SODIMM = {
1: (GND, False), 2: ('EMMC DISABLE N', False),
3: (GPIO0, False), 4: (NC, False),
5: (GPIO1, False), 6: (NC, False),
7: (GND, False), 8: (NC, False),
9: (GPIO2, False), 10: (NC, False),
11: (GPIO3, False), 12: (NC, False),
13: (GND, False), 14: (NC, False),
15: (GPIO4, False), 16: (NC, False),
17: (GPIO5, False), 18: (NC, False),
19: (GND, False), 20: (NC, False),
21: (GPIO6, False), 22: (NC, False),
23: (GPIO7, False), 24: (NC, False),
25: (GND, False), 26: (GND, False),
27: (GPIO8, False), 28: (GPIO28, False),
29: (GPIO9, False), 30: (GPIO29, False),
31: (GND, False), 32: (GND, False),
33: (GPIO10, False), 34: (GPIO30, False),
35: (GPIO11, False), 36: (GPIO31, False),
37: (GND, False), 38: (GND, False),
39: ('GPIO0-27 VREF', False), 40: ('GPIO0-27 VREF', False),
# Gap in SODIMM pins
41: ('GPIO28-45 VREF', False), 42: ('GPIO28-45 VREF', False),
43: (GND, False), 44: (GND, False),
45: (GPIO12, False), 46: (GPIO32, False),
47: (GPIO13, False), 48: (GPIO33, False),
49: (GND, False), 50: (GND, False),
51: (GPIO14, False), 52: (GPIO34, False),
53: (GPIO15, False), 54: (GPIO35, False),
55: (GND, False), 56: (GND, False),
57: (GPIO16, False), 58: (GPIO36, False),
59: (GPIO17, False), 60: (GPIO37, False),
61: (GND, False), 62: (GND, False),
63: (GPIO18, False), 64: (GPIO38, False),
65: (GPIO19, False), 66: (GPIO39, False),
67: (GND, False), 68: (GND, False),
69: (GPIO20, False), 70: (GPIO40, False),
71: (GPIO21, False), 72: (GPIO41, False),
73: (GND, False), 74: (GND, False),
75: (GPIO22, False), 76: (GPIO42, False),
77: (GPIO23, False), 78: (GPIO43, False),
79: (GND, False), 80: (GND, False),
81: (GPIO24, False), 82: (GPIO44, False),
83: (GPIO25, False), 84: (GPIO45, False),
85: (GND, False), 86: (GND, False),
87: (GPIO26, False), 88: ('GPIO46 1V8', False),
89: (GPIO27, False), 90: ('GPIO47 1V8', False),
91: (GND, False), 92: (GND, False),
93: ('DSI0 DN1', False), 94: ('DSI1 DP0', False),
95: ('DSI0 DP1', False), 96: ('DSI1 DN0', False),
97: (GND, False), 98: (GND, False),
99: ('DSI0 DN0', False), 100: ('DSI1 CP', False),
101: ('DSI0 DP0', False), 102: ('DSI1 CN', False),
103: (GND, False), 104: (GND, False),
105: ('DSI0 CN', False), 106: ('DSI1 DP3', False),
107: ('DSI0 CP', False), 108: ('DSI1 DN3', False),
109: (GND, False), 110: (GND, False),
111: ('HDMI CK N', False), 112: ('DSI1 DP2', False),
113: ('HDMI CK P', False), 114: ('DSI1 DN2', False),
115: (GND, False), 116: (GND, False),
117: ('HDMI D0 N', False), 118: ('DSI1 DP1', False),
119: ('HDMI D0 P', False), 120: ('DSI1 DN1', False),
121: (GND, False), 122: (GND, False),
123: ('HDMI D1 N', False), 124: (NC, False),
125: ('HDMI D1 P', False), 126: (NC, False),
127: (GND, False), 128: (NC, False),
129: ('HDMI D2 N', False), 130: (NC, False),
131: ('HDMI D2 P', False), 132: (NC, False),
133: (GND, False), 134: (GND, False),
135: ('CAM1 DP3', False), 136: ('CAM0 DP0', False),
137: ('CAM1 DN3', False), 138: ('CAM0 DN0', False),
139: (GND, False), 140: (GND, False),
141: ('CAM1 DP2', False), 142: ('CAM0 CP', False),
143: ('CAM1 DN2', False), 144: ('CAM0 CN', False),
145: (GND, False), 146: (GND, False),
147: ('CAM1 CP', False), 148: ('CAM0 DP1', False),
149: ('CAM1 CN', False), 150: ('CAM0 DN1', False),
151: (GND, False), 152: (GND, False),
153: ('CAM1 DP1', False), 154: (NC, False),
155: ('CAM1 DN1', False), 156: (NC, False),
157: (GND, False), 158: (NC, False),
159: ('CAM1 DP0', False), 160: (NC, False),
161: ('CAM1 DN0', False), 162: (NC, False),
163: (GND, False), 164: (GND, False),
165: ('USB DP', False), 166: ('TVDAC', False),
167: ('USB DM', False), 168: ('USB OTGID', False),
169: (GND, False), 170: (GND, False),
171: ('HDMI CEC', False), 172: ('VC TRST N', False),
173: ('HDMI SDA', False), 174: ('VC TDI', False),
175: ('HDMI SCL', False), 176: ('VC TMS', False),
177: ('RUN', False), 178: ('VC TDO', False),
179: ('VDD CORE', False), 180: ('VC TCK', False),
181: (GND, False), 182: (GND, False),
183: (V1_8, False), 184: (V1_8, False),
185: (V1_8, False), 186: (V1_8, False),
187: (GND, False), 188: (GND, False),
189: ('VDAC', False), 190: ('VDAC', False),
191: (V3_3, False), 192: (V3_3, False),
193: (V3_3, False), 194: (V3_3, False),
195: (GND, False), 196: (GND, False),
197: ('VBAT', False), 198: ('VBAT', False),
199: ('VBAT', False), 200: ('VBAT', False),
}
# The following data is sourced from a combination of the following locations:
#
# http://elinux.org/RPi_HardwareHistory
# http://elinux.org/RPi_Low-level_peripherals
# https://git.drogon.net/?p=wiringPi;a=blob;f=wiringPi/wiringPi.c#l807
PI_REVISIONS = {
# rev model pcb_rev released soc manufacturer ram storage usb eth wifi bt csi dsi headers
'beta': ('B', '?', '2012Q1', 'BCM2835', '?', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV1_P1}, ),
'0002': ('B', '1.0', '2012Q1', 'BCM2835', 'Egoman', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV1_P1}, ),
'0003': ('B', '1.0', '2012Q3', 'BCM2835', 'Egoman', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV1_P1}, ),
'0004': ('B', '2.0', '2012Q3', 'BCM2835', 'Sony', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0005': ('B', '2.0', '2012Q4', 'BCM2835', 'Qisda', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0006': ('B', '2.0', '2012Q4', 'BCM2835', 'Egoman', 256, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0007': ('A', '2.0', '2013Q1', 'BCM2835', 'Egoman', 256, 'SD', 1, 0, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0008': ('A', '2.0', '2013Q1', 'BCM2835', 'Sony', 256, 'SD', 1, 0, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0009': ('A', '2.0', '2013Q1', 'BCM2835', 'Qisda', 256, 'SD', 1, 0, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'000d': ('B', '2.0', '2012Q4', 'BCM2835', 'Egoman', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'000e': ('B', '2.0', '2012Q4', 'BCM2835', 'Sony', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'000f': ('B', '2.0', '2012Q4', 'BCM2835', 'Egoman', 512, 'SD', 2, 1, False, False, 1, 1, {'P1': REV2_P1, 'P5': REV2_P5},),
'0010': ('B+', '1.2', '2014Q3', 'BCM2835', 'Sony', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
'0011': ('CM', '1.2', '2014Q2', 'BCM2835', 'Sony', 512, 'eMMC', 0, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, ),
'0012': ('A+', '1.2', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ),
'0013': ('B+', '1.2', '2015Q1', 'BCM2835', 'Egoman', 512, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
'0014': ('CM', '1.1', '2014Q2', 'BCM2835', 'Sony', 512, 'eMMC', 0, 0, False, False, 2, 2, {'SODIMM': CM_SODIMM}, ),
'0015': ('A+', '1.1', '2014Q4', 'BCM2835', 'Sony', 256, 'MicroSD', 1, 0, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'a01041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Sony', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'a21041': ('2B', '1.1', '2015Q1', 'BCM2836', 'Embest', 1024, 'MicroSD', 4, 1, False, False, 1, 1, {'P1': PLUS_P1}, ),
#'900092': ('Zero', '1.2', '2015Q4', 'BCM2835', 'Sony', 512, 'MicroSD', 1, 0, False, False, 0, 0, {'P1': PLUS_P1}, ),
#'a02082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Sony', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ),
#'a22082': ('3B', '1.2', '2016Q1', 'BCM2837', 'Embest', 1024, 'MicroSD', 4, 1, True, True, 1, 1, {'P1': PLUS_P1}, ),
}
class PinInfo(namedtuple('PinInfo', (
'number',
'function',
'pull_up',
))):
"""
This class is a :func:`~collections.namedtuple` derivative used to
represent information about a pin present on a GPIO header. The following
attributes are defined:
.. attribute:: number
An integer containing the physical pin number on the header (starting
from 1 in accordance with convention).
.. attribute:: function
A string describing the function of the pin. Some common examples
include "GND" (for pins connecting to ground), "3V3" (for pins which
output 3.3 volts), "GPIO9" (for GPIO9 in the Broadcom numbering
scheme), etc.
.. attribute:: pull_up
A bool indicating whether the pin has a physical pull-up resistor
permanently attached (this is usually ``False`` but GPIO2 and GPIO3
are *usually* ``True``). This is used internally by gpiozero to raise
errors when pull-down is requested on a pin with a physical pull-up
resistor.
"""
class PiBoardInfo(namedtuple('PiBoardInfo', (
'revision',
'model',
'pcb_revision',
'released',
'soc',
'manufacturer',
'memory',
'storage',
'usb',
'ethernet',
'wifi',
'bluetooth',
'csi',
'dsi',
'headers',
))):
"""
This class is a :func:`~collections.namedtuple` derivative used to
represent information about a particular model of Raspberry Pi. While it is
a tuple, it is strongly recommended that you use the following named
attributes to access the data contained within.
.. attribute:: revision
A string indicating the revision of the Pi. This is unique to each
revision and can be considered the "key" from which all other
attributes are derived. However, in itself the string is fairly
meaningless.
.. attribute:: model
A string containing the model of the Pi (for example, "B", "B+", "A+",
"2B", "CM" (for the Compute Module), or "Zero").
.. attribute:: pcb_revision
A string containing the PCB revision number which is silk-screened onto
the Pi (on some models).
.. note::
This is primarily useful to distinguish between the model B
revision 1.0 and 2.0 (not to be confused with the model 2B) which
had slightly different pinouts on their 26-pin GPIO headers.
.. attribute:: released
A string containing an approximate release date for this revision of
the Pi (formatted as yyyyQq, e.g. 2012Q1 means the first quarter of
2012).
.. attribute:: soc
A string indicating the SoC (`system on a chip`_) that this revision
of the Pi is based upon.
.. attribute:: manufacturer
A string indicating the name of the manufacturer (usually "Sony" but a
few others exist).
.. attribute:: memory
An integer indicating the amount of memory (in Mb) connected to the
SoC.
.. note::
This can differ substantially from the amount of RAM available
to the operating system as the GPU's memory is shared with the
CPU. When the camera module is activated, at least 128Mb of RAM
is typically reserved for the GPU.
.. attribute:: storage
A string indicating the type of bootable storage used with this
revision of Pi, e.g. "SD", "MicroSD", or "eMMC" (for the Compute
Module).
.. attribute:: usb
An integer indicating how many USB ports are physically present on
this revision of the Pi.
.. note::
This does *not* include the micro-USB port used to power the Pi.
On the Compute Module this is listed as 0 as the compute module
itself doesn't have any physical USB headers, despite providing one
on the I/O development board and having the pins for one on the
module itself.
.. attribute:: ethernet
An integer indicating how many Ethernet ports are physically present
on this revision of the Pi.
.. attribute:: wifi
A bool indicating whether this revision of the Pi has wifi built-in.
.. attribute:: bluetooth
A bool indicating whether this revision of the Pi has bluetooth
built-in.
.. attribute:: csi
An integer indicating the number of CSI (camera) ports available on
this revision of the Pi.
.. attribute:: dsi
An integer indicating the number of DSI (display) ports available on
this revision of the Pi.
.. attribute:: headers
A dictionary which maps header labels to dictionaries which map
physical pin numbers to :class:`PinInfo` tuples. For example, to obtain
information about pin 12 on header P1 you would query
``headers['P1'][12]``.
.. _system on a chip: https://en.wikipedia.org/wiki/System_on_a_chip
"""
def physical_pins(self, function):
"""
Return the physical pins supporting the specified *function* as a tuple
of ``(header, pin_number)`` where *header* is a string specifying the
header containing the *pin_number*. Note that the return value is a
:class:`set` which is not indexable. Use :func:`physical_pin` if you
are expecting a single return value.
:param str function:
The pin function you wish to search for. Usually this is something
like "GPIO9" for Broadcom GPIO pin 9, or "GND" for all the pins
connecting to electrical ground.
"""
return {
(header, pin.number)
for (header, pins) in self.headers.items()
for pin in pins.values()
if pin.function == function
}
def physical_pin(self, function):
"""
Return the physical pin supporting the specified *function*. If no pins
support the desired *function*, this function raises :exc:`PinNoPins`.
If multiple pins support the desired *function*, :exc:`PinMultiplePins`
will be raised (use :func:`physical_pins` if you expect multiple pins
in the result, such as for electrical ground).
:param str function:
The pin function you wish to search for. Usually this is something
like "GPIO9" for Broadcom GPIO pin 9.
"""
result = self.physical_pins(function)
if len(result) > 1:
raise PinMultiplePins('multiple pins can be used for %s' % function)
elif result:
return result.pop()
else:
raise PinNoPins('no pins can be used for %s' % function)
def pulled_up(self, function):
"""
Returns a bool indicating whether a physical pull-up is attached to
the pin supporting the specified *function*. Either :exc:`PinNoPins`
or :exc:`PinMultiplePins` may be raised if the function is not
associated with a single pin.
:param str function:
The pin function you wish to determine pull-up for. Usually this is
something like "GPIO9" for Broadcom GPIO pin 9.
"""
header, number = self.physical_pin(function)
return self.headers[header][number].pull_up
_PI_REVISION = None
def _get_pi_revision():
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('1000')
if overvolted:
revision = revision[4:]
return revision
raise IOError('unable to locate Pi revision in /proc/cpuinfo')
def _parse_pi_revision(revision):
# For new-style revisions the value's bit pattern is as follows:
#
# MSB -----------------------> LSB
# uuuuuuuuFMMMCCCCPPPPTTTTTTTTRRRR
#
# 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)
# 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)
# RRR - Revision (0, 1, or 2)
i = int(revision, base=16)
if not (i & 0x800000):
raise ValueError('cannot parse "%s"; this is not a new-style revision' % revision)
try:
model = {
0: 'A',
1: 'B',
2: 'A+',
3: 'B+',
4: '2B',
6: 'CM',
8: '3B',
9: 'Zero',
}[(i & 0xff0) >> 4]
if model in ('A', 'B'):
pcb_revision = {
0: '1.0', # is this right?
1: '1.0',
2: '2.0',
}[i & 0x0f]
else:
pcb_revision = '1.%d' % (i & 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',
}[model]
soc = {
0: 'BCM2835',
1: 'BCM2836',
2: 'BCM2837',
}[(i & 0xf000) >> 12]
manufacturer = {
0: 'Sony',
1: 'Egoman',
2: 'Embest',
}[(i & 0xf0000) >> 16]
memory = {
0: 256,
1: 512,
2: 1024,
}[(i & 0x700000) >> 20]
storage = {
'A': 'SD',
'B': 'SD',
'CM': 'eMMC',
}.get(model, 'MicroSD')
usb = {
'A': 1,
'A+': 1,
'Zero': 1,
'B': 2,
'CM': 0,
}.get(model, 4)
ethernet = {
'A': 0,
'A+': 0,
'Zero': 0,
'CM': 0,
}.get(model, 1)
wifi = {
'3B': True,
}.get(model, False)
bluetooth = {
'3B': True,
}.get(model, False)
csi = {
'Zero': 0,
'CM': 2,
}.get(model, 1)
dsi = 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},
}.get(model, {'P1': PLUS_P1})
except KeyError:
raise ValueError('unable to parse new-style revision "%s"' % revision)
else:
return (
model,
pcb_revision,
released,
soc,
manufacturer,
memory,
storage,
usb,
ethernet,
wifi,
bluetooth,
csi,
dsi,
headers,
)
def pi_info(revision=None):
"""
Returns a :class:`PiBoardInfo` instance containing information about a
*revision* of the Raspberry Pi.
:param str revision:
The revision of the Pi to return information about. If this is omitted
or ``None`` (the default), then the library will attempt to determine
the model of Pi it is running on and return information about that.
"""
# cache the result as we can reasonably assume the revision of the Pi isn't
# going to change at runtime...
if revision is None:
global _PI_REVISION
if _PI_REVISION is None:
try:
_PI_REVISION = _get_pi_revision()
except IOError:
_PI_REVISION = 'unknown'
revision = _PI_REVISION
try:
(
model,
pcb_revision,
released,
soc,
manufacturer,
memory,
storage,
usb,
ethernet,
wifi,
bluetooth,
csi,
dsi,
headers,
) = PI_REVISIONS[revision]
except KeyError:
try:
(
model,
pcb_revision,
released,
soc,
manufacturer,
memory,
storage,
usb,
ethernet,
wifi,
bluetooth,
csi,
dsi,
headers,
) = _parse_pi_revision(revision)
except ValueError:
raise PinUnknownPi('unknown RPi revision "%s"' % revision)
headers = {
header: {
number: PinInfo(number, function, pull_up)
for number, (function, pull_up) in header_data.items()
}
for header, header_data in headers.items()
}
return PiBoardInfo(
revision,
model,
pcb_revision,
released,
soc,
manufacturer,
memory,
storage,
usb,
ethernet,
wifi,
bluetooth,
csi,
dsi,
headers,
)

View File

@@ -17,6 +17,7 @@ from threading import Thread, Event, Lock
from collections import Counter
from . import Pin, PINS_CLEANUP
from .data import pi_info
from ..exc import (
PinInvalidPull,
PinInvalidEdges,
@@ -198,10 +199,14 @@ class NativePin(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()}
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:
@@ -230,7 +235,7 @@ class NativePin(Pin):
self._change_thread = None
self._change_event = Event()
self.function = 'input'
self.pull = 'up' if number in (2, 3) else 'floating'
self.pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self.bounce = None
self.edges = 'both'
return self
@@ -245,7 +250,7 @@ class NativePin(Pin):
def close(self):
self.when_changed = None
self.function = 'input'
self.pull = 'up' if self.number in (2, 3) else 'floating'
self.pull = 'up' if self.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]
@@ -278,7 +283,7 @@ class NativePin(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._number in (2, 3):
if value != 'up' and self.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]

View File

@@ -9,6 +9,7 @@ str = type('')
import pigpio
from . import Pin
from .data import pi_info
from ..exc import (
PinInvalidFunction,
PinSetInput,
@@ -93,7 +94,14 @@ 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()}
PI_INFO = None
def __new__(cls, number, host='localhost', port=8888):
# XXX What about remote pins? This should probably be instance
# specific rather than class specific for pigpio. Need to check how
# to query remote info though...
if cls.PI_INFO is None:
cls.PI_INFO = pi_info()
try:
return cls._PINS[(host, port, number)]
except KeyError:
@@ -107,7 +115,7 @@ class PiGPIOPin(Pin):
self._host = host
self._port = port
self._number = number
self._pull = 'up' if number in (2, 3) else 'floating'
self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self._pwm = False
self._bounce = None
self._when_changed = None
@@ -150,7 +158,7 @@ class PiGPIOPin(Pin):
self.frequency = None
self.when_changed = None
self.function = 'input'
self.pull = 'up' if self.number in (2, 3) else 'floating'
self.pull = 'up' if self.PI_INFO.pulled_up('GPIO%d' % self.number) else 'floating'
def _get_function(self):
return self.GPIO_FUNCTION_NAMES[self._connection.get_mode(self._number)]
@@ -187,7 +195,7 @@ 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._number in (2, 3):
if value != 'up' and self.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])

View File

@@ -9,6 +9,7 @@ str = type('')
from RPi import GPIO
from . import Pin
from .data import pi_info
from ..exc import (
PinInvalidFunction,
PinSetInput,
@@ -71,17 +72,21 @@ class RPiGPIOPin(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()}
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)
cls._PINS[number] = self
self._number = number
self._pull = 'up' if number in (2, 3) else 'floating'
self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self._pwm = None
self._frequency = None
self._duty_cycle = None
@@ -108,7 +113,7 @@ class RPiGPIOPin(Pin):
GPIO.setup(self._number, GPIO.OUT, initial=state)
def input_with_pull(self, pull):
if pull != 'up' and self._number in (2, 3):
if pull != 'up' and self.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])
@@ -154,7 +159,7 @@ class RPiGPIOPin(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._number in (2, 3):
if value != 'up' and self.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])

View File

@@ -14,6 +14,7 @@ import RPIO.PWM
from RPIO.Exceptions import InvalidChannelException
from . import Pin, PINS_CLEANUP
from .data import pi_info
from ..exc import (
PinInvalidFunction,
PinSetInput,
@@ -62,6 +63,8 @@ class RPIOPin(Pin):
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)
@@ -72,13 +75,15 @@ class RPIOPin(Pin):
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()
try:
return cls._PINS[number]
except KeyError:
self = super(RPIOPin, cls).__new__(cls)
cls._PINS[number] = self
self._number = number
self._pull = 'up' if number in (2, 3) else 'floating'
self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
self._pwm = False
self._duty_cycle = None
self._bounce = None
@@ -145,7 +150,7 @@ class RPIOPin(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._number in (2, 3):
if value != 'up' and self.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])