KiCad PCB EDA Suite
export_d356.cpp File Reference

Export IPC-D-356 test format. More...

#include <confirm.h>
#include <gestfich.h>
#include <kiface_base.h>
#include <pcb_edit_frame.h>
#include <trigo.h>
#include <build_version.h>
#include <macros.h>
#include <wildcards_and_files_ext.h>
#include <locale_io.h>
#include <pcbnew.h>
#include <board.h>
#include <board_design_settings.h>
#include <footprint.h>
#include <pad.h>
#include <pcb_track.h>
#include <vector>
#include <cctype>
#include <math/util.h>
#include <export_d356.h>
#include <wx/filedlg.h>

Go to the source code of this file.

Functions

static int compute_pad_access_code (BOARD *aPcb, LSET aLayerMask)
 
static int iu_to_d356 (int iu, int clamp)
 
static void build_pad_testpoints (BOARD *aPcb, std::vector< D356_RECORD > &aRecords)
 
static int via_access_code (BOARD *aPcb, int top_layer, int bottom_layer)
 
static void build_via_testpoints (BOARD *aPcb, std::vector< D356_RECORD > &aRecords)
 
static const wxString intern_new_d356_netname (const wxString &aNetname, std::map< wxString, wxString > &aMap, std::set< wxString > &aSet)
 

Detailed Description

Export IPC-D-356 test format.

Definition in file export_d356.cpp.

Function Documentation

◆ build_pad_testpoints()

static void build_pad_testpoints ( BOARD aPcb,
std::vector< D356_RECORD > &  aRecords 
)
static

Definition at line 96 of file export_d356.cpp.

97 {
98  wxPoint origin = aPcb->GetDesignSettings().GetAuxOrigin();
99 
100  for( FOOTPRINT* footprint : aPcb->Footprints() )
101  {
102  for( PAD* pad : footprint->Pads() )
103  {
104  D356_RECORD rk;
105  rk.access = compute_pad_access_code( aPcb, pad->GetLayerSet() );
106 
107  // It could be a mask only pad, we only handle pads with copper here
108  if( rk.access != -1 )
109  {
110  rk.netname = pad->GetNetname();
111  rk.pin = pad->GetNumber();
112  rk.refdes = footprint->GetReference();
113  rk.midpoint = false; // XXX MAYBE need to be computed (how?)
114  const wxSize& drill = pad->GetDrillSize();
115  rk.drill = std::min( drill.x, drill.y );
116  rk.hole = (rk.drill != 0);
117  rk.smd = pad->GetAttribute() == PAD_ATTRIB::SMD;
118  rk.mechanical = ( pad->GetAttribute() == PAD_ATTRIB::NPTH );
119  rk.x_location = pad->GetPosition().x - origin.x;
120  rk.y_location = origin.y - pad->GetPosition().y;
121  rk.x_size = pad->GetSize().x;
122 
123  // Rule: round pads have y = 0
124  if( pad->GetShape() == PAD_SHAPE::CIRCLE )
125  rk.y_size = 0;
126  else
127  rk.y_size = pad->GetSize().y;
128 
129  rk.rotation = -KiROUND( pad->GetOrientation() ) / 10;
130  if( rk.rotation < 0 ) rk.rotation += 360;
131 
132  // the value indicates which sides are *not* accessible
133  rk.soldermask = 3;
134  if( pad->GetLayerSet()[F_Mask] )
135  rk.soldermask &= ~1;
136  if( pad->GetLayerSet()[B_Mask] )
137  rk.soldermask &= ~2;
138 
139  aRecords.push_back( rk );
140  }
141  }
142  }
143 }
wxString pin
Definition: export_d356.h:35
int x_location
Definition: export_d356.h:42
bool mechanical
Definition: export_d356.h:38
Smd pad, appears on the solder paste layer (default)
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
bool midpoint
Definition: export_d356.h:36
like PAD_PTH, but not plated
FOOTPRINTS & Footprints()
Definition: board.h:234
wxString refdes
Definition: export_d356.h:34
int soldermask
Definition: export_d356.h:40
wxString netname
Definition: export_d356.h:33
const wxPoint & GetAuxOrigin()
static int compute_pad_access_code(BOARD *aPcb, LSET aLayerMask)
Definition: export_d356.cpp:54
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
Definition: pad.h:57
int y_location
Definition: export_d356.h:43

