KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_info_impl.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 (C) 2011 Jean-Pierre Charras, <[email protected]>
5 * Copyright (C) 2013-2016 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23#include <footprint_info_impl.h>
24
26#include <footprint.h>
27#include <footprint_info.h>
29#include <kiway.h>
30#include <lib_id.h>
31#include <progress_reporter.h>
32#include <string_utils.h>
33#include <thread_pool.h>
34
35
37{
38 FOOTPRINT_LIBRARY_ADAPTER* adapter = m_owner->GetAdapter();
39 wxCHECK( adapter, /* void */ );
40
41 try
42 {
43 std::unique_ptr<FOOTPRINT> footprint( adapter->LoadFootprint( m_nickname, m_fpname, false ) );
44
45 if( footprint == nullptr ) // Should happen only with malformed/broken libraries
46 {
47 m_pad_count = 0;
50 }
51 else
52 {
53 m_pad_count = footprint->GetPadCount( DO_NOT_INCLUDE_NPTH );
54 m_unique_pad_count = footprint->GetUniquePadCount( DO_NOT_INCLUDE_NPTH );
55 m_numbered_pad_count = footprint->GetNumberedPadCount();
56 m_keywords = footprint->GetKeywords();
57 m_doc = footprint->GetLibDescription();
58 }
59 }
60 catch( const IO_ERROR& ioe )
61 {
62 // Store error in the owner's error list for later display
63 if( m_owner )
64 m_owner->PushError( std::make_unique<IO_ERROR>( ioe ) );
65
66 m_pad_count = 0;
69 }
70
71 m_loaded = true;
72}
73
74
76{
77 std::unique_lock<std::mutex> lock( m_loadInProgress );
78
79 m_list.clear();
81}
82
83
85 const wxString& aLibName,
86 const std::function<void( const std::vector<LIB_TREE_ITEM*>& )>& aCallback )
87{
88 std::unique_lock<std::mutex> lock( m_loadInProgress );
89
90 std::vector<LIB_TREE_ITEM*> libList;
91 const auto& fullList = GetList();
92
93 FOOTPRINT_INFO_IMPL dummy( aLibName, wxEmptyString );
94 std::unique_ptr<FOOTPRINT_INFO> dummyPtr( &dummy );
95
96 auto libBounds = std::equal_range( fullList.begin(), fullList.end(), dummyPtr,
97 []( const std::unique_ptr<FOOTPRINT_INFO>& a, const std::unique_ptr<FOOTPRINT_INFO>& b )
98 {
99 if( !a || !b )
100 return false;
101
102 return StrNumCmp( a->GetLibNickname(), b->GetLibNickname(), false ) < 0;
103 } );
104
105 dummyPtr.release();
106
107 for( auto i = libBounds.first; i != libBounds.second; ++i )
108 {
109 if( *i )
110 libList.push_back( i->get() );
111 }
112
113 aCallback( libList );
114}
115
116
117bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc )
118{
119 try
120 {
121 aFunc();
122 }
123 catch( const IO_ERROR& ioe )
124 {
125 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
126 return false;
127 }
128 catch( const std::exception& se )
129 {
130 // This is a round about way to do this, but who knows what THROW_IO_ERROR()
131 // may be tricked out to do someday, keep it in the game.
132 try
133 {
134 THROW_IO_ERROR( se.what() );
135 }
136 catch( const IO_ERROR& ioe )
137 {
138 m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) );
139 }
140
141 return false;
142 }
143
144 return true;
145}
146
147
149 PROGRESS_REPORTER* aProgressReporter )
150{
151 std::unique_lock<std::mutex> lock( m_loadInProgress );
152
153 m_adapter = aAdapter;
154
155 // AsyncLoad() must be called before BlockUntilLoaded() to ensure library loading is started.
156 // This is necessary when the footprint chooser is opened from contexts that don't preload
157 // footprint libraries (e.g., eeschema).
158 m_adapter->AsyncLoad();
159 m_adapter->BlockUntilLoaded();
160
161 long long int generatedTimestamp = 0;
162
163 if( !CatchErrors( [&]()
164 {
165 generatedTimestamp = aAdapter->GenerateTimestamp( aNickname );
166 } ) )
167 {
168 return false;
169 }
170
171 if( generatedTimestamp == m_list_timestamp )
172 return true;
173
174 // Disable KIID generation: not needed for library parts; sometimes very slow
175 KIID_NIL_SET_RESET reset_kiid;
176
177 m_progress_reporter = aProgressReporter;
178
179 m_cancelled = false;
180
181 // Clear data before reading files
182 m_errors.clear();
183 m_list.clear();
184 m_queue.clear();
185
186 if( aNickname )
187 {
188 m_queue.push( *aNickname );
189 }
190 else
191 {
192 for( const wxString& nickname : aAdapter->GetLibraryNames() )
193 m_queue.push( nickname );
194 }
195
197 {
198 m_progress_reporter->SetMaxProgress( (int) m_queue.size() );
199 m_progress_reporter->Report( _( "Loading footprints..." ) );
200 }
201
203
205 m_progress_reporter->AdvancePhase();
206
207 if( m_cancelled )
208 m_list_timestamp = 0; // God knows what we got before we were canceled
209 else
210 m_list_timestamp = generatedTimestamp;
211
212 return m_errors.empty();
213}
214
215
217{
218 // Parse the footprints in parallel.
219
222 size_t num_elements = m_queue.size();
223 std::vector<std::future<size_t>> returns( num_elements );
224
225 auto fp_thread =
226 [ this, &queue_parsed ]() -> size_t
227 {
228 // Each thread pool worker needs its own KIID_NIL_SET_RESET since g_createNilUuids
229 // is thread_local. This prevents generating real UUIDs for temporary footprint data.
230 KIID_NIL_SET_RESET reset_kiid;
231
232 wxString nickname;
233
234 if( m_cancelled || !m_queue.pop( nickname ) )
235 return 0;
236
237 std::vector<wxString> fpnames;
238
240 [&]()
241 {
242 fpnames = m_adapter->GetFootprintNames( nickname );
243 } );
244
245 for( wxString fpname : fpnames )
246 {
248 [&]()
249 {
250 auto* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname );
251 queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) );
252 } );
253
254 if( m_cancelled )
255 return 0;
256 }
257
259 m_progress_reporter->AdvanceProgress();
260
261 return 1;
262 };
263
264 for( size_t ii = 0; ii < num_elements; ++ii )
265 returns[ii] = tp.submit_task( fp_thread );
266
267 for( const std::future<size_t>& ret : returns )
268 {
269 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
270
271 while( status != std::future_status::ready )
272 {
274 m_progress_reporter->KeepRefreshing();
275
276 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
277 }
278 }
279
280 std::unique_ptr<FOOTPRINT_INFO> fpi;
281
282 while( queue_parsed.pop( fpi ) )
283 m_list.push_back( std::move( fpi ) );
284
285 std::sort( m_list.begin(), m_list.end(),
286 []( std::unique_ptr<FOOTPRINT_INFO> const& lhs,
287 std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool
288 {
289 if( !lhs || !rhs )
290 return false;
291
292 return *lhs < *rhs;
293 } );
294}
295
296
virtual void load() override
lazily load stuff not filled in by constructor. This may throw IO_ERRORS.
wxString m_doc
Footprint description.
wxString m_fpname
Module name.
wxString m_keywords
Footprint keywords.
unsigned m_numbered_pad_count
Number of unique electrical pads (numeric or BGA-style numbers)
unsigned m_unique_pad_count
Number of unique pads.
unsigned m_pad_count
Number of pads.
FOOTPRINT_LIST * m_owner
provides access to FP_LIB_TABLE
wxString m_nickname
library as known in FP_LIB_TABLE
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT * LoadFootprint(const wxString &aNickname, const wxString &aName, bool aKeepUUID)
Load a FOOTPRINT having aName from the library given by aNickname.
long long GenerateTimestamp(const wxString *aNickname)
Generates a filesystem timestamp / hash value for library(ies)
bool ReadFootprintFiles(FOOTPRINT_LIBRARY_ADAPTER *aAdapter, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the footprints provided by the combination of aTable and aNickname.
void WithFootprintsForLibrary(const wxString &aLibName, const std::function< void(const std::vector< LIB_TREE_ITEM * > &)> &aCallback)
Execute a callback with thread-safe access to the footprints for a library.
std::atomic_bool m_cancelled
SYNC_QUEUE< wxString > m_queue
bool CatchErrors(const std::function< void()> &aFunc)
Call aFunc, pushing any IO_ERRORs and std::exceptions it throws onto m_errors.
PROGRESS_REPORTER * m_progress_reporter
SYNC_QUEUE< std::unique_ptr< IO_ERROR > > m_errors
some can be PARSE_ERRORs also
std::vector< std::unique_ptr< FOOTPRINT_INFO > > m_list
FOOTPRINT_LIBRARY_ADAPTER * m_adapter
no ownership
const std::vector< std::unique_ptr< FOOTPRINT_INFO > > & GetList() const
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
RAII class to safely set/reset nil KIIDs for use in footprint/symbol loading.
Definition kiid.h:238
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
A progress reporter interface for use in multi-threaded environments.
Synchronized, locking queue.
Definition sync_queue.h:32
bool pop(T &aReceiver)
Pop a value if the queue into the provided variable.
Definition sync_queue.h:63
void move_push(T &&aValue)
Move a value onto the queue.
Definition sync_queue.h:50
#define _(s)
@ DO_NOT_INCLUDE_NPTH
Definition footprint.h:74
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::vector< FAB_LAYER_COLOR > dummy
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
static thread_pool * tp
BS::priority_thread_pool thread_pool
Definition thread_pool.h:31