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.

522 lines
16 KiB

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