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.

170 lines
5.6 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2022 KiCad Developers.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <common.h>
  24. #include <pcb_track.h>
  25. #include <drc/drc_engine.h>
  26. #include <drc/drc_item.h>
  27. #include <drc/drc_rule.h>
  28. #include <drc/drc_test_provider.h>
  29. /*
  30. Via/pad annular ring width test. Checks if there's sufficient copper ring around
  31. PTH/NPTH holes (vias/pads)
  32. Errors generated:
  33. - DRCE_ANNULAR_WIDTH
  34. Todo:
  35. - check pad holes too.
  36. - pad stack support (different IAR/OAR values depending on layer)
  37. */
  38. class DRC_TEST_PROVIDER_ANNULAR_WIDTH : public DRC_TEST_PROVIDER
  39. {
  40. public:
  41. DRC_TEST_PROVIDER_ANNULAR_WIDTH()
  42. {
  43. }
  44. virtual ~DRC_TEST_PROVIDER_ANNULAR_WIDTH()
  45. {
  46. }
  47. virtual bool Run() override;
  48. virtual const wxString GetName() const override
  49. {
  50. return wxT( "annular_width" );
  51. };
  52. virtual const wxString GetDescription() const override
  53. {
  54. return wxT( "Tests pad/via annular rings" );
  55. }
  56. };
  57. bool DRC_TEST_PROVIDER_ANNULAR_WIDTH::Run()
  58. {
  59. if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
  60. {
  61. reportAux( wxT( "Annular width violations ignored. Skipping check." ) );
  62. return true; // continue with other tests
  63. }
  64. const int delta = 250; // This is the number of tests between 2 calls to the progress bar
  65. if( !m_drcEngine->HasRulesForConstraintType( ANNULAR_WIDTH_CONSTRAINT ) )
  66. {
  67. reportAux( wxT( "No annular width constraints found. Tests not run." ) );
  68. return true; // continue with other tests
  69. }
  70. if( !reportPhase( _( "Checking via annular rings..." ) ) )
  71. return false; // DRC cancelled
  72. auto checkAnnularWidth =
  73. [&]( BOARD_ITEM* item ) -> bool
  74. {
  75. if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
  76. return false;
  77. int v_min = 0;
  78. int v_max = 0;
  79. PCB_VIA* via = dyn_cast<PCB_VIA*>( item );
  80. // fixme: check minimum IAR/OAR ring for THT pads too
  81. if( !via )
  82. return true;
  83. // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
  84. auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, via, nullptr,
  85. UNDEFINED_LAYER );
  86. int annularWidth = ( via->GetWidth() - via->GetDrillValue() ) / 2;
  87. bool fail_min = false;
  88. bool fail_max = false;
  89. if( constraint.GetSeverity() == RPT_SEVERITY_IGNORE )
  90. return true;
  91. if( constraint.Value().HasMin() )
  92. {
  93. v_min = constraint.Value().Min();
  94. fail_min = annularWidth < v_min;
  95. }
  96. if( constraint.Value().HasMax() )
  97. {
  98. v_max = constraint.Value().Max();
  99. fail_max = annularWidth > v_max;
  100. }
  101. if( fail_min || fail_max )
  102. {
  103. std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULAR_WIDTH );
  104. wxString msg;
  105. if( fail_min )
  106. msg.Printf( _( "(%s min annular width %s; actual %s)" ),
  107. constraint.GetName(),
  108. MessageTextFromValue( userUnits(), v_min ),
  109. MessageTextFromValue( userUnits(), annularWidth ) );
  110. if( fail_max )
  111. msg.Printf( _( "(%s max annular width %s; actual %s)" ),
  112. constraint.GetName(),
  113. MessageTextFromValue( userUnits(), v_max ),
  114. MessageTextFromValue( userUnits(), annularWidth ) );
  115. drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + msg );
  116. drcItem->SetItems( item );
  117. drcItem->SetViolatingRule( constraint.GetParentRule() );
  118. reportViolation( drcItem, via->GetPosition(), via->GetLayer() );
  119. }
  120. return true;
  121. };
  122. BOARD* board = m_drcEngine->GetBoard();
  123. int ii = 0;
  124. for( PCB_TRACK* item : board->Tracks() )
  125. {
  126. if( !reportProgress( ii++, board->Tracks().size(), delta ) )
  127. return false; // DRC cancelled
  128. if( !checkAnnularWidth( item ) )
  129. break;
  130. }
  131. reportRuleStatistics();
  132. return !m_drcEngine->IsCancelled();
  133. }
  134. namespace detail
  135. {
  136. static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_ANNULAR_WIDTH> dummy;
  137. }