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.

182 lines
5.6 KiB

5 years ago
5 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2020 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 <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_ANNULUS
  34. Todo:
  35. - check pad holes too.
  36. - pad stack support (different IAR/OAR values depending on layer)
  37. */
  38. class DRC_TEST_PROVIDER_ANNULUS : public DRC_TEST_PROVIDER
  39. {
  40. public:
  41. DRC_TEST_PROVIDER_ANNULUS()
  42. {
  43. }
  44. virtual ~DRC_TEST_PROVIDER_ANNULUS()
  45. {
  46. }
  47. virtual bool Run() override;
  48. virtual const wxString GetName() const override
  49. {
  50. return "annulus";
  51. };
  52. virtual const wxString GetDescription() const override
  53. {
  54. return "Tests pad/via annular rings";
  55. }
  56. virtual std::set<DRC_CONSTRAINT_T> GetConstraintTypes() const override;
  57. int GetNumPhases() const override;
  58. };
  59. bool DRC_TEST_PROVIDER_ANNULUS::Run()
  60. {
  61. if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
  62. {
  63. reportAux( "Annular width violations ignored. Skipping check." );
  64. return true; // continue with other tests
  65. }
  66. const int delta = 250; // This is the number of tests between 2 calls to the progress bar
  67. if( !m_drcEngine->HasRulesForConstraintType( ANNULAR_WIDTH_CONSTRAINT ) )
  68. {
  69. reportAux( "No annulus constraints found. Tests not run." );
  70. return true; // continue with other tests
  71. }
  72. if( !reportPhase( _( "Checking via annular rings..." ) ) )
  73. return false; // DRC cancelled
  74. auto checkAnnulus =
  75. [&]( BOARD_ITEM* item ) -> bool
  76. {
  77. if( m_drcEngine->IsErrorLimitExceeded( DRCE_ANNULAR_WIDTH ) )
  78. return false;
  79. int v_min = 0;
  80. int v_max = 0;
  81. VIA* via = dyn_cast<VIA*>( item );
  82. // fixme: check minimum IAR/OAR ring for THT pads too
  83. if( !via )
  84. return true;
  85. // PADSTACKS TODO: once we have padstacks we'll need to run this per-layer....
  86. auto constraint = m_drcEngine->EvalRules( ANNULAR_WIDTH_CONSTRAINT, via, nullptr,
  87. UNDEFINED_LAYER );
  88. int annulus = ( via->GetWidth() - via->GetDrillValue() ) / 2;
  89. bool fail_min = false;
  90. bool fail_max = false;
  91. if( constraint.Value().HasMin() )
  92. {
  93. v_min = constraint.Value().Min();
  94. fail_min = annulus < v_min;
  95. }
  96. if( constraint.Value().HasMax() )
  97. {
  98. v_max = constraint.Value().Max();
  99. fail_max = annulus > v_max;
  100. }
  101. if( fail_min || fail_max )
  102. {
  103. std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_ANNULAR_WIDTH );
  104. if( fail_min )
  105. m_msg.Printf( _( "(%s min annular width %s; actual %s)" ),
  106. constraint.GetName(),
  107. MessageTextFromValue( userUnits(), v_min ),
  108. MessageTextFromValue( userUnits(), annulus ) );
  109. if( fail_max )
  110. m_msg.Printf( _( "(%s max annular width %s; actual %s)" ),
  111. constraint.GetName(),
  112. MessageTextFromValue( userUnits(), v_max ),
  113. MessageTextFromValue( userUnits(), annulus ) );
  114. drcItem->SetErrorMessage( drcItem->GetErrorText() + wxS( " " ) + m_msg );
  115. drcItem->SetItems( item );
  116. drcItem->SetViolatingRule( constraint.GetParentRule() );
  117. reportViolation( drcItem, via->GetPosition() );
  118. }
  119. return true;
  120. };
  121. BOARD* board = m_drcEngine->GetBoard();
  122. int ii = 0;
  123. for( TRACK* item : board->Tracks() )
  124. {
  125. if( !reportProgress( ii++, board->Tracks().size(), delta ) )
  126. break;
  127. if( !checkAnnulus( item ) )
  128. return false; // DRC cancelled
  129. }
  130. reportRuleStatistics();
  131. return true;
  132. }
  133. int DRC_TEST_PROVIDER_ANNULUS::GetNumPhases() const
  134. {
  135. return 1;
  136. }
  137. std::set<DRC_CONSTRAINT_T> DRC_TEST_PROVIDER_ANNULUS::GetConstraintTypes() const
  138. {
  139. return { ANNULAR_WIDTH_CONSTRAINT };
  140. }
  141. namespace detail
  142. {
  143. static DRC_REGISTER_TEST_PROVIDER<DRC_TEST_PROVIDER_ANNULUS> dummy;
  144. }