Python library for working with the PD Buddy Sink Serial Console Configuration Interface
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

__init__.py 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. """Unit tests for the top-level pdbuddy classes"""
  2. import unittest
  3. import pdbuddy
  4. class SinkTestCase(unittest.TestCase):
  5. def setUp(self):
  6. # Get devices
  7. pdbs_devices = list(pdbuddy.Sink.get_devices())
  8. # If there are no devices, skip the test
  9. if len(pdbs_devices) == 0:
  10. self.skipTest("No PD Buddy Sink devices found")
  11. # Open the first device
  12. self.pdbs = pdbuddy.Sink(pdbs_devices[0])
  13. self.obj_valid = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  14. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  15. i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  16. self.obj_valid_gb = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  17. flags=pdbuddy.SinkFlags.GIVEBACK, v=15000, vmin=None,
  18. vmax=None, i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  19. self.obj_range = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  20. flags=pdbuddy.SinkFlags.HV_PREFERRED, v=13800, vmin=12000,
  21. vmax=16000, i=2000, idim=pdbuddy.SinkDimension.CURRENT)
  22. self.obj_valid_p = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  23. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  24. i=35000, idim=pdbuddy.SinkDimension.POWER)
  25. self.obj_valid_r = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  26. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  27. i=10000, idim=pdbuddy.SinkDimension.RESISTANCE)
  28. self.obj_huge_v = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  29. flags=pdbuddy.SinkFlags.NONE, v=65536, vmin=None, vmax=None,
  30. i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  31. self.obj_big_v = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  32. flags=pdbuddy.SinkFlags.NONE, v=21001, vmin=None, vmax=None,
  33. i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  34. self.obj_neg_v = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  35. flags=pdbuddy.SinkFlags.NONE, v=-1, vmin=None, vmax=None,
  36. i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  37. self.obj_inv_range = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  38. flags=pdbuddy.SinkFlags.HV_PREFERRED, v=13800, vmin=16000,
  39. vmax=12000, i=2000, idim=pdbuddy.SinkDimension.CURRENT)
  40. self.obj_huge_i = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  41. flags=pdbuddy.SinkFlags.NONE, v=5000, vmin=None, vmax=None,
  42. i=65536, idim=pdbuddy.SinkDimension.CURRENT)
  43. self.obj_big_i = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  44. flags=pdbuddy.SinkFlags.NONE, v=5000, vmin=None, vmax=None,
  45. i=5001, idim=pdbuddy.SinkDimension.CURRENT)
  46. self.obj_neg_i = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  47. flags=pdbuddy.SinkFlags.NONE, v=5000, vmin=None, vmax=None,
  48. i=-1, idim=pdbuddy.SinkDimension.CURRENT)
  49. self.obj_neg_p = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  50. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  51. i=-1, idim=pdbuddy.SinkDimension.POWER)
  52. self.obj_neg_r = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  53. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  54. i=-1, idim=pdbuddy.SinkDimension.RESISTANCE)
  55. def tearDown(self):
  56. # Close the connection to the PD Buddy Sink
  57. self.pdbs.close()
  58. def test_identify(self):
  59. self.pdbs.identify()
  60. def test_help(self):
  61. help_text = self.pdbs.help()
  62. self.assertTrue(len(help_text) > 0)
  63. self.assertTrue(len(help_text[0]) > 0)
  64. def test_license(self):
  65. license_text = self.pdbs.license()
  66. self.assertTrue(len(license_text) > 0)
  67. self.assertTrue(len(license_text[0]) > 0)
  68. def test_set_tmpcfg_valid(self):
  69. self.pdbs.set_tmpcfg(self.obj_valid)
  70. self.assertEqual(self.pdbs.get_tmpcfg(), self.obj_valid)
  71. def test_set_tmpcfg_valid_gb(self):
  72. self.pdbs.set_tmpcfg(self.obj_valid_gb)
  73. self.assertEqual(self.pdbs.get_tmpcfg(), self.obj_valid_gb)
  74. def test_set_tmpcfg_range(self):
  75. self.pdbs.set_tmpcfg(self.obj_range)
  76. self.assertEqual(self.pdbs.get_tmpcfg(), self.obj_range)
  77. def test_set_tmpcfg_valid_p(self):
  78. self.pdbs.set_tmpcfg(self.obj_valid_p)
  79. self.assertEqual(self.pdbs.get_tmpcfg(), self.obj_valid_p)
  80. def test_set_tmpcfg_valid_r(self):
  81. self.pdbs.set_tmpcfg(self.obj_valid_r)
  82. self.assertEqual(self.pdbs.get_tmpcfg(), self.obj_valid_r)
  83. def test_set_tmpcfg_huge_v(self):
  84. with self.assertRaises(ValueError):
  85. self.pdbs.set_tmpcfg(self.obj_huge_v)
  86. def test_set_tmpcfg_big_v(self):
  87. with self.assertRaises(ValueError):
  88. self.pdbs.set_tmpcfg(self.obj_big_v)
  89. def test_set_tmpcfg_neg_v(self):
  90. with self.assertRaises(ValueError):
  91. self.pdbs.set_tmpcfg(self.obj_neg_v)
  92. def test_set_tmpcfg_inv_range(self):
  93. with self.assertRaises(ValueError):
  94. self.pdbs.set_tmpcfg(self.obj_inv_range)
  95. def test_set_tmpcfg_huge_i(self):
  96. with self.assertRaises(ValueError):
  97. self.pdbs.set_tmpcfg(self.obj_huge_i)
  98. def test_set_tmpcfg_big_i(self):
  99. with self.assertRaises(ValueError):
  100. self.pdbs.set_tmpcfg(self.obj_big_i)
  101. def test_set_tmpcfg_neg_i(self):
  102. with self.assertRaises(ValueError):
  103. self.pdbs.set_tmpcfg(self.obj_neg_i)
  104. def test_set_tmpcfg_neg_p(self):
  105. with self.assertRaises(ValueError):
  106. self.pdbs.set_tmpcfg(self.obj_neg_p)
  107. def test_set_tmpcfg_neg_r(self):
  108. with self.assertRaises(ValueError):
  109. self.pdbs.set_tmpcfg(self.obj_neg_r)
  110. def test_write(self):
  111. self.test_set_tmpcfg_valid()
  112. self.pdbs.write()
  113. self.assertEqual(self.pdbs.get_cfg(), self.obj_valid)
  114. def test_get_cfg_index(self):
  115. self.assertIsInstance(self.pdbs.get_cfg(0), pdbuddy.SinkConfig)
  116. def test_get_cfg_index_bad(self):
  117. with self.assertRaises(IndexError):
  118. self.pdbs.get_cfg(-1)
  119. def test_load(self):
  120. # Write obj_valid to flash
  121. self.test_write()
  122. # Write obj_valid_gb to tmpcfg
  123. self.test_set_tmpcfg_valid_gb()
  124. self.assertNotEqual(self.pdbs.get_cfg(), self.pdbs.get_tmpcfg())
  125. # Load flash to tmpcfg
  126. self.pdbs.load()
  127. self.assertEqual(self.pdbs.get_cfg(), self.pdbs.get_tmpcfg())
  128. def test_erase(self):
  129. self.pdbs.erase()
  130. with self.assertRaises(KeyError):
  131. self.pdbs.load()
  132. def test_context_manager(self):
  133. self.pdbs.close()
  134. with pdbuddy.Sink(list(pdbuddy.Sink.get_devices())[0]) as pdbs:
  135. # Test something with the conext manager. For example, this is
  136. # essentially test_get_cfg_index.
  137. self.assertIsInstance(pdbs.get_cfg(0), pdbuddy.SinkConfig)
  138. def test_output(self):
  139. try:
  140. self.pdbs.output = False
  141. self.assertFalse(self.pdbs.output)
  142. self.pdbs.output = True
  143. self.assertTrue(self.pdbs.output)
  144. except KeyError:
  145. self.skipTest("Command output not supported")
  146. except ValueError:
  147. self.skipTest("Unknown value returned by PD Buddy Sink")
  148. def test_get_source_cap(self):
  149. self.assertIsInstance(self.pdbs.get_source_cap(), list)
  150. def test_send_command_invalid(self):
  151. with self.assertRaises(KeyError):
  152. self.pdbs.send_command("foo bar")
  153. class SinkConfigTestCase(unittest.TestCase):
  154. def setUp(self):
  155. self.obj_none = pdbuddy.SinkConfig(status=None, flags=None, v=None,
  156. vmin=None, vmax=None, i=None, idim=None)
  157. self.obj_empty = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.EMPTY,
  158. flags=None, v=None, vmin=None, vmax=None, i=None, idim=None)
  159. self.obj_valid = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  160. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  161. i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  162. self.obj_invalid = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.INVALID,
  163. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  164. i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  165. self.obj_valid_gb = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  166. flags=pdbuddy.SinkFlags.GIVEBACK, v=15000, vmin=None,
  167. vmax=None, i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  168. self.obj_valid_5v = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  169. flags=pdbuddy.SinkFlags.NONE, v=5000, vmin=None, vmax=None,
  170. i=3000, idim=pdbuddy.SinkDimension.CURRENT)
  171. self.obj_valid_1a = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  172. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  173. i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  174. self.obj_valid_range = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  175. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=12000, vmax=16000,
  176. i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  177. self.obj_valid_hv = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  178. flags=pdbuddy.SinkFlags.HV_PREFERRED, v=15000, vmin=12000,
  179. vmax=16000, i=1000, idim=pdbuddy.SinkDimension.CURRENT)
  180. self.obj_valid_10w = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  181. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  182. i=10000, idim=pdbuddy.SinkDimension.POWER)
  183. self.obj_valid_10r = pdbuddy.SinkConfig(status=pdbuddy.SinkStatus.VALID,
  184. flags=pdbuddy.SinkFlags.NONE, v=15000, vmin=None, vmax=None,
  185. i=10000, idim=pdbuddy.SinkDimension.RESISTANCE)
  186. def test_str_none(self):
  187. self.assertEqual(str(self.obj_none), "No configuration")
  188. def test_str_empty(self):
  189. self.assertEqual(str(self.obj_empty), "status: empty")
  190. def test_str_valid(self):
  191. self.assertEqual(str(self.obj_valid),
  192. "status: valid\nflags: (none)\nv: 15.000 V\ni: 3.00 A")
  193. def test_str_invalid(self):
  194. self.assertEqual(str(self.obj_invalid),
  195. "status: invalid\nflags: (none)\nv: 15.000 V\ni: 3.00 A")
  196. def test_str_valid_gb(self):
  197. self.assertEqual(str(self.obj_valid_gb),
  198. "status: valid\nflags: GiveBack\nv: 15.000 V\ni: 3.00 A")
  199. def test_str_valid_5v(self):
  200. self.assertEqual(str(self.obj_valid_5v),
  201. "status: valid\nflags: (none)\nv: 5.000 V\ni: 3.00 A")
  202. def test_str_valid_1a(self):
  203. self.assertEqual(str(self.obj_valid_1a),
  204. "status: valid\nflags: (none)\nv: 15.000 V\ni: 1.00 A")
  205. def test_str_valid_range(self):
  206. self.assertEqual(str(self.obj_valid_range),
  207. "status: valid\nflags: (none)\nv: 15.000 V\nvmin: 12.000 V\n"
  208. "vmax: 16.000 V\ni: 1.00 A")
  209. def test_str_valid_hv(self):
  210. self.assertEqual(str(self.obj_valid_hv),
  211. "status: valid\nflags: HV_Preferred\nv: 15.000 V\n"
  212. "vmin: 12.000 V\nvmax: 16.000 V\ni: 1.00 A")
  213. def test_str_valid_10w(self):
  214. self.assertEqual(str(self.obj_valid_10w),
  215. "status: valid\nflags: (none)\nv: 15.000 V\np: 10.00 W")
  216. def test_str_valid_10r(self):
  217. self.assertEqual(str(self.obj_valid_10r),
  218. "status: valid\nflags: (none)\nv: 15.000 V\nr: 10.00 \u03A9")
  219. def test_from_text_none(self):
  220. ft_none = pdbuddy.SinkConfig.from_text([])
  221. self.assertEqual(ft_none, self.obj_none)
  222. def test_from_text_empty(self):
  223. ft_empty = pdbuddy.SinkConfig.from_text([b"status: empty"])
  224. self.assertEqual(ft_empty, self.obj_empty)
  225. def test_from_text_valid(self):
  226. ft_valid = pdbuddy.SinkConfig.from_text([b"status: valid",
  227. b"flags: (none)",
  228. b"v: 15.000 V",
  229. b"i: 3.00 A"])
  230. self.assertEqual(ft_valid, self.obj_valid)
  231. def test_from_text_invalid(self):
  232. ft_invalid = pdbuddy.SinkConfig.from_text([b"status: invalid",
  233. b"flags: (none)",
  234. b"v: 15.000 V",
  235. b"i: 3.00 A"])
  236. self.assertEqual(ft_invalid, self.obj_invalid)
  237. def test_from_text_valid_gb(self):
  238. ft_valid_gb = pdbuddy.SinkConfig.from_text([b"status: valid",
  239. b"flags: GiveBack",
  240. b"v: 15.000 V",
  241. b"i: 3.00 A"])
  242. self.assertEqual(ft_valid_gb, self.obj_valid_gb)
  243. def test_from_text_valid_5v(self):
  244. ft_valid_5v = pdbuddy.SinkConfig.from_text([b"status: valid",
  245. b"flags: (none)",
  246. b"v: 5.000 V",
  247. b"i: 3.00 A"])
  248. self.assertEqual(ft_valid_5v, self.obj_valid_5v)
  249. def test_from_text_valid_1a(self):
  250. ft_valid_1a = pdbuddy.SinkConfig.from_text([b"status: valid",
  251. b"flags: (none)",
  252. b"v: 15.000 V",
  253. b"i: 1.00 A"])
  254. self.assertEqual(ft_valid_1a, self.obj_valid_1a)
  255. def test_from_text_valid_range(self):
  256. ft_valid_range = pdbuddy.SinkConfig.from_text([b"status: valid",
  257. b"flags: (none)",
  258. b"v: 15.000 V",
  259. b"vmin: 12.000 V",
  260. b"vmax: 16.000 V",
  261. b"i: 1.00 A"])
  262. self.assertEqual(ft_valid_range, self.obj_valid_range)
  263. def test_from_text_valid_hv(self):
  264. ft_valid_hv = pdbuddy.SinkConfig.from_text([b"status: valid",
  265. b"flags: HV_Preferred",
  266. b"v: 15.000 V",
  267. b"vmin: 12.000 V",
  268. b"vmax: 16.000 V",
  269. b"i: 1.00 A"])
  270. self.assertEqual(ft_valid_hv, self.obj_valid_hv)
  271. def test_from_text_valid_10w(self):
  272. ft_valid_10w = pdbuddy.SinkConfig.from_text([b"status: valid",
  273. b"flags: (none)",
  274. b"v: 15.000 V",
  275. b"p: 10.00 W"])
  276. self.assertEqual(ft_valid_10w, self.obj_valid_10w)
  277. def test_from_text_valid_10r(self):
  278. ft_valid_10r = pdbuddy.SinkConfig.from_text([b"status: valid",
  279. b"flags: (none)",
  280. b"v: 15.000 V",
  281. b"r: 10.00 \u03A9"])
  282. self.assertEqual(ft_valid_10r, self.obj_valid_10r)
  283. def test_from_text_invalid_index(self):
  284. with self.assertRaises(IndexError):
  285. pdbuddy.SinkConfig.from_text([b"Invalid index"])
  286. def test_from_text_no_configuration(self):
  287. ft_no_config = pdbuddy.SinkConfig.from_text([b"No configuration"])
  288. self.assertEqual(ft_no_config, self.obj_none)
  289. def test_from_text_valid_extra(self):
  290. ft_valid = pdbuddy.SinkConfig.from_text([b"status: valid",
  291. b"flags: (none)",
  292. b"This is an extra line, which shouldn't hurt anything.",
  293. b"v: 15.000 V",
  294. b"i: 3.00 A"])
  295. self.assertEqual(ft_valid, self.obj_valid)
  296. class UnknownPDOTestCase(unittest.TestCase):
  297. def setUp(self):
  298. self.obj_zero = pdbuddy.UnknownPDO(value=0x00000000)
  299. self.obj_notzero = pdbuddy.UnknownPDO(value=0xFFFFFFFF)
  300. def test_str_zero(self):
  301. self.assertEqual(str(self.obj_zero), "00000000")
  302. def test_str_notzero(self):
  303. self.assertEqual(str(self.obj_notzero), "FFFFFFFF")
  304. class SrcFixedPDOTestCase(unittest.TestCase):
  305. def setUp(self):
  306. self.obj_everything = pdbuddy.SrcFixedPDO(True, True, True, True, True,
  307. True, 3, 20000, 5000)
  308. self.obj_minimal = pdbuddy.SrcFixedPDO(False, False, False, False,
  309. False, False, 0, 5000, 1500)
  310. def test_str_everything(self):
  311. self.assertEqual(str(self.obj_everything),
  312. "fixed\n\tdual_role_pwr: 1\n\tusb_suspend: 1\n"
  313. "\tunconstrained_pwr: 1\n\tusb_comms: 1\n\tdual_role_data: 1\n"
  314. "\tunchunked_ext_msg: 1\n\tpeak_i: 3\n\tv: 20.00 V\n"
  315. "\ti: 5.00 A")
  316. def test_str_minimal(self):
  317. self.assertEqual(str(self.obj_minimal),
  318. "fixed\n\tv: 5.00 V\n\ti: 1.50 A")
  319. class SrcPPSAPDOTestCase(unittest.TestCase):
  320. def setUp(self):
  321. self.obj_15v = pdbuddy.SrcPPSAPDO(3000, 16000, 3000)
  322. def test_str_15v(self):
  323. self.assertEqual(str(self.obj_15v), "pps\n\tvmin: 3.00 V\n"
  324. "\tvmax: 16.00 V\n\ti: 3.00 A")
  325. class TypeCVirtualPDOTestCase(unittest.TestCase):
  326. def setUp(self):
  327. self.obj_1p5a = pdbuddy.TypeCVirtualPDO(1500)
  328. def test_str_1p5a(self):
  329. self.assertEqual(str(self.obj_1p5a), "typec_virtual\n\ti: 1.50 A")
  330. class ReadPDOTestCase(unittest.TestCase):
  331. def setUp(self):
  332. self.src_fixed_everything = pdbuddy.SrcFixedPDO(True, True, True, True,
  333. True, True, 3, 20000, 5000)
  334. self.src_fixed_minimal = pdbuddy.SrcFixedPDO(False, False, False,
  335. False, False, False, 0, 5000, 1500)
  336. self.unknown_zero = pdbuddy.UnknownPDO(value=0x00000000)
  337. self.unknown_notzero = pdbuddy.UnknownPDO(value=0xFFFFFFFF)
  338. self.typec_virtual = pdbuddy.TypeCVirtualPDO(1500)
  339. def test_read_src_fixed_everything(self):
  340. rp_src_fixed_everything = pdbuddy.read_pdo([b"PDO 1: fixed",
  341. b"\tdual_role_pwr: 1",
  342. b"\tusb_suspend: 1",
  343. b"\tunconstrained_pwr: 1",
  344. b"\tusb_comms: 1",
  345. b"\tdual_role_data: 1",
  346. b"\tunchunked_ext_msg: 1",
  347. b"\tpeak_i: 3",
  348. b"\tv: 20.00 V",
  349. b"\ti: 5.00 A"])
  350. self.assertEqual(self.src_fixed_everything, rp_src_fixed_everything)
  351. def test_read_src_fixed_minimal(self):
  352. rp_src_fixed_minimal = pdbuddy.read_pdo([b"PDO 1: fixed",
  353. b"\tv: 5.00 V",
  354. b"\ti: 1.50 A"])
  355. self.assertEqual(self.src_fixed_minimal, rp_src_fixed_minimal)
  356. def test_read_src_fixed_minimal_no_index(self):
  357. rp_src_fixed_minimal = pdbuddy.read_pdo([b"fixed",
  358. b"\tv: 5.00 V",
  359. b"\ti: 1.50 A"])
  360. self.assertEqual(self.src_fixed_minimal, rp_src_fixed_minimal)
  361. def test_read_unknown_zero(self):
  362. rp_unknown_zero = pdbuddy.read_pdo([b"PDO 1: 00000000"])
  363. self.assertEqual(self.unknown_zero, rp_unknown_zero)
  364. def test_read_unknown_notzero(self):
  365. rp_unknown_notzero = pdbuddy.read_pdo([b"PDO 1: FFFFFFFF"])
  366. self.assertEqual(self.unknown_notzero, rp_unknown_notzero)
  367. def test_read_typec_virtual(self):
  368. rp_typec_virtual = pdbuddy.read_pdo([b"PDO 5: typec_virtual",
  369. b"\ti: 1.50 A"])
  370. self.assertEqual(self.typec_virtual, rp_typec_virtual)
  371. def test_read_none(self):
  372. none_pdo = pdbuddy.read_pdo([b"No Source_Capabilities"])
  373. self.assertEqual(none_pdo, None)
  374. class ReadPDOListTestCase(unittest.TestCase):
  375. def setUp(self):
  376. self.src_fixed_everything = pdbuddy.SrcFixedPDO(True, True, True, True,
  377. True, True, 3, 20000, 5000)
  378. self.src_fixed_minimal = pdbuddy.SrcFixedPDO(False, False, False,
  379. False, False, False, 0, 5000, 1500)
  380. self.unknown_zero = pdbuddy.UnknownPDO(value=0x00000000)
  381. self.unknown_notzero = pdbuddy.UnknownPDO(value=0xFFFFFFFF)
  382. self.typec_virtual = pdbuddy.TypeCVirtualPDO(1500)
  383. def test_read_pdo_list(self):
  384. # It's not a legal list for USB Power Delivery, but it works fine for
  385. # testing this code
  386. text = [b"PDO 1: fixed",
  387. b"\tdual_role_pwr: 1",
  388. b"\tusb_suspend: 1",
  389. b"\tunconstrained_pwr: 1",
  390. b"\tusb_comms: 1",
  391. b"\tdual_role_data: 1",
  392. b"\tunchunked_ext_msg: 1",
  393. b"\tpeak_i: 3",
  394. b"\tv: 20.00 V",
  395. b"\ti: 5.00 A",
  396. b"PDO 2: fixed",
  397. b"\tv: 5.00 V",
  398. b"\ti: 1.50 A",
  399. b"PDO 3: 00000000",
  400. b"PDO 4: FFFFFFFF",
  401. b"PDO 5: typec_virtual",
  402. b"\ti: 1.50 A"]
  403. pdo_list = pdbuddy.read_pdo_list(text)
  404. self.assertEqual(pdo_list[0], self.src_fixed_everything)
  405. self.assertEqual(pdo_list[1], self.src_fixed_minimal)
  406. self.assertEqual(pdo_list[2], self.unknown_zero)
  407. self.assertEqual(pdo_list[3], self.unknown_notzero)
  408. self.assertEqual(pdo_list[4], self.typec_virtual)
  409. class PDOListCalculationsTestCase(unittest.TestCase):
  410. def setUp(self):
  411. self.src_fixed_5v_1p5a = pdbuddy.SrcFixedPDO(False, False, True,
  412. False, False, False, 0, 5000, 1500)
  413. self.src_fixed_5v_3a = pdbuddy.SrcFixedPDO(False, False, True, False,
  414. False, False, 0, 5000, 3000)
  415. self.src_fixed_9v_1p6a = pdbuddy.SrcFixedPDO(False, False, False,
  416. False, False, False, 0, 9000, 1600)
  417. self.src_fixed_9v_3a = pdbuddy.SrcFixedPDO(False, False, False, False,
  418. False, False, 0, 9000, 3000)
  419. self.src_fixed_10v_1p5a = pdbuddy.SrcFixedPDO(False, False, False,
  420. False, False, False, 0, 10000, 1500)
  421. self.src_fixed_12v_5a = pdbuddy.SrcFixedPDO(False, False, False, False,
  422. False, False, 0, 12000, 5000)
  423. self.src_fixed_15v_1p8a = pdbuddy.SrcFixedPDO(False, False, False,
  424. False, False, False, 0, 15000, 1800)
  425. self.src_fixed_15v_3a = pdbuddy.SrcFixedPDO(False, False, False, False,
  426. False, False, 0, 15000, 3000)
  427. self.src_fixed_20v_2p25a = pdbuddy.SrcFixedPDO(False, False, False,
  428. False, False, False, 0, 20000, 2250)
  429. self.src_fixed_20v_3a = pdbuddy.SrcFixedPDO(False, False, False, False,
  430. False, False, 0, 20000, 3000)
  431. self.src_fixed_20v_5a = pdbuddy.SrcFixedPDO(False, False, False, False,
  432. False, False, 0, 20000, 5000)
  433. self.src_pps_5v_1p5a = pdbuddy.SrcPPSAPDO(3000, 5900, 1500)
  434. self.src_pps_5v_3a = pdbuddy.SrcPPSAPDO(3000, 5900, 3000)
  435. self.src_pps_9v_1p6a = pdbuddy.SrcPPSAPDO(3000, 11000, 1600)
  436. self.src_pps_9v_3a = pdbuddy.SrcPPSAPDO(3000, 11000, 3000)
  437. self.src_pps_10v_1p5a = pdbuddy.SrcPPSAPDO(3000, 10000, 1500)
  438. self.src_pps_15v_1p8a = pdbuddy.SrcPPSAPDO(3000, 16000, 1800)
  439. self.src_pps_15v_3a = pdbuddy.SrcPPSAPDO(3000, 16000, 3000)
  440. self.src_pps_20v_2p25a = pdbuddy.SrcPPSAPDO(3000, 21000, 2250)
  441. self.src_pps_20v_5a = pdbuddy.SrcPPSAPDO(3000, 21000, 5000)
  442. self.typec_virtual_1p5a = pdbuddy.TypeCVirtualPDO(1500)
  443. def test_calculate_pdp_typec_virtual(self):
  444. self.assertEqual(pdbuddy.calculate_pdp([self.typec_virtual_1p5a]), 7.5)
  445. def test_calculate_pdp_15w(self):
  446. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a]), 15)
  447. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  448. self.src_fixed_9v_1p6a]), 15)
  449. def test_calculate_pdp_27w(self):
  450. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  451. self.src_fixed_9v_3a]), 27)
  452. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  453. self.src_fixed_9v_3a, self.src_fixed_15v_1p8a]), 27)
  454. def test_calculate_pdp_45w(self):
  455. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  456. self.src_fixed_9v_3a, self.src_fixed_15v_3a]), 45)
  457. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  458. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  459. self.src_fixed_20v_2p25a]), 45)
  460. def test_calculate_pdp_100w(self):
  461. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_3a,
  462. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  463. self.src_fixed_20v_5a]), 100)
  464. self.assertEqual(pdbuddy.calculate_pdp([self.src_fixed_5v_1p5a,
  465. self.src_fixed_12v_5a, self.src_fixed_20v_5a]), 100)
  466. def test_follows_power_rules_true(self):
  467. # <= 15 W
  468. self.assertTrue(pdbuddy.follows_power_rules([]))
  469. self.assertTrue(pdbuddy.follows_power_rules([self.typec_virtual_1p5a]))
  470. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a]))
  471. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a]))
  472. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  473. self.src_fixed_9v_1p6a]))
  474. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  475. self.src_pps_5v_1p5a]))
  476. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  477. self.src_pps_5v_3a]))
  478. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  479. self.src_fixed_9v_1p6a, self.src_pps_5v_3a]))
  480. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  481. self.src_fixed_9v_1p6a, self.src_pps_5v_3a,
  482. self.src_pps_9v_1p6a]))
  483. # <= 27 W
  484. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  485. self.src_fixed_9v_3a]))
  486. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  487. self.src_fixed_9v_3a, self.src_fixed_15v_1p8a]))
  488. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  489. self.src_fixed_9v_3a, self.src_pps_9v_3a]))
  490. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  491. self.src_fixed_9v_3a, self.src_pps_5v_3a, self.src_pps_9v_3a,
  492. self.src_pps_15v_1p8a]))
  493. # <= 45 W
  494. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  495. self.src_fixed_9v_3a, self.src_fixed_15v_3a]))
  496. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  497. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  498. self.src_fixed_20v_2p25a]))
  499. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  500. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  501. self.src_pps_15v_3a]))
  502. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  503. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  504. self.src_pps_9v_3a, self.src_pps_15v_3a,
  505. self.src_pps_20v_2p25a]))
  506. # <= 100 W
  507. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  508. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  509. self.src_fixed_20v_5a]))
  510. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  511. self.src_fixed_9v_3a, self.src_fixed_10v_1p5a,
  512. self.src_fixed_12v_5a, self.src_fixed_15v_3a,
  513. self.src_fixed_20v_5a]))
  514. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  515. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  516. self.src_fixed_20v_5a, self.src_pps_20v_5a]))
  517. self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  518. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  519. self.src_fixed_20v_5a, self.src_pps_9v_3a, self.src_pps_15v_3a,
  520. self.src_pps_20v_5a]))
  521. def test_follows_power_rules_false(self):
  522. # <= 15 W
  523. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_10v_1p5a]))
  524. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  525. self.src_fixed_10v_1p5a]))
  526. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  527. self.src_pps_5v_3a]))
  528. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  529. self.src_pps_9v_1p6a]))
  530. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  531. self.src_pps_10v_1p5a]))
  532. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  533. self.src_pps_15v_3a]))
  534. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  535. self.src_pps_20v_2p25a]))
  536. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  537. self.src_pps_5v_1p5a]))
  538. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  539. self.src_pps_9v_1p6a]))
  540. # <= 27 W
  541. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_9v_3a]))
  542. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  543. self.src_fixed_9v_3a]))
  544. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  545. self.src_fixed_9v_3a, self.src_pps_5v_1p5a,
  546. self.src_pps_9v_3a]))
  547. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  548. self.src_fixed_9v_3a, self.src_pps_5v_3a,
  549. self.src_pps_9v_1p6a]))
  550. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  551. self.src_fixed_9v_1p6a, self.src_fixed_15v_1p8a]))
  552. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  553. self.src_fixed_9v_3a, self.src_pps_15v_1p8a]))
  554. # <= 45 W
  555. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_20v_2p25a]))
  556. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  557. self.src_fixed_9v_3a, self.src_fixed_15v_3a]))
  558. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  559. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  560. self.src_pps_9v_3a]))
  561. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  562. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  563. self.src_pps_9v_1p6a, self.src_pps_15v_3a]))
  564. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  565. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  566. self.src_pps_9v_3a, self.src_pps_15v_1p8a]))
  567. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  568. self.src_fixed_9v_1p6a, self.src_fixed_15v_3a]))
  569. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  570. self.src_fixed_9v_3a, self.src_fixed_15v_1p8a,
  571. self.src_fixed_20v_2p25a]))
  572. # <= 100 W
  573. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_20v_5a]))
  574. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  575. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  576. self.src_fixed_20v_3a, self.src_pps_20v_2p25a]))
  577. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
  578. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  579. self.src_fixed_20v_5a]))
  580. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  581. self.src_fixed_9v_1p6a, self.src_fixed_15v_3a,
  582. self.src_fixed_20v_5a]))
  583. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  584. self.src_fixed_9v_3a, self.src_fixed_15v_1p8a,
  585. self.src_fixed_20v_5a]))
  586. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  587. self.src_fixed_9v_3a, self.src_fixed_12v_5a,
  588. self.src_fixed_15v_3a, self.src_fixed_20v_2p25a]))
  589. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  590. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  591. self.src_fixed_20v_5a, self.src_pps_15v_1p8a]))
  592. self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
  593. self.src_fixed_9v_3a, self.src_fixed_15v_3a,
  594. self.src_fixed_20v_5a, self.src_pps_15v_3a]))