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().IsEmpty() )
69 pinName = " '" + pin->GetName() + "'";
70
71 if( !next->GetName().IsEmpty() )
72 nextName = " '" + next->GetName() + "'";
73
74 if( aSymbol->IsMultiBodyStyle() && 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 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).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->GetUnitDisplayName( next->GetUnit(), false ),
105 aSymbol->GetUnitDisplayName( pin->GetUnit(), false ),
106 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).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->GetUnitDisplayName( next->GetUnit(), false ),
138 aSymbol->GetUnitDisplayName( pin->GetUnit(), false ) );
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
176 if( reference_base.IsEmpty() )
177 {
178 aMessages.push_back( _( "<b>Warning: reference is empty</b><br><br>" ) );
179 }
180 else
181 {
182 wxString illegal_end( wxT( "0123456789?" ) );
183 wxUniChar last_char = reference_base.Last();
184
185 if( illegal_end.Find( last_char ) != wxNOT_FOUND )
186 {
187 msg.Printf( _( "<b>Warning: reference prefix</b><br>prefix ending by '%s' can create"
188 " issues if saved in a symbol library" ),
189 illegal_end );
190 msg += wxT( "<br><br>" );
191 aMessages.push_back( msg );
192 }
193 }
194
195 CheckDuplicatePins( aSymbol, aMessages, aUnitsProvider );
196
197 std::vector<SCH_PIN*> pinList = aSymbol->GetPins();
198 sort( pinList.begin(), pinList.end(), sort_by_pin_number );
199
200 // The minimal grid size allowed to place a pin is 25 mils
201 // the best grid size is 50 mils, but 25 mils is still usable
202 // this is because all aSymbols are using a 50 mils grid to place pins, and therefore
203 // the wires must be on the 50 mils grid
204 // So raise an error if a pin is not on a 25 (or bigger :50 or 100) mils grid
205 const int min_grid_size = schIUScale.MilsToIU( 25 );
206 const int clamped_grid_size = ( aGridForPins < min_grid_size ) ? min_grid_size : aGridForPins;
207
208 // Test for a valid power aSymbol.
209 // A valid power aSymbol has only one unit, no alternate body styles and one pin.
210 // And this pin should be PT_POWER_IN (invisible to be automatically connected)
211 // or PT_POWER_OUT for a power flag
212 if( aSymbol->IsPower() )
213 {
214 if( aSymbol->GetUnitCount() != 1 )
215 {
216 msg.Printf( _( "<b>A Power Symbol should have only one unit</b><br><br>" ) );
217 aMessages.push_back( msg );
218 }
219
220 if( pinList.size() != 1 )
221 {
222 msg.Printf( _( "<b>A Power Symbol should have only one pin</b><br><br>" ) );
223 aMessages.push_back( msg );
224 }
225
226 SCH_PIN* pin = pinList[0];
227
228 if( pin->GetType() != ELECTRICAL_PINTYPE::PT_POWER_IN
229 && pin->GetType() != ELECTRICAL_PINTYPE::PT_POWER_OUT )
230 {
231 msg.Printf( _( "<b>Suspicious Power Symbol</b><br>"
232 "Only an input or output power pin has meaning<br><br>" ) );
233 aMessages.push_back( msg );
234 }
235
236 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN && !pin->IsVisible() )
237 {
238 msg.Printf( _( "<b>Suspicious Power Symbol</b><br>"
239 "Invisible input power pins are no longer required<br><br>" ) );
240 aMessages.push_back( msg );
241 }
242 }
243
244
245 for( SCH_PIN* pin : pinList )
246 {
247 wxString pinName = pin->GetName();
248
249 if( pinName.IsEmpty() || pinName == "~" )
250 pinName = "";
251 else
252 pinName = "'" + pinName + "'";
253
254 if( !aSymbol->IsGlobalPower()
255 && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
256 && !pin->IsVisible() )
257 {
258 // hidden power pin
259 if( aSymbol->IsMultiBodyStyle() && pin->GetBodyStyle() )
260 {
261 if( aSymbol->GetUnitCount() <= 1 )
262 {
263 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
264 " in %s body style." ),
265 pin->GetNumber(),
266 pinName,
267 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
268 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
269 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
270 }
271 else
272 {
273 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
274 " in unit %c of %s body style." ),
275 pin->GetNumber(),
276 pinName,
277 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
278 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
279 'A' + pin->GetUnit() - 1,
280 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
281 }
282 }
283 else
284 {
285 if( aSymbol->GetUnitCount() <= 1 )
286 {
287 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>"
288 "(%s, %s)</b>." ),
289 pin->GetNumber(),
290 pinName,
291 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
292 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
293 }
294 else
295 {
296 msg.Printf( _( "Info: <b>Hidden power pin %s</b> %s at location <b>(%s, %s)</b>"
297 " in unit %c." ),
298 pin->GetNumber(),
299 pinName,
300 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
301 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
302 'A' + pin->GetUnit() - 1 );
303 }
304 }
305
306 msg += wxT( "<br>" );
307 msg += _( "(Hidden power pins will drive their pin names on to any connected nets.)" );
308 msg += wxT( "<br><br>" );
309 aMessages.push_back( msg );
310 }
311
312 if( ( (pin->GetPosition().x % clamped_grid_size) != 0 )
313 || ( (pin->GetPosition().y % clamped_grid_size) != 0 ) )
314 {
315 // pin is off grid
316 msg.Empty();
317
318 if( aSymbol->IsMultiBodyStyle() && pin->GetBodyStyle() )
319 {
320 if( aSymbol->GetUnitCount() <= 1 )
321 {
322 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
323 " of %s body style." ),
324 pin->GetNumber(),
325 pinName,
326 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
327 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
328 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
329 }
330 else
331 {
332 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
333 " in unit %c of %s body style." ),
334 pin->GetNumber(),
335 pinName,
336 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
337 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
338 'A' + pin->GetUnit() - 1,
339 aSymbol->GetBodyStyleDescription( pin->GetBodyStyle(), true ).Lower() );
340 }
341 }
342 else
343 {
344 if( aSymbol->GetUnitCount() <= 1 )
345 {
346 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>." ),
347 pin->GetNumber(),
348 pinName,
349 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
350 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ) );
351 }
352 else
353 {
354 msg.Printf( _( "<b>Off grid pin %s</b> %s at location <b>(%s, %s)</b>"
355 " in unit %c." ),
356 pin->GetNumber(),
357 pinName,
358 aUnitsProvider->MessageTextFromValue( pin->GetPosition().x ),
359 aUnitsProvider->MessageTextFromValue( -pin->GetPosition().y ),
360 'A' + pin->GetUnit() - 1 );
361 }
362 }
363
364 msg += wxT( "<br><br>" );
365 aMessages.push_back( msg );
366 }
367 }
368
369 CheckLibSymbolGraphics( aSymbol, aMessages, aUnitsProvider );
370}
371
372
373void CheckLibSymbolGraphics( LIB_SYMBOL* aSymbol, std::vector<wxString>& aMessages,
374 UNITS_PROVIDER* aUnitsProvider )
375{
376 if( !aSymbol )
377 return;
378
379 wxString msg;
380
381 for( const SCH_ITEM& item : aSymbol->GetDrawItems() )
382 {
383 if( item.Type() != SCH_SHAPE_T )
384 continue;
385
386 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( &item );
387
388 switch( shape->GetShape() )
389 {
390 case SHAPE_T::ARC:
391 break;
392
393 case SHAPE_T::CIRCLE:
394 if( shape->GetRadius() <= 0 )
395 {
396 msg.Printf( _( "<b>Graphic circle has radius = 0</b> at location "
397 "<b>(%s, %s)</b>." ),
398 aUnitsProvider->MessageTextFromValue(shape->GetPosition().x ),
399 aUnitsProvider->MessageTextFromValue( -shape->GetPosition().y ) );
400 msg += wxT( "<br>" );
401 aMessages.push_back( msg );
402 }
403 break;
404
406 if( shape->GetPosition() == shape->GetEnd() )
407 {
408 msg.Printf( _( "<b>Graphic rectangle has size 0</b> at location <b>(%s, %s)</b>." ),
409 aUnitsProvider->MessageTextFromValue(shape->GetPosition().x ),
410 aUnitsProvider->MessageTextFromValue( -shape->GetPosition().y ) );
411 msg += wxT( "<br>" );
412 aMessages.push_back( msg );
413 }
414 break;
415
416 case SHAPE_T::POLY:
417 break;
418
419 case SHAPE_T::BEZIER:
420 break;
421
422 default:
424 }
425 }
426}
427
428
429bool sort_by_pin_number( const SCH_PIN* ref, const SCH_PIN* tst )
430{
431 // Use number as primary key
432 int test = ref->GetNumber().Cmp( tst->GetNumber() );
433
434 // Use DeMorgan variant as secondary key
435 if( test == 0 )
436 test = ref->GetBodyStyle() - tst->GetBodyStyle();
437
438 // Use unit as tertiary key
439 if( test == 0 )
440 test = ref->GetUnit() - tst->GetUnit();
441
442 return test < 0;
443}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:168
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:215
wxString SHAPE_T_asString() const
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
Define a library symbol object.
Definition lib_symbol.h:85
bool IsPower() const override
bool IsMultiBodyStyle() const override
Definition lib_symbol.h:594
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:532
std::vector< SCH_PIN * > GetPins() const override
bool IsGlobalPower() const override
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
int GetUnitCount() const override
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the user-defined display name for aUnit for symbols with units.
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:340
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:244
int GetUnit() const
Definition sch_item.h:238
const wxString & GetNumber() const
Definition sch_pin.h:124
VECTOR2I GetPosition() const override
Definition sch_shape.h:85
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.
Definition eda_shape.h:46
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
Definition pin_type.h:47
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:46
CITER next(CITER it)
Definition ptree.cpp:124
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:151