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.

442 lines
14 KiB

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