1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2021 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 <board.h>
25 #include <footprint.h>
26 #include <macros.h>
27 #include <pad.h>
28 #include <pcb_track.h>
29 #include <zone.h>
30 #include <netinfo.h>
31 #include <wx/log.h>
32 
33 
34 // Constructor and destructor
NETINFO_LIST(BOARD * aParent)35 NETINFO_LIST::NETINFO_LIST( BOARD* aParent ) :
36         m_parent( aParent )
37 {
38     // Make sure that the unconnected net has number 0
39     AppendNet( new NETINFO_ITEM( aParent, wxEmptyString, 0 ) );
40 
41     m_newNetCode = 0;
42 }
43 
44 
~NETINFO_LIST()45 NETINFO_LIST::~NETINFO_LIST()
46 {
47     clear();
48 }
49 
50 
clear()51 void NETINFO_LIST::clear()
52 {
53     NETNAMES_MAP::iterator it, itEnd;
54     for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
55         delete it->second;
56 
57     m_netNames.clear();
58     m_netCodes.clear();
59     m_newNetCode = 0;
60 }
61 
62 
GetNetItem(int aNetCode) const63 NETINFO_ITEM* NETINFO_LIST::GetNetItem( int aNetCode ) const
64 {
65     NETCODES_MAP::const_iterator result = m_netCodes.find( aNetCode );
66 
67     if( result != m_netCodes.end() )
68         return (*result).second;
69 
70     return nullptr;
71 }
72 
73 
GetNetItem(const wxString & aNetName) const74 NETINFO_ITEM* NETINFO_LIST::GetNetItem( const wxString& aNetName ) const
75 {
76     NETNAMES_MAP::const_iterator result = m_netNames.find( aNetName );
77 
78     if( result != m_netNames.end() )
79         return (*result).second;
80 
81     return nullptr;
82 }
83 
84 
RemoveNet(NETINFO_ITEM * aNet)85 void NETINFO_LIST::RemoveNet( NETINFO_ITEM* aNet )
86 {
87     bool removed = false;
88 
89     for( NETCODES_MAP::iterator i = m_netCodes.begin(); i != m_netCodes.end(); ++i )
90     {
91         if ( i->second == aNet )
92         {
93             removed = true;
94             m_netCodes.erase(i);
95             break;
96         }
97     }
98 
99     for( NETNAMES_MAP::iterator i = m_netNames.begin(); i != m_netNames.end(); ++i )
100     {
101         if ( i->second == aNet )
102         {
103             wxASSERT_MSG( removed, "NETINFO_LIST::RemoveNet: target net found in m_netNames "
104                           "but not m_netCodes!" );
105             m_netNames.erase(i);
106             break;
107         }
108     }
109 
110     if( removed )
111         m_newNetCode = std::min( m_newNetCode, aNet->m_netCode - 1 );
112 }
113 
114 
RemoveUnusedNets()115 void NETINFO_LIST::RemoveUnusedNets()
116 {
117     NETCODES_MAP existingNets = m_netCodes;
118 
119     m_netCodes.clear();
120     m_netNames.clear();
121 
122     for( std::pair<const int, NETINFO_ITEM*> item : existingNets )
123     {
124         if( item.second->IsCurrent() )
125         {
126             m_netNames.insert( std::make_pair( item.second->GetNetname(), item.second ) );
127             m_netCodes.insert( std::make_pair( item.first, item.second ) );
128         }
129     }
130 }
131 
132 
AppendNet(NETINFO_ITEM * aNewElement)133 void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement )
134 {
135     // if there is a net with such name then just assign the correct number
136     NETINFO_ITEM* sameName = GetNetItem( aNewElement->GetNetname() );
137 
138     if( sameName != nullptr )
139     {
140         aNewElement->m_netCode = sameName->GetNetCode();
141 
142         return;
143     }
144     else if( aNewElement->m_netCode != (int) m_netCodes.size() || aNewElement->m_netCode < 0 )
145     {
146         // be sure that net codes are consecutive
147         // negative net code means that it has to be auto assigned
148         aNewElement->m_netCode = getFreeNetCode();
149     }
150 
151     // net names & codes are supposed to be unique
152     assert( GetNetItem( aNewElement->GetNetname() ) == nullptr );
153     assert( GetNetItem( aNewElement->GetNetCode() ) == nullptr );
154 
155     // add an entry for fast look up by a net name using a map
156     m_netNames.insert( std::make_pair( aNewElement->GetNetname(), aNewElement ) );
157     m_netCodes.insert( std::make_pair( aNewElement->GetNetCode(), aNewElement ) );
158 }
159 
160 
buildListOfNets()161 void NETINFO_LIST::buildListOfNets()
162 {
163     // Restore the initial state of NETINFO_ITEMs
164     for( NETINFO_ITEM* net : *this )
165         net->Clear();
166 
167     m_parent->SynchronizeNetsAndNetClasses( );
168     m_parent->SetAreasNetCodesFromNetNames();
169 }
170 
171 
172 #if defined(DEBUG)
Show() const173 void NETINFO_LIST::Show() const
174 {
175     int i = 0;
176     NETNAMES_MAP::const_iterator it, itEnd;
177 
178     for( it = m_netNames.begin(), itEnd = m_netNames.end(); it != itEnd; ++it )
179     {
180         wxLogDebug( "[%d]: netcode:%d  netname:<%s>\n",
181                     i++,
182                     it->second->GetNetCode(),
183                     TO_UTF8( it->second->GetNetname() ) );
184     }
185 }
186 #endif
187 
188 
getFreeNetCode()189 int NETINFO_LIST::getFreeNetCode()
190 {
191     do
192     {
193         if( m_newNetCode < 0 )
194             m_newNetCode = 0;
195     } while( m_netCodes.count( ++m_newNetCode ) != 0 );
196 
197     return m_newNetCode;
198 }
199 
200 
Translate(int aNetCode) const201 int NETINFO_MAPPING::Translate( int aNetCode ) const
202 {
203     std::map<int, int>::const_iterator value = m_netMapping.find( aNetCode );
204 
205     if( value != m_netMapping.end() )
206         return value->second;
207 
208     // There was no entry for the given net code
209     return aNetCode;
210 }
211 
212 
Update()213 void NETINFO_MAPPING::Update()
214 {
215     // Collect all the used nets
216     std::set<int> nets;
217 
218     // Be sure that the unconnected gets 0 and is mapped as 0
219     nets.insert( 0 );
220 
221     // Zones
222     for( ZONE* zone : m_board->Zones() )
223         nets.insert( zone->GetNetCode() );
224 
225     // Tracks
226     for( PCB_TRACK* track : m_board->Tracks() )
227         nets.insert( track->GetNetCode() );
228 
229     // footprints/pads
230     for( FOOTPRINT* footprint : m_board->Footprints() )
231     {
232         for( PAD* pad : footprint->Pads() )
233             nets.insert( pad->GetNetCode() );
234     }
235 
236     // Prepare the new mapping
237     m_netMapping.clear();
238 
239     // Now the nets variable stores all the used net codes (not only for pads) and we are ready to
240     // assign new consecutive net numbers
241     int newNetCode = 0;
242 
243     for( auto net : nets )
244         m_netMapping[net] = newNetCode++;
245 }
246 
247 
operator *() const248 NETINFO_ITEM* NETINFO_MAPPING::iterator::operator*() const
249 {
250     return m_mapping->m_board->FindNet( m_iterator->first );
251 }
252 
253 
operator ->() const254 NETINFO_ITEM* NETINFO_MAPPING::iterator::operator->() const
255 {
256     return m_mapping->m_board->FindNet( m_iterator->first );
257 }
258 
259 
260 const int NETINFO_LIST::UNCONNECTED = 0;
261 const int NETINFO_LIST::ORPHANED = -1;
262 
263