You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

619 lines
19 KiB

  1. """Detect boards."""
  2. import os
  3. import re
  4. import adafruit_platformdetect.chip as ap_chip
  5. # Allow for aligned constant definitions:
  6. # pylint: disable=bad-whitespace
  7. BEAGLEBONE = 'BEAGLEBONE'
  8. BEAGLEBONE_BLACK = 'BEAGLEBONE_BLACK'
  9. BEAGLEBONE_BLUE = 'BEAGLEBONE_BLUE'
  10. BEAGLEBONE_BLACK_WIRELESS = 'BEAGLEBONE_BLACK_WIRELESS'
  11. BEAGLEBONE_POCKETBEAGLE = 'BEAGLEBONE_POCKETBEAGLE'
  12. BEAGLEBONE_GREEN = 'BEAGLEBONE_GREEN'
  13. BEAGLEBONE_GREEN_WIRELESS = 'BEAGLEBONE_GREEN_WIRELESS'
  14. BEAGLEBONE_BLACK_INDUSTRIAL = 'BEAGLEBONE_BLACK_INDUSTRIAL'
  15. BEAGLEBONE_ENHANCED = 'BEAGLEBONE_ENHANCED'
  16. BEAGLEBONE_USOMIQ = 'BEAGLEBONE_USOMIQ'
  17. BEAGLEBONE_AIR = 'BEAGLEBONE_AIR'
  18. BEAGLEBONE_POCKETBONE = 'BEAGLEBONE_POCKETBONE'
  19. BEAGLELOGIC_STANDALONE = 'BEAGLELOGIC_STANDALONE'
  20. OSD3358_DEV_BOARD = 'OSD3358_DEV_BOARD'
  21. OSD3358_SM_RED = 'OSD3358_SM_RED'
  22. FEATHER_HUZZAH = "FEATHER_HUZZAH"
  23. FEATHER_M0_EXPRESS = "FEATHER_M0_EXPRESS"
  24. GENERIC_LINUX_PC = "GENERIC_LINUX_PC"
  25. PYBOARD = "PYBOARD"
  26. NODEMCU = "NODEMCU"
  27. GIANT_BOARD = "GIANT_BOARD"
  28. # Orange Pi boards
  29. ORANGE_PI_PC = "ORANGE_PI_PC"
  30. ORANGE_PI_R1 = "ORANGE_PI_R1"
  31. ORANGE_PI_ZERO = "ORANGE_PI_ZERO"
  32. ORANGE_PI_ONE = "ORANGE_PI_ONE"
  33. ORANGE_PI_LITE = "ORANGE_PI_LITE"
  34. ORANGE_PI_PC_PLUS = "ORANGE_PI_PC_PLUS"
  35. ORANGE_PI_PLUS_2E = "ORANGE_PI_PLUS_2E"
  36. # NVIDIA Jetson boards
  37. JETSON_TX1 = 'JETSON_TX1'
  38. JETSON_TX2 = 'JETSON_TX2'
  39. JETSON_XAVIER = 'JETSON_XAVIER'
  40. JETSON_NANO = 'JETSON_NANO'
  41. # Google Coral dev board
  42. CORAL_EDGE_TPU_DEV = "CORAL_EDGE_TPU_DEV"
  43. # Various Raspberry Pi models
  44. RASPBERRY_PI_B_REV1 = "RASPBERRY_PI_B_REV1"
  45. RASPBERRY_PI_B_REV2 = "RASPBERRY_PI_B_REV2"
  46. RASPBERRY_PI_B_PLUS = "RASPBERRY_PI_B_PLUS"
  47. RASPBERRY_PI_A = "RASPBERRY_PI_A"
  48. RASPBERRY_PI_A_PLUS = "RASPBERRY_PI_A_PLUS"
  49. RASPBERRY_PI_CM1 = "RASPBERRY_PI_CM1"
  50. RASPBERRY_PI_ZERO = "RASPBERRY_PI_ZERO"
  51. RASPBERRY_PI_ZERO_W = "RASPBERRY_PI_ZERO_W"
  52. RASPBERRY_PI_2B = "RASPBERRY_PI_2B"
  53. RASPBERRY_PI_3B = "RASPBERRY_PI_3B"
  54. RASPBERRY_PI_3B_PLUS = "RASPBERRY_PI_3B_PLUS"
  55. RASPBERRY_PI_CM3 = "RASPBERRY_PI_CM3"
  56. RASPBERRY_PI_3A_PLUS = "RASPBERRY_PI_3A_PLUS"
  57. RASPBERRY_PI_CM3_PLUS = "RASPBERRY_PI_CM3_PLUS"
  58. RASPBERRY_PI_4B = "RASPBERRY_PI_4B"
  59. ODROID_C1 = "ODROID_C1"
  60. ODROID_C1_PLUS = "ODROID_C1_PLUS"
  61. ODROID_C2 = "ODROID_C2"
  62. ODROID_N2 = "ODROID_N2"
  63. FTDI_FT232H = "FTDI_FT232H"
  64. DRAGONBOARD_410C = "DRAGONBOARD_410C"
  65. SIFIVE_UNLEASHED = "SIFIVE_UNLEASHED"
  66. MICROCHIP_MCP2221 = "MICROCHIP_MCP2221"
  67. BINHO_NOVA = "BINHO_NOVA"
  68. ONION_OMEGA = "ONION_OMEGA"
  69. ONION_OMEGA2 = "ONION_OMEGA2"
  70. PINE64 = "PINE64"
  71. PINEBOOK = "PINEBOOK"
  72. PINEPHONE = "PINEPHONE"
  73. # pylint: enable=bad-whitespace
  74. #OrangePI
  75. _ORANGE_PI_IDS = (
  76. ORANGE_PI_PC,
  77. ORANGE_PI_R1,
  78. ORANGE_PI_ZERO,
  79. ORANGE_PI_ONE,
  80. ORANGE_PI_LITE,
  81. ORANGE_PI_PC_PLUS,
  82. ORANGE_PI_PLUS_2E,
  83. )
  84. _CORAL_IDS = (
  85. CORAL_EDGE_TPU_DEV,
  86. )
  87. _JETSON_IDS = (
  88. JETSON_TX1,
  89. JETSON_TX2,
  90. JETSON_XAVIER,
  91. JETSON_NANO
  92. )
  93. _RASPBERRY_PI_40_PIN_IDS = (
  94. RASPBERRY_PI_B_PLUS,
  95. RASPBERRY_PI_A_PLUS,
  96. RASPBERRY_PI_ZERO,
  97. RASPBERRY_PI_ZERO_W,
  98. RASPBERRY_PI_2B,
  99. RASPBERRY_PI_3B,
  100. RASPBERRY_PI_3B_PLUS,
  101. RASPBERRY_PI_3A_PLUS,
  102. RASPBERRY_PI_4B
  103. )
  104. _RASPBERRY_PI_CM_IDS = (
  105. RASPBERRY_PI_CM1,
  106. RASPBERRY_PI_CM3,
  107. RASPBERRY_PI_CM3_PLUS
  108. )
  109. _ODROID_40_PIN_IDS = (
  110. ODROID_C1,
  111. ODROID_C1_PLUS,
  112. ODROID_C2,
  113. ODROID_N2
  114. )
  115. _BEAGLEBONE_IDS = (
  116. BEAGLEBONE,
  117. BEAGLEBONE_BLACK,
  118. BEAGLEBONE_BLUE,
  119. BEAGLEBONE_BLACK_WIRELESS,
  120. BEAGLEBONE_POCKETBEAGLE,
  121. BEAGLEBONE_GREEN,
  122. BEAGLEBONE_GREEN_WIRELESS,
  123. BEAGLEBONE_BLACK_INDUSTRIAL,
  124. BEAGLEBONE_ENHANCED,
  125. BEAGLEBONE_USOMIQ,
  126. BEAGLEBONE_AIR,
  127. BEAGLEBONE_POCKETBONE,
  128. BEAGLELOGIC_STANDALONE,
  129. OSD3358_DEV_BOARD,
  130. OSD3358_SM_RED,
  131. )
  132. _LINARO_96BOARDS_IDS = (
  133. DRAGONBOARD_410C,
  134. )
  135. _SIFIVE_IDS = (
  136. SIFIVE_UNLEASHED,
  137. )
  138. # BeagleBone eeprom board ids from:
  139. # https://github.com/beagleboard/image-builder
  140. # Thanks to zmatt on freenode #beagle for pointers.
  141. _BEAGLEBONE_BOARD_IDS = {
  142. # Original bone/white:
  143. BEAGLEBONE: (
  144. ('A4', 'A335BONE00A4'),
  145. ('A5', 'A335BONE00A5'),
  146. ('A6', 'A335BONE00A6'),
  147. ('A6A', 'A335BONE0A6A'),
  148. ('A6B', 'A335BONE0A6B'),
  149. ('B', 'A335BONE000B'),
  150. ),
  151. BEAGLEBONE_BLACK: (
  152. ('A5', 'A335BNLT00A5'),
  153. ('A5A', 'A335BNLT0A5A'),
  154. ('A5B', 'A335BNLT0A5B'),
  155. ('A5C', 'A335BNLT0A5C'),
  156. ('A6', 'A335BNLT00A6'),
  157. ('C', 'A335BNLT000C'),
  158. ('C', 'A335BNLT00C0'),
  159. ),
  160. BEAGLEBONE_BLUE: (
  161. ('A2', 'A335BNLTBLA2'),
  162. ),
  163. BEAGLEBONE_BLACK_WIRELESS: (
  164. ('A5', 'A335BNLTBWA5'),
  165. ),
  166. BEAGLEBONE_POCKETBEAGLE: (
  167. ('A2', 'A335PBGL00A2'),
  168. ),
  169. BEAGLEBONE_GREEN: (
  170. ('1A', 'A335BNLT....'),
  171. ('UNKNOWN', 'A335BNLTBBG1'),
  172. ),
  173. BEAGLEBONE_GREEN_WIRELESS: (
  174. ('W1A', 'A335BNLTGW1A'),
  175. ),
  176. BEAGLEBONE_BLACK_INDUSTRIAL: (
  177. ('A0', 'A335BNLTAIA0'), # Arrow
  178. ('A0', 'A335BNLTEIA0'), # Element14
  179. ),
  180. BEAGLEBONE_ENHANCED: (
  181. ('A', 'A335BNLTSE0A'),
  182. ),
  183. BEAGLEBONE_USOMIQ: (
  184. ('6', 'A335BNLTME06'),
  185. ),
  186. BEAGLEBONE_AIR: (
  187. ('A0', 'A335BNLTNAD0'),
  188. ),
  189. BEAGLEBONE_POCKETBONE: (
  190. ('0', 'A335BNLTBP00'),
  191. ),
  192. OSD3358_DEV_BOARD: (
  193. ('0.1', 'A335BNLTGH01'),
  194. ),
  195. OSD3358_SM_RED: (
  196. ('0', 'A335BNLTOS00'),
  197. ),
  198. BEAGLELOGIC_STANDALONE: (
  199. ('A', 'A335BLGC000A'),
  200. )
  201. }
  202. # Pi revision codes from:
  203. # https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
  204. # Each tuple here contains both the base codes, and the versions that indicate
  205. # the Pi is overvolted / overclocked - for 4-digit codes, this will be prefixed
  206. # with 1000, and for 6-digit codes it'll be prefixed with 1. These are placed
  207. # on separate lines.
  208. _PI_REV_CODES = {
  209. RASPBERRY_PI_B_REV1: (
  210. # Regular codes:
  211. '0002', '0003',
  212. # Overvolted/clocked versions:
  213. '1000002', '1000003',
  214. ),
  215. RASPBERRY_PI_B_REV2: (
  216. '0005', '0006', '000d', '000e', '000f',
  217. '1000005', '1000006', '100000d', '100000e', '100000f',
  218. ),
  219. RASPBERRY_PI_B_PLUS: (
  220. '0010', '0013', '900032',
  221. '1000010', '1000013', '1900032',
  222. ),
  223. RASPBERRY_PI_A: (
  224. '0007', '0008', '0009',
  225. '1000007', '1000008', '1000009',
  226. ),
  227. RASPBERRY_PI_A_PLUS: (
  228. '0012', '0015', '900021',
  229. '1000012', '1000015', '1900021',
  230. ),
  231. RASPBERRY_PI_CM1: (
  232. '0011', '0014',
  233. '10000011', '10000014',
  234. ),
  235. RASPBERRY_PI_ZERO: (
  236. '900092', '920092', '900093', '920093',
  237. '1900092', '1920092', '1900093', '1920093', # warranty bit 24
  238. '2900092', '2920092', '2900093', '2920093', # warranty bit 25
  239. ),
  240. RASPBERRY_PI_ZERO_W: (
  241. '9000c1',
  242. '19000c1', '29000c1', # warranty bits
  243. ),
  244. RASPBERRY_PI_2B: (
  245. 'a01040', 'a01041', 'a21041', 'a22042',
  246. '1a01040', '1a01041', '1a21041', '1a22042', # warranty bit 24
  247. '2a01040', '2a01041', '2a21041', '2a22042', # warranty bit 25
  248. ),
  249. RASPBERRY_PI_3B: (
  250. 'a02082', 'a22082', 'a32082', 'a52082',
  251. '1a02082', '1a22082', '1a32082', '1a52082', # warranty bit 24
  252. '2a02082', '2a22082', '2a32082', '2a52082', # warranty bit 25
  253. ),
  254. RASPBERRY_PI_3B_PLUS: (
  255. 'a020d3',
  256. '1a020d3', '2a020d3', # warranty bits
  257. ),
  258. RASPBERRY_PI_CM3: (
  259. 'a020a0', 'a220a0',
  260. '1a020a0', '2a020a0', # warranty bits
  261. '1a220a0', '2a220a0',
  262. ),
  263. RASPBERRY_PI_3A_PLUS: (
  264. '9020e0',
  265. '19020e0', '29020e0', # warranty bits
  266. ),
  267. RASPBERRY_PI_CM3_PLUS: (
  268. 'a02100',
  269. '1a02100', '2a02100', # warranty bits
  270. ),
  271. RASPBERRY_PI_4B: (
  272. 'a03111', 'b03111', 'c03111',
  273. 'a03112', 'b03112', 'c03112',
  274. '1a03111', '2a03111', '1b03111', '2b03111', # warranty bits
  275. '1c03111', '2c03111', '1a03112', '2a03112',
  276. '1b03112', '2b03112', '1c03112', '2c03112',
  277. ),
  278. }
  279. # Onion omega boards
  280. _ONION_OMEGA_BOARD_IDS = (
  281. ONION_OMEGA,
  282. ONION_OMEGA2,
  283. )
  284. # Pine64 boards and devices
  285. _PINE64_DEV_IDS = (
  286. PINE64,
  287. PINEBOOK,
  288. PINEPHONE
  289. )
  290. class Board:
  291. """Attempt to detect specific boards."""
  292. def __init__(self, detector):
  293. self.detector = detector
  294. # pylint: disable=invalid-name, too-many-branches
  295. @property
  296. def id(self):
  297. """Return a unique id for the detected board, if any."""
  298. # There are some times we want to trick the platform detection
  299. # say if a raspberry pi doesn't have the right ID, or for testing
  300. try:
  301. return os.environ['BLINKA_FORCEBOARD']
  302. except KeyError: # no forced board, continue with testing!
  303. pass
  304. chip_id = self.detector.chip.id
  305. board_id = None
  306. if chip_id == ap_chip.BCM2XXX:
  307. board_id = self._pi_id()
  308. elif chip_id == ap_chip.AM33XX:
  309. board_id = self._beaglebone_id()
  310. elif chip_id == ap_chip.GENERIC_X86:
  311. board_id = GENERIC_LINUX_PC
  312. elif chip_id == ap_chip.SUN8I:
  313. board_id = self._armbian_id()
  314. elif chip_id == ap_chip.SAMA5:
  315. board_id = self._sama5_id()
  316. elif chip_id == ap_chip.IMX8MX:
  317. board_id = self._imx8mx_id()
  318. elif chip_id == ap_chip.ESP8266:
  319. board_id = FEATHER_HUZZAH
  320. elif chip_id == ap_chip.SAMD21:
  321. board_id = FEATHER_M0_EXPRESS
  322. elif chip_id == ap_chip.STM32:
  323. board_id = PYBOARD
  324. elif chip_id == ap_chip.S805:
  325. board_id = ODROID_C1
  326. elif chip_id == ap_chip.S905:
  327. board_id = ODROID_C2
  328. elif chip_id == ap_chip.S922X:
  329. board_id = ODROID_N2
  330. elif chip_id == ap_chip.FT232H:
  331. board_id = FTDI_FT232H
  332. elif chip_id == ap_chip.APQ8016:
  333. board_id = DRAGONBOARD_410C
  334. elif chip_id in (ap_chip.T210, ap_chip.T186, ap_chip.T194):
  335. board_id = self._tegra_id()
  336. elif chip_id == ap_chip.HFU540:
  337. board_id = self._sifive_id()
  338. elif chip_id == ap_chip.MCP2221:
  339. board_id = MICROCHIP_MCP2221
  340. elif chip_id == ap_chip.BINHO:
  341. board_id = BINHO_NOVA
  342. elif chip_id == ap_chip.MIPS24KC:
  343. board_id = ONION_OMEGA
  344. elif chip_id == ap_chip.MIPS24KEC:
  345. board_id = ONION_OMEGA2
  346. elif chip_id == ap_chip.A64:
  347. board_id = self._pine64_id()
  348. return board_id
  349. # pylint: enable=invalid-name
  350. def _pi_id(self):
  351. """Try to detect id of a Raspberry Pi."""
  352. # Check for Pi boards:
  353. pi_rev_code = self._pi_rev_code()
  354. if pi_rev_code:
  355. for model, codes in _PI_REV_CODES.items():
  356. if pi_rev_code in codes:
  357. return model
  358. # We may be on a non-Raspbian OS, so try to lazily determine
  359. # the version based on `get_device_model`
  360. else:
  361. pi_model = self.detector.get_device_model()
  362. if pi_model:
  363. pi_model = pi_model.upper().replace(' ', '_')
  364. if "PLUS" in pi_model:
  365. re_model = re.search(r'(RASPBERRY_PI_\d).*([AB]_*)(PLUS)',
  366. pi_model)
  367. elif "CM" in pi_model: # untested for Compute Module
  368. re_model = re.search(r'(RASPBERRY_PI_CM)(\d)',
  369. pi_model)
  370. else: # untested for non-plus models
  371. re_model = re.search(r'(RASPBERRY_PI_\d).*([AB]_*)',
  372. pi_model)
  373. if re_model:
  374. pi_model = "".join(re_model.groups())
  375. available_models = _PI_REV_CODES.keys()
  376. for model in available_models:
  377. if model == pi_model:
  378. return model
  379. return None
  380. def _pi_rev_code(self):
  381. """Attempt to find a Raspberry Pi revision code for this board."""
  382. # 2708 is Pi 1
  383. # 2709 is Pi 2
  384. # 2835 is Pi 3 (or greater) on 4.9.x kernel
  385. # Anything else is not a Pi.
  386. if self.detector.chip.id != ap_chip.BCM2XXX:
  387. # Something else, not a Pi.
  388. return None
  389. return self.detector.get_cpuinfo_field('Revision')
  390. # pylint: disable=no-self-use
  391. def _beaglebone_id(self):
  392. """Try to detect id of a Beaglebone."""
  393. try:
  394. with open("/sys/bus/nvmem/devices/0-00500/nvmem", "rb") as eeprom:
  395. eeprom_bytes = eeprom.read(16)
  396. except FileNotFoundError:
  397. return None
  398. if eeprom_bytes[:4] != b'\xaaU3\xee':
  399. return None
  400. id_string = eeprom_bytes[4:].decode("ascii")
  401. for model, bb_ids in _BEAGLEBONE_BOARD_IDS.items():
  402. for bb_id in bb_ids:
  403. if id_string == bb_id[1]:
  404. return model
  405. return None
  406. # pylint: enable=no-self-use
  407. # pylint: disable=too-many-return-statements
  408. def _armbian_id(self):
  409. """Check whether the current board is an OrangePi PC or OrangePI R1."""
  410. board_value = self.detector.get_armbian_release_field('BOARD')
  411. if board_value == "orangepipc":
  412. return ORANGE_PI_PC
  413. if board_value == "orangepi-r1":
  414. return ORANGE_PI_R1
  415. if board_value == "orangepizero":
  416. return ORANGE_PI_ZERO
  417. if board_value == "orangepione":
  418. return ORANGE_PI_ONE
  419. if board_value == "orangepilite":
  420. return ORANGE_PI_LITE
  421. if board_value == "orangepiplus2e":
  422. return ORANGE_PI_PLUS_2E
  423. if board_value == "orangepipcplus":
  424. return ORANGE_PI_PC_PLUS
  425. if board_value == "pinebook-a64":
  426. return PINEBOOK
  427. return None
  428. # pylint: enable=too-many-return-statements
  429. def _sama5_id(self):
  430. """Check what type sama5 board."""
  431. board_value = self.detector.get_device_model()
  432. if "Giant Board" in board_value:
  433. return GIANT_BOARD
  434. return None
  435. def _imx8mx_id(self):
  436. """Check what type iMX8M board."""
  437. board_value = self.detector.get_device_model()
  438. if "Phanbell" in board_value:
  439. return CORAL_EDGE_TPU_DEV
  440. return None
  441. def _tegra_id(self):
  442. """Try to detect the id of aarch64 board."""
  443. board_value = self.detector.get_device_model()
  444. board = None
  445. if 'tx1' in board_value.lower():
  446. board = JETSON_TX1
  447. elif 'quill' in board_value or "storm" in board_value or "lightning" in board_value:
  448. board = JETSON_TX2
  449. elif 'xavier' in board_value.lower() or 'agx' in board_value.lower():
  450. board = JETSON_XAVIER
  451. elif 'nano' in board_value.lower():
  452. board = JETSON_NANO
  453. return board
  454. def _sifive_id(self):
  455. """Try to detect the id for Sifive RISCV64 board."""
  456. board_value = self.detector.get_device_model()
  457. if 'hifive-unleashed-a00' in board_value:
  458. return SIFIVE_UNLEASHED
  459. return None
  460. def _pine64_id(self):
  461. """Try to detect the id for Pine64 board or device."""
  462. board_value = self.detector.get_device_model()
  463. board = None
  464. if 'pine64' in board_value.lower():
  465. board = PINE64
  466. elif 'pinebook' in board_value.lower():
  467. board = PINEBOOK
  468. elif 'pinephone' in board_value.lower():
  469. board = PINEPHONE
  470. return board
  471. @property
  472. def any_96boards(self):
  473. """Check whether the current board is any 96boards board."""
  474. return self.id in _LINARO_96BOARDS_IDS
  475. @property
  476. def any_raspberry_pi(self):
  477. """Check whether the current board is any Raspberry Pi."""
  478. return self._pi_rev_code() is not None
  479. @property
  480. def any_raspberry_pi_40_pin(self):
  481. """Check whether the current board is any 40-pin Raspberry Pi."""
  482. return self.id in _RASPBERRY_PI_40_PIN_IDS
  483. @property
  484. def any_raspberry_pi_cm(self):
  485. """Check whether the current board is any Compute Module Raspberry Pi."""
  486. return self.id in _RASPBERRY_PI_CM_IDS
  487. @property
  488. def any_beaglebone(self):
  489. """Check whether the current board is any Beaglebone-family system."""
  490. return self.id in _BEAGLEBONE_IDS
  491. @property
  492. def any_orange_pi(self):
  493. """Check whether the current board is any defined Orange Pi."""
  494. return self.id in _ORANGE_PI_IDS
  495. @property
  496. def any_coral_board(self):
  497. """Check whether the current board is any defined Coral."""
  498. return self.CORAL_EDGE_TPU_DEV
  499. @property
  500. def any_giant_board(self):
  501. """Check whether the current board is any defined Giant Board."""
  502. return self.GIANT_BOARD
  503. @property
  504. def any_odroid_40_pin(self):
  505. """Check whether the current board is any defined 40-pin Odroid."""
  506. return self.id in _ODROID_40_PIN_IDS
  507. @property
  508. def any_jetson_board(self):
  509. """Check whether the current board is any defined Jetson Board."""
  510. return self.id in _JETSON_IDS
  511. @property
  512. def any_sifive_board(self):
  513. """Check whether the current board is any defined Jetson Board."""
  514. return self.id in _SIFIVE_IDS
  515. @property
  516. def any_onion_omega_board(self):
  517. """Check whether the current board is any defined OpenWRT board."""
  518. return self.id in _ONION_OMEGA_BOARD_IDS
  519. @property
  520. def any_pine64_board(self):
  521. """Check whether the current board is any Pine64 device."""
  522. return self.id in _PINE64_DEV_IDS
  523. @property
  524. def any_embedded_linux(self):
  525. """Check whether the current board is any embedded Linux device."""
  526. return self.any_raspberry_pi or self.any_beaglebone or \
  527. self.any_orange_pi or self.any_giant_board or self.any_jetson_board or \
  528. self.any_coral_board or self.any_odroid_40_pin or self.any_96boards or \
  529. self.any_sifive_board or self.any_onion_omega_board or self.any_pine64_board
  530. @property
  531. def ftdi_ft232h(self):
  532. """Check whether the current board is an FTDI FT232H."""
  533. return self.id == FTDI_FT232H
  534. @property
  535. def microchip_mcp2221(self):
  536. """Check whether the current board is a Microchip MCP2221."""
  537. return self.id == MICROCHIP_MCP2221
  538. @property
  539. def binho_nova(self):
  540. """Check whether the current board is an BINHO NOVA."""
  541. return self.id == BINHO_NOVA
  542. def __getattr__(self, attr):
  543. """
  544. Detect whether the given attribute is the currently-detected board. See list
  545. of constants at the top of this module for available options.
  546. """
  547. if self.id == attr:
  548. return True
  549. return False