Adafruit_Python_PlatformDetect/adafruit_platformdetect/board.py
bibekbasu 2051282bbd
Update board.py for nvidia Jetson boards
Recently, Model names are updated for Jetson Nvidia boards.
This change takes care of model name check of Jetson TX1 nano and Xavier. Change also adds support for
Quill derivatives like storm and lightning.
2019-08-12 15:59:12 +05:30

493 lines
15 KiB
Python

"""Detect boards."""
import os
import adafruit_platformdetect.chip as ap_chip
# Allow for aligned constant definitions:
# pylint: disable=bad-whitespace
BEAGLEBONE = 'BEAGLEBONE'
BEAGLEBONE_BLACK = 'BEAGLEBONE_BLACK'
BEAGLEBONE_BLUE = 'BEAGLEBONE_BLUE'
BEAGLEBONE_BLACK_WIRELESS = 'BEAGLEBONE_BLACK_WIRELESS'
BEAGLEBONE_POCKETBEAGLE = 'BEAGLEBONE_POCKETBEAGLE'
BEAGLEBONE_GREEN = 'BEAGLEBONE_GREEN'
BEAGLEBONE_GREEN_WIRELESS = 'BEAGLEBONE_GREEN_WIRELESS'
BEAGLEBONE_BLACK_INDUSTRIAL = 'BEAGLEBONE_BLACK_INDUSTRIAL'
BEAGLEBONE_ENHANCED = 'BEAGLEBONE_ENHANCED'
BEAGLEBONE_USOMIQ = 'BEAGLEBONE_USOMIQ'
BEAGLEBONE_AIR = 'BEAGLEBONE_AIR'
BEAGLEBONE_POCKETBONE = 'BEAGLEBONE_POCKETBONE'
BEAGLELOGIC_STANDALONE = 'BEAGLELOGIC_STANDALONE'
OSD3358_DEV_BOARD = 'OSD3358_DEV_BOARD'
OSD3358_SM_RED = 'OSD3358_SM_RED'
FEATHER_HUZZAH = "FEATHER_HUZZAH"
FEATHER_M0_EXPRESS = "FEATHER_M0_EXPRESS"
GENERIC_LINUX_PC = "GENERIC_LINUX_PC"
PYBOARD = "PYBOARD"
NODEMCU = "NODEMCU"
ORANGE_PI_PC = "ORANGE_PI_PC"
ORANGE_PI_R1 = "ORANGE_PI_R1"
GIANT_BOARD = "GIANT_BOARD"
# NVIDIA Jetson boards
JETSON_TX1 = 'JETSON_TX1'
JETSON_TX2 = 'JETSON_TX2'
JETSON_XAVIER = 'JETSON_XAVIER'
JETSON_NANO = 'JETSON_NANO'
# Google Coral dev board
CORAL_EDGE_TPU_DEV = "CORAL_EDGE_TPU_DEV"
# Various Raspberry Pi models
RASPBERRY_PI_B_REV1 = "RASPBERRY_PI_B_REV1"
RASPBERRY_PI_B_REV2 = "RASPBERRY_PI_B_REV2"
RASPBERRY_PI_B_PLUS = "RASPBERRY_PI_B_PLUS"
RASPBERRY_PI_A = "RASPBERRY_PI_A"
RASPBERRY_PI_A_PLUS = "RASPBERRY_PI_A_PLUS"
RASPBERRY_PI_CM1 = "RASPBERRY_PI_CM1"
RASPBERRY_PI_ZERO = "RASPBERRY_PI_ZERO"
RASPBERRY_PI_ZERO_W = "RASPBERRY_PI_ZERO_W"
RASPBERRY_PI_2B = "RASPBERRY_PI_2B"
RASPBERRY_PI_3B = "RASPBERRY_PI_3B"
RASPBERRY_PI_3B_PLUS = "RASPBERRY_PI_3B_PLUS"
RASPBERRY_PI_CM3 = "RASPBERRY_PI_CM3"
RASPBERRY_PI_3A_PLUS = "RASPBERRY_PI_3A_PLUS"
RASPBERRY_PI_CM3_PLUS = "RASPBERRY_PI_CM3_PLUS"
RASPBERRY_PI_4B = "RASPBERRY_PI_4B"
ODROID_C1 = "ODROID_C1"
ODROID_C1_PLUS = "ODROID_C1_PLUS"
ODROID_C2 = "ODROID_C2"
ODROID_N2 = "ODROID_N2"
FTDI_FT232H = "FT232H"
DRAGONBOARD_410C = "DRAGONBOARD_410C"
SIFIVE_UNLEASHED = "SIFIVE_UNLEASHED"
# pylint: enable=bad-whitespace
#OrangePI
_ORANGE_PI_IDS = (
ORANGE_PI_PC,
ORANGE_PI_R1
)
_CORAL_IDS = (
CORAL_EDGE_TPU_DEV,
)
_JETSON_IDS = (
JETSON_TX1,
JETSON_TX2,
JETSON_XAVIER,
JETSON_NANO
)
_RASPBERRY_PI_40_PIN_IDS = (
RASPBERRY_PI_B_PLUS,
RASPBERRY_PI_A_PLUS,
RASPBERRY_PI_ZERO,
RASPBERRY_PI_ZERO_W,
RASPBERRY_PI_2B,
RASPBERRY_PI_3B,
RASPBERRY_PI_3B_PLUS,
RASPBERRY_PI_3A_PLUS,
RASPBERRY_PI_4B
)
_RASPBERRY_PI_CM_IDS = (
RASPBERRY_PI_CM1,
RASPBERRY_PI_CM3,
RASPBERRY_PI_CM3_PLUS
)
_ODROID_40_PIN_IDS = (
ODROID_C1,
ODROID_C1_PLUS,
ODROID_C2,
ODROID_N2
)
_BEAGLEBONE_IDS = (
BEAGLEBONE,
BEAGLEBONE_BLACK,
BEAGLEBONE_BLUE,
BEAGLEBONE_BLACK_WIRELESS,
BEAGLEBONE_POCKETBEAGLE,
BEAGLEBONE_GREEN,
BEAGLEBONE_GREEN_WIRELESS,
BEAGLEBONE_BLACK_INDUSTRIAL,
BEAGLEBONE_ENHANCED,
BEAGLEBONE_USOMIQ,
BEAGLEBONE_AIR,
BEAGLEBONE_POCKETBONE,
BEAGLELOGIC_STANDALONE,
OSD3358_DEV_BOARD,
OSD3358_SM_RED,
)
_LINARO_96BOARDS_IDS = (
DRAGONBOARD_410C,
)
_SIFIVE_IDS = (
SIFIVE_UNLEASHED,
)
# BeagleBone eeprom board ids from:
# https://github.com/beagleboard/image-builder
# Thanks to zmatt on freenode #beagle for pointers.
_BEAGLEBONE_BOARD_IDS = {
# Original bone/white:
BEAGLEBONE: (
('A4', 'A335BONE00A4'),
('A5', 'A335BONE00A5'),
('A6', 'A335BONE00A6'),
('A6A', 'A335BONE0A6A'),
('A6B', 'A335BONE0A6B'),
('B', 'A335BONE000B'),
),
BEAGLEBONE_BLACK: (
('A5', 'A335BNLT00A5'),
('A5A', 'A335BNLT0A5A'),
('A5B', 'A335BNLT0A5B'),
('A5C', 'A335BNLT0A5C'),
('A6', 'A335BNLT00A6'),
('C', 'A335BNLT000C'),
('C', 'A335BNLT00C0'),
),
BEAGLEBONE_BLUE: (
('A2', 'A335BNLTBLA2'),
),
BEAGLEBONE_BLACK_WIRELESS: (
('A5', 'A335BNLTBWA5'),
),
BEAGLEBONE_POCKETBEAGLE: (
('A2', 'A335PBGL00A2'),
),
BEAGLEBONE_GREEN: (
('1A', 'A335BNLT....'),
('UNKNOWN', 'A335BNLTBBG1'),
),
BEAGLEBONE_GREEN_WIRELESS: (
('W1A', 'A335BNLTGW1A'),
),
BEAGLEBONE_BLACK_INDUSTRIAL: (
('A0', 'A335BNLTAIA0'), # Arrow
('A0', 'A335BNLTEIA0'), # Element14
),
BEAGLEBONE_ENHANCED: (
('A', 'A335BNLTSE0A'),
),
BEAGLEBONE_USOMIQ: (
('6', 'A335BNLTME06'),
),
BEAGLEBONE_AIR: (
('A0', 'A335BNLTNAD0'),
),
BEAGLEBONE_POCKETBONE: (
('0', 'A335BNLTBP00'),
),
OSD3358_DEV_BOARD: (
('0.1', 'A335BNLTGH01'),
),
OSD3358_SM_RED: (
('0', 'A335BNLTOS00'),
),
BEAGLELOGIC_STANDALONE: (
('A', 'A335BLGC000A'),
)
}
# Pi revision codes from:
# https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
# Each tuple here contains both the base codes, and the versions that indicate
# the Pi is overvolted / overclocked - for 4-digit codes, this will be prefixed
# with 1000, and for 6-digit codes it'll be prefixed with 1. These are placed
# on separate lines.
_PI_REV_CODES = {
RASPBERRY_PI_B_REV1: (
# Regular codes:
'0002', '0003',
# Overvolted/clocked versions:
'1000002', '1000003',
),
RASPBERRY_PI_B_REV2: (
'0005', '0006', '000d', '000e', '000f',
'1000005', '1000006', '100000d', '100000e', '100000f',
),
RASPBERRY_PI_B_PLUS: (
'0010', '0013', '900032',
'1000010', '1000013', '1900032',
),
RASPBERRY_PI_A: (
'0007', '0008', '0009',
'1000007', '1000008', '1000009',
),
RASPBERRY_PI_A_PLUS: (
'0012', '0015', '900021',
'1000012', '1000015', '1900021',
),
RASPBERRY_PI_CM1: (
'0011', '0014',
'10000011', '10000014',
),
RASPBERRY_PI_ZERO: (
'900092', '920092', '900093', '920093',
'1900092', '1920092', '1900093', '1920093', # warranty bit 24
'2900092', '2920092', '2900093', '2920093', # warranty bit 25
),
RASPBERRY_PI_ZERO_W: (
'9000c1',
'19000c1', '29000c1', # warranty bits
),
RASPBERRY_PI_2B: (
'a01040', 'a01041', 'a21041', 'a22042',
'1a01040', '1a01041', '1a21041', '1a22042', # warranty bit 24
'2a01040', '2a01041', '2a21041', '2a22042', # warranty bit 25
),
RASPBERRY_PI_3B: (
'a02082', 'a22082', 'a32082', 'a52082',
'1a02082', '1a22082', '1a32082', '1a52082', # warranty bit 24
'2a02082', '2a22082', '2a32082', '2a52082', # warranty bit 25
),
RASPBERRY_PI_3B_PLUS: (
'a020d3',
'1a020d3', '2a020d3', # warranty bits
),
RASPBERRY_PI_CM3: (
'a020a0', 'a220a0',
'1a020a0', '2a020a0', # warranty bits
'1a220a0', '2a220a0',
),
RASPBERRY_PI_3A_PLUS: (
'9020e0',
'19020e0', '29020e0', # warranty bits
),
RASPBERRY_PI_CM3_PLUS: (
'a02100',
'1a02100', '2a02100', # warranty bits
),
RASPBERRY_PI_4B: (
'a03111', 'b03111', 'c03111',
'1a03111', '2a03111', '1b03111', '2b03111', # warranty bits
'1c03111', '2c03111',
),
}
class Board:
"""Attempt to detect specific boards."""
def __init__(self, detector):
self.detector = detector
# pylint: disable=invalid-name, too-many-branches
@property
def id(self):
"""Return a unique id for the detected board, if any."""
# There are some times we want to trick the platform detection
# say if a raspberry pi doesn't have the right ID, or for testing
try:
return os.environ['BLINKA_FORCEBOARD']
except KeyError: # no forced board, continue with testing!
pass
chip_id = self.detector.chip.id
board_id = None
if chip_id == ap_chip.BCM2XXX:
board_id = self._pi_id()
elif chip_id == ap_chip.AM33XX:
board_id = self._beaglebone_id()
elif chip_id == ap_chip.GENERIC_X86:
board_id = GENERIC_LINUX_PC
elif chip_id == ap_chip.SUN8I:
board_id = self._armbian_id()
elif chip_id == ap_chip.SAMA5:
board_id = self._sama5_id()
elif chip_id == ap_chip.IMX8MX:
board_id = self._imx8mx_id()
elif chip_id == ap_chip.ESP8266:
board_id = FEATHER_HUZZAH
elif chip_id == ap_chip.SAMD21:
board_id = FEATHER_M0_EXPRESS
elif chip_id == ap_chip.STM32:
board_id = PYBOARD
elif chip_id == ap_chip.S805:
board_id = ODROID_C1
elif chip_id == ap_chip.S905:
board_id = ODROID_C2
elif chip_id == ap_chip.S922X:
board_id = ODROID_N2
elif chip_id == ap_chip.FT232H:
board_id = FTDI_FT232H
elif chip_id == ap_chip.APQ8016:
board_id = DRAGONBOARD_410C
elif chip_id in (ap_chip.T210, ap_chip.T186, ap_chip.T194):
board_id = self._tegra_id()
elif chip_id == ap_chip.HFU540:
board_id = self._sifive_id()
return board_id
# pylint: enable=invalid-name
def _pi_id(self):
"""Try to detect id of a Raspberry Pi."""
# Check for Pi boards:
pi_rev_code = self._pi_rev_code()
if pi_rev_code:
for model, codes in _PI_REV_CODES.items():
if pi_rev_code in codes:
return model
return None
def _pi_rev_code(self):
"""Attempt to find a Raspberry Pi revision code for this board."""
# 2708 is Pi 1
# 2709 is Pi 2
# 2835 is Pi 3 (or greater) on 4.9.x kernel
# Anything else is not a Pi.
if self.detector.chip.id != ap_chip.BCM2XXX:
# Something else, not a Pi.
return None
return self.detector.get_cpuinfo_field('Revision')
# pylint: disable=no-self-use
def _beaglebone_id(self):
"""Try to detect id of a Beaglebone."""
try:
with open("/sys/bus/nvmem/devices/0-00500/nvmem", "rb") as eeprom:
eeprom_bytes = eeprom.read(16)
except FileNotFoundError:
return None
if eeprom_bytes[:4] != b'\xaaU3\xee':
return None
id_string = eeprom_bytes[4:].decode("ascii")
for model, bb_ids in _BEAGLEBONE_BOARD_IDS.items():
for bb_id in bb_ids:
if id_string == bb_id[1]:
return model
return None
# pylint: enable=no-self-use
def _armbian_id(self):
"""Check whether the current board is an OrangePi PC or OrangePI R1."""
board_value = self.detector.get_armbian_release_field('BOARD')
if board_value == "orangepipc":
return ORANGE_PI_PC
if board_value == "orangepi-r1":
return ORANGE_PI_R1
return None
def _sama5_id(self):
"""Check what type sama5 board."""
board_value = self.detector.get_device_model()
if "Giant Board" in board_value:
return GIANT_BOARD
return None
def _imx8mx_id(self):
"""Check what type iMX8M board."""
board_value = self.detector.get_device_model()
if "Phanbell" in board_value:
return CORAL_EDGE_TPU_DEV
return None
def _tegra_id(self):
"""Try to detect the id of aarch64 board."""
board_value = self.detector.get_device_model()
board = None
if 'tx1' in board_value.lower():
board = JETSON_TX1
elif 'quill' in board_value or "storm" in board_value or "lightning" in board_value:
board = JETSON_TX2
elif 'xavier' in board_value.lower():
board = JETSON_XAVIER
elif 'nano' in board_value.lower():
board = JETSON_NANO
return board
def _sifive_id(self):
"""Try to detect the id for Sifive RISCV64 board."""
board_value = self.detector.get_device_model()
if 'hifive-unleashed-a00' in board_value:
return SIFIVE_UNLEASHED
return None
@property
def any_96boards(self):
"""Check whether the current board is any 96boards board."""
return self.id in _LINARO_96BOARDS_IDS
@property
def any_raspberry_pi(self):
"""Check whether the current board is any Raspberry Pi."""
return self._pi_rev_code() is not None
@property
def any_raspberry_pi_40_pin(self):
"""Check whether the current board is any 40-pin Raspberry Pi."""
return self.id in _RASPBERRY_PI_40_PIN_IDS
@property
def any_raspberry_pi_cm(self):
"""Check whether the current board is any Compute Module Raspberry Pi."""
return self.id in _RASPBERRY_PI_CM_IDS
@property
def any_beaglebone(self):
"""Check whether the current board is any Beaglebone-family system."""
return self.id in _BEAGLEBONE_IDS
@property
def any_orange_pi(self):
"""Check whether the current board is any defined Orange Pi."""
return self.id in _ORANGE_PI_IDS
@property
def any_coral_board(self):
"""Check whether the current board is any defined Coral."""
return self.CORAL_EDGE_TPU_DEV
@property
def any_giant_board(self):
"""Check whether the current board is any defined Giant Board."""
return self.GIANT_BOARD
@property
def any_odroid_40_pin(self):
"""Check whether the current board is any defined 40-pin Odroid."""
return self.id in _ODROID_40_PIN_IDS
@property
def any_jetson_board(self):
"""Check whether the current board is any defined Jetson Board."""
return self.id in _JETSON_IDS
@property
def any_sifive_board(self):
"""Check whether the current board is any defined Jetson Board."""
return self.id in _SIFIVE_IDS
@property
def any_embedded_linux(self):
"""Check whether the current board is any embedded Linux device."""
return self.any_raspberry_pi or self.any_beaglebone or \
self.any_orange_pi or self.any_giant_board or self.any_jetson_board or \
self.any_coral_board or self.any_odroid_40_pin or self.any_96boards or \
self.any_sifive_board
def __getattr__(self, attr):
"""
Detect whether the given attribute is the currently-detected board. See list
of constants at the top of this module for available options.
"""
if self.id == attr:
return True
return False