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