Browse Source

Add power rule testing for PPS APDOs

That function is getting complicated.
Clara Hobbs 4 years ago
parent
commit
edfff3353f
2 changed files with 201 additions and 27 deletions
  1. 120
    25
      pdbuddy/__init__.py
  2. 81
    2
      test_pdbuddy/__init__.py

+ 120
- 25
pdbuddy/__init__.py View File

@@ -483,7 +483,7 @@ class SrcFixedPDO(namedtuple("SrcFixedPDO", "dual_role_pwr usb_suspend "
483 483
         return s
484 484
 
485 485
 
486
-class SourcePPSAPDO(namedtuple("SourcePPSAPDO", "vmin vmax i")):
486
+class SrcPPSAPDO(namedtuple("SrcPPSAPDO", "vmin vmax i")):
487 487
     """A Source Programmable Power Supply APDO
488 488
 
489 489
     ``vmin`` and ``vmax`` are the minimum and maximum voltage in millivolts,
@@ -494,7 +494,7 @@ class SourcePPSAPDO(namedtuple("SourcePPSAPDO", "vmin vmax i")):
494 494
     pdo_type = "pps"
495 495
 
496 496
     def __str__(self):
497
-        """Print the SourcePPSAPDO in the manner of the configuration shell"""
497
+        """Print the SrcPPSAPDO in the manner of the configuration shell"""
498 498
         s = self.pdo_type + "\n"
499 499
 
500 500
         s += "\tvmin: {:.2f} V\n".format(self.vmin / 1000.0)
@@ -572,8 +572,8 @@ def read_pdo(text):
572 572
                 peak_i=peak_i,
573 573
                 v=v,
574 574
                 i=i)
575
-    elif pdo_type == SourcePPSAPDO.pdo_type:
576
-        # Load a SourcePPSAPDO
575
+    elif pdo_type == SrcPPSAPDO.pdo_type:
576
+        # Load a SrcPPSAPDO
577 577
         for line in text[1:]:
578 578
             fields = line.split(b":")
579 579
             fields[0] = fields[0].strip()
@@ -585,8 +585,8 @@ def read_pdo(text):
585 585
             if fields[0] == b"i":
586 586
                 i = round(1000*float(fields[1].split()[0]))
587 587
 
588
-        # Make the SourcePPSAPDO
589
-        return SourcePPSAPDO(vmin=vmin, vmax=vmax, i=i)
588
+        # Make the SrcPPSAPDO
589
+        return SrcPPSAPDO(vmin=vmin, vmax=vmax, i=i)
590 590
     elif pdo_type == TypeCVirtualPDO.pdo_type:
591 591
         # Load a TypeCVirtualPDO
592 592
         for line in text[1:]:
@@ -646,7 +646,7 @@ def calculate_pdp(pdo_list):
646 646
 
647 647
 
648 648
 def follows_power_rules(pdo_list):
649
-    """Test whether a list of PDOs follows the Power Rules for PD 2.0
649
+    """Test whether a list of PDOs follows the Power Rules for PD 3.0
650 650
 
651 651
     This function is a false-biased approximation; that is, when it returns
652 652
     False it is definitely correct, but when it returns True it might be
@@ -662,12 +662,35 @@ def follows_power_rules(pdo_list):
662 662
     if pdo_list and pdo_list[0].pdo_type == "typec_virtual":
663 663
         return True
664 664
 
665
+    fixed = [p for p in pdo_list if p.pdo_type == "fixed"]
666
+    pps = [p for p in pdo_list if p.pdo_type == "pps"]
667
+
665 668
     # Make sure nothing exceeds the PDP
666
-    for pdo in pdo_list:
667
-        if pdo.pdo_type == "fixed":
668
-            if pdp < pdo.v / 1000.0 * pdo.i / 1000.0:
669
+    for pdo in fixed:
670
+        if pdp < pdo.v / 1000.0 * pdo.i / 1000.0:
671
+            return False
672
+    # TODO: in the future, there will be more types of PDO checked here
673
+    for pdo in pps:
674
+        # 5V Prog nominal PDO
675
+        if pdo.vmin == 3000 and pdo.vmax == 5900:
676
+            if pdp < 5.0 * pdo.i / 1000.0:
677
+                return False
678
+        # 9V Prog nominal PDO
679
+        elif pdo.vmin == 3000 and pdo.vmax == 11000:
680
+            if pdp < 9.0 * pdo.i / 1000.0:
681
+                return False
682
+        # 15V Prog nominal PDO
683
+        elif pdo.vmin == 3000 and pdo.vmax == 16000:
684
+            if pdp < 15.0 * pdo.i / 1000.0:
685
+                return False
686
+        # 20V Prog nominal PDO
687
+        elif pdo.vmin == 3000 and pdo.vmax == 21000:
688
+            if pdp < 20.0 * pdo.i / 1000.0:
689
+                return False
690
+        # Non-standard programmable PDO
691
+        else:
692
+            if pdp < pdo.vmax / 1000.0 * pdo.i / 1000.0:
669 693
                 return False
670
-        # TODO: in the future, there will be more types of PDO checked here
671 694
 
672 695
     # Check that the fixed supply PDOs look right
673 696
     seen_5v = False
@@ -680,8 +703,8 @@ def follows_power_rules(pdo_list):
680 703
         seen_normative_voltages = True
681 704
     elif pdp <= 15:
682 705
         # Below 15 W, make sure the PDP is available at 5 V.
683
-        for pdo in pdo_list:
684
-            if pdo.pdo_type == "fixed" and pdo.v == 5000:
706
+        for pdo in fixed:
707
+            if pdo.v == 5000:
685 708
                 seen_5v = True
686 709
                 if pdo.v / 1000.0 * pdo.i / 1000.0 != pdp:
687 710
                     return False
@@ -689,12 +712,12 @@ def follows_power_rules(pdo_list):
689 712
     elif pdp <= 27:
690 713
         # Between 15 and 27 W, make sure at least 3 A is available at 5 V and
691 714
         # the PDP is available at 9 V.
692
-        for pdo in pdo_list:
693
-            if pdo.pdo_type == "fixed" and pdo.v == 5000:
715
+        for pdo in fixed:
716
+            if pdo.v == 5000:
694 717
                 seen_5v = True
695 718
                 if pdo.i < 3000.0:
696 719
                     return False
697
-            elif pdo.pdo_type == "fixed" and pdo.v == 9000:
720
+            elif pdo.v == 9000:
698 721
                 seen_9v = True
699 722
                 if pdo.v / 1000.0 * pdo.i / 1000.0 != pdp:
700 723
                     return False
@@ -702,16 +725,16 @@ def follows_power_rules(pdo_list):
702 725
     elif pdp <= 45:
703 726
         # Between 27 and 45 W, make sure at least 3 A is available at 5 and
704 727
         # 9 V, and the PDP is available at 15 V.
705
-        for pdo in pdo_list:
706
-            if pdo.pdo_type == "fixed" and pdo.v == 5000:
728
+        for pdo in fixed:
729
+            if pdo.v == 5000:
707 730
                 seen_5v = True
708 731
                 if pdo.i < 3000.0:
709 732
                     return False
710
-            elif pdo.pdo_type == "fixed" and pdo.v == 9000:
733
+            elif pdo.v == 9000:
711 734
                 seen_9v = True
712 735
                 if pdo.i < 3000.0:
713 736
                     return False
714
-            elif pdo.pdo_type == "fixed" and pdo.v == 15000:
737
+            elif pdo.v == 15000:
715 738
                 seen_15v = True
716 739
                 if pdo.v / 1000.0 * pdo.i / 1000.0 != pdp:
717 740
                     return False
@@ -719,20 +742,20 @@ def follows_power_rules(pdo_list):
719 742
     else:
720 743
         # Above 45 W, make sure at least 3 A is available at 5, 9, and 15 V,
721 744
         # and the PDP is available at 20 V.
722
-        for pdo in pdo_list:
723
-            if pdo.pdo_type == "fixed" and pdo.v == 5000:
745
+        for pdo in fixed:
746
+            if pdo.v == 5000:
724 747
                 seen_5v = True
725 748
                 if pdo.i < 3000.0:
726 749
                     return False
727
-            elif pdo.pdo_type == "fixed" and pdo.v == 9000:
750
+            elif pdo.v == 9000:
728 751
                 seen_9v = True
729 752
                 if pdo.i < 3000.0:
730 753
                     return False
731
-            elif pdo.pdo_type == "fixed" and pdo.v == 15000:
754
+            elif pdo.v == 15000:
732 755
                 seen_15v = True
733 756
                 if pdo.i < 3000.0:
734 757
                     return False
735
-            elif pdo.pdo_type == "fixed" and pdo.v == 20000:
758
+            elif pdo.v == 20000:
736 759
                 seen_20v = True
737 760
                 if pdo.v / 1000.0 * pdo.i / 1000.0 != pdp:
738 761
                     return False
@@ -744,4 +767,76 @@ def follows_power_rules(pdo_list):
744 767
     # TODO: there are several things this currently doesn't test, such as
745 768
     # variable and battery PDOs.
746 769
 
770
+    # Check that the PPS APDOs look right
771
+    seen_5v = False
772
+    seen_9v = False
773
+    seen_15v = False
774
+    seen_20v = False
775
+
776
+    if pdp == 0:
777
+        # No power is fine
778
+        pass
779
+    elif pdp <= 15:
780
+        # Below 15 W, make sure the PDP is available with 5V Prog.
781
+        for pdo in pps:
782
+            if pdo.vmin == 3000 and pdo.vmax == 5900:
783
+                seen_5v = True
784
+                if 5.0 * pdo.i / 1000.0 != pdp:
785
+                    return False
786
+        if pps and not seen_5v:
787
+            return False
788
+    elif pdp <= 27:
789
+        # Between 15 and 27 W, make sure at least 3 A is available at 5V Prog
790
+        # and the PDP is available at 9V Prog.
791
+        for pdo in pps:
792
+            if pdo.vmin == 3000 and pdo.vmax == 5900:
793
+                seen_5v = True
794
+                if pdo.i < 3000.0:
795
+                    return False
796
+            elif pdo.vmin == 3000 and pdo.vmax == 11000:
797
+                seen_9v = True
798
+                if 9.0 * pdo.i / 1000.0 != pdp:
799
+                    return False
800
+                # If we're at full power for this range, 5V Prog is optional
801
+                if pdp == 27:
802
+                    seen_5v = True
803
+        if pps and not (seen_5v and seen_9v):
804
+            return False
805
+    elif pdp <= 45:
806
+        # Between 27 and 45 W, make sure at least 3 A is available at 9V Prog,
807
+        # and the PDP is available at 15V Prog.
808
+        for pdo in pps:
809
+            # 5V Prog is optional at this power level
810
+            if pdo.vmin == 3000 and pdo.vmax == 11000:
811
+                seen_9v = True
812
+                if pdo.i < 3000.0:
813
+                    return False
814
+            elif pdo.vmin == 3000 and pdo.vmax == 16000:
815
+                seen_15v = True
816
+                if 15.0 * pdo.i / 1000.0 != pdp:
817
+                    return False
818
+                # If we're at full power for this range, 9V Prog is optional
819
+                if pdp == 45:
820
+                    seen_9v = True
821
+        if pps and not (seen_9v and seen_15v):
822
+            return False
823
+    else:
824
+        # Above 45 W, make sure at least 3 A is available at 15V Prog, and the
825
+        # PDP is available at 20V Prog.
826
+        for pdo in pps:
827
+            # 5V and 9V Prog are optional at this power level
828
+            if pdo.vmin == 3000 and pdo.vmax == 16000:
829
+                seen_15v = True
830
+                if pdo.i < 3000.0:
831
+                    return False
832
+            elif pdo.vmin == 3000 and pdo.vmax == 21000:
833
+                seen_20v = True
834
+                if 20.0 * pdo.i / 1000.0 != pdp:
835
+                    return False
836
+                # If we have at least 60 W, 15V Prog is optional
837
+                if pdp >= 60:
838
+                    seen_15v = True
839
+        if pps and not (seen_15v and seen_20v):
840
+            return False
841
+
747 842
     return True

+ 81
- 2
test_pdbuddy/__init__.py View File

@@ -397,10 +397,10 @@ class SrcFixedPDOTestCase(unittest.TestCase):
397 397
                 "fixed\n\tv: 5.00 V\n\ti: 1.50 A")
398 398
 
399 399
 
400
-class SourcePPSAPDOTestCase(unittest.TestCase):
400
+class SrcPPSAPDOTestCase(unittest.TestCase):
401 401
 
402 402
     def setUp(self):
403
-        self.obj_15v = pdbuddy.SourcePPSAPDO(3000, 16000, 3000)
403
+        self.obj_15v = pdbuddy.SrcPPSAPDO(3000, 16000, 3000)
404 404
 
405 405
     def test_str_15v(self):
406 406
         self.assertEqual(str(self.obj_15v), "pps\n\tvmin: 3.00 V\n"
@@ -531,8 +531,19 @@ class PDOListCalculationsTestCase(unittest.TestCase):
531 531
                 False, False, 0, 15000, 3000)
532 532
         self.src_fixed_20v_2p25a = pdbuddy.SrcFixedPDO(False, False, False,
533 533
                 False, False, False, 0, 20000, 2250)
534
+        self.src_fixed_20v_3a = pdbuddy.SrcFixedPDO(False, False, False, False,
535
+                False, False, 0, 20000, 3000)
534 536
         self.src_fixed_20v_5a = pdbuddy.SrcFixedPDO(False, False, False, False,
535 537
                 False, False, 0, 20000, 5000)
538
+        self.src_pps_5v_1p5a = pdbuddy.SrcPPSAPDO(3000, 5900, 1500)
539
+        self.src_pps_5v_3a = pdbuddy.SrcPPSAPDO(3000, 5900, 3000)
540
+        self.src_pps_9v_1p6a = pdbuddy.SrcPPSAPDO(3000, 11000, 1600)
541
+        self.src_pps_9v_3a = pdbuddy.SrcPPSAPDO(3000, 11000, 3000)
542
+        self.src_pps_10v_1p5a = pdbuddy.SrcPPSAPDO(3000, 10000, 1500)
543
+        self.src_pps_15v_1p8a = pdbuddy.SrcPPSAPDO(3000, 16000, 1800)
544
+        self.src_pps_15v_3a = pdbuddy.SrcPPSAPDO(3000, 16000, 3000)
545
+        self.src_pps_20v_2p25a = pdbuddy.SrcPPSAPDO(3000, 21000, 2250)
546
+        self.src_pps_20v_5a = pdbuddy.SrcPPSAPDO(3000, 21000, 5000)
536 547
         self.typec_virtual_1p5a = pdbuddy.TypeCVirtualPDO(1500)
537 548
 
538 549
     def test_calculate_pdp_typec_virtual(self):
@@ -571,17 +582,38 @@ class PDOListCalculationsTestCase(unittest.TestCase):
571 582
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a]))
572 583
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
573 584
                 self.src_fixed_9v_1p6a]))
585
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
586
+                self.src_pps_5v_1p5a]))
587
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
588
+                self.src_pps_5v_3a]))
589
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
590
+                self.src_fixed_9v_1p6a, self.src_pps_5v_3a]))
591
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
592
+                self.src_fixed_9v_1p6a, self.src_pps_5v_3a,
593
+                self.src_pps_9v_1p6a]))
574 594
         # <= 27 W
575 595
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
576 596
                 self.src_fixed_9v_3a]))
577 597
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
578 598
                 self.src_fixed_9v_3a, self.src_fixed_15v_1p8a]))
599
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
600
+                self.src_fixed_9v_3a, self.src_pps_9v_3a]))
601
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
602
+                self.src_fixed_9v_3a, self.src_pps_5v_3a, self.src_pps_9v_3a,
603
+                self.src_pps_15v_1p8a]))
579 604
         # <= 45 W
580 605
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
581 606
                 self.src_fixed_9v_3a, self.src_fixed_15v_3a]))
582 607
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
583 608
                 self.src_fixed_9v_3a, self.src_fixed_15v_3a,
584 609
                 self.src_fixed_20v_2p25a]))
610
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
611
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
612
+                self.src_pps_15v_3a]))
613
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
614
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
615
+                self.src_pps_9v_3a, self.src_pps_15v_3a,
616
+                self.src_pps_20v_2p25a]))
585 617
         # <= 100 W
586 618
         self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
587 619
                 self.src_fixed_9v_3a, self.src_fixed_15v_3a,
@@ -590,22 +622,60 @@ class PDOListCalculationsTestCase(unittest.TestCase):
590 622
                 self.src_fixed_9v_3a, self.src_fixed_10v_1p5a,
591 623
                 self.src_fixed_12v_5a, self.src_fixed_15v_3a,
592 624
                 self.src_fixed_20v_5a]))
625
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
626
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
627
+                self.src_fixed_20v_5a, self.src_pps_20v_5a]))
628
+        self.assertTrue(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
629
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
630
+                self.src_fixed_20v_5a, self.src_pps_9v_3a, self.src_pps_15v_3a,
631
+                self.src_pps_20v_5a]))
593 632
 
594 633
     def test_follows_power_rules_false(self):
595 634
         # <= 15 W
596 635
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_10v_1p5a]))
597 636
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
598 637
             self.src_fixed_10v_1p5a]))
638
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
639
+            self.src_pps_5v_3a]))
640
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
641
+            self.src_pps_9v_1p6a]))
642
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
643
+            self.src_pps_10v_1p5a]))
644
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
645
+            self.src_pps_15v_3a]))
646
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
647
+            self.src_pps_20v_2p25a]))
648
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
649
+            self.src_pps_5v_1p5a]))
650
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
651
+            self.src_pps_9v_1p6a]))
599 652
         # <= 27 W
600 653
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_9v_3a]))
601 654
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
602 655
                 self.src_fixed_9v_3a]))
656
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
657
+                self.src_fixed_9v_3a, self.src_pps_5v_1p5a,
658
+                self.src_pps_9v_3a]))
659
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
660
+                self.src_fixed_9v_3a, self.src_pps_5v_3a,
661
+                self.src_pps_9v_1p6a]))
603 662
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
604 663
                 self.src_fixed_9v_1p6a, self.src_fixed_15v_1p8a]))
664
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
665
+                self.src_fixed_9v_3a, self.src_pps_15v_1p8a]))
605 666
         # <= 45 W
606 667
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_20v_2p25a]))
607 668
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
608 669
                 self.src_fixed_9v_3a, self.src_fixed_15v_3a]))
670
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
671
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
672
+                self.src_pps_9v_3a]))
673
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
674
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
675
+                self.src_pps_9v_1p6a, self.src_pps_15v_3a]))
676
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
677
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
678
+                self.src_pps_9v_3a, self.src_pps_15v_1p8a]))
609 679
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
610 680
                 self.src_fixed_9v_1p6a, self.src_fixed_15v_3a]))
611 681
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
@@ -613,6 +683,9 @@ class PDOListCalculationsTestCase(unittest.TestCase):
613 683
                 self.src_fixed_20v_2p25a]))
614 684
         # <= 100 W
615 685
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_20v_5a]))
686
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
687
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
688
+                self.src_fixed_20v_3a, self.src_pps_20v_2p25a]))
616 689
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_1p5a,
617 690
                 self.src_fixed_9v_3a, self.src_fixed_15v_3a,
618 691
                 self.src_fixed_20v_5a]))
@@ -625,3 +698,9 @@ class PDOListCalculationsTestCase(unittest.TestCase):
625 698
         self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
626 699
                 self.src_fixed_9v_3a, self.src_fixed_12v_5a,
627 700
                 self.src_fixed_15v_3a, self.src_fixed_20v_2p25a]))
701
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
702
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
703
+                self.src_fixed_20v_5a, self.src_pps_15v_1p8a]))
704
+        self.assertFalse(pdbuddy.follows_power_rules([self.src_fixed_5v_3a,
705
+                self.src_fixed_9v_3a, self.src_fixed_15v_3a,
706
+                self.src_fixed_20v_5a, self.src_pps_15v_3a]))

Loading…
Cancel
Save