KiCad PCB EDA Suite
Loading...
Searching...
No Matches
board_stackup_reporter.cpp
Go to the documentation of this file.
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) 2026 Krishna Swaroop <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
25
26#include "wx/string.h"
27#include "wx/sstream.h"
28
29#include <base_units.h>
30#include <io/csv.h>
31#include <locale_io.h>
32#include <vector>
33
34#include "board_stackup.h"
36
37
38static wxString layerDisplayName( const BOARD_STACKUP_ITEM* aItem )
39{
40 if( aItem->GetType() == BS_ITEM_TYPE_DIELECTRIC )
41 return aItem->FormatDielectricLayerName();
42
43 return aItem->GetLayerName();
44}
45
46
47static void appendCsvProperties( std::vector<std::vector<wxString>>& aRows, BOARD_STACKUP& aStackup,
48 const STACKUP_CSV_OPTIONS& aOptions )
49{
50 auto appendProperty = [&]( const wxString& aName, const wxString& aValue )
51 {
52 aRows.push_back( { aName, aValue } );
53 };
54
55 if( aOptions.includeFinish )
56 appendProperty( wxT( "Finish" ), aStackup.m_FinishType );
57
58 if( aOptions.includeBoardOptions )
59 {
60 if( aStackup.m_HasDielectricConstrains )
61 appendProperty( wxT( "Impedance Controlled" ), wxT( "yes" ) );
62
63 if( aStackup.m_EdgePlating )
64 appendProperty( wxT( "Plated edges" ), wxT( "yes" ) );
65
67 {
68 wxString conn = wxT( "yes" );
69
71 conn << wxT( ",bevelled" );
72
73 appendProperty( wxT( "EdgeConnector" ), conn );
74 }
75 }
76}
77
78
79wxString BuildStackupReport( BOARD_STACKUP& aStackup, EDA_UNITS aUnits )
80{
81 // Build a ascii representation of stackup and copy it in the clipboard
82 wxString report;
83
84 wxString txt;
85 LOCALE_IO toggle; // toggles on the C locale to write floating values, then off.
86
87 for( const BOARD_STACKUP_ITEM* item : aStackup.GetList() )
88 {
89 // Skip stackup items useless for the current board
90 if( !item->IsEnabled() )
91 continue;
92
93 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
94 {
95 wxString sublayer_text;
96
97 if( item->GetSublayersCount() )
98 {
99 sublayer_text.Printf( wxT( "\n sublayer \"1/%d\"" ),
100 item->GetSublayersCount() );
101 }
102
103 txt.Printf( wxT( "layer \"%s\" type \"%s\"%s" ),
104 item->FormatDielectricLayerName(),
105 item->GetTypeName(), sublayer_text );
106 }
107 else
108 {
109 txt.Printf( wxT( "layer \"%s\" type \"%s\"" ),
110 item->GetLayerName(),
111 item->GetTypeName() );
112 }
113
114 report << txt;
115
116 if( item->IsColorEditable() )
117 {
118 txt.Printf( wxT( " Color \"%s\"" ), item->GetColor() );
119 report << txt;
120 }
121
122 for( int idx = 0; idx < item->GetSublayersCount(); idx++ )
123 {
124 if( idx ) // not printed for the main (first) layer.
125 {
126 txt.Printf( wxT( "\n sublayer \"%d/%d\"" ), idx+1, item->GetSublayersCount() );
127 report << txt;
128 }
129
130 if( item->IsThicknessEditable() )
131 {
132 txt.Printf( wxT( " Thickness %s" ),
133 EDA_UNIT_UTILS::UI::StringFromValue( pcbIUScale, aUnits, item->GetThickness( idx ), true ) );
134 report << txt;
135
136 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked( idx ) )
137 {
138 txt.Printf( wxT( " Locked" ) );
139 report << txt;
140 }
141 }
142
143 if( item->IsMaterialEditable() )
144 {
145 txt.Printf( wxT( " Material \"%s\"" ), item->GetMaterial( idx ) );
146 report << txt;
147 }
148
149 if( item->HasEpsilonRValue() )
150 {
151 txt.Printf( wxT( " EpsilonR %s" ), item->FormatEpsilonR( idx ) );
152 report << txt;
153 }
154
155 if( item->HasLossTangentValue() )
156 {
157 txt.Printf( wxT( " LossTg %s" ), item->FormatLossTangent( idx ) );
158 report << txt;
159 }
160 }
161
162 report << '\n';
163 }
164
165 // Finish and other options:
166 txt.Printf( wxT( "Finish \"%s\"" ), aStackup.m_FinishType );
167 report << txt;
168
169 if( aStackup.m_HasDielectricConstrains )
170 report << wxT( " Option \"Impedance Controlled\"" );
171
172 if( aStackup.m_EdgePlating )
173 report << wxT( " Option \"Plated edges\"" );
174
176 {
177 wxString conn_txt = wxT( "yes" );
178
180 conn_txt << wxT( ",bevelled" );
181
182 txt.Printf( wxT( " EdgeConnector \"%s\"" ), conn_txt );
183 report << txt;
184 }
185
186 report << '\n';
187
188 return report;
189}
190
191
192wxString BuildStackupCsv( BOARD_STACKUP& aStackup, EDA_UNITS aUnits, const STACKUP_CSV_OPTIONS& aOptions )
193{
194 std::vector<std::vector<wxString>> rows;
195 LOCALE_IO toggle;
196
197 std::vector<wxString> header = { wxT( "Layer" ), wxT( "Type" ), wxT( "Sublayer" ) };
198
199 if( aOptions.includeThickness )
200 {
201 header.push_back( wxT( "Thickness" ) );
202 header.push_back( wxT( "Locked" ) );
203 }
204
205 if( aOptions.includeMaterial )
206 header.push_back( wxT( "Material" ) );
207
208 if( aOptions.includeColor )
209 header.push_back( wxT( "Color" ) );
210
211 if( aOptions.includeEpsilonR )
212 header.push_back( wxT( "EpsilonR" ) );
213
214 if( aOptions.includeLossTangent )
215 header.push_back( wxT( "LossTg" ) );
216
217 rows.push_back( header );
218
219 for( const BOARD_STACKUP_ITEM* item : aStackup.GetList() )
220 {
221 if( !item->IsEnabled() )
222 continue;
223
224 int sublayerCount = item->GetSublayersCount();
225
226 if( sublayerCount <= 0 )
227 sublayerCount = 1;
228
229 for( int idx = 0; idx < sublayerCount; idx++ )
230 {
231 const bool hasSublayerData = item->GetSublayersCount() > 0;
232 std::vector<wxString> row;
233
234 row.push_back( layerDisplayName( item ) );
235 row.push_back( item->GetTypeName() );
236
237 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->GetSublayersCount() > 1 )
238 row.push_back( wxString::Format( wxT( "%d/%d" ), idx + 1, item->GetSublayersCount() ) );
239 else
240 row.push_back( wxEmptyString );
241
242 if( aOptions.includeThickness )
243 {
244 wxString thickness;
245
246 if( item->IsThicknessEditable() && hasSublayerData )
247 {
248 thickness =
249 EDA_UNIT_UTILS::UI::StringFromValue( pcbIUScale, aUnits, item->GetThickness( idx ), true );
250 }
251
252 row.push_back( thickness );
253
254 const bool locked =
255 item->GetType() == BS_ITEM_TYPE_DIELECTRIC && hasSublayerData && item->IsThicknessLocked( idx );
256 row.push_back( locked ? wxT( "yes" ) : wxEmptyString );
257 }
258
259 if( aOptions.includeMaterial )
260 {
261 row.push_back( ( item->IsMaterialEditable() && hasSublayerData ) ? item->GetMaterial( idx )
262 : wxString() );
263 }
264
265 if( aOptions.includeColor )
266 row.push_back( item->IsColorEditable() ? item->GetColor() : wxString() );
267
268 if( aOptions.includeEpsilonR )
269 {
270 row.push_back( ( item->HasEpsilonRValue() && hasSublayerData ) ? item->FormatEpsilonR( idx )
271 : wxString() );
272 }
273
274 if( aOptions.includeLossTangent )
275 {
276 row.push_back( ( item->HasLossTangentValue() && hasSublayerData ) ? item->FormatLossTangent( idx )
277 : wxString() );
278 }
279
280 rows.push_back( row );
281 }
282 }
283
284 if( aOptions.includeFinish || aOptions.includeBoardOptions )
285 {
286 rows.push_back( {} );
287 rows.push_back( { wxT( "Property" ), wxT( "Value" ) } );
288 appendCsvProperties( rows, aStackup, aOptions );
289 }
290
291 wxStringOutputStream os;
292 CSV_WRITER writer( os );
293 writer.WriteLines( rows );
294
295 return os.GetString();
296}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
@ BS_EDGE_CONNECTOR_BEVELLED
@ BS_EDGE_CONNECTOR_NONE
@ BS_ITEM_TYPE_DIELECTRIC
wxString BuildStackupCsv(BOARD_STACKUP &aStackup, EDA_UNITS aUnits, const STACKUP_CSV_OPTIONS &aOptions)
wxString BuildStackupReport(BOARD_STACKUP &aStackup, EDA_UNITS aUnits)
static wxString layerDisplayName(const BOARD_STACKUP_ITEM *aItem)
static void appendCsvProperties(std::vector< std::vector< wxString > > &aRows, BOARD_STACKUP &aStackup, const STACKUP_CSV_OPTIONS &aOptions)
Manage one layer needed to make a physical board.
wxString FormatDielectricLayerName() const
wxString GetLayerName() const
BOARD_STACKUP_ITEM_TYPE GetType() const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
void WriteLines(const std::vector< std::vector< wxString > > &aRows)
Write a vector of rows to the stream.
Definition csv.cpp:18
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
EDA_UNITS
Definition eda_units.h:44
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
Options controlling which stackup fields are included in CSV exports.