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.

334 lines
12 KiB

4 years ago
4 years ago
  1. """Detect boards."""
  2. import os
  3. import re
  4. # Allow for aligned constant definitions:
  5. # pylint: disable=bad-whitespace
  6. from adafruit_platformdetect.constants import boards, chips
  7. class Board:
  8. """Attempt to detect specific boards."""
  9. def __init__(self, detector):
  10. self.detector = detector
  11. # pylint: disable=invalid-name, too-many-branches, protected-access
  12. @property
  13. def id(self):
  14. """Return a unique id for the detected board, if any."""
  15. # There are some times we want to trick the platform detection
  16. # say if a raspberry pi doesn't have the right ID, or for testing
  17. try:
  18. return os.environ['BLINKA_FORCEBOARD']
  19. except KeyError: # no forced board, continue with testing!
  20. pass
  21. chip_id = self.detector.chip.id
  22. board_id = None
  23. if chip_id == chips.BCM2XXX:
  24. board_id = self._pi_id()
  25. elif chip_id == chips.AM33XX:
  26. board_id = self._beaglebone_id()
  27. elif chip_id == chips.GENERIC_X86:
  28. board_id = boards.GENERIC_LINUX_PC
  29. elif chip_id == chips.SUN8I:
  30. board_id = self._armbian_id()
  31. elif chip_id == chips.SAMA5:
  32. board_id = self._sama5_id()
  33. elif chip_id == chips.IMX8MX:
  34. board_id = self._imx8mx_id()
  35. elif chip_id == chips.ESP8266:
  36. board_id = boards.FEATHER_HUZZAH
  37. elif chip_id == chips.SAMD21:
  38. board_id = boards.FEATHER_M0_EXPRESS
  39. elif chip_id == chips.STM32:
  40. board_id = boards.PYBOARD
  41. elif chip_id == chips.S805:
  42. board_id = boards.ODROID_C1
  43. elif chip_id == chips.S905:
  44. board_id = boards.ODROID_C2
  45. elif chip_id == chips.S922X:
  46. board_id = boards.ODROID_N2
  47. elif chip_id == chips.FT232H:
  48. board_id = boards.FTDI_FT232H
  49. elif chip_id == chips.APQ8016:
  50. board_id = boards.DRAGONBOARD_410C
  51. elif chip_id in (chips.T210, chips.T186, chips.T194):
  52. board_id = self._tegra_id()
  53. elif chip_id == chips.HFU540:
  54. board_id = self._sifive_id()
  55. elif chip_id == chips.MCP2221:
  56. board_id = boards.MICROCHIP_MCP2221
  57. elif chip_id == chips.BINHO:
  58. board_id = boards.BINHO_NOVA
  59. elif chip_id == chips.MIPS24KC:
  60. board_id = boards.ONION_OMEGA
  61. elif chip_id == chips.MIPS24KEC:
  62. board_id = boards.ONION_OMEGA2
  63. elif chip_id == chips.A64:
  64. board_id = self._pine64_id()
  65. return board_id
  66. # pylint: enable=invalid-name
  67. def _pi_id(self):
  68. """Try to detect id of a Raspberry Pi."""
  69. # Check for Pi boards:
  70. pi_rev_code = self._pi_rev_code()
  71. if pi_rev_code:
  72. for model, codes in boards._PI_REV_CODES.items():
  73. if pi_rev_code in codes:
  74. return model
  75. # We may be on a non-Raspbian OS, so try to lazily determine
  76. # the version based on `get_device_model`
  77. else:
  78. pi_model = self.detector.get_device_model()
  79. if pi_model:
  80. pi_model = pi_model.upper().replace(' ', '_')
  81. if "PLUS" in pi_model:
  82. re_model = re.search(r'(RASPBERRY_PI_\d).*([AB]_*)(PLUS)',
  83. pi_model)
  84. elif "CM" in pi_model: # untested for Compute Module
  85. re_model = re.search(r'(RASPBERRY_PI_CM)(\d)',
  86. pi_model)
  87. else: # untested for non-plus models
  88. re_model = re.search(r'(RASPBERRY_PI_\d).*([AB])',
  89. pi_model)
  90. if re_model:
  91. pi_model = "".join(re_model.groups())
  92. available_models = boards._PI_REV_CODES.keys()
  93. for model in available_models:
  94. if model == pi_model:
  95. return model
  96. return None
  97. def _pi_rev_code(self):
  98. """Attempt to find a Raspberry Pi revision code for this board."""
  99. # 2708 is Pi 1
  100. # 2709 is Pi 2
  101. # 2835 is Pi 3 (or greater) on 4.9.x kernel
  102. # Anything else is not a Pi.
  103. if self.detector.chip.id != chips.BCM2XXX:
  104. # Something else, not a Pi.
  105. return None
  106. rev = self.detector.get_cpuinfo_field('Revision')
  107. if rev is not None:
  108. return rev
  109. else:
  110. try:
  111. with open("/proc/device-tree/system/linux,revision", "rb") as revision:
  112. rev_bytes = revision.read()
  113. if rev_bytes[:1] == b'\x00':
  114. rev_bytes = rev_bytes[1:]
  115. return rev_bytes.hex()
  116. except FileNotFoundError:
  117. return None
  118. # pylint: disable=no-self-use
  119. def _beaglebone_id(self):
  120. """Try to detect id of a Beaglebone."""
  121. try:
  122. with open("/sys/bus/nvmem/devices/0-00500/nvmem", "rb") as eeprom:
  123. eeprom_bytes = eeprom.read(16)
  124. except FileNotFoundError:
  125. return None
  126. if eeprom_bytes[:4] != b'\xaaU3\xee':
  127. return None
  128. # special condition for BeagleBone Green rev. 1A
  129. # refer to GitHub issue #57 in this repo for more info
  130. if eeprom_bytes == b'\xaaU3\xeeA335BNLT\x1a\x00\x00\x00':
  131. return boards.BEAGLEBONE_GREEN
  132. id_string = eeprom_bytes[4:].decode("ascii")
  133. for model, bb_ids in boards._BEAGLEBONE_BOARD_IDS.items():
  134. for bb_id in bb_ids:
  135. if id_string == bb_id[1]:
  136. return model
  137. return None
  138. # pylint: enable=no-self-use
  139. # pylint: disable=too-many-return-statements
  140. def _armbian_id(self):
  141. """Check whether the current board is an OrangePi board."""
  142. board_value = self.detector.get_armbian_release_field('BOARD')
  143. board = None
  144. if board_value == "orangepipc":
  145. board = boards.ORANGE_PI_PC
  146. if board_value == "orangepi-r1":
  147. board = boards.ORANGE_PI_R1
  148. if board_value == "orangepizero":
  149. board = boards.ORANGE_PI_ZERO
  150. if board_value == "orangepione":
  151. board = boards.ORANGE_PI_ONE
  152. if board_value == "orangepilite":
  153. board = boards.ORANGE_PI_LITE
  154. if board_value == "orangepiplus2e":
  155. board = boards.ORANGE_PI_PLUS_2E
  156. if board_value == "orangepipcplus":
  157. board = boards.ORANGE_PI_PC_PLUS
  158. if board_value == "pinebook-a64":
  159. board = boards.PINEBOOK
  160. return board
  161. # pylint: enable=too-many-return-statements
  162. # pylint: enable=too-many-return-statements
  163. def _sama5_id(self):
  164. """Check what type sama5 board."""
  165. board_value = self.detector.get_device_model()
  166. if "Giant Board" in board_value:
  167. return boards.GIANT_BOARD
  168. return None
  169. def _imx8mx_id(self):
  170. """Check what type iMX8M board."""
  171. board_value = self.detector.get_device_model()
  172. if "Phanbell" in board_value:
  173. return boards.CORAL_EDGE_TPU_DEV
  174. return None
  175. def _tegra_id(self):
  176. """Try to detect the id of aarch64 board."""
  177. compatible = self.detector.get_device_compatible()
  178. if not compatible:
  179. return None
  180. compats = compatible.split('\x00')
  181. for board_id, board_compats in boards._JETSON_IDS.items():
  182. if any(v in compats for v in board_compats):
  183. return board_id
  184. return None
  185. def _sifive_id(self):
  186. """Try to detect the id for Sifive RISCV64 board."""
  187. board_value = self.detector.get_device_model()
  188. if 'hifive-unleashed-a00' in board_value:
  189. return boards.SIFIVE_UNLEASHED
  190. return None
  191. def _pine64_id(self):
  192. """Try to detect the id for Pine64 board or device."""
  193. board_value = self.detector.get_device_model()
  194. board = None
  195. if 'pine64' in board_value.lower():
  196. board = boards.PINE64
  197. elif 'pinebook' in board_value.lower():
  198. board = boards.PINEBOOK
  199. elif 'pinephone' in board_value.lower():
  200. board = boards.PINEPHONE
  201. return board
  202. @property
  203. def any_96boards(self):
  204. """Check whether the current board is any 96boards board."""
  205. return self.id in boards._LINARO_96BOARDS_IDS
  206. @property
  207. def any_raspberry_pi(self):
  208. """Check whether the current board is any Raspberry Pi."""
  209. return self._pi_rev_code() is not None
  210. @property
  211. def any_raspberry_pi_40_pin(self):
  212. """Check whether the current board is any 40-pin Raspberry Pi."""
  213. return self.id in boards._RASPBERRY_PI_40_PIN_IDS
  214. @property
  215. def any_raspberry_pi_cm(self):
  216. """Check whether the current board is any Compute Module Raspberry Pi."""
  217. return self.id in boards._RASPBERRY_PI_CM_IDS
  218. @property
  219. def any_beaglebone(self):
  220. """Check whether the current board is any Beaglebone-family system."""
  221. return self.id in boards._BEAGLEBONE_IDS
  222. @property
  223. def any_orange_pi(self):
  224. """Check whether the current board is any defined Orange Pi."""
  225. return self.id in boards._ORANGE_PI_IDS
  226. @property
  227. def any_coral_board(self):
  228. """Check whether the current board is any defined Coral."""
  229. return self.CORAL_EDGE_TPU_DEV
  230. @property
  231. def any_giant_board(self):
  232. """Check whether the current board is any defined Giant Board."""
  233. return self.GIANT_BOARD
  234. @property
  235. def any_odroid_40_pin(self):
  236. """Check whether the current board is any defined 40-pin Odroid."""
  237. return self.id in boards._ODROID_40_PIN_IDS
  238. @property
  239. def any_jetson_board(self):
  240. """Check whether the current board is any defined Jetson Board."""
  241. return self.id in boards._JETSON_IDS
  242. @property
  243. def any_sifive_board(self):
  244. """Check whether the current board is any defined Jetson Board."""
  245. return self.id in boards._SIFIVE_IDS
  246. @property
  247. def any_onion_omega_board(self):
  248. """Check whether the current board is any defined OpenWRT board."""
  249. return self.id in boards._ONION_OMEGA_BOARD_IDS
  250. @property
  251. def any_pine64_board(self):
  252. """Check whether the current board is any Pine64 device."""
  253. return self.id in boards._PINE64_DEV_IDS
  254. @property
  255. def any_embedded_linux(self):
  256. """Check whether the current board is any embedded Linux device."""
  257. return any(
  258. [
  259. self.any_raspberry_pi, self.any_beaglebone, self.any_orange_pi,
  260. self.any_giant_board, self.any_jetson_board, self.any_coral_board,
  261. self.any_odroid_40_pin, self.any_96boards, self.any_sifive_board,
  262. self.any_onion_omega_board, self.any_pine64_board,
  263. ]
  264. )
  265. @property
  266. def ftdi_ft232h(self):
  267. """Check whether the current board is an FTDI FT232H."""
  268. return self.id == boards.FTDI_FT232H
  269. @property
  270. def microchip_mcp2221(self):
  271. """Check whether the current board is a Microchip MCP2221."""
  272. return self.id == boards.MICROCHIP_MCP2221
  273. @property
  274. def binho_nova(self):
  275. """Check whether the current board is an BINHO NOVA."""
  276. return self.id == boards.BINHO_NOVA
  277. def __getattr__(self, attr):
  278. """
  279. Detect whether the given attribute is the currently-detected board. See list
  280. of constants at the top of this module for available options.
  281. """
  282. if self.id == attr:
  283. return True
  284. return False