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.

229 lines
7.3 KiB

  1. """Detect boards."""
  2. import adafruit_platformdetect.chip as ap_chip
  3. # Allow for aligned constant definitions:
  4. # pylint: disable=bad-whitespace
  5. BEAGLEBONE = 'BEAGLEBONE'
  6. BEAGLEBONE_BLACK = 'BEAGLEBONE_BLACK'
  7. BEAGLEBONE_BLUE = 'BEAGLEBONE_BLUE'
  8. BEAGLEBONE_BLACK_WIRELESS = 'BEAGLEBONE_BLACK_WIRELESS'
  9. BEAGLEBONE_POCKETBEAGLE = 'BEAGLEBONE_POCKETBEAGLE'
  10. BEAGLEBONE_GREEN = 'BEAGLEBONE_GREEN'
  11. BEAGLEBONE_GREEN_WIRELESS = 'BEAGLEBONE_GREEN_WIRELESS'
  12. BEAGLEBONE_BLACK_INDUSTRIAL = 'BEAGLEBONE_BLACK_INDUSTRIAL'
  13. BEAGLEBONE_ENHANCED = 'BEAGLEBONE_ENHANCED'
  14. BEAGLEBONE_USOMIQ = 'BEAGLEBONE_USOMIQ'
  15. BEAGLEBONE_AIR = 'BEAGLEBONE_AIR'
  16. BEAGLEBONE_POCKETBONE = 'BEAGLEBONE_POCKETBONE'
  17. BEAGLELOGIC_STANDALONE = 'BEAGLELOGIC_STANDALONE'
  18. OSD3358_DEV_BOARD = 'OSD3358_DEV_BOARD'
  19. OSD3358_SM_RED = 'OSD3358_SM_RED'
  20. FEATHER_HUZZAH = "FEATHER_HUZZAH"
  21. FEATHER_M0_EXPRESS = "FEATHER_M0_EXPRESS"
  22. GENERIC_LINUX_PC = "GENERIC_LINUX_PC"
  23. PYBOARD = "PYBOARD"
  24. NODEMCU = "NODEMCU"
  25. ORANGE_PI_PC = "ORANGE_PI_PC"
  26. RASPBERRY_PI_B = "RASPBERRY_PI_B"
  27. RASPBERRY_PI_B_PLUS = "RASPBERRY_PI_B_PLUS"
  28. RASPBERRY_PI_A = "RASPBERRY_PI_A"
  29. RASPBERRY_PI_A_PLUS = "RASPBERRY_PI_A_PLUS"
  30. RASPBERRY_PI_CM1 = "RASPBERRY_PI_CM1"
  31. RASPBERRY_PI_ZERO = "RASPBERRY_PI_ZERO"
  32. RASPBERRY_PI_ZERO_W = "RASPBERRY_PI_ZERO_W"
  33. RASPBERRY_PI_2B = "RASPBERRY_PI_2B"
  34. RASPBERRY_PI_3B = "RASPBERRY_PI_3B"
  35. RASPBERRY_PI_3B_PLUS = "RASPBERRY_PI_3B_PLUS"
  36. RASPBERRY_PI_CM3 = "RASPBERRY_PI_CM3"
  37. RASPBERRY_PI_3A_PLUS = "RASPBERRY_PI_3A_PLUS"
  38. # pylint: enable=bad-whitespace
  39. ANY_RASPBERRY_PI_2_OR_3 = (
  40. RASPBERRY_PI_2B,
  41. RASPBERRY_PI_3B,
  42. RASPBERRY_PI_3B_PLUS
  43. )
  44. # BeagleBone eeprom board ids from:
  45. # https://github.com/beagleboard/image-builder
  46. # Thanks to zmatt on freenode #beagle for pointers.
  47. _BEAGLEBONE_BOARD_IDS = {
  48. # Original bone/white:
  49. BEAGLEBONE: (
  50. ('A4', 'A335BONE00A4'),
  51. ('A5', 'A335BONE00A5'),
  52. ('A6', 'A335BONE00A6'),
  53. ('A6A', 'A335BONE0A6A'),
  54. ('A6B', 'A335BONE0A6B'),
  55. ('B', 'A335BONE000B'),
  56. ),
  57. BEAGLEBONE_BLACK: (
  58. ('A5', 'A335BNLT00A5'),
  59. ('A5A', 'A335BNLT0A5A'),
  60. ('A5B', 'A335BNLT0A5B'),
  61. ('A5C', 'A335BNLT0A5C'),
  62. ('A6', 'A335BNLT00A6'),
  63. ('C', 'A335BNLT000C'),
  64. ('C', 'A335BNLT00C0'),
  65. ),
  66. BEAGLEBONE_BLUE: (
  67. ('A2', 'A335BNLTBLA2'),
  68. ),
  69. BEAGLEBONE_BLACK_WIRELESS: (
  70. ('A5', 'A335BNLTBWA5'),
  71. ),
  72. BEAGLEBONE_POCKETBEAGLE: (
  73. ('A2', 'A335PBGL00A2'),
  74. ),
  75. BEAGLEBONE_GREEN: (
  76. ('1A', 'A335BNLT....'),
  77. ('UNKNOWN', 'A335BNLTBBG1'),
  78. ),
  79. BEAGLEBONE_GREEN_WIRELESS: (
  80. ('W1A', 'A335BNLTGW1A'),
  81. ),
  82. BEAGLEBONE_BLACK_INDUSTRIAL: (
  83. ('A0', 'A335BNLTAIA0'), # Arrow
  84. ('A0', 'A335BNLTEIA0'), # Element14
  85. ),
  86. BEAGLEBONE_ENHANCED: (
  87. ('A', 'A335BNLTSE0A'),
  88. ),
  89. BEAGLEBONE_USOMIQ: (
  90. ('6', 'A335BNLTME06'),
  91. ),
  92. BEAGLEBONE_AIR: (
  93. ('A0', 'A335BNLTNAD0'),
  94. ),
  95. BEAGLEBONE_POCKETBONE: (
  96. ('0', 'A335BNLTBP00'),
  97. ),
  98. OSD3358_DEV_BOARD: (
  99. ('0.1', 'A335BNLTGH01'),
  100. ),
  101. OSD3358_SM_RED: (
  102. ('0', 'A335BNLTOS00'),
  103. ),
  104. BEAGLELOGIC_STANDALONE: (
  105. ('A', 'A335BLGC000A'),
  106. )
  107. }
  108. # Pi revision codes from:
  109. # https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
  110. _PI_REV_CODES = {
  111. RASPBERRY_PI_B: ('0002', '0003', '0004', '0005', '0006', '000d', '000e', '000f'),
  112. RASPBERRY_PI_B_PLUS: ('0010', '0013', '900032'),
  113. RASPBERRY_PI_A: ('0007', '0008', '0009'),
  114. RASPBERRY_PI_A_PLUS: ('0012', '0015', '900021'),
  115. RASPBERRY_PI_CM1: ('0011', '0014'),
  116. RASPBERRY_PI_ZERO: ('900092', '920092', '900093', '920093'),
  117. RASPBERRY_PI_ZERO_W: ('9000c1',),
  118. RASPBERRY_PI_2B: ('a01040', 'a01041', 'a21041', 'a22042'),
  119. RASPBERRY_PI_3B: ('a02082', 'a22082', 'a32082', 'a52082'),
  120. RASPBERRY_PI_3B_PLUS: ('a020d3',),
  121. RASPBERRY_PI_CM3: ('a020a0',),
  122. RASPBERRY_PI_3A_PLUS: ('9020e0',),
  123. }
  124. class Board:
  125. """Attempt to detect specific boards."""
  126. def __init__(self, detector):
  127. self.detector = detector
  128. # pylint: disable=invalid-name
  129. @property
  130. def id(self):
  131. """Return a unique id for the detected board, if any."""
  132. chip_id = self.detector.chip.id
  133. board_id = None
  134. if chip_id == ap_chip.BCM2XXX:
  135. board_id = self._pi_id()
  136. elif chip_id == ap_chip.AM33XX:
  137. board_id = self._beaglebone_id()
  138. elif chip_id == ap_chip.GENERIC_X86:
  139. board_id = GENERIC_LINUX_PC
  140. elif chip_id == ap_chip.SUN8I:
  141. board_id = self._armbian_id()
  142. elif chip_id == ap_chip.ESP8266:
  143. board_id = FEATHER_HUZZAH
  144. elif chip_id == ap_chip.SAMD21:
  145. board_id = FEATHER_M0_EXPRESS
  146. elif chip_id == ap_chip.STM32:
  147. board_id = PYBOARD
  148. return board_id
  149. # pylint: enable=invalid-name
  150. def _pi_id(self):
  151. """Try to detect id of a Raspberry Pi."""
  152. # Check for Pi boards:
  153. pi_rev_code = self._pi_rev_code()
  154. if pi_rev_code:
  155. for model, codes in _PI_REV_CODES.items():
  156. if pi_rev_code in codes:
  157. return model
  158. return None
  159. def _pi_rev_code(self):
  160. """Attempt to find a Raspberry Pi revision code for this board."""
  161. # 2708 is Pi 1
  162. # 2709 is Pi 2
  163. # 2835 is Pi 3 (or greater) on 4.9.x kernel
  164. # Anything else is not a Pi.
  165. if self.detector.chip.id != ap_chip.BCM2XXX:
  166. # Something else, not a Pi.
  167. return None
  168. return self.detector.get_cpuinfo_field('Revision')
  169. # pylint: disable=no-self-use
  170. def _beaglebone_id(self):
  171. """Try to detect id of a Beaglebone."""
  172. try:
  173. with open("/sys/bus/nvmem/devices/0-00500/nvmem", "rb") as eeprom:
  174. eeprom_bytes = eeprom.read(16)
  175. except FileNotFoundError:
  176. return None
  177. if eeprom_bytes[:4] != b'\xaaU3\xee':
  178. return None
  179. id_string = eeprom_bytes[4:].decode("ascii")
  180. for model, bb_ids in _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. def _armbian_id(self):
  187. """Check whether the current board is an OrangePi PC."""
  188. board_value = self.detector.get_armbian_release_field('BOARD')
  189. if board_value == "orangepipc":
  190. return ORANGE_PI_PC
  191. return None
  192. @property
  193. def any_raspberry_pi(self):
  194. """Check whether the current board is any Raspberry Pi."""
  195. return self._pi_rev_code() is not None
  196. @property
  197. def any_raspberry_pi_2_or_3(self):
  198. """Check whether the current board is any Raspberry Pi 2 or 3."""
  199. return self.id in ANY_RASPBERRY_PI_2_OR_3
  200. def __getattr__(self, attr):
  201. """
  202. Detect whether the given attribute is the currently-detected board. See list
  203. of constants at the top of this module for available options.
  204. """
  205. if self.id == attr:
  206. return True
  207. return False