KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_netlist.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21
22#include <confirm.h>
23#include <gestfich.h>
24#include <kiface_base.h>
25#include <pcb_edit_frame.h>
26#include <trigo.h>
27#include <build_version.h>
28#include <macros.h>
30#include <board.h>
31#include <footprint.h>
32#include <pad.h>
33#include <pcb_track.h>
34#include <vector>
35#include <cctype>
36#include <odb_netlist.h>
37#include <wx/filedlg.h>
38#include <wx/log.h>
39#include "odb_util.h"
40
41
42// Compute the side code for a pad. Returns "" if there is no copper
43std::string ODB_NET_LIST::ComputePadAccessSide( BOARD* aBoard, LSET aLayerMask )
44{
45 // Non-copper is not interesting here
46 aLayerMask &= LSET::AllCuMask( aBoard->GetCopperLayerCount() );
47
48 if( !aLayerMask.any() )
49 return "";
50
51 // Traditional TH pad
52 if( aLayerMask[F_Cu] && aLayerMask[B_Cu] )
53 return "B";
54
55 // Front SMD pad
56 if( aLayerMask[F_Cu] )
57 return "T";
58
59 // Back SMD pad
60 if( aLayerMask[B_Cu] )
61 return "D";
62
63 // Inner. We've already checked that there is no copper on the front or back, so
64 // since we checked that there is at least one copper layer, this must be an inner layer
65 return "I";
66}
67
68
70 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
71{
72 for( FOOTPRINT* footprint : aBoard->Footprints() )
73 {
74 for( PAD* pad : footprint->Pads() )
75 {
76 ODB_NET_RECORD net_point;
77 net_point.side = ComputePadAccessSide( aBoard, pad->GetLayerSet() );
78
79 // It could be a mask only pad, we only handle pads with copper here
80 if( !net_point.side.empty() && net_point.side != "I" )
81 {
82 if( pad->GetNetCode() == 0 )
83 net_point.netname = "$NONE$";
84 else
85 net_point.netname = pad->GetNetname();
86 // net_point.pin = pad->GetNumber();
87 net_point.refdes = footprint->GetReference();
88 const VECTOR2I& drill = pad->GetDrillSize();
89 net_point.hole = pad->HasHole();
90
91 if( !net_point.hole )
92 net_point.drill_radius = 0;
93 else
94 net_point.drill_radius = std::min( drill.x, drill.y );
95
96 net_point.smd = pad->GetAttribute() == PAD_ATTRIB::SMD
97 || pad->GetAttribute() == PAD_ATTRIB::CONN;
98 net_point.is_via = false;
99 net_point.mechanical = ( pad->GetAttribute() == PAD_ATTRIB::NPTH );
100 net_point.x_location = pad->GetPosition().x;
101 net_point.y_location = -pad->GetPosition().y;
102
103 // net_point.rotation = ( ANGLE_360 - pad->GetOrientation() ).Normalize().AsDegrees();
104
105 // if( net_point.rotation < 0 )
106 // net_point.rotation += 360;
107
108 // always output NET end point as net test point
109 net_point.epoint = "e";
110
111 // the value indicates which sides are *not* accessible
112 net_point.soldermask = 3;
113
114 if( pad->GetLayerSet()[F_Mask] )
115 net_point.soldermask &= ~1;
116
117 if( pad->GetLayerSet()[B_Mask] )
118 net_point.soldermask &= ~2;
119
120 // The land size is written only for undrilled pads, which are single-sided, so
121 // the access side gives the copper to report
122 PCB_LAYER_ID sideLayer = pad->Padstack().EffectiveLayerFor(
123 net_point.side == "D" ? B_Cu : F_Cu );
124
125 net_point.x_size = pad->GetSize( sideLayer ).x;
126
127 // Rule: round pads have y = 0
128 if( pad->GetShape( sideLayer ) == PAD_SHAPE::CIRCLE )
129 net_point.y_size = net_point.x_size;
130 else
131 net_point.y_size = pad->GetSize( sideLayer ).y;
132
133 aRecords[pad->GetNetCode()].push_back( net_point );
134 }
135 }
136 }
137}
138
139// Compute the side code for a via.
140std::string ODB_NET_LIST::ComputeViaAccessSide( BOARD* aBoard, int top_layer, int bottom_layer )
141{
142 // Easy case for through vias: top_layer is component, bottom_layer is
143 // solder, side code is Both
144 if( ( top_layer == F_Cu ) && ( bottom_layer == B_Cu ) )
145 return "B";
146
147 // Blind via, reachable from front, Top
148 if( top_layer == F_Cu )
149 return "T";
150
151 // Blind via, reachable from bottom, Down
152 if( bottom_layer == B_Cu )
153 return "D";
154
155 // It's a buried via, accessible from some inner layer, Inner
156 return "I";
157}
158
159
161 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
162{
163 // Enumerate all the track segments and keep the vias
164 for( auto track : aBoard->Tracks() )
165 {
166 if( track->Type() == PCB_VIA_T )
167 {
168 PCB_VIA* via = static_cast<PCB_VIA*>( track );
169 PCB_LAYER_ID top_layer, bottom_layer;
170
171 via->LayerPair( &top_layer, &bottom_layer );
172
173 ODB_NET_RECORD net_point;
174 net_point.side = ComputeViaAccessSide( aBoard, top_layer, bottom_layer );
175
176 if( net_point.side != "I" )
177 {
178 NETINFO_ITEM* net = track->GetNet();
179 net_point.smd = false;
180 net_point.hole = true;
181
182 if( net->GetNetCode() == 0 )
183 net_point.netname = "$NONE$";
184 else
185 net_point.netname = net->GetNetname();
186
187 net_point.refdes = "VIA";
188 net_point.is_via = true;
189 net_point.drill_radius = via->GetDrillValue();
190 net_point.mechanical = false;
191 net_point.x_location = via->GetPosition().x;
192 net_point.y_location = -via->GetPosition().y;
193
194 // via always has drill radius, Width and Height are 0
195 net_point.x_size = 0;
196 net_point.y_size = 0; // Round so height = 0
197 net_point.epoint = "e"; // only buried via is "m" net mid point
198
199 // the value indicates which sides are *not* accessible
200 net_point.soldermask = 3;
201
202 if( via->GetLayerSet()[F_Mask] )
203 net_point.soldermask &= ~1;
204
205 if( via->GetLayerSet()[B_Mask] )
206 net_point.soldermask &= ~2;
207
208 aRecords[net->GetNetCode()].push_back( net_point );
209 }
210 }
211 }
212}
213
214
215void ODB_NET_LIST::WriteNetPointRecords( std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords,
216 std::ostream& aStream )
217{
218 aStream << "H optimize n staggered n" << std::endl;
219
220 for( const auto& [key, vec] : aRecords )
221 {
222 aStream << "$" << key << " " << ODB::GenLegalNetName( vec.front().netname ) << std::endl;
223 }
224
225 aStream << "#" << std::endl << "#Netlist points" << std::endl << "#" << std::endl;
226
227 for( const auto& [key, vec] : aRecords )
228 {
229 for( const auto& net_point : vec )
230 {
231 aStream << key << " ";
232
233 if( net_point.hole )
234 aStream << ODB::Data2String( net_point.drill_radius );
235 else
236 aStream << 0;
237
238 aStream << " " << ODB::Data2String( net_point.x_location ) << " "
239 << ODB::Data2String( net_point.y_location ) << " " << net_point.side << " ";
240
241 if( !net_point.hole )
242 aStream << ODB::Data2String( net_point.x_size ) << " "
243 << ODB::Data2String( net_point.y_size ) << " ";
244
245 std::string exp;
246
247 if( net_point.soldermask == 3 )
248 exp = "c";
249 else if( net_point.soldermask == 2 )
250 exp = "s";
251 else if( net_point.soldermask == 1 )
252 exp = "p";
253 else if( net_point.soldermask == 0 )
254 exp = "e";
255
256 aStream << net_point.epoint << " " << exp;
257
258 if( net_point.hole )
259 aStream << " staggered 0 0 0";
260
261 if( net_point.is_via )
262 aStream << " v";
263
264 aStream << std::endl;
265 }
266 }
267}
268
269
270void ODB_NET_LIST::Write( std::ostream& aStream )
271{
272 std::map<size_t, std::vector<ODB_NET_RECORD>> net_point_records;
273
274 InitViaNetPoints( m_board, net_point_records );
275
276 InitPadNetPoints( m_board, net_point_records );
277
278 WriteNetPointRecords( net_point_records, aStream );
279}
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
int GetCopperLayerCount() const
Definition board.cpp:1131
const FOOTPRINTS & Footprints() const
Definition board.h:463
const TRACKS & Tracks() const
Definition board.h:461
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetname() const
Definition netinfo.h:110
int GetNetCode() const
Definition netinfo.h:104
BOARD * m_board
Definition odb_netlist.h:66
void WriteNetPointRecords(std::map< size_t, std::vector< ODB_NET_RECORD > > &aRecords, std::ostream &aStream)
Writes a list of records to the given output stream.
void InitViaNetPoints(BOARD *aBoard, std::map< size_t, std::vector< ODB_NET_RECORD > > &aRecords)
std::string ComputeViaAccessSide(BOARD *aBoard, int top_layer, int bottom_layer)
void Write(std::ostream &aStream)
void InitPadNetPoints(BOARD *aBoard, std::map< size_t, std::vector< ODB_NET_RECORD > > &aRecords)
std::string ComputePadAccessSide(BOARD *aBoard, LSET aLayerMask)
Definition pad.h:61
This file is part of the common library.
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
wxString Data2String(double aVal)
Definition odb_util.cpp:185
wxString GenLegalNetName(const wxString &aStr)
Definition odb_util.cpp:57
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
std::string side
Definition odb_netlist.h:36
std::string epoint
Definition odb_netlist.h:46
wxString netname
Definition odb_netlist.h:32
std::string refdes
Definition odb_netlist.h:33
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
Definition of file extensions used in Kicad.