References D356_RECORD::access, B_Mask, CIRCLE, compute_pad_access_code(), D356_RECORD::drill, F_Mask, BOARD::Footprints(), BOARD_DESIGN_SETTINGS::GetAuxOrigin(), BOARD::GetDesignSettings(), D356_RECORD::hole, KiROUND(), D356_RECORD::mechanical, D356_RECORD::midpoint, D356_RECORD::netname, NPTH, pad, D356_RECORD::pin, D356_RECORD::refdes, D356_RECORD::rotation, D356_RECORD::smd, SMD, D356_RECORD::soldermask, D356_RECORD::x_location, D356_RECORD::x_size, D356_RECORD::y_location, and D356_RECORD::y_size.

Referenced by IPC356D_WRITER::Write().

◆ build_via_testpoints()

static void build_via_testpoints ( BOARD aPcb,
std::vector< D356_RECORD > &  aRecords 
)
static

Definition at line 169 of file export_d356.cpp.

170 {
171  wxPoint origin = aPcb->GetDesignSettings().GetAuxOrigin();
172 
173  // Enumerate all the track segments and keep the vias
174  for( auto track : aPcb->Tracks() )
175  {
176  if( track->Type() == PCB_VIA_T )
177  {
178  PCB_VIA *via = static_cast<PCB_VIA*>( track );
179  NETINFO_ITEM *net = track->GetNet();
180 
181  D356_RECORD rk;
182  rk.smd = false;
183  rk.hole = true;
184  if( net )
185  rk.netname = net->GetNetname();
186  else
187  rk.netname = wxEmptyString;
188  rk.refdes = wxT("VIA");
189  rk.pin = wxT("");
190  rk.midpoint = true; // Vias are always midpoints
191  rk.drill = via->GetDrillValue();
192  rk.mechanical = false;
193 
194  PCB_LAYER_ID top_layer, bottom_layer;
195 
196  via->LayerPair( &top_layer, &bottom_layer );
197 
198  rk.access = via_access_code( aPcb, top_layer, bottom_layer );
199  rk.x_location = via->GetPosition().x - origin.x;
200  rk.y_location = origin.y - via->GetPosition().y;
201  rk.x_size = via->GetWidth();
202  rk.y_size = 0; // Round so height = 0
203  rk.rotation = 0;
204  rk.soldermask = 3; // XXX always tented?
205 
206  aRecords.push_back( rk );
207  }
208  }
209 }
wxString pin
Definition: export_d356.h:35
int x_location
Definition: export_d356.h:42
bool mechanical
Definition: export_d356.h:38
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
bool midpoint
Definition: export_d356.h:36
wxString refdes
Definition: export_d356.h:34
const wxString & GetNetname() const
Definition: netinfo.h:126
int soldermask
Definition: export_d356.h:40
wxString netname
Definition: export_d356.h:33
Handle the data for a net.
Definition: netinfo.h:66
const wxPoint & GetAuxOrigin()
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
static int via_access_code(BOARD *aPcb, int top_layer, int bottom_layer)
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
int y_location
Definition: export_d356.h:43
TRACKS & Tracks()
Definition: board.h:231

References D356_RECORD::access, D356_RECORD::drill, BOARD_DESIGN_SETTINGS::GetAuxOrigin(), BOARD::GetDesignSettings(), NETINFO_ITEM::GetNetname(), D356_RECORD::hole, D356_RECORD::mechanical, D356_RECORD::midpoint, D356_RECORD::netname, PCB_VIA_T, D356_RECORD::pin, D356_RECORD::refdes, D356_RECORD::rotation, D356_RECORD::smd, D356_RECORD::soldermask, BOARD::Tracks(), via, via_access_code(), D356_RECORD::x_location, D356_RECORD::x_size, D356_RECORD::y_location, and D356_RECORD::y_size.

Referenced by IPC356D_WRITER::Write().

◆ compute_pad_access_code()

static int compute_pad_access_code ( BOARD aPcb,
LSET  aLayerMask 
)
static

Definition at line 54 of file export_d356.cpp.

