KiCad PCB EDA Suite
Loading...
Searching...
No Matches
netlist_exporter_allegro.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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <confirm.h>
21#include <refdes_utils.h>
22#include <sch_edit_frame.h>
23#include <sch_reference_list.h>
24#include <string_utils.h>
25#include <core/kicad_algo.h>
26#include <netlist.h>
29#include <regex>
30#include <fmt.h>
31#include <fmt/ranges.h>
32
33bool NETLIST_EXPORTER_ALLEGRO::writeNetlist( const wxString& aOutFileName, unsigned /* aNetlistOptions */,
34 REPORTER& aReporter )
35{
36 m_f = nullptr;
37 bool success = true;
38
39 // Create the devices directory
40 m_exportPath = wxFileName( aOutFileName ).GetPath( static_cast<int>( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) )
41 + wxString( "devices" );
42
43 if( !wxDirExists( m_exportPath ) )
44 {
45 if( !wxMkdir( m_exportPath, wxS_DIR_DEFAULT ) )
46 {
47 wxString msg = wxString::Format( _( "Failed to create directory 'devices' ." ) );
48 aReporter.Report( msg, RPT_SEVERITY_ERROR );
49 return false;
50 }
51 }
52
53 // Write the netlist file
54 if( ( m_f = wxFopen( aOutFileName, wxT( "wt" ) ) ) == nullptr )
55 {
56 wxString msg = wxString::Format( _( "Failed to create file '%s'." ), aOutFileName );
57 aReporter.Report( msg, RPT_SEVERITY_ERROR );
58 return false;
59 }
60
61 try
62 {
63 fmt::print( m_f, "(NETLIST)\n" );
64 fmt::print( m_f, "(Source: {})\n", TO_UTF8( m_schematic->GetFileName() ) );
65 fmt::print( m_f, "(Date: {})\n", TO_UTF8( GetISO8601CurrentDateTime() ) );
66
67 m_packageProperties.clear();
68 m_componentGroups.clear();
70 m_netNameNodes.clear();
71
73
74 // Start with package definitions, which we create from component groups.
75 success &= toAllegroPackages();
76
77 // Write out package properties. NOTE: Allegro doesn't recognize much...
79
80 // Write out nets
82
83 fmt::print( m_f, "$END\n" );
84 }
85 catch (...)
86 {
87 success = false;
88 }
89
90 // Done with the netlist
91 fclose( m_f );
92
93 m_f = nullptr;
94
95 return success;
96}
97
98
100 SCH_SHEET_PATH>& aItem1,
101 const std::pair<SCH_SYMBOL*,
102 SCH_SHEET_PATH>& aItem2 )
103{
104 wxString refText1 = aItem1.first->GetRef( &aItem1.second );
105 wxString refText2 = aItem2.first->GetRef( &aItem2.second );
106
107 if( refText1 == refText2 )
108 {
109 return aItem1.second.PathHumanReadable() < aItem2.second.PathHumanReadable();
110 }
111
112 return CompareSymbolRef( refText1, refText2 );
113}
114
115
116bool NETLIST_EXPORTER_ALLEGRO::CompareSymbolRef( const wxString& aRefText1,
117 const wxString& aRefText2 )
118{
119 if( removeTailDigits( aRefText1 ) == removeTailDigits( aRefText2 ) )
120 {
121 return extractTailNumber( aRefText1 ) < extractTailNumber( aRefText2 );
122 }
123
124 return aRefText1 < aRefText2;
125}
126
127
129{
130 // return "lhs < rhs"
131 return StrNumCmp( aPin1->GetShownNumber(), aPin2->GetShownNumber(), true ) < 0;
132}
133
134
136{
138 m_libParts.clear();
139
140 for( const SCH_SHEET_PATH& sheet : m_exportSheets )
141 {
142 m_schematic->SetCurrentSheet( sheet );
143
144 auto cmp =
145 [&sheet]( SCH_SYMBOL* a, SCH_SYMBOL* b )
146 {
147 return ( StrNumCmp( a->GetRef( &sheet, false ),
148 b->GetRef( &sheet, false ), true ) < 0 );
149 };
150
151 std::set<SCH_SYMBOL*, decltype( cmp )> ordered_symbols( cmp );
152 std::multiset<SCH_SYMBOL*, decltype( cmp )> extra_units( cmp );
153
154 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
155 {
156 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
157 auto test = ordered_symbols.insert( symbol );
158
159 if( !test.second )
160 {
161 if( ( *( test.first ) )->m_Uuid > symbol->m_Uuid )
162 {
163 extra_units.insert( *( test.first ) );
164 ordered_symbols.erase( test.first );
165 ordered_symbols.insert( symbol );
166 }
167 else
168 {
169 extra_units.insert( symbol );
170 }
171 }
172 }
173
174 for( EDA_ITEM* item : ordered_symbols )
175 {
176 SCH_SYMBOL* symbol = findNextSymbol( item, sheet );
177
178 if( !symbol || symbol->GetExcludedFromBoard( &sheet, m_exportVariant ) )
179 continue;
180
181 if( symbol->GetLibPins().empty() )
182 continue;
183
184 m_packageProperties.insert( std::pair<wxString, wxString>( formatRoom( sheet ),
185 symbol->GetRef( &sheet ) ) );
186 m_orderedSymbolsSheetpath.push_back( std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>( symbol, sheet ) );
187 }
188 }
189
190 struct NET_RECORD
191 {
192 NET_RECORD( const wxString& aName ) :
193 m_Name( aName )
194 {};
195
196 wxString m_Name;
197 std::vector<NET_NODE> m_Nodes;
198 };
199
200 std::vector<NET_RECORD*> nets;
201
202 for( const EXPORT_NET& net : m_exportNets )
203 {
204 nets.emplace_back( new NET_RECORD( net.name ) );
205 NET_RECORD* net_record = nets.back();
206
207 for( const auto& [pin, sheet] : net.pins )
208 {
209 SYMBOL* symbol = pin->GetParentSymbol();
210
211 if( symbol && !symbol->GetExcludedFromBoard( &sheet, m_exportVariant ) )
212 net_record->m_Nodes.emplace_back( pin, sheet );
213 }
214 }
215
216 // Netlist ordering: Net name, then ref des, then pin name
217 std::sort( nets.begin(), nets.end(),
218 []( const NET_RECORD* a, const NET_RECORD*b )
219 {
220 return StrNumCmp( a->m_Name, b->m_Name ) < 0;
221 } );
222
223 for( NET_RECORD* net_record : nets )
224 {
225 // Netlist ordering: Net name, then ref des, then pin name
226 std::sort( net_record->m_Nodes.begin(), net_record->m_Nodes.end(),
227 []( const NET_NODE& a, const NET_NODE& b )
228 {
229 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
230 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
231
232 if( refA == refB )
233 return a.m_Pin->GetShownNumber() < b.m_Pin->GetShownNumber();
234
235 return refA < refB;
236 } );
237
238 // Some duplicates can exist, for example on multi-unit parts with duplicated pins across
239 // units. If the user connects the pins on each unit, they will appear on separate
240 // subgraphs. Remove those here:
241 alg::remove_duplicates( net_record->m_Nodes,
242 []( const NET_NODE& a, const NET_NODE& b )
243 {
244 wxString refA = a.m_Pin->GetParentSymbol()->GetRef( &a.m_Sheet );
245 wxString refB = b.m_Pin->GetParentSymbol()->GetRef( &b.m_Sheet );
246
247 return refA == refB && a.m_Pin->GetShownNumber() == b.m_Pin->GetShownNumber();
248 } );
249
250 for( const NET_NODE& netNode : net_record->m_Nodes )
251 {
252 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
253
254 // Skip power symbols and virtual symbols
255 if( refText[0] == wxChar( '#' ) )
256 continue;
257
258 m_netNameNodes.insert( std::pair<wxString, NET_NODE>( net_record->m_Name, netNode ) );
259 }
260 }
261
262 for( NET_RECORD* record : nets )
263 delete record;
264}
265
266
268{
269 int groupCount = 1;
270 wxString deviceFileCreatingError = wxString( "" );
271
272 //Group the components......
273 while( !m_orderedSymbolsSheetpath.empty() )
274 {
275 std::pair<SCH_SYMBOL*, SCH_SHEET_PATH> first_ele = m_orderedSymbolsSheetpath.front();
276 m_orderedSymbolsSheetpath.pop_front();
277 m_componentGroups.insert( std::pair<int, std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>>( groupCount, first_ele ) );
278
279 for( auto it = m_orderedSymbolsSheetpath.begin(); it != m_orderedSymbolsSheetpath.end(); )
280 {
281 if( it->first->GetValue( &it->second, RAW_VALUE, m_exportVariant )
282 != first_ele.first->GetValue( &first_ele.second, RAW_VALUE, m_exportVariant ) )
283 {
284 ++it;
285 continue;
286 }
287
288 if( it->first->GetFootprintFieldText( &it->second, RAW_VALUE, m_exportVariant )
289 != first_ele.first->GetFootprintFieldText( &first_ele.second, RAW_VALUE, m_exportVariant ) )
290 {
291 ++it;
292 continue;
293 }
294
295 wxString ref1 = it->first->GetRef( &it->second );
296 wxString ref2 = first_ele.first->GetRef( &first_ele.second );
297
298 if( removeTailDigits( ref1 ) == removeTailDigits( ref2 ) )
299 {
300 m_componentGroups.insert( std::pair<int, std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>>( groupCount, *it ) );
301 it = m_orderedSymbolsSheetpath.erase( it );
302
303 if( m_orderedSymbolsSheetpath.size() == 0 )
304 break;
305 else
306 continue; // Don't increment iterator; we want the item that replaced the erased one
307 }
308
309 ++it;
310 }
311
312 groupCount++;
313 }
314
315 struct COMP_PACKAGE_STRUCT
316 {
317 wxString m_value;
318 wxString m_tolerance;
319 std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> m_symbolSheetpaths;
320 };
321
322 COMP_PACKAGE_STRUCT compPackageStruct;
323 std::map<wxString, COMP_PACKAGE_STRUCT> compPackageMap;
324
325 for( int groupIndex = 1; groupIndex < groupCount; groupIndex++ )
326 {
327 auto pairIter = m_componentGroups.equal_range( groupIndex );
328 auto beginIter = pairIter.first;
329 auto endIter = pairIter.second;
330
331 SCH_SYMBOL* sym = ( beginIter->second ).first;
332 SCH_SHEET_PATH sheetPath = ( beginIter->second ).second;
333
334 wxString valueText = sym->GetValue( &sheetPath, RAW_VALUE, m_exportVariant );
335 wxString footprintText = sym->GetFootprintFieldText( &sheetPath, RAW_VALUE, m_exportVariant );
336 wxString deviceType = valueText + wxT( "_" ) + footprintText;
337
338 while( deviceType.Length() > 0 && deviceType.GetChar( deviceType.Length() - 1 ) == '_' )
339 deviceType.RemoveLast();
340
341 deviceType = formatDevice( deviceType );
342
343 wxArrayString fieldArray;
344 fieldArray.Add( "Spice_Model" );
345 fieldArray.Add( "VALUE" );
346
347 wxString value = getGroupField( groupIndex, fieldArray );
348
349 fieldArray.clear();
350 fieldArray.Add( "TOLERANCE" );
351 fieldArray.Add( "TOL" );
352 wxString tol = getGroupField( groupIndex, fieldArray );
353
354 std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> symbolSheetpaths;
355
356 for( auto iter = beginIter; iter != endIter; iter++ )
357 {
358 symbolSheetpaths.push_back( std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>( iter->second.first,
359 iter->second.second ) );
360 }
361
362 std::stable_sort( symbolSheetpaths.begin(), symbolSheetpaths.end(),
364
365 compPackageStruct.m_value = value;
366 compPackageStruct.m_tolerance = tol;
367 compPackageStruct.m_symbolSheetpaths = symbolSheetpaths;
368 compPackageMap.insert( std::pair( deviceType, compPackageStruct ) );
369
370 // Write out the corresponding device file
371 FILE* d = nullptr;
372 wxString deviceFileName = wxFileName( m_exportPath, deviceType, wxString( "txt" ) ).GetFullPath();
373
374 if( ( d = wxFopen( deviceFileName, wxT( "wt" ) ) ) == nullptr )
375 {
376 wxString msg;
377 msg.Printf( _( "Failed to create file '%s'.\n" ), deviceFileName );
378 deviceFileCreatingError += msg;
379 continue;
380 }
381
382 footprintText = footprintText.AfterLast( ':' );
383
384 wxArrayString footprintAlt;
385 wxArrayString footprintArray = sym->GetLibSymbolRef()->GetFPFilters();
386
387 for( const wxString& fp : footprintArray )
388 {
389 if( ( fp.Find( '*' ) != wxNOT_FOUND ) || ( fp.Find( '?' ) != wxNOT_FOUND ) )
390 continue;
391
392 footprintAlt.Add( fp.AfterLast( ':' ) );
393 }
394
395 if( footprintText.IsEmpty() )
396 {
397 if( !footprintAlt.IsEmpty() )
398 {
399 footprintText = footprintAlt[0];
400 footprintAlt.RemoveAt( 0 );
401 }
402 else
403 {
404 footprintText = deviceType;
405 }
406 }
407
408 fmt::print( d, "PACKAGE '{}'\n", TO_UTF8( formatDevice( footprintText ) ) );
409 fmt::print( d, "CLASS IC\n" );
410
411 std::vector<SCH_PIN*> pinList = sym->GetLibSymbolRef()->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES );
412
413 /*
414 * We must erase redundant Pins references in pinList
415 * These redundant pins exist because some pins are found more than one time when a
416 * symbol has multiple parts per package or has 2 representations (DeMorgan conversion).
417 * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes, and
418 * therefore each pin appears 2 times in the list. Common pins (VCC, GND) can also be
419 * found more than once.
420 */
421 sort( pinList.begin(), pinList.end(), NETLIST_EXPORTER_ALLEGRO::CompareLibPin );
422
423 for( int ii = 0; ii < (int) pinList.size() - 1; ii++ )
424 {
425 if( pinList[ii]->GetNumber() == pinList[ii + 1]->GetNumber() )
426 {
427 // 2 pins have the same number, remove the redundant pin at index i+1
428 pinList.erase( pinList.begin() + ii + 1 );
429 ii--;
430 }
431 }
432
433 unsigned int pinCount = pinList.size();
434 fmt::print( d, "PINCOUNT {}\n", pinCount );
435
436 if( pinCount > 0 )
437 fmt::print( d, "{}", TO_UTF8( formatFunction( "main", pinList ) ) );
438
439 if( !value.IsEmpty() )
440 fmt::print( d, "PACKAGEPROP VALUE {}\n", TO_UTF8( value ) );
441
442 if( !tol.IsEmpty() )
443 fmt::print( d, "PACKAGEPROP TOL {}\n", TO_UTF8( tol ) );
444
445 if( !footprintAlt.IsEmpty() )
446 fmt::print( d, "PACKAGEPROP ALT_SYMBOLS '({})'\n", fmt::join( footprintAlt, "," ) );
447
448 wxArrayString propArray;
449 propArray.Add( "PART_NUMBER" );
450 propArray.Add( "mpn" );
451 propArray.Add( "mfr_pn" );
452 wxString data = getGroupField( groupIndex, propArray );
453
454 if(!data.IsEmpty())
455 fmt::print( d, "PACKAGEPROP {} {}\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
456
457 propArray.clear();
458 propArray.Add( "HEIGHT" );
459 data = getGroupField( groupIndex, propArray );
460
461 if(!data.IsEmpty())
462 fmt::print( d, "PACKAGEPROP {} {}\n", TO_UTF8( propArray[0] ), TO_UTF8( data ) );
463
464 fmt::print( d, "END\n" );
465
466 fclose( d );
467 }
468
469 fmt::print( m_f, "$PACKAGES\n" );
470
471 for( auto iter = compPackageMap.begin(); iter != compPackageMap.end(); iter++ )
472 {
473 wxString deviceType = iter->first;
474 wxString value = iter->second.m_value;
475 wxString tolerance = iter->second.m_tolerance;
476
477 // Remove quotes in value (can be added by formatText), if any.
478 // (they are already in print format string)
479 if( value.StartsWith( "'" ) and value.EndsWith( "'" ) )
480 {
481 value.Remove( 0, 1 );
482 value.RemoveLast();
483 }
484
485 if( value.IsEmpty() && tolerance.IsEmpty() )
486 {
487 fmt::print( m_f, "! '{}' ; ", TO_UTF8( deviceType ) );
488 }
489 else if( tolerance.IsEmpty() )
490 {
491 fmt::print( m_f, "! '{}' ! '{}' ; ",
492 TO_UTF8( deviceType ),
493 TO_UTF8( value ) );
494 }
495 else
496 {
497 fmt::print( m_f, "! '{}' ! '{}' ! {} ; ",
498 TO_UTF8( deviceType ),
499 TO_UTF8( value ),
500 TO_UTF8( tolerance ) );
501 }
502
503 std::vector<std::pair<SCH_SYMBOL*, SCH_SHEET_PATH>> symbolSheetpaths = iter->second.m_symbolSheetpaths;
504
505 std::vector<wxString> refTexts;
506
507 for( const auto& [ sym, sheetPath ] : symbolSheetpaths)
508 refTexts.push_back( sym->GetRef( &sheetPath ) );
509
510 fmt::print( m_f, "{}", fmt::join( refTexts, ",\n\t" ) );
511
512 fmt::print( m_f, "\n" );
513 }
514
515 if( !deviceFileCreatingError.IsEmpty() )
516 {
517 DisplayError( nullptr, deviceFileCreatingError );
518 return false;
519 }
520
521 return true;
522}
523
524
525wxString NETLIST_EXPORTER_ALLEGRO::formatText( wxString aString )
526{
527 if( aString.IsEmpty() )
528 return wxEmptyString;
529
530 // Replace 'µ' ("\u00b5") by 'u' to keep ASCII7 constraint
531 wxString mu( wxUniChar( 0x00B5 ) );
532 aString.Replace( mu, "u" );
533 mu = wxUniChar( 0x03BC );
534 aString.Replace( mu, "u" );
535
536 std::regex reg( "[!']|[^ -~]" );
537 wxString processedString = wxString( std::regex_replace( std::string( aString ), reg, "?" ) );
538
539 std::regex search_reg( "[^a-zA-Z0-9_/]" );
540
541 if( std::regex_search( std::string( processedString ), search_reg ) )
542 return wxString( "'" ) + processedString + wxString( "'" );
543
544 return processedString;
545}
546
547
549{
550 wxString pinName4Telesis = aPin.GetName() + wxString( "__" ) + aPin.GetNumber();
551 std::regex reg( "[^A-Za-z0-9_+?/-]" );
552 return wxString( std::regex_replace( std::string( pinName4Telesis ), reg, "?" ) );
553}
554
555
556wxString NETLIST_EXPORTER_ALLEGRO::formatFunction( wxString aName, std::vector<SCH_PIN*> aPinList )
557{
558 aName.MakeUpper();
559 std::list<wxString> pinNameList;
560
561 std::stable_sort( aPinList.begin(), aPinList.end(), NETLIST_EXPORTER_ALLEGRO::CompareLibPin );
562
563 for( auto pin : aPinList )
564 pinNameList.push_back( formatPin( *pin ) );
565
566 wxString out_str = "";
567 wxString str;
568
569 out_str.Printf( wxT( "PINORDER %s " ), TO_UTF8( aName ) );
570
571 for( const wxString& pinName : pinNameList )
572 {
573 str.Printf( ",\n\t%s", TO_UTF8( pinName ) );
574 out_str += str;
575 }
576
577 out_str += wxString( "\n" );
578
579 str.Printf( wxT( "FUNCTION %s %s " ), TO_UTF8( aName ), TO_UTF8( aName ) );
580 out_str += str;
581
582 for( const SCH_PIN* pin : aPinList )
583 {
584 str.Printf( ",\n\t%s", TO_UTF8( pin->GetNumber() ) );
585 out_str += str;
586 }
587
588 out_str += wxString( "\n" );
589
590 return out_str;
591}
592
593
594wxString NETLIST_EXPORTER_ALLEGRO::getGroupField( int aGroupIndex, const wxArrayString& aFieldArray, bool aSanitize )
595{
596 auto pairIter = m_componentGroups.equal_range( aGroupIndex );
597
598 for( auto iter = pairIter.first; iter != pairIter.second; ++iter )
599 {
600 SCH_SYMBOL* sym = ( iter->second ).first;
601 SCH_SHEET_PATH sheetPath = ( iter->second ).second;
602
603 for( const wxString& field : aFieldArray )
604 {
605 if( SCH_FIELD* fld = sym->FindFieldCaseInsensitive( field ) )
606 {
607 // TODO: FOR_CANVAS seems like an odd context here....
608 wxString fieldText = fld->GetShownText( &sheetPath, FOR_CANVAS, m_exportVariant );
609
610 if( !fieldText.IsEmpty() )
611 {
612 if( aSanitize )
613 return formatText( fieldText );
614 else
615 return fieldText;
616 }
617 }
618 }
619 }
620
621 for( auto iter = pairIter.first; iter != pairIter.second; ++iter )
622 {
623 SCH_SYMBOL* sym = ( iter->second ).first;
624
625 for( const wxString& field : aFieldArray )
626 {
627 if( SCH_FIELD* fld = sym->GetLibSymbolRef()->FindFieldCaseInsensitive( field ) )
628 {
629 wxString fieldText = fld->GetShownText( RESOLVED );
630
631 if( !fieldText.IsEmpty() )
632 {
633 if( aSanitize )
634 return formatText( fieldText );
635 else
636 return fieldText;
637 }
638 }
639 }
640 }
641
642 return wxEmptyString;
643}
644
645
647{
648 wxString path = aSheetPath.PathHumanReadable();
649
650 // Use root schematic file name for root
651 if( path == wxS( "/" ) )
652 path = aSheetPath.PathHumanReadable( false );
653
654 // The leading and trailing separators carry no information; the ones in between become
655 // dashes below.
656 while( path.StartsWith( wxS( "/" ) ) )
657 path = path.Mid( 1 );
658
659 while( path.EndsWith( wxS( "/" ) ) )
660 path.RemoveLast();
661
662 wxString roomName;
663
664 for( wxUniChar c : path )
665 {
666 if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' )
667 || c == '_' || c == '-' )
668 {
669 roomName << c;
670 }
671 else if( c == '/' )
672 {
673 // Use dash to represent our hierarchy breaks
674 roomName << wxS( "-" );
675 }
676 else
677 {
678 roomName << wxS( "_" );
679 }
680 }
681
682 return roomName;
683}
684
685
686wxString NETLIST_EXPORTER_ALLEGRO::formatDevice( wxString aString )
687{
688 aString.MakeLower();
689 std::regex reg( "[^a-z0-9_-]" );
690 return wxString( std::regex_replace( std::string( aString ), reg, "_" ) );
691}
692
693
695{
696 fmt::print( m_f, "$A_PROPERTIES\n" );
697
698 while( !m_packageProperties.empty() )
699 {
700 std::multimap<wxString, wxString>::iterator iter = m_packageProperties.begin();
701 wxString roomName = iter->first;
702
703 std::vector<wxString> refTexts;
704
705 auto pairIter = m_packageProperties.equal_range( roomName );
706
707 for( iter = pairIter.first; iter != pairIter.second; ++iter )
708 {
709 wxString refText = iter->second;
710 refTexts.push_back( refText );
711 }
712
713 m_packageProperties.erase( pairIter.first, pairIter.second );
714
715 // Nothing to name the room after (a schematic with no file name yet); leave these
716 // symbols without a ROOM rather than writing out an empty property.
717 if( roomName.IsEmpty() )
718 continue;
719
720 // formatRoom() already restricted this to characters that need no quoting or escaping.
721 fmt::print( m_f, "'ROOM' '{}' ; ", TO_UTF8( roomName ) );
722
723 std::stable_sort( refTexts.begin(), refTexts.end(), NETLIST_EXPORTER_ALLEGRO::CompareSymbolRef );
724
725 fmt::print( m_f, "{}", fmt::join( refTexts, ",\n\t" ) );
726
727 fmt::print( m_f, "\n" );
728 }
729}
730
731
733{
734 fmt::print( m_f, "$NETS\n" );
735
736 while( !m_netNameNodes.empty() )
737 {
738 std::multimap<wxString, NET_NODE>::iterator iter = m_netNameNodes.begin();
739 std::vector<NET_NODE> netNodes;
740
741 wxString netName = iter->first;
742
743 fmt::print( m_f, "{}; ", TO_UTF8( formatText( netName ).MakeUpper() ) );
744
745 auto pairIter = m_netNameNodes.equal_range( netName );
746
747 for( iter = pairIter.first; iter != pairIter.second; ++iter )
748 {
749 NET_NODE netNode = iter->second;
750 netNodes.push_back( netNode );
751 }
752
753 m_netNameNodes.erase( pairIter.first, pairIter.second );
754
755 std::stable_sort( netNodes.begin(), netNodes.end() );
756
757 std::vector<wxString> nets;
758
759 for( const NET_NODE& netNode : netNodes )
760 {
761 wxString refText = netNode.m_Pin->GetParentSymbol()->GetRef( &netNode.m_Sheet );
762
763 // Emit the resolved footprint pad number(s), not the raw symbol pin number, so a
764 // remapped pin's net lands on the right pad when the board reads this netlist
765 // (issue #2282). Shared with the PIN_INFO path via resolvePadNumbers.
766 for( const wxString& num : resolvePadNumbers( netNode.m_Pin, netNode.m_Sheet ) )
767 nets.push_back( refText + wxString( "." ) + num );
768 }
769
770 fmt::print( m_f, "{}", fmt::join( nets, ",\n\t" ) );
771
772 fmt::print( m_f, "\n" );
773 }
774}
775
776
778{
779 while( aString.Length() > 0
780 && aString.GetChar( aString.Length() - 1 ) >= '0'
781 && aString.GetChar( aString.Length() - 1 ) <= '9' )
782 {
783 aString.RemoveLast();
784 }
785
786 return aString;
787}
788
789
790unsigned int NETLIST_EXPORTER_ALLEGRO::extractTailNumber( wxString aString )
791{
792 wxString numString;
793
794 while( aString.Length() > 0
795 && aString.GetChar( aString.Length() - 1 ) >= '0'
796 && aString.GetChar( aString.Length() - 1 ) <= '9' )
797 {
798 numString.insert( 0, aString.GetChar( aString.Length() - 1 ) );
799 aString.RemoveLast();
800 }
801
802 unsigned long val;
803
804 //From wxWidgets 3.1.6, here we can use ToUInt instead of ToULong function.
805 numString.ToULong( &val );
806 return (unsigned int) val;
807}
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:599
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
wxArrayString GetFPFilters() const
Definition lib_symbol.h:252
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
bool toAllegroPackages()
Write the $PACKAGES section.
static wxString formatRoom(const SCH_SHEET_PATH &aSheetPath)
Generate an Allegro room name from a sheet path.
wxString formatDevice(wxString aString)
Convert a string into one safe for a Telesis device name.
wxString m_exportPath
Directory to store device files.
static unsigned int extractTailNumber(wxString aString)
Extract the str's tailing number.
FILE * m_f
File pointer for netlist file writing operation.
static wxString removeTailDigits(wxString aString)
Remove the str's tailing digits.
void toAllegroPackageProperties()
Write $A_PROPERTIES section.
std::list< std::pair< SCH_SYMBOL *, SCH_SHEET_PATH > > m_orderedSymbolsSheetpath
Store the ordered symbols with sheetpath.
bool writeNetlist(const wxString &aOutFileName, unsigned aNetlistOptions, REPORTER &aReporter) override
Write netlist to aOutFileName.
static bool CompareSymbolSheetpath(const std::pair< SCH_SYMBOL *, SCH_SHEET_PATH > &aItem1, const std::pair< SCH_SYMBOL *, SCH_SHEET_PATH > &aItem2)
Compare two std::pair<SCH_SYMBOL*, SCH_SHEET_PATH> variables.
wxString formatText(wxString aString)
Convert a string into Telesis-safe format.
std::multimap< wxString, wxString > m_packageProperties
wxString formatFunction(wxString aName, std::vector< SCH_PIN * > aPinList)
Generate the definition of a function in Telesis format, which consists of multiple declarations (PIN...
static bool CompareLibPin(const SCH_PIN *aPin1, const SCH_PIN *aPin2)
Compare two SCH_PIN* variables.
wxString formatPin(const SCH_PIN &aPin)
Generate a Telesis-compatible pin name from a pin node.
static bool CompareSymbolRef(const wxString &aRefText1, const wxString &aRefText2)
Compare two wxString variables.
wxString getGroupField(int aGroupIndex, const wxArrayString &aFieldArray, bool aSanitize=true)
Look up a field for a component group, which may have mismatched case, or the component group may not...
std::multimap< wxString, NET_NODE > m_netNameNodes
Store the NET_NODE with the net name.
std::multimap< int, std::pair< SCH_SYMBOL *, SCH_SHEET_PATH > > m_componentGroups
Store the component group.
void toAllegroNets()
Write the $NETS section.
SCH_SYMBOL * findNextSymbol(EDA_ITEM *aItem, const SCH_SHEET_PATH &aSheetPath)
Check if the given symbol should be processed for netlisting.
std::set< LIB_SYMBOL *, LIB_SYMBOL_LESS_THAN > m_libParts
unique library symbols used. LIB_SYMBOL items are sorted by names
std::vector< wxString > resolvePadNumbers(const SCH_PIN *aPin, const SCH_SHEET_PATH &aSheetPath) const
Resolve aPin to its effective pad number(s) for every netlist path (issue #2282).
UNIQUE_STRINGS m_referencesAlreadyFound
Used for "multiple symbols per package" symbols to avoid processing a lib symbol more than once.
std::vector< EXPORT_NET > m_exportNets
wxString m_exportVariant
The schematic we're generating a netlist for.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:350
const wxString & GetName() const
Definition sch_pin.cpp:527
const wxString & GetShownNumber() const
Definition sch_pin.cpp:708
const wxString & GetNumber() const
Definition sch_pin.h:144
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
Schematic symbol object.
Definition sch_symbol.h:75
const wxString GetFootprintFieldText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
Search for a SCH_FIELD with aFieldName.
std::vector< SCH_PIN * > GetLibPins() const
Populate a vector with all the pins from the library object that match the current unit and bodyStyle...
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
const wxString GetValue(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:60
virtual const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const =0
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:216
@ FOR_CANVAS
Definition common.h:92
@ RAW_VALUE
Definition common.h:98
@ RESOLVED
Definition common.h:97
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
#define _(s)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
Definition kicad_algo.h:157
Collection of utility functions for component reference designators (refdes)
@ RPT_SEVERITY_ERROR
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString GetISO8601CurrentDateTime()
#define ALL_UNITS
Definition symbol.h:150
#define ALL_BODY_STYLES
Definition symbol.h:151
std::string path
KIBIS_PIN * pin
@ SCH_SYMBOL_T
Definition typeinfo.h:168