Browse Source

PCB: import from netlist, save, and load unit info from footprints

For upcoming gate swap feature
master
Mike Williams 2 months ago
parent
commit
e69be53860
  1. 3
      common/pcb.keywords
  2. 63
      pcbnew/netlist_reader/board_netlist_updater.cpp
  3. 2
      pcbnew/netlist_reader/board_netlist_updater.h
  4. 20
      pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp
  5. 3
      pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h
  6. 62
      pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp

3
common/pcb.keywords

@ -370,6 +370,9 @@ true
tstamp
type
units
unit
pins
num
units_format
unlocked
user

63
pcbnew/netlist_reader/board_netlist_updater.cpp

@ -1166,6 +1166,67 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( FOOTPRINT* aFootprint
}
bool BOARD_NETLIST_UPDATER::updateComponentUnits( FOOTPRINT* aFootprint, COMPONENT* aNewComponent )
{
// Build the footprint-side representation from the netlist component
std::vector<FOOTPRINT::FP_UNIT_INFO> newUnits;
for( const COMPONENT::UNIT_INFO& u : aNewComponent->GetUnitInfo() )
newUnits.push_back( { u.m_unitName, u.m_pins } );
const std::vector<FOOTPRINT::FP_UNIT_INFO>& curUnits = aFootprint->GetUnitInfo();
auto unitsEqual = []( const std::vector<FOOTPRINT::FP_UNIT_INFO>& a,
const std::vector<FOOTPRINT::FP_UNIT_INFO>& b )
{
if( a.size() != b.size() )
return false;
for( size_t i = 0; i < a.size(); ++i )
{
if( a[i].m_unitName != b[i].m_unitName )
return false;
if( a[i].m_pins != b[i].m_pins )
return false;
}
return true;
};
if( unitsEqual( curUnits, newUnits ) )
return false;
wxString msg;
if( m_isDryRun )
{
msg.Printf( _( "Update %s unit metadata." ), aFootprint->GetReference() );
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
return false; // no actual change on board during dry run
}
// Create a copy only if the footprint has not been added during this update
FOOTPRINT* copy = nullptr;
if( !m_commit.GetStatus( aFootprint ) )
{
copy = static_cast<FOOTPRINT*>( aFootprint->Clone() );
copy->SetParentGroup( nullptr );
}
aFootprint->SetUnitInfo( newUnits );
msg.Printf( _( "Updated %s unit metadata." ), aFootprint->GetReference() );
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
if( copy )
m_commit.Modified( aFootprint, copy );
return true;
}
void BOARD_NETLIST_UPDATER::cacheCopperZoneConnections()
{
for( ZONE* zone : m_board->Zones() )
@ -1567,6 +1628,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
updateFootprintGroup( tmp, component );
updateComponentPadConnections( tmp, component );
updateComponentClass( tmp, component );
updateComponentUnits( tmp, component );
sheetPaths.insert( footprint->GetSheetname() );
}
@ -1593,6 +1655,7 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
updateFootprintGroup( footprint, component );
updateComponentPadConnections( footprint, component );
updateComponentClass( footprint, component );
updateComponentUnits( footprint, component );
sheetPaths.insert( footprint->GetSheetname() );
}

2
pcbnew/netlist_reader/board_netlist_updater.h

@ -121,6 +121,8 @@ private:
void updateComponentClass( FOOTPRINT* aFootprint, COMPONENT* aNewComponent );
bool updateComponentUnits( FOOTPRINT* aFootprint, COMPONENT* aNewComponent );
void cacheCopperZoneConnections();
bool updateCopperZoneNets( NETLIST& aNetlist );

20
pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.cpp

@ -1238,6 +1238,26 @@ void PCB_IO_KICAD_SEXPR::format( const FOOTPRINT* aFootprint ) const
if( !aFootprint->GetSheetfile().empty() )
m_out->Print( "(sheetfile %s)", m_out->Quotew( aFootprint->GetSheetfile() ).c_str() );
// Emit unit info for gate swapping metadata (flat pin list form)
if( !aFootprint->GetUnitInfo().empty() )
{
m_out->Print( "(units" );
for( const FOOTPRINT::FP_UNIT_INFO& u : aFootprint->GetUnitInfo() )
{
m_out->Print( "(unit (name %s)", m_out->Quotew( u.m_unitName ).c_str() );
m_out->Print( "(pins" );
for( const wxString& n : u.m_pins )
m_out->Print( " %s", m_out->Quotew( n ).c_str() );
m_out->Print( ")" ); // </pins>
m_out->Print( ")" ); // </unit>
}
m_out->Print( ")" ); // </units>
}
if( aFootprint->GetLocalSolderMaskMargin().has_value() )
{
m_out->Print( "(solder_mask_margin %s)",

3
pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr.h

@ -191,7 +191,8 @@ class PCB_IO_KICAD_SEXPR; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20250818 // Support for custom layer counts in footprints
//#define SEXPR_BOARD_FILE_VERSION 20250829 // Support Rounded Rectangles
//#define SEXPR_BOARD_FILE_VERSION 20250901 // PCB points
#define SEXPR_BOARD_FILE_VERSION 20250907 // uuids for tables
//#define SEXPR_BOARD_FILE_VERSION 20250907 // uuids for tables
#define SEXPR_BOARD_FILE_VERSION 20250909 // footprint unit metadata (units/pins)
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting

62
pcbnew/pcb_io/kicad_sexpr/pcb_io_kicad_sexpr_parser.cpp

@ -4758,6 +4758,68 @@ FOOTPRINT* PCB_IO_KICAD_SEXPR_PARSER::parseFOOTPRINT_unchecked( wxArrayString* a
NeedRIGHT();
break;
case T_units:
{
std::vector<FOOTPRINT::FP_UNIT_INFO> unitInfos;
// (units (unit (name "A") (pins "1" "2" ...)) ...)
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_LEFT )
token = NextTok();
if( token == T_unit )
{
FOOTPRINT::FP_UNIT_INFO info;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_LEFT )
token = NextTok();
if( token == T_name )
{
NeedSYMBOLorNUMBER();
info.m_unitName = FromUTF8();
NeedRIGHT();
}
else if( token == T_pins )
{
// Parse a flat list of quoted numbers or symbols until ')'
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token == T_STRING || token == T_NUMBER )
{
info.m_pins.emplace_back( FromUTF8() );
}
else
{
Expecting( "pin number" );
}
}
}
else
{
// Unknown sub-token inside unit; skip its list if any
skipCurrent();
}
}
unitInfos.push_back( info );
}
else
{
// Unknown entry under units; skip
skipCurrent();
}
}
if( !unitInfos.empty() )
footprint->SetUnitInfo( unitInfos );
break;
}
case T_autoplace_cost90:
case T_autoplace_cost180:
parseInt( "legacy auto-place cost" );

Loading…
Cancel
Save