55 {
56  // Non-copper is not interesting here
57  aLayerMask &= LSET::AllCuMask();
58  if( !aLayerMask.any() )
59  return -1;
60 
61  // Traditional TH pad
62  if( aLayerMask[F_Cu] && aLayerMask[B_Cu] )
63  return 0;
64 
65  // Front SMD pad
66  if( aLayerMask[F_Cu] )
67  return 1;
68 
69  // Back SMD pad
70  if( aLayerMask[B_Cu] )
71  return aPcb->GetCopperLayerCount();
72 
73  // OK, we have an inner-layer only pad (and I have no idea about
74  // what could be used for); anyway, find the first copper layer
75  // it's on
76  for( LAYER_NUM layer = In1_Cu; layer < B_Cu; ++layer )
77  {
78  if( aLayerMask[layer] )
79  return layer + 1;
80  }
81 
82  // This shouldn't happen
83  return -1;
84 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
int LAYER_NUM
This can be replaced with int and removed.
Definition: layer_ids.h:41
Definition: layer_ids.h:71
int GetCopperLayerCount() const
Definition: board.cpp:455

References LSET::AllCuMask(), B_Cu, F_Cu, BOARD::GetCopperLayerCount(), and In1_Cu.

Referenced by build_pad_testpoints().

◆ intern_new_d356_netname()

static const wxString intern_new_d356_netname ( const wxString &  aNetname,
std::map< wxString, wxString > &  aMap,
std::set< wxString > &  aSet 
)
static

Definition at line 212 of file export_d356.cpp.

214 {
215  wxString canon;
216 
217  for( size_t ii = 0; ii < aNetname.Len(); ++ii )
218  {
219  // Rule: we can only use the standard ASCII, control excluded
220  wxUniChar ch = aNetname[ii];
221 
222  if( ch > 126 || !std::isgraph( static_cast<unsigned char>( ch ) ) )
223  ch = '?';
224 
225  canon += ch;
226  }
227 
228  // Rule: only uppercase (unofficial, but known to give problems
229  // otherwise)
230  canon.MakeUpper();
231 
232  // Rule: maximum length is 14 characters, otherwise we keep the tail
233  if( canon.size() > 14 )
234  {
235  canon = canon.Right( 14 );
236  }
237 
238  // Check if it's still unique
239  if( aSet.count( canon ) )
240  {
241  // Nope, need to uniquify it, trim it more and add a number
242  wxString base( canon );
243  if( base.size() > 10 )
244  {
245  base = base.Right( 10 );
246  }
247 
248  int ctr = 0;
249  do
250  {
251  ++ctr;
252  canon = base;
253  canon << '#' << ctr;
254  } while ( aSet.count( canon ) );
255  }
256 
257  // Register it
258  aMap[aNetname] = canon;
259  aSet.insert( canon );
260  return canon;
261 }

Referenced by IPC356D_WRITER::write_D356_records().

◆ iu_to_d356()

static int iu_to_d356 ( int  iu,
int  clamp 
)
static

Definition at line 87 of file export_d356.cpp.

88 {
89  int val = KiROUND( iu / ( IU_PER_MILS / 10 ) );
90  if( val > clamp ) return clamp;
91  if( val < -clamp ) return -clamp;
92  return val;
93 }
#define IU_PER_MILS
Definition: plotter.cpp:136
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73

References IU_PER_MILS, and KiROUND().

Referenced by IPC356D_WRITER::write_D356_records().

◆ via_access_code()

static int via_access_code ( BOARD aPcb,
int  top_layer,
int  bottom_layer 
)
static

Definition at line 148 of file export_d356.cpp.

149 {
150  // Easy case for through vias: top_layer is component, bottom_layer is
151  // solder, access code is 0
152  if( (top_layer == F_Cu) && (bottom_layer == B_Cu) )
153  return 0;
154 
155  // Blind via, reachable from front
156  if( top_layer == F_Cu )
157  return 1;
158 
159  // Blind via, reachable from bottom
160  if( bottom_layer == B_Cu )
161  return aPcb->GetCopperLayerCount();
162 
163  // It's a buried via, accessible from some inner layer
164  // (maybe could be used for testing before laminating? no idea)
165  return bottom_layer + 1; // XXX is this correct?
166 }
Definition: layer_ids.h:71
int GetCopperLayerCount() const
Definition: board.cpp:455

References B_Cu, F_Cu, and BOARD::GetCopperLayerCount().

Referenced by build_via_testpoints().