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.

330 lines
13 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2009-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * @file board_stackup.h
  22. */
  23. #ifndef BOARD_STACKUP_H
  24. #define BOARD_STACKUP_H
  25. #include <vector>
  26. #include <wx/string.h>
  27. #include <layer_ids.h>
  28. class BOARD;
  29. class BOARD_DESIGN_SETTINGS;
  30. class OUTPUTFORMATTER;
  31. // A enum to manage the different layers inside the stackup layers.
  32. // Note the stackup layers include both dielectric and some layers handled by the board editor
  33. // Therefore a stackup layer item is not exactly like a board layer
  34. enum BOARD_STACKUP_ITEM_TYPE
  35. {
  36. BS_ITEM_TYPE_UNDEFINED, // For not yet initialized BOARD_STACKUP_ITEM item
  37. BS_ITEM_TYPE_COPPER, // A initialized BOARD_STACKUP_ITEM item for copper layers
  38. BS_ITEM_TYPE_DIELECTRIC, // A initialized BOARD_STACKUP_ITEM item for the
  39. // dielectric between copper layers
  40. BS_ITEM_TYPE_SOLDERPASTE, // A initialized BOARD_STACKUP_ITEM item for solder paste layers
  41. BS_ITEM_TYPE_SOLDERMASK, // A initialized BOARD_STACKUP_ITEM item for solder mask layers
  42. // note: this is a specialized dielectric material
  43. BS_ITEM_TYPE_SILKSCREEN, // A initialized BOARD_STACKUP_ITEM item for silkscreen layers
  44. };
  45. // A enum to manage edge connector fab info
  46. enum BS_EDGE_CONNECTOR_CONSTRAINTS
  47. {
  48. BS_EDGE_CONNECTOR_NONE, // No edge connector in board
  49. BS_EDGE_CONNECTOR_IN_USE, // some edge connector in board
  50. BS_EDGE_CONNECTOR_BEVELLED // Some connector in board, and the connector must be beveled
  51. };
  52. /**
  53. * A helper class to manage a dielectric layer set of parameters
  54. */
  55. class DIELECTRIC_PRMS
  56. {
  57. public:
  58. DIELECTRIC_PRMS() :
  59. m_Thickness(0), m_ThicknessLocked( false ),
  60. m_EpsilonR( 1.0 ), m_LossTangent( 0.0 )
  61. {}
  62. private:
  63. friend class BOARD_STACKUP_ITEM;
  64. wxString m_Material; /// type of material (for dielectric and solder mask)
  65. int m_Thickness; /// the physical layer thickness in internal units
  66. bool m_ThicknessLocked; /// true for dielectric layers with a fixed thickness
  67. /// (for impedance controlled purposes), unused for other layers
  68. double m_EpsilonR; /// For dielectric (and solder mask) the dielectric constant
  69. double m_LossTangent; /// For dielectric (and solder mask) the dielectric loss
  70. wxString m_Color; /// mainly for silkscreen and solder mask
  71. };
  72. /**
  73. * Manage one layer needed to make a physical board.
  74. *
  75. * It can be a solder mask, silk screen, copper or a dielectric.
  76. */
  77. class BOARD_STACKUP_ITEM
  78. {
  79. public:
  80. BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType );
  81. BOARD_STACKUP_ITEM( const BOARD_STACKUP_ITEM& aOther );
  82. /**
  83. * Add (insert) a DIELECTRIC_PRMS item to m_DielectricPrmsList
  84. * all values are set to default
  85. * @param aDielectricPrmsIdx is a index in m_DielectricPrmsList
  86. * the new item will be inserted at this position
  87. */
  88. void AddDielectricPrms( int aDielectricPrmsIdx );
  89. /**
  90. * Remove a DIELECTRIC_PRMS item from m_DielectricPrmsList
  91. * @param aDielectricPrmsIdx is the index of the parameters set
  92. * to remove in m_DielectricPrmsList
  93. */
  94. void RemoveDielectricPrms( int aDielectricPrmsIdx );
  95. /// @return true if the layer has a meaningful Epsilon R parameter
  96. /// namely dielectric layers: dielectric and solder mask
  97. bool HasEpsilonRValue() const;
  98. /// @return true if the layer has a meaningfully Dielectric Loss parameter
  99. /// namely dielectric layers: dielectric and solder mask
  100. bool HasLossTangentValue() const;
  101. /// @return true if the material is specified
  102. bool HasMaterialValue( int aDielectricSubLayer = 0 ) const;
  103. /// @return true if the material is editable
  104. bool IsMaterialEditable() const;
  105. /// @return true if the color is editable
  106. bool IsColorEditable() const;
  107. /// @return true if Thickness is editable
  108. bool IsThicknessEditable() const;
  109. /// @return a reasonable default value for a copper layer thickness
  110. static int GetCopperDefaultThickness();
  111. /// @return a reasonable default value for a solder mask layer thickness
  112. static int GetMaskDefaultThickness();
  113. /// @return a the number of sublayers in a dielectric layer.
  114. /// the count is >= 1 (there is at least one layer)
  115. int GetSublayersCount() const { return m_DielectricPrmsList.size(); }
  116. /// @return a wxString to print/display Epsilon R
  117. wxString FormatEpsilonR( int aDielectricSubLayer = 0 ) const;
  118. /// @return a wxString to print/display Loss Tangent
  119. wxString FormatLossTangent( int aDielectricSubLayer = 0 ) const;
  120. /// @return a wxString to print/display a dielectric name
  121. wxString FormatDielectricLayerName() const;
  122. // Getters:
  123. bool IsEnabled() const { return m_enabled; }
  124. BOARD_STACKUP_ITEM_TYPE GetType() const { return m_Type; }
  125. PCB_LAYER_ID GetBrdLayerId() const { return m_LayerId; }
  126. wxString GetLayerName() const { return m_LayerName; }
  127. wxString GetTypeName() const { return m_TypeName; }
  128. int GetDielectricLayerId() const { return m_DielectricLayerId; }
  129. wxString GetColor( int aDielectricSubLayer = 0 ) const;
  130. int GetThickness( int aDielectricSubLayer = 0 ) const;
  131. bool IsThicknessLocked( int aDielectricSubLayer = 0 ) const;
  132. double GetEpsilonR( int aDielectricSubLayer = 0 ) const;
  133. double GetLossTangent( int aDielectricSubLayer = 0 ) const;
  134. wxString GetMaterial( int aDielectricSubLayer = 0 ) const;
  135. // Setters:
  136. void SetEnabled( bool aEnable) { m_enabled = aEnable; }
  137. void SetBrdLayerId( PCB_LAYER_ID aBrdLayerId ) { m_LayerId = aBrdLayerId; }
  138. void SetLayerName( const wxString& aName ) { m_LayerName = aName; }
  139. void SetTypeName( const wxString& aName ) { m_TypeName = aName; }
  140. void SetDielectricLayerId( int aLayerId ) { m_DielectricLayerId = aLayerId; }
  141. void SetColor( const wxString& aColorName, int aDielectricSubLayer = 0 );
  142. void SetThickness( int aThickness, int aDielectricSubLayer = 0 );
  143. void SetThicknessLocked( bool aLocked, int aDielectricSubLayer = 0 );
  144. void SetEpsilonR( double aEpsilon, int aDielectricSubLayer = 0 );
  145. void SetLossTangent( double aTg, int aDielectricSubLayer = 0 );
  146. void SetMaterial( const wxString& aName, int aDielectricSubLayer = 0 );
  147. private:
  148. BOARD_STACKUP_ITEM_TYPE m_Type;
  149. wxString m_LayerName; /// name of layer as shown in layer manager. Useful to create reports
  150. wxString m_TypeName; /// type name of layer (copper, silk screen, core, prepreg ...)
  151. PCB_LAYER_ID m_LayerId; /// the layer id (F.Cu to B.Cu, F.Silk, B.silk, F.Mask, B.Mask)
  152. /// and UNDEFINED_LAYER (-1) for dielectric layers that are not
  153. /// really layers for the board editor
  154. int m_DielectricLayerId;/// the "layer" id for dielectric layers,
  155. /// from 1 (top) to 31 (bottom)
  156. /// (only 31 dielectric layers for 32 copper layers)
  157. /// List of dielectric parameters
  158. /// usually only one item, but in complex (microwave) boards, one can have
  159. /// more than one dielectric layer between 2 copper layers, and therefore
  160. /// more than one item in list
  161. std::vector<DIELECTRIC_PRMS> m_DielectricPrmsList;
  162. bool m_enabled; /// true if this stackup item must be taken in account,
  163. /// false to ignore it. Mainly used in dialog stackup editor.
  164. };
  165. /**
  166. * Manage layers needed to make a physical board.
  167. *
  168. * They are solder mask, silk screen, copper and dielectric. Some other layers, used in
  169. * fabrication, are not managed here because they are not used to make a physical board itself.
  170. *
  171. * @note There are a few other parameters related to the physical stackup like finish type,
  172. * impedance control and a few others.
  173. */
  174. class BOARD_STACKUP
  175. {
  176. public:
  177. BOARD_STACKUP();
  178. BOARD_STACKUP( const BOARD_STACKUP& aOther );
  179. BOARD_STACKUP& operator=( const BOARD_STACKUP& aOther );
  180. ~BOARD_STACKUP() { RemoveAll(); }
  181. const std::vector<BOARD_STACKUP_ITEM*>& GetList() const { return m_list; }
  182. /// @return a reference to the layer aIndex, or nullptr if not exists
  183. BOARD_STACKUP_ITEM* GetStackupLayer( int aIndex );
  184. /**
  185. * @return the board layers full mask allowed in the stackup list
  186. * i.e. the SilkS, Mask, Paste and all copper layers
  187. */
  188. static LSET StackupAllowedBrdLayers()
  189. {
  190. return LSET( 6, F_SilkS, F_Mask, F_Paste, B_SilkS, B_Mask, B_Paste )
  191. | LSET::ExternalCuMask() | LSET::InternalCuMask();
  192. }
  193. /// Delete all items in list and clear the list
  194. void RemoveAll();
  195. /// @return the number of layers in the stackup
  196. int GetCount() const { return (int) m_list.size(); }
  197. /// @return the board thickness ( in UI) from the thickness of BOARD_STACKUP_ITEM list
  198. int BuildBoardThicknessFromStackup() const;
  199. /// Add a new item in stackup layer
  200. void Add( BOARD_STACKUP_ITEM* aItem ) { m_list.push_back( aItem ); }
  201. /**
  202. * Synchronize the BOARD_STACKUP_ITEM* list with the board.
  203. * Not enabled layers are removed
  204. * Missing layers are added
  205. * @param aSettings, is the current board setting.
  206. * @return true if changes are made
  207. */
  208. bool SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings );
  209. /**
  210. * Create a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
  211. * @param aSettings is the current board setting.
  212. * if nullptr, build a full stackup (with 32 copper layers)
  213. * @param aActiveCopperLayersCount is used only if aSettings == nullptr is the number
  214. * of copper layers to use to calculate a default dielectric thickness.
  215. * ((<= 0 to use all copper layers)
  216. */
  217. void BuildDefaultStackupList( const BOARD_DESIGN_SETTINGS* aSettings,
  218. int aActiveCopperLayersCount = 0 );
  219. /**
  220. * Write the stackup info on board file
  221. * @param aFormatter is the OUTPUTFORMATTER used to create the file
  222. * @param aBoard is the board
  223. * @param aNestLevel is the index to nest level to indent the lines in file
  224. */
  225. void FormatBoardStackup( OUTPUTFORMATTER* aFormatter,
  226. const BOARD* aBoard, int aNestLevel ) const;
  227. /**
  228. * Calculate the distance (height) between the two given copper layers.
  229. *
  230. * This factors in the thickness of any dielectric and copper layers between the two given
  231. * layers, and half the height of the given start and end layers. This half-height calculation
  232. * allows this to be used for consistent length measurements when calculating net length through
  233. * a series of vias. A more advanced algorithm would be possible once we have a good concept of
  234. * the start and end for a length measurement, but for now this will do.
  235. * See https://gitlab.com/kicad/code/kicad/-/issues/8384 for more background.
  236. *
  237. * @param aFirstLayer is a copper layer
  238. * @param aSecondLayer is a different copper layer
  239. * @return the height (in IU) between the two layers
  240. */
  241. int GetLayerDistance( PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer ) const;
  242. /**
  243. * The name of external copper finish
  244. */
  245. wxString m_FinishType;
  246. /**
  247. * True if some layers have impedance controlled tracks or have specific
  248. * constrains for micro-wave applications
  249. * If the board has dielectric constrains, the .gbrjob will contain
  250. * info about dielectric constrains: loss tangent and Epsilon rel.
  251. * If not, these values will be not specified in job file.
  252. */
  253. bool m_HasDielectricConstrains;
  254. /**
  255. * True if some layers (copper and/or dielectric) have specific thickness
  256. */
  257. bool m_HasThicknessConstrains;
  258. /**
  259. * If the board has edge connector cards, some constrains can be specified
  260. * in job file:
  261. * BS_EDGE_CONNECTOR_NONE = no edge connector
  262. * BS_EDGE_CONNECTOR_IN_USE = board has edge connectors
  263. * BS_EDGE_CONNECTOR_BEVELLED = edge connectors are beveled
  264. */
  265. BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints;
  266. bool m_CastellatedPads; ///< True if castellated pads exist
  267. bool m_EdgePlating; ///< True if the edge board is plated
  268. private:
  269. // The list of items describing the stackup for fabrication.
  270. // this is not just copper layers, but also mask dielectric layers
  271. std::vector<BOARD_STACKUP_ITEM*> m_list;
  272. };
  273. #endif // BOARD_STACKUP_H