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 (C) 2024 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();
49 if( !aLayerMask.any() )
50 return "";
51
52 // Traditional TH pad
53 if( aLayerMask[F_Cu] && aLayerMask[B_Cu] )
54 return "B";
55
56 // Front SMD pad
57 if( aLayerMask[F_Cu] )
58 return "T";
59
60 // Back SMD pad
61 if( aLayerMask[B_Cu] )
62 return "D";
63
64 // Inner
65 for( int layer = In1_Cu; layer < B_Cu; ++layer )
66 {
67 if( aLayerMask[layer] )
68 return "I";
69 }
70
71 // This shouldn't happen
72 wxLogDebug( "Unhandled layer mask input when compute pad access side of ODB++ netlist file." );
73 return "";
74}
75
76
78 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
79{
80 VECTOR2I origin = aBoard->GetDesignSettings().GetAuxOrigin();
81
82 for( FOOTPRINT* footprint : aBoard->Footprints() )
83 {
84 for( PAD* pad : footprint->Pads() )
85 {
86 ODB_NET_RECORD net_point;
87 net_point.side = ComputePadAccessSide( aBoard, pad->GetLayerSet() );
88
89 // It could be a mask only pad, we only handle pads with copper here
90 if( !net_point.side.empty() && net_point.side != "I" )
91 {
92 if( pad->GetNetCode() == 0 )
93 net_point.netname = "$NONE$";
94 else
95 net_point.netname = pad->GetNetname();
96 // net_point.pin = pad->GetNumber();
97 net_point.refdes = footprint->GetReference();
98 const VECTOR2I& drill = pad->GetDrillSize();
99 net_point.hole = pad->HasHole();
100
101 if( !net_point.hole )
102 net_point.drill_radius = 0;
103 else
104 net_point.drill_radius = std::min( drill.x, drill.y );
105
106 net_point.smd = pad->GetAttribute() == PAD_ATTRIB::SMD
107 || pad->GetAttribute() == PAD_ATTRIB::CONN;
108 net_point.is_via = false;
109 net_point.mechanical = ( pad->GetAttribute() == PAD_ATTRIB::NPTH );
110 net_point.x_location = pad->GetPosition().x - origin.x;
111 net_point.y_location = origin.y - pad->GetPosition().y;
112 net_point.x_size = pad->GetSize( PADSTACK::ALL_LAYERS ).x;
113
114 // Rule: round pads have y = 0
115 if( pad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CIRCLE )
116 net_point.y_size = net_point.x_size;
117 else
118 net_point.y_size = pad->GetSize( PADSTACK::ALL_LAYERS ).y;
119
120 // net_point.rotation = ( ANGLE_360 - pad->GetOrientation() ).Normalize().AsDegrees();
121
122 // if( net_point.rotation < 0 )
123 // net_point.rotation += 360;
124
125 // always output NET end point as net test point
126 net_point.epoint = "e";
127
128 // the value indicates which sides are *not* accessible
129 net_point.soldermask = 3;
130
131 if( pad->GetLayerSet()[F_Mask] )
132 net_point.soldermask &= ~1;
133
134 if( pad->GetLayerSet()[B_Mask] )
135 net_point.soldermask &= ~2;
136
137 aRecords[pad->GetNetCode()].push_back( net_point );
138 }
139 }
140 }
141}
142
143// Compute the side code for a via.
144std::string ODB_NET_LIST::ComputeViaAccessSide( BOARD* aBoard, int top_layer, int bottom_layer )
145{
146 // Easy case for through vias: top_layer is component, bottom_layer is
147 // solder, side code is Both
148 if( ( top_layer == F_Cu ) && ( bottom_layer == B_Cu ) )
149 return "B";
150
151 // Blind via, reachable from front, Top
152 if( top_layer == F_Cu )
153 return "T";
154
155 // Blind via, reachable from bottom, Down
156 if( bottom_layer == B_Cu )
157 return "D";
158
159 // It's a buried via, accessible from some inner layer, Inner
160 return "I";
161}
162
163
165 std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords )
166{
167 VECTOR2I origin = aBoard->GetDesignSettings().GetAuxOrigin();
168
169 // Enumerate all the track segments and keep the vias
170 for( auto track : aBoard->Tracks() )
171 {
172 if( track->Type() == PCB_VIA_T )
173 {
174 PCB_VIA* via = static_cast<PCB_VIA*>( track );
175 PCB_LAYER_ID top_layer, bottom_layer;
176
177 via->LayerPair( &top_layer, &bottom_layer );
178
179 ODB_NET_RECORD net_point;
180 net_point.side = ComputeViaAccessSide( aBoard, top_layer, bottom_layer );
181
182 if( net_point.side != "I" )
183 {
184 NETINFO_ITEM* net = track->GetNet();
185 net_point.smd = false;
186 net_point.hole = true;
187
188 if( net->GetNetCode() == 0 )
189 net_point.netname = "$NONE$";
190 else
191 net_point.netname = net->GetNetname();
192
193 net_point.refdes = "VIA";
194 net_point.is_via = true;
195 net_point.drill_radius = via->GetDrillValue();
196 net_point.mechanical = false;
197 net_point.x_location = via->GetPosition().x - origin.x;
198 net_point.y_location = origin.y - via->GetPosition().y;
199
200 // via always has drill radius, Width and Height are 0
201 net_point.x_size = 0;
202 net_point.y_size = 0; // Round so height = 0
203 net_point.epoint = "e"; // only buried via is "m" net mid point
204
205 // the value indicates which sides are *not* accessible
206 net_point.soldermask = 3;
207
208 if( via->GetLayerSet()[F_Mask] )
209 net_point.soldermask &= ~1;
210
211 if( via->GetLayerSet()[B_Mask] )
212 net_point.soldermask &= ~2;
213
214 aRecords[net->GetNetCode()].push_back( net_point );
215 }
216 }
217 }
218}
219
220
221void ODB_NET_LIST::WriteNetPointRecords( std::map<size_t, std::vector<ODB_NET_RECORD>>& aRecords,
222 std::ostream& aStream )
223{
224 aStream << "H optimize n staggered n" << std::endl;
225
226 for( const auto& [key, vec] : aRecords )
227 {
228 aStream << "$" << key << " " << ODB::GenLegalNetName( vec.front().netname ) << std::endl;
229 }
230
231 aStream << "#" << std::endl << "#Netlist points" << std::endl << "#" << std::endl;
232
233 for( const auto& [key, vec] : aRecords )
234 {
235 for( const auto& net_point : vec )
236 {
237 aStream << key << " ";
238
239 if( net_point.hole )
240 aStream << ODB::Data2String( net_point.drill_radius );
241 else
242 aStream << 0;
243
244 aStream << " " << ODB::Data2String( net_point.x_location ) << " "
245 << ODB::Data2String( net_point.y_location ) << " " << net_point.side << " ";
246
247 if( !net_point.hole )
248 aStream << ODB::Data2String( net_point.x_size ) << " "
249 << ODB::Data2String( net_point.y_size ) << " ";
250
251 std::string exp;
252
253 if( net_point.soldermask == 3 )
254 exp = "c";
255 else if( net_point.soldermask == 2 )
256 exp = "s";
257 else if( net_point.soldermask == 1 )
258 exp = "p";
259 else if( net_point.soldermask == 0 )
260 exp = "e";
261
262 aStream << net_point.epoint << " " << exp;
263
264 if( net_point.hole )
265 aStream << " staggered 0 0 0";
266
267 if( net_point.is_via )
268 aStream << " v";
269
270 aStream << std::endl;
271 }
272 }
273}
274
275
276void ODB_NET_LIST::Write( std::ostream& aStream )
277{
278 std::map<size_t, std::vector<ODB_NET_RECORD>> net_point_records;
279
280 InitViaNetPoints( m_board, net_point_records );
281
282 InitPadNetPoints( m_board, net_point_records );
283
284 WriteNetPointRecords( net_point_records, aStream );
285}
const VECTOR2I & GetAuxOrigin()
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
const FOOTPRINTS & Footprints() const
Definition: board.h:331
const TRACKS & Tracks() const
Definition: board.h:329
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:890
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:676
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:77
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:138
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
@ In1_Cu
Definition: layer_ids.h:66
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
wxString Data2String(double aVal)
Definition: odb_util.cpp:152
wxString GenLegalNetName(const wxString &aStr)
Definition: odb_util.cpp:56
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.