# Copyright (c) 2020 Canonical Ltd.
# Copyright (c) 2019, 2020 Dave Jones <dave@waveform.org.uk>
#
# This file is part of pibootctl.
#
# pibootctl is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pibootctl is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pibootctl. If not, see <https://www.gnu.org/licenses/>.
"""
The :mod:`pibootctl.info` module contains some simple routines for determining
information about the Pi that the application is running on.
.. autofunction:: get_board_revision
.. autofunction:: get_board_serial
.. autofunction:: get_board_type
.. autofunction:: get_board_types
.. autofunction:: get_board_mem
"""
import io
import struct
def _hexdump(filename, fmt='>L'):
try:
size = struct.calcsize(fmt)
with io.open(filename, 'rb') as f:
return struct.unpack(fmt, f.read(size))[0]
except FileNotFoundError:
return None
[docs]def get_board_revision():
"""
Return the Pi's board revision as an unsigned 32-bit integer number. This
is the same number as reported under "Revision" in :file:`/proc/cpuinfo`.
"""
return _hexdump('/proc/device-tree/system/linux,revision')
[docs]def get_board_serial():
"""
Return the Pi's serial number as an unsigned 64-bit integer number. This
can also be queried as "Serial" under :file:`/proc/cpuinfo`.
"""
return _hexdump('/proc/device-tree/system/linux,serial', '>Q')
[docs]def get_board_type():
"""
Return a string indicating the overall model of the Pi, e.g. "pi0w", "pi2",
or "pi3+". This is derived from the result of :func:`get_board_revision`
according to the Pi's `revision codes table`_.
.. _revision codes table:
https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
"""
try:
rev = get_board_revision()
if rev is None:
return None
if rev & 0x800000:
known_models = {
0x0: 'pi1', # a
0x1: 'pi1', # b
0x2: 'pi1', # a+
0x3: 'pi1', # b+
0x4: 'pi2',
0x5: 'pi1', # alpha prototype
0x6: 'pi1', # cm1
0x8: 'pi3',
0x9: 'pi0',
0xa: 'pi3', # cm3
0xc: 'pi0w',
0xd: 'pi3+', # 3b+
0xe: 'pi3+', # 3a+
0x10: 'pi3+', # cm3+
0x11: 'pi4',
0x13: 'pi400',
0x14: 'cm4',
}
model_id = rev >> 4 & 0xff
try:
return known_models[model_id]
except KeyError:
# Assume unknown IDs in excess of the maximum match the [pi4]
# section for now
if model_id > max(known_models.keys()):
return 'pi4'
else:
raise
else:
# All old-style revs are pi1 models (A, B, A+, B+, CM1)
return 'pi1'
except KeyError:
return None
[docs]def get_board_types():
"""
Return a set of strings used for matching the model of Pi against
configuration sections according to the `conditional filters table`_.
.. _conditional filters table:
https://www.raspberrypi.org/documentation/configuration/config-txt/conditional.md
"""
return {
None: set(),
'pi0': {'pi0'},
'pi0w': {'pi0', 'pi0w'},
'pi1': {'pi1'},
'pi2': {'pi2'},
'pi3': {'pi3'},
'pi3+': {'pi3', 'pi3+'},
'pi4': {'pi4'},
'pi400': {'pi4', 'pi400'},
'cm4': {'pi4', 'cm4'},
}[get_board_type()]
[docs]def get_board_mem():
"""
Return the amount of memory (in megabytes) present on the Pi, according to
the model returned by :func:`get_board_revision`.
"""
try:
rev = get_board_revision()
if rev is None:
return 0
if rev & 0x800000:
return {
0: 256,
1: 512,
2: 1024,
3: 2048,
4: 4096,
5: 8192,
}[rev >> 20 & 0x7]
else:
return {
0x0002: 256,
0x0003: 256,
0x0004: 256,
0x0005: 256,
0x0006: 256,
0x0007: 256,
0x0008: 256,
0x0009: 256,
0x0012: 256,
0x0015: 256, # sometimes 512
0x000d: 512,
0x000e: 512,
0x000f: 512,
0x0010: 512,
0x0011: 512,
0x0013: 512,
0x0014: 512,
}[rev]
except KeyError:
return 0
def get_display_id(display=None):
raise NotImplementedError