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 along
18 * with this program. If not, see <http://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 <locale_io.h>
31#include <board.h>
33#include <footprint.h>
34#include <pad.h>
35#include <pcb_track.h>
36#include <vector>
37#include <cctype>
38#include <odb_netlist.h>
39#include <wx/filedlg.h>
40#include <wx/log.h>
41#include "odb_util.h"
42
43
44// Compute the side code for a pad. Returns "" if there is no copper
45std::string ODB_NET_LIST::ComputePadAccessSide( BOARD* aBoard, LSET aLayerMask )
46{
47 // Non-copper is not interesting here
48 aLayerMask &= LSET::AllCuMask( aBoard->GetCopperLayerCount() );
49
50 if( !aLayerMask.any() )
51 return "";
52
53 // Traditional TH pad
54 if( aLayerMask[F_Cu] && aLayerMask[B_Cu] )
55 return "B";
56
57 // Front SMD pad
58 if( aLayerMask[F_Cu] )
59 return "T";
60
61 // Back SMD pad
62 if( aLayerMask[B_Cu] )
63 return "D";
64
65 // Inner. We've already checked that there is no copper on the front or back, so
66 // since we checked that there is at least one copper layer, this must be an inner layer
67 return "I";
68}
69
70
72 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
73{
74 VECTOR2I origin = aBoard->GetDesignSettings().GetAuxOrigin();
75
76 for( FOOTPRINT* footprint : aBoard->Footprints() )
77 {
78 for( PAD* pad : footprint->Pads() )
79 {
80 ODB_NET_RECORD net_point;
81 net_point.side = ComputePadAccessSide( aBoard, pad->GetLayerSet() );
82
83 // It could be a mask only pad, we only handle pads with copper here
84 if( !net_point.side.empty() && net_point.side != "I" )
85 {
86 if( pad->GetNetCode() == 0 )
87 net_point.netname = "$NONE$";
88 else
89 net_point.netname = pad->GetNetname();
90 // net_point.pin = pad->GetNumber();
91 net_point.refdes = footprint->GetReference();
92 const VECTOR2I& drill = pad->GetDrillSize();
93 net_point.hole = pad->HasHole();
94
95 if( !net_point.hole )
96 net_point.drill_radius = 0;
97 else
98 net_point.drill_radius = std::min( drill.x, drill.y );
99
100 net_point.smd = pad->GetAttribute() == PAD_ATTRIB::SMD
101 || pad->GetAttribute() == PAD_ATTRIB::CONN;
102 net_point.is_via = false;
103 net_point.mechanical = ( pad->GetAttribute() == PAD_ATTRIB::NPTH );
104 net_point.x_location = pad->GetPosition().x - origin.x;
105 net_point.y_location = origin.y - pad->GetPosition().y;
106 net_point.x_size = pad->GetSize( PADSTACK::ALL_LAYERS ).x;
107
108 // Rule: round pads have y = 0
109 if( pad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CIRCLE )
110 net_point.y_size = net_point.x_size;
111 else
112 net_point.y_size = pad->GetSize( PADSTACK::ALL_LAYERS ).y;
113
114 // net_point.rotation = ( ANGLE_360 - pad->GetOrientation() ).Normalize().AsDegrees();
115
116 // if( net_point.rotation < 0 )
117 // net_point.rotation += 360;
118
119 // always output NET end point as net test point
120 net_point.epoint = "e";
121
122 // the value indicates which sides are *not* accessible
123 net_point.soldermask = 3;
124
125 if( pad->GetLayerSet()[F_Mask] )
126 net_point.soldermask &= ~1;
127
128 if( pad->GetLayerSet()[B_Mask] )
129 net_point.soldermask &= ~2;
130
131 aRecords[pad->GetNetCode()].push_back( net_point );
132 }
133 }
134 }
135}
136
137// Compute the side code for a via.
138std::string ODB_NET_LIST::ComputeViaAccessSide( BOARD* aBoard, int top_layer, int bottom_layer )
139{
140 // Easy case for through vias: top_layer is component, bottom_layer is
141 // solder, side code is Both
142 if( ( top_layer == F_Cu ) && ( bottom_layer == B_Cu ) )
143 return "B";
144
145 // Blind via, reachable from front, Top
146 if( top_layer == F_Cu )
147 return "T";
148
149 // Blind via, reachable from bottom, Down
150 if( bottom_layer == B_Cu )
151 return "D";
152
153 // It's a buried via, accessible from some inner layer, Inner
154 return "I";
155}
156
157
159 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
160{
161 VECTOR2I origin = aBoard->GetDesignSettings().GetAuxOrigin();
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 - origin.x;
192 net_point.y_location = origin.y - 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}
const VECTOR2I & GetAuxOrigin() const
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
int GetCopperLayerCount() const
Definition: board.cpp:777
const FOOTPRINTS & Footprints() const
Definition: board.h:338
const TRACKS & Tracks() const
Definition: board.h:336
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:942
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:583
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
int GetNetCode() const
Definition: netinfo.h:108
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)
Definition: odb_netlist.cpp:71
std::string ComputePadAccessSide(BOARD *aBoard, LSET aLayerMask)
Definition: odb_netlist.cpp:45
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
Definition: pad.h:54
This file is part of the common library.
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ F_Mask
Definition: layer_ids.h:97
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
wxString Data2String(double aVal)
Definition: odb_util.cpp:161
wxString GenLegalNetName(const wxString &aStr)
Definition: odb_util.cpp:57
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:97
Definition of file extensions used in Kicad.