2016-01-29 10:24:39 +00:00
|
|
|
/**
|
|
|
|
* @file board_netlist_updater.h
|
|
|
|
* @brief BOARD_NETLIST_UPDATER class definition
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
|
|
|
* Copyright (C) 2015 CERN
|
|
|
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
|
|
|
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
|
|
|
|
*
|
2017-03-25 01:18:16 +00:00
|
|
|
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
2016-01-29 10:24:39 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <common.h> // for PAGE_INFO
|
|
|
|
|
|
|
|
#include <class_board.h>
|
|
|
|
#include <class_netinfo.h>
|
|
|
|
#include <class_module.h>
|
|
|
|
#include <class_pad.h>
|
|
|
|
#include <class_zone.h>
|
|
|
|
|
|
|
|
#include <pcb_netlist.h>
|
|
|
|
#include <ratsnest_data.h>
|
|
|
|
#include <reporter.h>
|
|
|
|
|
|
|
|
#include <board_netlist_updater.h>
|
|
|
|
|
|
|
|
#include <wxPcbStruct.h>
|
|
|
|
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
BOARD_NETLIST_UPDATER::BOARD_NETLIST_UPDATER( PCB_EDIT_FRAME* aFrame, BOARD* aBoard ) :
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit( aFrame ),
|
2016-09-02 13:53:51 +00:00
|
|
|
m_frame( aFrame ),
|
2016-01-29 10:24:39 +00:00
|
|
|
m_board( aBoard )
|
|
|
|
{
|
|
|
|
m_reporter = &NULL_REPORTER::GetInstance();
|
2016-04-07 11:09:31 +00:00
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
m_deleteSinglePadNets = true;
|
|
|
|
m_deleteUnusedComponents = false;
|
|
|
|
m_isDryRun = false;
|
|
|
|
m_replaceFootprints = true;
|
|
|
|
m_lookupByTimestamp = false;
|
2016-04-07 11:09:31 +00:00
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
m_warningCount = 0;
|
|
|
|
m_errorCount = 0;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
|
|
|
BOARD_NETLIST_UPDATER::~BOARD_NETLIST_UPDATER()
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
wxPoint BOARD_NETLIST_UPDATER::estimateComponentInsertionPosition()
|
|
|
|
{
|
|
|
|
wxPoint bestPosition;
|
|
|
|
|
|
|
|
if( !m_board->IsEmpty() )
|
|
|
|
{
|
|
|
|
// Position new components below any existing board features.
|
2017-02-23 04:31:26 +00:00
|
|
|
EDA_RECT bbox = m_board->GetBoardEdgesBoundingBox();
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
if( bbox.GetWidth() || bbox.GetHeight() )
|
|
|
|
{
|
|
|
|
bestPosition.x = bbox.Centre().x;
|
|
|
|
bestPosition.y = bbox.GetBottom() + Millimeter2iu( 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Position new components in the center of the page when the board is empty.
|
|
|
|
wxSize pageSize = m_board->GetPageSettings().GetSizeIU();
|
|
|
|
|
|
|
|
bestPosition.x = pageSize.GetWidth() / 2;
|
|
|
|
bestPosition.y = pageSize.GetHeight() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bestPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MODULE* BOARD_NETLIST_UPDATER::addNewComponent( COMPONENT* aComponent )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
if( aComponent->GetModule() != NULL )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Adding new component \"%s:%s\" footprint \"%s\".\n" ),
|
|
|
|
GetChars( aComponent->GetReference() ),
|
|
|
|
GetChars( aComponent->GetTimeStamp() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
|
|
|
msg.Printf( _( "Add component %s, footprint: %s.\n" ),
|
|
|
|
GetChars( aComponent->GetReference() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
|
|
|
|
if( !m_isDryRun )
|
|
|
|
{
|
|
|
|
// Owned by NETLIST, can only copy it.
|
2016-09-02 13:53:51 +00:00
|
|
|
MODULE* footprint = new MODULE( *aComponent->GetModule() );
|
2016-01-29 10:24:39 +00:00
|
|
|
footprint->SetParent( m_board );
|
|
|
|
footprint->SetPosition( estimateComponentInsertionPosition( ) );
|
|
|
|
footprint->SetTimeStamp( GetNewTimeStamp() );
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
m_addedComponents.push_back( footprint );
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Add( footprint );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
return footprint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Cannot add component %s due to missing footprint %s.\n" ),
|
|
|
|
GetChars( aComponent->GetReference() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ERROR );
|
|
|
|
|
|
|
|
msg.Printf( _( "Cannot add new component \"%s:%s\" due to missing "
|
|
|
|
"footprint \"%s\".\n" ),
|
|
|
|
GetChars( aComponent->GetReference() ),
|
|
|
|
GetChars( aComponent->GetTimeStamp() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
2016-09-02 13:53:51 +00:00
|
|
|
++m_errorCount;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
|
|
|
MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE* aPcbComponent, COMPONENT* aNewComponent )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
if( !m_replaceFootprints )
|
|
|
|
return NULL;
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
// Test if the footprint has not changed
|
|
|
|
if( aNewComponent->GetFPID().empty() || aPcbComponent->GetFPID() == aNewComponent->GetFPID() )
|
2016-01-29 10:24:39 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if( aNewComponent->GetModule() != NULL )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Change component %s footprint from %s to %s.\n"),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aPcbComponent->GetFPID().Format() ) ),
|
|
|
|
GetChars( FROM_UTF8( aNewComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Replacing component \"%s:%s\" footprint \"%s\" with "
|
|
|
|
"\"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aPcbComponent->GetFPID().Format() ) ),
|
|
|
|
GetChars( FROM_UTF8( aNewComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
|
|
|
if( !m_isDryRun )
|
|
|
|
{
|
|
|
|
wxASSERT( aPcbComponent != NULL );
|
2016-09-05 13:38:01 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
MODULE* newFootprint = new MODULE( *aNewComponent->GetModule() );
|
2016-09-05 13:38:01 +00:00
|
|
|
newFootprint->SetParent( m_board );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
if( aNetlist.IsFindByTimeStamp() )
|
|
|
|
newFootprint->SetReference( aPcbComponent->GetReference() );
|
|
|
|
else
|
|
|
|
newFootprint->SetPath( aPcbComponent->GetPath() );
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
aPcbComponent->CopyNetlistSettings( newFootprint, false );
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Remove( aPcbComponent );
|
|
|
|
m_commit.Add( newFootprint );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
return newFootprint;
|
|
|
|
}
|
2016-09-02 13:53:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-01-29 10:24:39 +00:00
|
|
|
msg.Printf( _( "Cannot change component %s footprint due to missing "
|
|
|
|
"footprint %s.\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aNewComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ERROR );
|
|
|
|
|
|
|
|
msg.Printf( _( "Cannot replace component \"%s:%s\" due to missing "
|
|
|
|
"footprint \"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( aNewComponent->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
++m_errorCount;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
|
|
|
bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE* aPcbComponent, COMPONENT* aNewComponent )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
if( !aPcbComponent )
|
|
|
|
return false;
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
bool changed = false;
|
|
|
|
MODULE* copy = (MODULE*) aPcbComponent->Clone();
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
// Test for reference designator field change.
|
|
|
|
if( aPcbComponent->GetReference() != aNewComponent->GetReference() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Change component %s reference to %s.\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aNewComponent->GetReference() ) );
|
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Changing component \"%s:%s\" reference to \"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
|
|
|
GetChars( aNewComponent->GetReference() ) );
|
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
|
|
|
if ( !m_isDryRun )
|
2016-01-29 14:43:40 +00:00
|
|
|
{
|
|
|
|
changed = true;
|
|
|
|
aPcbComponent->SetReference( aNewComponent->GetReference() );
|
|
|
|
}
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test for value field change.
|
|
|
|
if( aPcbComponent->GetValue() != aNewComponent->GetValue() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Change component %s value from %s to %s.\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetValue() ),
|
|
|
|
GetChars( aNewComponent->GetValue() ) );
|
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Changing component \"%s:%s\" value from \"%s\" to \"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
|
|
|
GetChars( aPcbComponent->GetValue() ),
|
|
|
|
GetChars( aNewComponent->GetValue() ) );
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
if( !m_isDryRun )
|
2016-01-29 14:43:40 +00:00
|
|
|
{
|
|
|
|
changed = true;
|
2016-01-29 10:24:39 +00:00
|
|
|
aPcbComponent->SetValue( aNewComponent->GetValue() );
|
2016-01-29 14:43:40 +00:00
|
|
|
}
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test for time stamp change.
|
|
|
|
if( aPcbComponent->GetPath() != aNewComponent->GetTimeStamp() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Changing component path \"%s:%s\" to \"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
|
|
|
GetChars( aNewComponent->GetTimeStamp() ) );
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
2016-09-05 13:38:01 +00:00
|
|
|
if( !m_isDryRun )
|
2016-01-29 14:43:40 +00:00
|
|
|
{
|
|
|
|
changed = true;
|
2016-01-29 10:24:39 +00:00
|
|
|
aPcbComponent->SetPath( aNewComponent->GetTimeStamp() );
|
2016-01-29 14:43:40 +00:00
|
|
|
}
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
if( changed )
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Modified( aPcbComponent, copy );
|
2016-01-29 14:43:40 +00:00
|
|
|
else
|
|
|
|
delete copy;
|
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
|
|
|
bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE* aPcbComponent, COMPONENT* aNewComponent )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
bool changed = false;
|
|
|
|
MODULE* copy = (MODULE*) aPcbComponent->Clone();
|
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
// At this point, the component footprint is updated. Now update the nets.
|
2016-09-02 13:53:51 +00:00
|
|
|
for( D_PAD* pad = aPcbComponent->Pads(); pad; pad = pad->Next() )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
COMPONENT_NET net = aNewComponent->GetNet( pad->GetPadName() );
|
|
|
|
|
|
|
|
if( !net.IsValid() ) // New footprint pad has no net.
|
|
|
|
{
|
|
|
|
if( !pad->GetNetname().IsEmpty() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Disconnect component %s pin %s.\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( pad->GetPadName() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Clearing component \"%s:%s\" pin \"%s\" net name.\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
|
|
|
GetChars( pad->GetPadName() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !m_isDryRun )
|
|
|
|
{
|
2016-01-29 14:43:40 +00:00
|
|
|
changed = true;
|
2016-01-29 10:24:39 +00:00
|
|
|
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // New footprint pad has a net.
|
|
|
|
{
|
|
|
|
if( net.GetNetName() != pad->GetNetname() )
|
|
|
|
{
|
2016-09-05 13:38:01 +00:00
|
|
|
const wxString& netName = net.GetNetName();
|
|
|
|
NETINFO_ITEM* netinfo = m_board->FindNet( netName );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
2016-09-05 13:38:01 +00:00
|
|
|
if( netinfo == nullptr )
|
|
|
|
{
|
|
|
|
// It might be a new net that has not been added to the board yet
|
|
|
|
auto netIt = m_addedNets.find( netName );
|
|
|
|
|
|
|
|
if( netIt != m_addedNets.end() )
|
|
|
|
netinfo = netIt->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( netinfo == nullptr )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
// It is a new net, we have to add it
|
|
|
|
if( !m_isDryRun )
|
|
|
|
{
|
2016-01-29 14:43:40 +00:00
|
|
|
changed = true;
|
2016-09-05 13:38:01 +00:00
|
|
|
netinfo = new NETINFO_ITEM( m_board, netName );
|
|
|
|
m_commit.Add( netinfo );
|
|
|
|
m_addedNets[netName] = netinfo;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
2016-09-05 13:38:01 +00:00
|
|
|
msg.Printf( _( "Add net %s.\n" ), GetChars( netName ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
if( !pad->GetNetname().IsEmpty() )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
msg.Printf( _( "Reconnect component %s pin %s from net %s to net %s.\n"),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( pad->GetPadName() ),
|
|
|
|
GetChars( pad->GetNetname() ),
|
2016-09-05 13:38:01 +00:00
|
|
|
GetChars( netName ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
msg.Printf( _( "Connect component %s pin %s to net %s.\n"),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( pad->GetPadName() ),
|
2016-09-05 13:38:01 +00:00
|
|
|
GetChars( netName ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Changing component \"%s:%s\" pin \"%s\" net name from "
|
|
|
|
"\"%s\" to \"%s\".\n" ),
|
|
|
|
GetChars( aPcbComponent->GetReference() ),
|
|
|
|
GetChars( aPcbComponent->GetPath() ),
|
|
|
|
GetChars( pad->GetPadName() ),
|
|
|
|
GetChars( pad->GetNetname() ),
|
2016-09-05 13:38:01 +00:00
|
|
|
GetChars( netName ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
if( !m_isDryRun )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
2016-01-29 14:43:40 +00:00
|
|
|
changed = true;
|
2016-09-05 13:38:01 +00:00
|
|
|
pad->SetNet( netinfo );
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-29 14:43:40 +00:00
|
|
|
if( changed )
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Modified( aPcbComponent, copy );
|
2016-01-29 14:43:40 +00:00
|
|
|
else
|
|
|
|
delete copy;
|
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
MODULE* nextModule;
|
|
|
|
const COMPONENT* component;
|
|
|
|
|
|
|
|
for( MODULE* module = m_board->m_Modules; module != NULL; module = nextModule )
|
|
|
|
{
|
|
|
|
nextModule = module->Next();
|
|
|
|
|
|
|
|
if( m_lookupByTimestamp )
|
|
|
|
component = aNetlist.GetComponentByTimeStamp( module->GetPath() );
|
|
|
|
else
|
|
|
|
component = aNetlist.GetComponentByReference( module->GetReference() );
|
|
|
|
|
|
|
|
if( component == NULL )
|
|
|
|
{
|
2016-09-05 13:46:29 +00:00
|
|
|
if( module->IsLocked() )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Component %s is locked, skipping removal.\n" ),
|
|
|
|
GetChars( module->GetReference() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
msg.Printf( _( "Remove component %s." ),
|
|
|
|
GetChars( module->GetReference() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Removing unused component \"%s:%s\".\n" ),
|
|
|
|
GetChars( module->GetReference() ),
|
|
|
|
GetChars( module->GetPath() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
|
|
|
if( !m_isDryRun )
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Remove( module );
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
bool BOARD_NETLIST_UPDATER::deleteSinglePadNets()
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
wxString netname;
|
|
|
|
wxString msg;
|
|
|
|
D_PAD* pad = NULL;
|
|
|
|
D_PAD* previouspad = NULL;
|
|
|
|
|
|
|
|
// We need the pad list, for next tests.
|
|
|
|
// padlist is the list of pads, sorted by netname.
|
|
|
|
|
|
|
|
m_board->BuildListOfNets();
|
|
|
|
|
|
|
|
if( m_isDryRun )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::vector<D_PAD*> padlist = m_board->GetPads();
|
|
|
|
|
2016-05-23 15:47:16 +00:00
|
|
|
for( unsigned kk = 0; kk < padlist.size(); kk++ )
|
|
|
|
{
|
|
|
|
pad = padlist[kk];
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
if( pad->GetNetname().IsEmpty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( netname != pad->GetNetname() ) // End of net
|
|
|
|
{
|
|
|
|
if( previouspad && count == 1 )
|
|
|
|
{
|
|
|
|
// First, see if we have a copper zone attached to this pad.
|
|
|
|
// If so, this is not really a single pad net
|
|
|
|
|
|
|
|
for( int ii = 0; ii < m_board->GetAreaCount(); ii++ )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* zone = m_board->GetArea( ii );
|
|
|
|
|
|
|
|
if( !zone->IsOnCopperLayer() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( zone->GetIsKeepout() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( zone->GetNet() == previouspad->GetNet() )
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( count == 1 ) // Really one pad, and nothing else
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Remove single pad net %s." ),
|
|
|
|
GetChars( previouspad->GetNetname() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
msg.Printf( _( "Remove single pad net \"%s\" on \"%s\" pad '%s'\n" ),
|
|
|
|
GetChars( previouspad->GetNetname() ),
|
|
|
|
GetChars( previouspad->GetParent()->GetReference() ),
|
|
|
|
GetChars( previouspad->GetPadName() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
|
|
|
previouspad->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
netname = pad->GetNetname();
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
previouspad = pad;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Examine last pad
|
|
|
|
if( pad && count == 1 )
|
|
|
|
pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
|
2016-09-05 13:38:01 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist )
|
|
|
|
{
|
|
|
|
// Last step: Some tests:
|
|
|
|
// verify all pads found in netlist:
|
|
|
|
// They should exist in footprints, otherwise the footprint is wrong
|
|
|
|
// note also references or time stamps are updated, so we use only
|
|
|
|
// the reference to find a footprint
|
|
|
|
//
|
|
|
|
// Also verify if zones have acceptable nets, i.e. nets with pads.
|
|
|
|
// Zone with no pad belongs to a "dead" net which happens after changes in schematic
|
|
|
|
// when no more pad use this net name.
|
|
|
|
|
|
|
|
wxString msg;
|
|
|
|
wxString padname;
|
|
|
|
|
|
|
|
for( int i = 0; i < (int) aNetlist.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
const COMPONENT* component = aNetlist.GetComponent( i );
|
|
|
|
MODULE* footprint = m_board->FindModuleByReference( component->GetReference() );
|
|
|
|
|
|
|
|
if( footprint == NULL ) // It can be missing in partial designs
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Explore all pins/pads in component
|
|
|
|
for( unsigned jj = 0; jj < component->GetNetCount(); jj++ )
|
|
|
|
{
|
|
|
|
COMPONENT_NET net = component->GetNet( jj );
|
|
|
|
padname = net.GetPinName();
|
|
|
|
|
|
|
|
if( footprint->FindPadByName( padname ) )
|
|
|
|
continue; // OK, pad found
|
|
|
|
|
|
|
|
// not found: bad footprint, report error
|
|
|
|
msg.Printf( _( "Component %s pad %s not found in footprint %s\n" ),
|
|
|
|
GetChars( component->GetReference() ),
|
|
|
|
GetChars( padname ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( footprint->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ERROR );
|
2016-09-02 13:53:51 +00:00
|
|
|
++m_errorCount;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test copper zones to detect "dead" nets (nets without any pad):
|
|
|
|
for( int i = 0; i < m_board->GetAreaCount(); i++ )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* zone = m_board->GetArea( i );
|
|
|
|
|
|
|
|
if( !zone->IsOnCopperLayer() || zone->GetIsKeepout() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int nc = zone->GetNet()->GetNodesCount();
|
|
|
|
|
|
|
|
if( nc == 0 )
|
|
|
|
{
|
|
|
|
msg.Printf( _( "Copper zone (net name %s): net has no pads connected." ),
|
|
|
|
GetChars( zone->GetNet()->GetNetname() ) );
|
|
|
|
m_reporter->Report( msg, REPORTER::RPT_WARNING );
|
2016-09-02 13:53:51 +00:00
|
|
|
++m_warningCount;
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist )
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
m_errorCount = 0;
|
|
|
|
m_warningCount = 0;
|
|
|
|
|
|
|
|
if( !m_isDryRun )
|
|
|
|
{
|
|
|
|
m_board->SetStatus( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = 0; i < (int) aNetlist.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
COMPONENT* component = aNetlist.GetComponent( i );
|
2016-09-02 13:53:51 +00:00
|
|
|
MODULE* footprint = NULL;
|
2016-01-29 10:24:39 +00:00
|
|
|
|
|
|
|
msg.Printf( _( "Processing component \"%s:%s:%s\".\n" ),
|
|
|
|
GetChars( component->GetReference() ),
|
|
|
|
GetChars( component->GetTimeStamp() ),
|
2017-03-25 01:18:16 +00:00
|
|
|
GetChars( FROM_UTF8( component->GetFPID().Format() ) ) );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_INFO );
|
|
|
|
|
|
|
|
if( aNetlist.IsFindByTimeStamp() )
|
|
|
|
footprint = m_board->FindModule( component->GetTimeStamp(), true );
|
|
|
|
else
|
|
|
|
footprint = m_board->FindModule( component->GetReference() );
|
|
|
|
|
|
|
|
if( footprint ) // An existing footprint.
|
|
|
|
{
|
2016-09-02 13:53:51 +00:00
|
|
|
MODULE* newFootprint = replaceComponent( aNetlist, footprint, component );
|
|
|
|
|
|
|
|
if( newFootprint )
|
2016-01-29 10:24:39 +00:00
|
|
|
footprint = newFootprint;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
footprint = addNewComponent( component );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( footprint )
|
|
|
|
{
|
|
|
|
updateComponentParameters( footprint, component );
|
|
|
|
updateComponentPadConnections( footprint, component );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//aNetlist.GetDeleteExtraFootprints()
|
|
|
|
|
|
|
|
if( m_deleteUnusedComponents )
|
|
|
|
deleteUnusedComponents( aNetlist );
|
|
|
|
|
|
|
|
if( m_deleteSinglePadNets )
|
|
|
|
deleteSinglePadNets();
|
|
|
|
|
2016-09-05 13:38:01 +00:00
|
|
|
if( !m_isDryRun )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
2016-09-05 13:38:01 +00:00
|
|
|
m_commit.Push( _( "Update netlist" ) );
|
|
|
|
m_frame->Compile_Ratsnest( NULL, false );
|
2016-01-29 14:43:40 +00:00
|
|
|
m_board->GetRatsnest()->ProcessBoard();
|
|
|
|
testConnectivity( aNetlist );
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the ratsnest
|
2016-09-02 13:53:51 +00:00
|
|
|
m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION );
|
|
|
|
m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION );
|
2016-01-29 10:24:39 +00:00
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
msg.Printf( _( "Total warnings: %d, errors: %d." ), m_warningCount, m_errorCount );
|
2016-01-29 10:24:39 +00:00
|
|
|
m_reporter->Report( msg, REPORTER::RPT_ACTION );
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
if( m_errorCount )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
2016-09-02 13:53:51 +00:00
|
|
|
m_reporter->Report( _( "Errors occured during the netlist update. Unless you "
|
|
|
|
"fix them, your board will not be consistent with the schematics." ),
|
2016-01-29 10:24:39 +00:00
|
|
|
REPORTER::RPT_ERROR );
|
|
|
|
|
|
|
|
return false;
|
2016-09-02 13:53:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_reporter->Report( _( "Netlist update successful!" ), REPORTER::RPT_ACTION );
|
2016-01-29 10:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-02 13:53:51 +00:00
|
|
|
|
2016-01-29 10:24:39 +00:00
|
|
|
bool BOARD_NETLIST_UPDATER::UpdateNetlist( const wxString& aNetlistFileName,
|
2016-09-02 13:53:51 +00:00
|
|
|
const wxString& aCmpFileName )
|
2016-01-29 10:24:39 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|