KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_checker.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 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <vector>
25#include <eda_draw_frame.h>
26#include <lib_symbol.h>
27#include <sch_shape.h>
28#include <macros.h>
29
30// helper function to sort pins by pin num
31static bool sort_by_pin_number( const SCH_PIN* ref, const SCH_PIN* tst );
32
33
34static void CheckLibSymbolGraphics( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
35 UNITS_PROVIDER* aUnitsProvider );
36
37
38void CheckDuplicatePins( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
39 UNITS_PROVIDER* aUnitsProvider )
40{
41 wxString msg;
42 std::vector<SCH_PIN*> pinList = aSymbol->GetPins();
43
44 // Test for duplicates:
45 // Sort pins by pin num, so 2 duplicate pins
46 // (pins with the same number) will be consecutive in list
47 sort( pinList.begin(), pinList.end(), sort_by_pin_number );
48
49 for( unsigned ii = 1; ii < pinList.size(); ii++ )
50 {
51 SCH_PIN* pin = pinList[ii - 1];
52 SCH_PIN* next = pinList[ii];
53
54 if( pin->GetNumber() != next->GetNumber() )
55 continue;
56
57 // Pins are not duplicated only if they are in different body styles
58 // (but GetBodyStyle() == 0 means common to all body styles)
59 if( pin->GetBodyStyle() != 0 && next->GetBodyStyle() != 0 )
60 {
61 if( pin->GetBodyStyle() != next->GetBodyStyle() )
62 continue;
63 }
64
65 wxString pinName;
66 wxString nextName;
67
68 if( pin->GetName() != "~" && !pin->GetName().IsEmpty() )
69 pinName = " '" + pin->GetName() + "'";
70
71 if( next->GetName() != "~" && !next->GetName().IsEmpty() )
72 nextName = " '" + next->GetName() + "'";
73
74 if( aSymbol->HasAlternateBodyStyle() && next->GetBodyStyle() )
75 {
76 if( pin->GetUnit() == 0 || next->GetUnit() == 0 )
77 {
78 msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
79 " conflicts with pin %s%s at location <b>(%s, %s)</b>"
80 " in %s body style." ),
81 next->GetNumber(),
82 nextName,
83 aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
84 aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
85 pin->GetNumber(),
86 pin->GetName(),
87 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
88 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
89 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
90 }
91 else
92 {
93 msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
94 " conflicts with pin %s%s at location <b>(%s, %s)</b>"
95 " in units %s and %s of %s body style." ),
96 next->GetNumber(),
97 nextName,
98 aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
99 aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
100 pin->GetNumber(),
101 pinName,
102 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
103 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
104 aSymbol->GetUnitReference( next->GetUnit() ),
105 aSymbol->GetUnitReference( pin->GetUnit() ),
106 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
107 }
108 }
109 else
110 {
111 if( pin->GetUnit() == 0 || next->GetUnit() == 0 )
112 {
113 msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
114 " conflicts with pin %s%s at location <b>(%s, %s)</b>." ),
115 next->GetNumber(),
116 nextName,
117 aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
118 aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
119 pin->GetNumber(),
120 pinName,
121 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
122 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
123 }
124 else
125 {
126 msg.Printf( _( "<b>Duplicate pin %s</b> %s at location <b>(%s, %s)</b>"
127 " conflicts with pin %s%s at location <b>(%s, %s)</b>"
128 " in units %s and %s." ),
129 next->GetNumber(),
130 nextName,
131 aUnitsProvider->MessageTextFromValue( next->GetPosition().x ),
132 aUnitsProvider->MessageTextFromValue( -next->GetPosition().y ),
133 pin->GetNumber(),
134 pinName,
135 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
136 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
137 aSymbol->GetUnitReference( next->GetUnit() ),
138 aSymbol->GetUnitReference( pin->GetUnit() ) );
139 }
140 }
141
142 msg += wxT( "<br><br>" );
143 aMessages.push_back( msg );
144 }
145}
146
147
163void CheckLibSymbol( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
164 int aGridForPins, UNITS_PROVIDER* aUnitsProvider )
165{
166 if( !aSymbol )
167 return;
168
169 wxString msg;
170
171 // Test reference prefix validity:
172 // if the symbol is saved in a library, the prefix should not ends by a digit or a '?'
173 // but it is acceptable if the symbol is saved to a schematic.
174 wxString reference_base = aSymbol->GetReferenceField().GetText();
175 wxString illegal_end( wxT( "0123456789?" ) );
176 wxUniChar last_char = reference_base.Last();
177
178 if( illegal_end.Find( last_char ) != wxNOT_FOUND )
179 {
180 msg.Printf( _( "<b>Warning: reference prefix</b><br>prefix ending by '%s' can create"
181 " issues if saved in a symbol library" ),
182 illegal_end );
183 msg += wxT( "<br><br>" );
184 aMessages.push_back( msg );
185 }
186
187 CheckDuplicatePins( aSymbol, aMessages, aUnitsProvider );
188
189 std::vector<SCH_PIN*> pinList = aSymbol->GetPins();
190 sort( pinList.begin(), pinList.end(), sort_by_pin_number );
191
192 // The minimal grid size allowed to place a pin is 25 mils
193 // the best grid size is 50 mils, but 25 mils is still usable
194 // this is because all aSymbols are using a 50 mils grid to place pins, and therefore
195 // the wires must be on the 50 mils grid
196 // So raise an error if a pin is not on a 25 (or bigger :50 or 100) mils grid
197 const int min_grid_size = schIUScale.MilsToIU( 25 );
198 const int clamped_grid_size = ( aGridForPins < min_grid_size ) ? min_grid_size : aGridForPins;
199
200 // Test for a valid power aSymbol.
201 // A valid power aSymbol has only one unit, no alternate body styles and one pin.
202 // And this pin should be PT_POWER_IN (invisible to be automatically connected)
203 // or PT_POWER_OUT for a power flag
204 if( aSymbol->IsPower() )
205 {
206 if( aSymbol->GetUnitCount() != 1 )
207 {
208 msg.Printf( _( "<b>A Power Symbol should have only one unit</b><br><br>" ) );
209 aMessages.push_back( msg );
210 }
211
212 if( aSymbol->HasAlternateBodyStyle() )
213 {
214 msg.Printf( _( "<b>A Power Symbol should not have DeMorgan variants</b><br><br>" ) );
215 aMessages.push_back( msg );
216 }
217
218 if( pinList.size() != 1 )
219 {
220 msg.Printf( _( "<b>A Power Symbol should have only one pin</b><br><br>" ) );
221 aMessages.push_back( msg );
222 }
223
224 SCH_PIN* pin = pinList[0];
225
226 if( pin->GetType() != ELECTRICAL_PINTYPE::PT_POWER_IN
227 && pin->GetType() != ELECTRICAL_PINTYPE::PT_POWER_OUT )
228 {
229 msg.Printf( _( "<b>Suspicious Power Symbol</b><br>"
230 "Only an input or output power pin has meaning<br><br>" ) );
231 aMessages.push_back( msg );
232 }
233
234 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN && !pin->IsVisible() )
235 {
236 msg.Printf( _( "<b>Suspicious Power Symbol</b><br>"
237 "Invisible input power pins are no longer required<br><br>" ) );
238 aMessages.push_back( msg );
239 }
240 }
241
242
243 for( SCH_PIN* pin : pinList )
244 {
245 wxString pinName = pin->GetName();
246
247 if( pinName.IsEmpty() || pinName == "~" )
248 pinName = "";
249 else
250 pinName = "'" + pinName + "'";
251
252 if( !aSymbol->IsPower()
253 && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
254 && !pin->IsVisible() )
255 {
256 // hidden power pin
257 if( aSymbol->HasAlternateBodyStyle() && pin->GetBodyStyle() )
258 {
259 if( aSymbol->GetUnitCount() <= 1 )
260 {
261 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
262 " in %s body style." ),
263 pin->GetNumber(),
264 pinName,
265 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
266 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
267 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
268 }
269 else
270 {
271 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
272 " in unit %c of %s body style." ),
273 pin->GetNumber(),
274 pinName,
275 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
276 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
277 'A' + pin->GetUnit() - 1,
278 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
279 }
280 }
281 else
282 {
283 if( aSymbol->GetUnitCount() <= 1 )
284 {
285 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>"
286 "(%s, %s)</b>." ),
287 pin->GetNumber(),
288 pinName,
289 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
290 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
291 }
292 else
293 {
294 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
295 " in unit %c." ),
296 pin->GetNumber(),
297 pinName,
298 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
299 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
300 'A' + pin->GetUnit() - 1 );
301 }
302 }
303
304 msg += wxT( "<br>" );
305 msg += _( "(Hidden power pins will drive their pin names on to any connected nets.)" );
306 msg += wxT( "<br><br>" );
307 aMessages.push_back( msg );
308 }
309
310 if( ( (pin->GetPosition().x % clamped_grid_size) != 0 )
311 || ( (pin->GetPosition().y % clamped_grid_size) != 0 ) )
312 {
313 // pin is off grid
314 msg.Empty();
315
316 if( aSymbol->HasAlternateBodyStyle() && pin->GetBodyStyle() )
317 {
318 if( aSymbol->GetUnitCount() <= 1 )
319 {
320 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
321 " of %s body style." ),
322 pin->GetNumber(),
323 pinName,
324 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
325 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
326 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
327 }
328 else
329 {
330 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
331 " in unit %c of %s body style." ),
332 pin->GetNumber(),
333 pinName,
334 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
335 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
336 'A' + pin->GetUnit() - 1,
337 SCH_ITEM::GetBodyStyleDescription( pin->GetBodyStyle() ).Lower() );
338 }
339 }
340 else
341 {
342 if( aSymbol->GetUnitCount() <= 1 )
343 {
344 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>." ),
345 pin->GetNumber(),
346 pinName,
347 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
348 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
349 }
350 else
351 {
352 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
353 " in unit %c." ),
354 pin->GetNumber(),
355 pinName,
356 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
357 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
358 'A' + pin->GetUnit() - 1 );
359 }
360 }
361
362 msg += wxT( "<br><br>" );
363 aMessages.push_back( msg );
364 }
365 }
366
367 CheckLibSymbolGraphics( aSymbol, aMessages, aUnitsProvider );
368}
369
370
371void CheckLibSymbolGraphics( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
372 UNITS_PROVIDER* aUnitsProvider )
373{
374 if( !aSymbol )
375 return;
376
377 wxString msg;
378
379 for( const SCH_ITEM& item : aSymbol->GetDrawItems() )
380 {
381 if( item.Type() != SCH_SHAPE_T )
382 continue;
383
384 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( &item );
385
386 switch( shape->GetShape() )
387 {
388 case SHAPE_T::ARC:
389 break;
390
391 case SHAPE_T::CIRCLE:
392 if( shape->GetRadius() <= 0 )
393 {
394 msg.Printf( _( "<b>Graphic circle has radius = 0</b> at location "
395 "<b>(%s, %s)</b>." ),
396 aUnitsProvider->MessageTextFromValue(shape->GetPosition().x ),
397 aUnitsProvider->MessageTextFromValue( -shape->GetPosition().y ) );
398 msg += wxT( "<br>" );
399 aMessages.push_back( msg );
400 }
401 break;
402
404 if( shape->GetPosition() == shape->GetEnd() )
405 {
406 msg.Printf( _( "<b>Graphic rectangle has size 0</b> at location <b>(%s, %s)</b>." ),
407 aUnitsProvider->MessageTextFromValue(shape->GetPosition().x ),
408 aUnitsProvider->MessageTextFromValue( -shape->GetPosition().y ) );
409 msg += wxT( "<br>" );
410 aMessages.push_back( msg );
411 }
412 break;
413
414 case SHAPE_T::POLY:
415 break;
416
417 case SHAPE_T::BEZIER:
418 break;
419
420 default:
422 }
423 }
424}
425
426
427bool sort_by_pin_number( const SCH_PIN* ref, const SCH_PIN* tst )
428{
429 // Use number as primary key
430 int test = ref->GetNumber().Cmp( tst->GetNumber() );
431
432 // Use DeMorgan variant as secondary key
433 if( test == 0 )
434 test = ref->GetBodyStyle() - tst->GetBodyStyle();
435
436 // Use unit as tertiary key
437 if( test == 0 )
438 test = ref->GetUnit() - tst->GetUnit();
439
440 return test < 0;
441}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
int GetRadius() const
Definition: eda_shape.cpp:840
SHAPE_T GetShape() const
Definition: eda_shape.h:132
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:174
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:340
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
Define a library symbol object.
Definition: lib_symbol.h:84
std::vector< SCH_PIN * > GetPins(int aUnit, int aBodyStyle) const
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:857
bool IsPower() const override
Definition: lib_symbol.cpp:423
bool HasAlternateBodyStyle() const override
Test if symbol has more than one body conversion type (DeMorgan).
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:531
SCH_FIELD & GetReferenceField() const
Return reference to the reference designator field.
wxString GetUnitReference(int aUnit) override
Return an identifier for aUnit for symbols with units.
Definition: lib_symbol.cpp:282
int GetUnitCount() const override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:167
int GetBodyStyle() const
Definition: sch_item.h:236
int GetUnit() const
Definition: sch_item.h:233
static wxString GetBodyStyleDescription(int aBodyStyle)
Definition: sch_item.cpp:61
const wxString & GetNumber() const
Definition: sch_pin.h:123
VECTOR2I GetPosition() const override
Definition: sch_shape.h:73
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
#define _(s)
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:96
@ PT_POWER_OUT
output of a regulator: intended to be connected to power input pins
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
CITER next(CITER it)
Definition: ptree.cpp:124
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
static bool sort_by_pin_number(const SCH_PIN *ref, const SCH_PIN *tst)
void CheckDuplicatePins(LIB_SYMBOL *aSymbol, std::vector< wxString > &aMessages, UNITS_PROVIDER *aUnitsProvider)
void CheckLibSymbol(LIB_SYMBOL *aSymbol, std::vector< wxString > &aMessages, int aGridForPins, UNITS_PROVIDER *aUnitsProvider)
Check a library symbol to find incorrect settings.
static void CheckLibSymbolGraphics(LIB_SYMBOL *aSymbol, std::vector< wxString > &aMessages, UNITS_PROVIDER *aUnitsProvider)
@ SCH_SHAPE_T
Definition: typeinfo.h:149