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.

499 lines
17 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. # The MIT License (MIT)
  2. #
  3. # Copyright (c) 2020 Melissa LeBlanc-Williams for Adafruit Industries
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. # THE SOFTWARE.
  22. """
  23. `adafruit_platformdetect.board`
  24. ================================================================================
  25. Detect boards
  26. * Author(s): Melissa LeBlanc-Williams
  27. Implementation Notes
  28. --------------------
  29. **Software and Dependencies:**
  30. * Linux and Python 3.5 or Higher
  31. """
  32. # imports
  33. import os
  34. import re
  35. from adafruit_platformdetect.constants import boards, chips
  36. __version__ = "0.0.0-auto.0"
  37. __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PlatformDetect.git"
  38. class Board:
  39. """Attempt to detect specific boards."""
  40. def __init__(self, detector):
  41. self.detector = detector
  42. # pylint: disable=invalid-name, protected-access
  43. @property
  44. def id(self):
  45. """Return a unique id for the detected board, if any."""
  46. # There are some times we want to trick the platform detection
  47. # say if a raspberry pi doesn't have the right ID, or for testing
  48. try:
  49. return os.environ["BLINKA_FORCEBOARD"]
  50. except KeyError: # no forced board, continue with testing!
  51. pass
  52. chip_id = self.detector.chip.id
  53. board_id = None
  54. if chip_id == chips.BCM2XXX:
  55. board_id = self._pi_id()
  56. elif chip_id == chips.AM33XX:
  57. board_id = self._beaglebone_id()
  58. elif chip_id == chips.GENERIC_X86:
  59. board_id = boards.GENERIC_LINUX_PC
  60. elif chip_id == chips.SUN8I:
  61. board_id = self._armbian_id()
  62. elif chip_id == chips.SAMA5:
  63. board_id = self._sama5_id()
  64. elif chip_id == chips.IMX8MX:
  65. board_id = self._imx8mx_id()
  66. elif chip_id == chips.ESP8266:
  67. board_id = boards.FEATHER_HUZZAH
  68. elif chip_id == chips.SAMD21:
  69. board_id = boards.FEATHER_M0_EXPRESS
  70. elif chip_id == chips.STM32F405:
  71. board_id = boards.PYBOARD
  72. elif chip_id == chips.S805:
  73. board_id = boards.ODROID_C1
  74. elif chip_id == chips.S905:
  75. board_id = boards.ODROID_C2
  76. elif chip_id == chips.S905X3:
  77. board_id = boards.ODROID_C4
  78. elif chip_id == chips.S922X:
  79. board_id = boards.ODROID_N2
  80. elif chip_id == chips.EXYNOS5422:
  81. board_id = boards.ODROID_XU4
  82. elif chip_id == chips.FT232H:
  83. board_id = boards.FTDI_FT232H
  84. elif chip_id == chips.APQ8016:
  85. board_id = boards.DRAGONBOARD_410C
  86. elif chip_id in (chips.T210, chips.T186, chips.T194):
  87. board_id = self._tegra_id()
  88. elif chip_id == chips.HFU540:
  89. board_id = self._sifive_id()
  90. elif chip_id == chips.MCP2221:
  91. board_id = boards.MICROCHIP_MCP2221
  92. elif chip_id == chips.BINHO:
  93. board_id = boards.BINHO_NOVA
  94. elif chip_id == chips.LPC4330:
  95. board_id = boards.GREATFET_ONE
  96. elif chip_id == chips.MIPS24KC:
  97. board_id = boards.ONION_OMEGA
  98. elif chip_id == chips.MIPS24KEC:
  99. board_id = boards.ONION_OMEGA2
  100. elif chip_id == chips.ZYNQ7000:
  101. board_id = self._pynq_id()
  102. elif chip_id == chips.A64:
  103. board_id = self._pine64_id()
  104. elif chip_id == chips.A33:
  105. board_id = self._clockwork_pi_id()
  106. elif chip_id == chips.RK3308:
  107. board_id = self._rock_pi_id()
  108. elif chip_id == chips.RK3288:
  109. board_id = self._asus_tinker_board_id()
  110. elif chip_id == chips.RYZEN_V1605B:
  111. board_id = self._udoo_id()
  112. elif chip_id == chips.PENTIUM_N3710:
  113. board_id = self._udoo_id()
  114. elif chip_id == chips.STM32MP157:
  115. board_id = self._stm32mp1_id()
  116. return board_id
  117. # pylint: enable=invalid-name
  118. def _pi_id(self):
  119. """Try to detect id of a Raspberry Pi."""
  120. # Check for Pi boards:
  121. pi_rev_code = self._pi_rev_code()
  122. if pi_rev_code:
  123. for model, codes in boards._PI_REV_CODES.items():
  124. if pi_rev_code in codes:
  125. return model
  126. # We may be on a non-Raspbian OS, so try to lazily determine
  127. # the version based on `get_device_model`
  128. else:
  129. pi_model = self.detector.get_device_model()
  130. if pi_model:
  131. pi_model = pi_model.upper().replace(" ", "_")
  132. if "PLUS" in pi_model:
  133. re_model = re.search(r"(RASPBERRY_PI_\d).*([AB]_*)(PLUS)", pi_model)
  134. elif "CM" in pi_model: # untested for Compute Module
  135. re_model = re.search(r"(RASPBERRY_PI_CM)(\d)", pi_model)
  136. else: # untested for non-plus models
  137. re_model = re.search(r"(RASPBERRY_PI_\d).*([AB])", pi_model)
  138. if re_model:
  139. pi_model = "".join(re_model.groups())
  140. available_models = boards._PI_REV_CODES.keys()
  141. for model in available_models:
  142. if model == pi_model:
  143. return model
  144. return None
  145. def _pi_rev_code(self):
  146. """Attempt to find a Raspberry Pi revision code for this board."""
  147. # 2708 is Pi 1
  148. # 2709 is Pi 2
  149. # 2835 is Pi 3 (or greater) on 4.9.x kernel
  150. # Anything else is not a Pi.
  151. if self.detector.chip.id != chips.BCM2XXX:
  152. # Something else, not a Pi.
  153. return None
  154. rev = self.detector.get_cpuinfo_field("Revision")
  155. if rev is not None:
  156. return rev
  157. try:
  158. with open("/proc/device-tree/system/linux,revision", "rb") as revision:
  159. rev_bytes = revision.read()
  160. if rev_bytes[:1] == b"\x00":
  161. rev_bytes = rev_bytes[1:]
  162. return rev_bytes.hex()
  163. except FileNotFoundError:
  164. return None
  165. # pylint: disable=no-self-use
  166. def _beaglebone_id(self):
  167. """Try to detect id of a Beaglebone."""
  168. try:
  169. with open("/sys/bus/nvmem/devices/0-00500/nvmem", "rb") as eeprom:
  170. eeprom_bytes = eeprom.read(16)
  171. except FileNotFoundError:
  172. return None
  173. if eeprom_bytes[:4] != b"\xaaU3\xee":
  174. return None
  175. # special condition for BeagleBone Green rev. 1A
  176. # refer to GitHub issue #57 in this repo for more info
  177. if eeprom_bytes == b"\xaaU3\xeeA335BNLT\x1a\x00\x00\x00":
  178. return boards.BEAGLEBONE_GREEN
  179. id_string = eeprom_bytes[4:].decode("ascii")
  180. for model, bb_ids in boards._BEAGLEBONE_BOARD_IDS.items():
  181. for bb_id in bb_ids:
  182. if id_string == bb_id[1]:
  183. return model
  184. return None
  185. # pylint: enable=no-self-use
  186. # pylint: disable=too-many-return-statements
  187. def _armbian_id(self):
  188. """Check whether the current board is an OrangePi board."""
  189. board_value = self.detector.get_armbian_release_field("BOARD")
  190. board = None
  191. if board_value == "orangepipc":
  192. board = boards.ORANGE_PI_PC
  193. if board_value == "orangepi-r1":
  194. board = boards.ORANGE_PI_R1
  195. if board_value == "orangepizero":
  196. board = boards.ORANGE_PI_ZERO
  197. if board_value == "orangepione":
  198. board = boards.ORANGE_PI_ONE
  199. if board_value == "orangepilite":
  200. board = boards.ORANGE_PI_LITE
  201. if board_value == "orangepiplus2e":
  202. board = boards.ORANGE_PI_PLUS_2E
  203. if board_value == "orangepipcplus":
  204. board = boards.ORANGE_PI_PC_PLUS
  205. if board_value == "pinebook-a64":
  206. board = boards.PINEBOOK
  207. if board_value == "orangepi2":
  208. board = boards.ORANGE_PI_2
  209. return board
  210. # pylint: enable=too-many-return-statements
  211. # pylint: enable=too-many-return-statements
  212. def _sama5_id(self):
  213. """Check what type sama5 board."""
  214. board_value = self.detector.get_device_model()
  215. if "Giant Board" in board_value:
  216. return boards.GIANT_BOARD
  217. return None
  218. def _stm32mp1_id(self):
  219. """Check what type stm32mp1 board."""
  220. board_value = self.detector.get_device_model()
  221. if "STM32MP157C-DK2" in board_value:
  222. return boards.STM32MP157C_DK2
  223. return None
  224. def _imx8mx_id(self):
  225. """Check what type iMX8M board."""
  226. board_value = self.detector.get_device_model()
  227. if "Phanbell" in board_value:
  228. return boards.CORAL_EDGE_TPU_DEV
  229. return None
  230. def _tegra_id(self):
  231. """Try to detect the id of aarch64 board."""
  232. compatible = self.detector.get_device_compatible()
  233. if not compatible:
  234. return None
  235. compats = compatible.split("\x00")
  236. for board_id, board_compats in boards._JETSON_IDS.items():
  237. if any(v in compats for v in board_compats):
  238. return board_id
  239. return None
  240. def _sifive_id(self):
  241. """Try to detect the id for Sifive RISCV64 board."""
  242. board_value = self.detector.get_device_model()
  243. if "hifive-unleashed-a00" in board_value:
  244. return boards.SIFIVE_UNLEASHED
  245. return None
  246. def _pine64_id(self):
  247. """Try to detect the id for Pine64 board or device."""
  248. board_value = self.detector.get_device_model()
  249. board = None
  250. if "pine64" in board_value.lower():
  251. board = boards.PINE64
  252. elif "pinebook" in board_value.lower():
  253. board = boards.PINEBOOK
  254. elif "pinephone" in board_value.lower():
  255. board = boards.PINEPHONE
  256. return board
  257. # pylint: disable=no-self-use
  258. def _pynq_id(self):
  259. """Try to detect the id for Xilinx PYNQ boards."""
  260. try:
  261. with open("/proc/device-tree/chosen/pynq_board", "r") as board_file:
  262. board_model = board_file.read()
  263. match = board_model.upper().replace("-", "_").rstrip("\x00")
  264. for model in boards._PYNQ_IDS:
  265. if model == match:
  266. return model
  267. return None
  268. except FileNotFoundError:
  269. return None
  270. def _rock_pi_id(self):
  271. """Check what type of Rock Pi board."""
  272. board_value = self.detector.get_device_model()
  273. board = None
  274. if board_value and "ROCK Pi S" in board_value:
  275. board = boards.ROCK_PI_S
  276. return board
  277. def _clockwork_pi_id(self):
  278. """Check what type of Clockwork Pi board."""
  279. board_value = self.detector.get_device_model()
  280. board = None
  281. if board_value and "Clockwork CPI3" in board_value:
  282. board = boards.CLOCKWORK_CPI3
  283. return board
  284. def _udoo_id(self):
  285. """Try to detect the id of udoo board."""
  286. board_asset_tag = self.detector.check_board_asset_tag_value()
  287. for board_id, board_tags in boards._UDOO_BOARD_IDS.items():
  288. if any(v == board_asset_tag for v in board_tags):
  289. return board_id
  290. if self.detector.check_board_name_value() == "UDOO x86":
  291. return boards.UDOO_X86
  292. return None
  293. def _asus_tinker_board_id(self):
  294. """Check what type of Tinker Board."""
  295. board_value = self.detector.get_device_model()
  296. board = None
  297. if board_value and "ASUS Tinker Board" in board_value:
  298. board = boards._ASUS_TINKER_BOARD_IDS
  299. return board
  300. @property
  301. def any_96boards(self):
  302. """Check whether the current board is any 96boards board."""
  303. return self.id in boards._LINARO_96BOARDS_IDS
  304. @property
  305. def any_raspberry_pi(self):
  306. """Check whether the current board is any Raspberry Pi."""
  307. return self._pi_rev_code() is not None
  308. @property
  309. def any_raspberry_pi_40_pin(self):
  310. """Check whether the current board is any 40-pin Raspberry Pi."""
  311. return self.id in boards._RASPBERRY_PI_40_PIN_IDS
  312. @property
  313. def any_raspberry_pi_cm(self):
  314. """Check whether the current board is any Compute Module Raspberry Pi."""
  315. return self.id in boards._RASPBERRY_PI_CM_IDS
  316. @property
  317. def any_beaglebone(self):
  318. """Check whether the current board is any Beaglebone-family system."""
  319. return self.id in boards._BEAGLEBONE_IDS
  320. @property
  321. def any_orange_pi(self):
  322. """Check whether the current board is any defined Orange Pi."""
  323. return self.id in boards._ORANGE_PI_IDS
  324. @property
  325. def any_coral_board(self):
  326. """Check whether the current board is any defined Coral."""
  327. return self.CORAL_EDGE_TPU_DEV
  328. @property
  329. def any_pynq_board(self):
  330. """Check whether the current board is any defined PYNQ Board."""
  331. return self.id in boards._PYNQ_IDS
  332. @property
  333. def any_giant_board(self):
  334. """Check whether the current board is any defined Giant Board."""
  335. return self.GIANT_BOARD
  336. @property
  337. def any_odroid_40_pin(self):
  338. """Check whether the current board is any defined 40-pin Odroid."""
  339. return self.id in boards._ODROID_40_PIN_IDS
  340. @property
  341. def any_jetson_board(self):
  342. """Check whether the current board is any defined Jetson Board."""
  343. return self.id in boards._JETSON_IDS
  344. @property
  345. def any_sifive_board(self):
  346. """Check whether the current board is any defined Jetson Board."""
  347. return self.id in boards._SIFIVE_IDS
  348. @property
  349. def any_onion_omega_board(self):
  350. """Check whether the current board is any defined OpenWRT board."""
  351. return self.id in boards._ONION_OMEGA_BOARD_IDS
  352. @property
  353. def any_pine64_board(self):
  354. """Check whether the current board is any Pine64 device."""
  355. return self.id in boards._PINE64_DEV_IDS
  356. @property
  357. def any_rock_pi_board(self):
  358. """Check whether the current board is any Clockwork Pi device."""
  359. return self.ROCK_PI_S
  360. @property
  361. def any_clockwork_pi_board(self):
  362. """Check whether the current board is any Clockwork Pi device."""
  363. return self.CLOCKWORK_CPI3
  364. @property
  365. def any_udoo_board(self):
  366. """Check to see if the current board is an UDOO board"""
  367. return self.id in boards._UDOO_BOARD_IDS
  368. @property
  369. def any_asus_tinker_board(self):
  370. """Check to see if the current board is an ASUS Tinker Board"""
  371. return self.id in boards._ASUS_TINKER_BOARD_IDS
  372. @property
  373. def any_stm32mp1(self):
  374. """Check whether the current board is any stm32mp1 board."""
  375. return self.id in boards._STM32MP1_IDS
  376. @property
  377. def any_embedded_linux(self):
  378. """Check whether the current board is any embedded Linux device."""
  379. return any(
  380. [
  381. self.any_raspberry_pi,
  382. self.any_beaglebone,
  383. self.any_orange_pi,
  384. self.any_giant_board,
  385. self.any_jetson_board,
  386. self.any_coral_board,
  387. self.any_odroid_40_pin,
  388. self.any_96boards,
  389. self.any_sifive_board,
  390. self.any_onion_omega_board,
  391. self.any_pine64_board,
  392. self.any_pynq_board,
  393. self.any_rock_pi_board,
  394. self.any_clockwork_pi_board,
  395. self.any_udoo_board,
  396. self.any_asus_tinker_board,
  397. self.any_stm32mp1,
  398. ]
  399. )
  400. @property
  401. def ftdi_ft232h(self):
  402. """Check whether the current board is an FTDI FT232H."""
  403. return self.id == boards.FTDI_FT232H
  404. @property
  405. def microchip_mcp2221(self):
  406. """Check whether the current board is a Microchip MCP2221."""
  407. return self.id == boards.MICROCHIP_MCP2221
  408. @property
  409. def binho_nova(self):
  410. """Check whether the current board is an BINHO NOVA."""
  411. return self.id == boards.BINHO_NOVA
  412. @property
  413. def greatfet_one(self):
  414. """Check whether the current board is a GreatFET One."""
  415. return self.id == boards.GREATFET_ONE
  416. def __getattr__(self, attr):
  417. """
  418. Detect whether the given attribute is the currently-detected board. See list
  419. of constants at the top of this module for available options.
  420. """
  421. if self.id == attr:
  422. return True
  423. return False