/** * Function not_implemented * throws an IO_ERROR and complains of an API function not being implemented. * * @param aPlugin is a PLUGIN instance * @param aCaller is the name of the unimplemented API function. */ static void not_implemented( PLUGIN* aPlugin, const char* aCaller ) { THROW_IO_ERROR( wxString::Format( FMT_UNIMPLEMENTED, aPlugin->PluginName().GetData(), wxString::FromUTF8( aCaller ).GetData() ) ); }
char* FILE_LINE_READER::ReadLine() throw( IO_ERROR ) { length = 0; for(;;) { if( length >= maxLineLength ) THROW_IO_ERROR( _( "Maximum line length exceeded" ) ); if( length >= capacity ) expandCapacity( capacity * 2 ); // faster, POSIX compatible fgetc(), no locking. int cc = getc_unlocked( fp ); if( cc == EOF ) break; line[ length++ ] = (char) cc; if( cc == '\n' ) break; } line[ length ] = 0; // lineNum is incremented even if there was no line read, because this // leads to better error reporting when we hit an end of file. ++lineNum; return length ? line : NULL; }
char* STRING_LINE_READER::ReadLine() throw( IO_ERROR ) { size_t nlOffset = lines.find( '\n', ndx ); if( nlOffset == std::string::npos ) length = lines.length() - ndx; else length = nlOffset - ndx + 1; // include the newline, so +1 if( length ) { if( length >= maxLineLength ) THROW_IO_ERROR( _("Line length exceeded") ); if( length+1 > capacity ) // +1 for terminating nul expandCapacity( length+1 ); wxASSERT( ndx + length <= lines.length() ); memcpy( line, &lines[ndx], length ); ndx += length; } ++lineNum; // this gets incremented even if no bytes were read line[length] = 0; return length ? line : NULL; }
char* INPUTSTREAM_LINE_READER::ReadLine() throw( IO_ERROR ) { length = 0; for(;;) { if( length >= maxLineLength ) THROW_IO_ERROR( _( "Maximum line length exceeded" ) ); if( length + 1 > capacity ) expandCapacity( capacity * 2 ); // this read may fail, docs say to test LastRead() before trusting cc. char cc = m_stream->GetC(); if( !m_stream->LastRead() ) break; line[ length++ ] = cc; if( cc == '\n' ) break; } line[ length ] = 0; // lineNum is incremented even if there was no line read, because this // leads to better error reporting when we hit an end of file. ++lineNum; return length ? line : NULL; }
PLUGIN* IO_MGR::PluginFind( PCB_FILE_T aFileType ) { // This implementation is subject to change, any magic is allowed here. // The public IO_MGR API is the only pertinent public information. switch( aFileType ) { case LEGACY: return new LEGACY_PLUGIN(); case KICAD: return new PCB_IO(); case EAGLE: return new EAGLE_PLUGIN(); case PCAD: return new PCAD_PLUGIN(); case GEDA_PCB: return new GPCB_PLUGIN(); case GITHUB: #if defined(BUILD_GITHUB_PLUGIN) return new GITHUB_PLUGIN(); #else THROW_IO_ERROR( "BUILD_GITHUB_PLUGIN not enabled in cmake build environment" ); #endif } return NULL; }
bool FOOTPRINT_LIST_IMPL::CatchErrors( const std::function<void()>& aFunc ) { try { aFunc(); } catch( const IO_ERROR& ioe ) { m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) ); return false; } catch( const std::exception& se ) { // This is a round about way to do this, but who knows what THROW_IO_ERROR() // may be tricked out to do someday, keep it in the game. try { THROW_IO_ERROR( se.what() ); } catch( const IO_ERROR& ioe ) { m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) ); } return false; } return true; }
void FOOTPRINT_LIST::loader_job( const wxString* aNicknameList, int aJobZ ) { //DBG(printf( "%s: first:'%s' count:%d\n", __func__, (char*) TO_UTF8( *aNicknameList ), aJobZ );) for( int i=0; i<aJobZ; ++i ) { if( m_error_count >= NTOLERABLE_ERRORS ) break; const wxString& nickname = aNicknameList[i]; try { wxArrayString fpnames = m_lib_table->FootprintEnumerate( nickname ); for( unsigned ni=0; ni<fpnames.GetCount(); ++ni ) { FOOTPRINT_INFO* fpinfo = new FOOTPRINT_INFO( this, nickname, fpnames[ni] ); addItem( fpinfo ); } } catch( const PARSE_ERROR& pe ) { // m_errors.push_back is not thread safe, lock its MUTEX. MUTLOCK lock( m_errors_lock ); ++m_error_count; // modify only under lock m_errors.push_back( new IO_ERROR( pe ) ); } catch( const IO_ERROR& ioe ) { MUTLOCK lock( m_errors_lock ); ++m_error_count; m_errors.push_back( new IO_ERROR( ioe ) ); } // Catch anything unexpected and map it into the expected. // Likely even more important since this function runs on GUI-less // worker threads. catch( const std::exception& se ) { // This is a round about way to do this, but who knows what THROW_IO_ERROR() // may be tricked out to do someday, keep it in the game. try { THROW_IO_ERROR( se.what() ); } catch( const IO_ERROR& ioe ) { MUTLOCK lock( m_errors_lock ); ++m_error_count; m_errors.push_back( new IO_ERROR( ioe ) ); } } } }
void FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount ) throw( IO_ERROR ) { if( 1 != fwrite( aOutBuf, aCount, 1, m_fp ) ) { wxString msg = wxString::Format( _( "error writing to file '%s'" ), m_filename.GetData() ); THROW_IO_ERROR( msg ); } }
void IO_MGR::Save( PCB_FILE_T aFileType, const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties ) { // release the PLUGIN even if an exception is thrown. PLUGIN::RELEASER pi( PluginFind( aFileType ) ); if( (PLUGIN*) pi ) // test pi->plugin { pi->Save( aFileName, aBoard, aProperties ); // virtual return; } THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) ); }
IFSTREAM_LINE_READER::IFSTREAM_LINE_READER( const wxFileName& aFileName ) throw( IO_ERROR ) : m_fStream( aFileName.GetFullName().ToUTF8() ) { if( !m_fStream.is_open() ) { wxString msg = wxString::Format( _( "Unable to open filename '%s' for reading" ), aFileName.GetFullPath().GetData() ); THROW_IO_ERROR( msg ); } setStream( m_fStream ); source = aFileName.GetFullName(); }
FILE_OUTPUTFORMATTER::FILE_OUTPUTFORMATTER( const wxString& aFileName, const wxChar* aMode, char aQuoteChar ) throw( IO_ERROR ) : OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ), m_filename( aFileName ) { m_fp = wxFopen( aFileName, aMode ); if( !m_fp ) { wxString msg = wxString::Format( _( "cannot open or save file '%s'" ), m_filename.GetData() ); THROW_IO_ERROR( msg ); } }
void STREAM_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount ) throw( IO_ERROR ) { int lastWrite; // This might delay awhile if you were writing to say a socket, but for // a file it should only go through the loop once. for( int total = 0; total<aCount; total += lastWrite ) { lastWrite = os.Write( aOutBuf, aCount ).LastWrite(); if( !os.IsOk() ) { THROW_IO_ERROR( _( "OUTPUTSTREAM_OUTPUTFORMATTER write error" ) ); } } }
void PCB_PAD::AddToBoard() { PCB_PAD_SHAPE* padShape; int i; int width = 0; int height = 0; // choose one of the shapes for( i = 0; i < (int) m_shapes.GetCount(); i++ ) { padShape = m_shapes[i]; if( padShape->m_width > 0 && padShape->m_height > 0 ) { if( padShape->m_KiCadLayer == LAYER_N_FRONT || padShape->m_KiCadLayer == LAYER_N_BACK ) { width = padShape->m_width; height = padShape->m_height; break; } } } if( width == 0 || height == 0 ) THROW_IO_ERROR( wxT( "pad or via with zero size" ) ); if( IsValidCopperLayerIndex( m_KiCadLayer ) ) { SEGVIA* via = new SEGVIA( m_board ); m_board->m_Track.Append( via ); via->SetTimeStamp( 0 ); via->SetPosition( wxPoint( m_positionX, m_positionY ) ); via->SetEnd( wxPoint( m_positionX, m_positionY ) ); via->SetWidth( height ); via->SetShape( VIA_THROUGH ); ( (SEGVIA*) via )->SetLayerPair( LAYER_N_FRONT, LAYER_N_BACK ); via->SetDrill( m_hole ); via->SetLayer( m_KiCadLayer ); via->SetNet( m_netCode ); } }
static inline long parseInt( const wxString& aValue, double aScalar ) { double value = LONG_MAX; /* * In 2011 gEDA/pcb introduced values with units, like "10mm" or "200mil". * Unit-less values are still centimils (100000 units per inch), like with * the previous format. * * Distinction between the even older format (mils, 1000 units per inch) * and the pre-2011 format is done in ::parseMODULE already; the * distinction is by wether an object definition opens with '(' or '['. * All values with explicite unit open with a '[' so there's no need to * consider this distinction when parsing them. * * The solution here is to watch for a unit and, if present, convert the * value to centimils. All unit-less values are read unaltered. This way * the code below can contine to consider all read values to be in mils or * centimils. It also matches the strategy gEDA/pcb uses for backwards * compatibility with its own layouts. * * Fortunately gEDA/pcb allows only units 'mil' and 'mm' in files, see * definition of ALLOW_READABLE in gEDA/pcb's pcb_printf.h. So we don't * have to test for all 11 units gEDA/pcb allows in user dialogs. */ if( aValue.EndsWith( wxT( "mm" ) ) ) { aScalar *= 100000.0 / 25.4; } else if( aValue.EndsWith( wxT( "mil" ) ) ) { aScalar *= 100.; } // This conversion reports failure on strings as simple as "1000", still // it returns the right result in &value. Thus, ignore the return value. aValue.ToCDouble(&value); if( value == LONG_MAX ) // conversion really failed { THROW_IO_ERROR( wxString::Format( _( "Cannot convert \"%s\" to an integer" ), aValue.GetData() ) ); return 0; } return KiROUND( value * aScalar ); }
void GPCB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties ) { LOCALE_IO toggle; // toggles on, then off, the C locale. init( aProperties ); cacheLib( aLibraryPath ); if( !m_cache->IsWritable() ) { THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only" ), aLibraryPath.GetData() ) ); } m_cache->Remove( aFootprintName ); }
FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName, unsigned aStartingLineNumber, unsigned aMaxLineLength ) throw( IO_ERROR ) : LINE_READER( aMaxLineLength ), iOwn( true ) { fp = wxFopen( aFileName, wxT( "rt" ) ); if( !fp ) { wxString msg = wxString::Format( _( "Unable to open filename '%s' for reading" ), aFileName.GetData() ); THROW_IO_ERROR( msg ); } source = aFileName; lineNum = aStartingLineNumber; }
void GPCB_FPL_CACHE::Remove( const wxString& aFootprintName ) { std::string footprintName = TO_UTF8( aFootprintName ); MODULE_CITER it = m_modules.find( footprintName ); if( it == m_modules.end() ) { THROW_IO_ERROR( wxString::Format( _( "library <%s> has no footprint '%s' to delete" ), m_lib_path.GetPath().GetData(), aFootprintName.GetData() ) ); } // Remove the module from the cache and delete the module file from the library. wxString fullPath = it->second->GetFileName().GetFullPath(); m_modules.erase( footprintName ); wxRemoveFile( fullPath ); }
wxArrayString GPCB_PLUGIN::FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties ) { LOCALE_IO toggle; // toggles on, then off, the C locale. wxArrayString ret; wxDir dir( aLibraryPath ); if( !dir.IsOpened() ) { THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ), GetChars( aLibraryPath ) ) ); } init( aProperties ); #if 1 // Set to 0 to only read directory contents, not load cache. cacheLib( aLibraryPath ); const MODULE_MAP& mods = m_cache->GetModules(); for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it ) { ret.Add( FROM_UTF8( it->first.c_str() ) ); } #else wxString fpFileName; wxString wildcard = wxT( "*." ) + GedaPcbFootprintLibFileExtension; if( dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) ) { do { wxFileName fn( aLibraryPath, fpFileName ); ret.Add( fn.GetName() ); } while( dir.GetNext( &fpFileName ) ); } #endif return ret; }
TRACK* SPECCTRA_DB::makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IO_ERROR ) { int layerNdx = findLayerName( aPath->layer_id ); if( layerNdx == -1 ) { wxString layerName = FROM_UTF8( aPath->layer_id.c_str() ); THROW_IO_ERROR( wxString::Format( _("Session file uses invalid layer id \"%s\""), GetChars( layerName ) ) ); } TRACK* track = new TRACK( sessionBoard ); track->SetStart( mapPt( aPath->points[aPointIndex+0], routeResolution ) ); track->SetEnd( mapPt( aPath->points[aPointIndex+1], routeResolution ) ); track->SetLayer( pcbLayer2kicad[layerNdx] ); track->SetWidth( scale( aPath->aperture_width, routeResolution ) ); track->SetNetCode( aNetcode ); return track; }
void KICAD_CURL::Init() { // We test s_initialized twice in an effort to avoid // unnecessarily locking s_lock. This understands that the common case // will not need to lock. if( !s_initialized ) { MUTLOCK lock( s_lock ); if( !s_initialized ) { if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK ) { THROW_IO_ERROR( "curl_global_init() failed." ); } init_locks(); wxLogDebug( "Using %s", GetVersion() ); s_initialized = true; } } }
void GPCB_FPL_CACHE::Load() { wxDir dir( m_lib_path.GetPath() ); if( !dir.IsOpened() ) { THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ), m_lib_path.GetPath().GetData() ) ); } wxString fpFileName; wxString wildcard = wxT( "*." ) + GedaPcbFootprintLibFileExtension; if( !dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) ) return; do { wxFileName fn( m_lib_path.GetPath(), fpFileName ); // reader now owns fp, will close on exception or return FILE_LINE_READER reader( fn.GetFullPath() ); std::string name = TO_UTF8( fn.GetName() ); MODULE* footprint = parseMODULE( &reader ); // The footprint name is the file name without the extension. footprint->SetFPID( FPID( fn.GetName() ) ); m_modules.insert( name, new GPCB_FPL_CACHE_ITEM( footprint, fn.GetName() ) ); } while( dir.GetNext( &fpFileName ) ); // Remember the file modification time of library file when the // cache snapshot was made, so that in a networked environment we will // reload the cache as needed. m_mod_time = GetLibModificationTime(); }
void PCB_PAD::AddToModule( MODULE* aModule, int aRotation, bool aEncapsulatedPad ) { PCB_PAD_SHAPE* padShape; wxString padShapeName = wxT( "Ellipse" ); PAD_ATTR_T padType; int i; int width = 0; int height = 0; D_PAD* pad = new D_PAD( aModule ); aModule->Pads().PushBack( pad ); if( !m_isHolePlated && m_hole ) { // mechanical hole pad->SetShape( PAD_CIRCLE ); pad->SetAttribute( PAD_HOLE_NOT_PLATED ); pad->SetDrillShape( PAD_DRILL_CIRCLE ); pad->SetDrillSize( wxSize( m_hole, m_hole ) ); pad->SetSize( wxSize( m_hole, m_hole ) ); pad->SetLayerSet( LSET::AllCuMask() | LSET( 2, B_Mask, F_Mask ) ); } else { ( m_hole ) ? padType = PAD_STANDARD : padType = PAD_SMD; // form layer mask for( i = 0; i < (int) m_shapes.GetCount(); i++ ) { padShape = m_shapes[i]; if( padShape->m_width > 0 && padShape->m_height > 0 ) { if( padShape->m_KiCadLayer == F_Cu || padShape->m_KiCadLayer == B_Cu ) { padShapeName = padShape->m_shape; width = padShape->m_width; height = padShape->m_height; // assume this is SMD pad if( padShape->m_KiCadLayer == F_Cu ) pad->SetLayerSet( LSET( 3, F_Cu, F_Paste, F_Mask ) ); else pad->SetLayerSet( LSET( 3, B_Cu, B_Paste, B_Mask ) ); break; } } } if( padType == PAD_STANDARD ) // actually this is a thru-hole pad pad->SetLayerSet( LSET::AllCuMask() | LSET( 2, B_Mask, F_Mask ) ); if( width == 0 || height == 0 ) THROW_IO_ERROR( wxT( "pad with zero size" ) ); pad->SetPadName( m_name.text ); if( padShapeName == wxT( "Oval" ) || padShapeName == wxT( "Ellipse" ) || padShapeName == wxT( "MtHole" ) ) { if( width != height ) pad->SetShape( PAD_OVAL ); else pad->SetShape( PAD_CIRCLE ); } else if( padShapeName == wxT( "Rect" ) || padShapeName == wxT( "RndRect" ) ) pad->SetShape( PAD_RECT ); else if( padShapeName == wxT( "Polygon" ) ) pad->SetShape( PAD_RECT ); // approximation pad->SetSize( wxSize( width, height ) ); pad->SetDelta( wxSize( 0, 0 ) ); pad->SetOrientation( m_rotation + aRotation ); pad->SetDrillShape( PAD_DRILL_CIRCLE ); pad->SetOffset( wxPoint( 0, 0 ) ); pad->SetDrillSize( wxSize( m_hole, m_hole ) ); pad->SetAttribute( padType ); // Set the proper net code NETINFO_ITEM* netinfo = m_board->FindNet( m_net ); if( netinfo == NULL ) // I believe this should not happen, but just in case { // It is a new net netinfo = new NETINFO_ITEM( m_board, m_net ); m_board->AppendNet( netinfo ); } pad->SetNetCode( netinfo->GetNet() ); } if( !aEncapsulatedPad ) { // pad's "Position" is not relative to the module's, // whereas Pos0 is relative to the module's but is the unrotated coordinate. wxPoint padpos( m_positionX, m_positionY ); pad->SetPos0( padpos ); RotatePoint( &padpos, aModule->GetOrientation() ); pad->SetPosition( padpos + aModule->GetPosition() ); } }
bool FOOTPRINT_LIST_IMPL::JoinWorkers() { { std::lock_guard<std::mutex> lock1( m_join ); for( auto& i : m_threads ) i.join(); m_threads.clear(); m_queue_in.clear(); m_count_finished.store( 0 ); } size_t total_count = m_queue_out.size(); LOCALE_IO toggle_locale; // Parse the footprints in parallel. WARNING! This requires changing the locale, which is // GLOBAL. It is only threadsafe to construct the LOCALE_IO before the threads are created, // destroy it after they finish, and block the main (GUI) thread while they work. Any deviation // from this will cause nasal demons. // // TODO: blast LOCALE_IO into the sun SYNC_QUEUE<std::unique_ptr<FOOTPRINT_INFO>> queue_parsed; std::vector<std::thread> threads; for( size_t ii = 0; ii < std::thread::hardware_concurrency() + 1; ++ii ) { threads.push_back( std::thread( [this, &queue_parsed]() { wxString nickname; while( this->m_queue_out.pop( nickname ) && !m_cancelled ) { wxArrayString fpnames; try { m_lib_table->FootprintEnumerate( fpnames, nickname ); } catch( const IO_ERROR& ioe ) { m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) ); } catch( const std::exception& se ) { // This is a round about way to do this, but who knows what THROW_IO_ERROR() // may be tricked out to do someday, keep it in the game. try { THROW_IO_ERROR( se.what() ); } catch( const IO_ERROR& ioe ) { m_errors.move_push( std::make_unique<IO_ERROR>( ioe ) ); } } for( unsigned jj = 0; jj < fpnames.size() && !m_cancelled; ++jj ) { wxString fpname = fpnames[jj]; FOOTPRINT_INFO* fpinfo = new FOOTPRINT_INFO_IMPL( this, nickname, fpname ); queue_parsed.move_push( std::unique_ptr<FOOTPRINT_INFO>( fpinfo ) ); } if( m_progress_reporter ) m_progress_reporter->AdvanceProgress(); m_count_finished.fetch_add( 1 ); } } ) ); } while( !m_cancelled && (size_t)m_count_finished.load() < total_count ) { if( m_progress_reporter && !m_progress_reporter->KeepRefreshing() ) m_cancelled = true; wxMilliSleep( 30 ); } for( auto& thr : threads ) thr.join(); std::unique_ptr<FOOTPRINT_INFO> fpi; while( queue_parsed.pop( fpi ) ) m_list.push_back( std::move( fpi ) ); std::sort( m_list.begin(), m_list.end(), []( std::unique_ptr<FOOTPRINT_INFO> const& lhs, std::unique_ptr<FOOTPRINT_INFO> const& rhs ) -> bool { return *lhs < *rhs; } ); return m_errors.empty(); }
::VIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNetCode, int aViaDrillDefault ) throw( IO_ERROR ) { ::VIA* via = 0; SHAPE* shape; int shapeCount = aPadstack->Length(); int drill_diam_iu = -1; int copperLayerCount = sessionBoard->GetCopperLayerCount(); // The drill diameter is encoded in the padstack name if Pcbnew did the DSN export. // It is after the colon and before the last '_' int drillStartNdx = aPadstack->padstack_id.find( ':' ); if( drillStartNdx != -1 ) { ++drillStartNdx; // skip over the ':' int drillEndNdx = aPadstack->padstack_id.rfind( '_' ); if( drillEndNdx != -1 ) { std::string diam_txt( aPadstack->padstack_id, drillStartNdx, drillEndNdx-drillStartNdx ); double drill_um = strtod( diam_txt.c_str(), 0 ); drill_diam_iu = int( drill_um * (IU_PER_MM / 1000.0) ); if( drill_diam_iu == aViaDrillDefault ) drill_diam_iu = UNDEFINED_DRILL_DIAMETER; } } if( shapeCount == 0 ) { THROW_IO_ERROR( _( "Session via padstack has no shapes" ) ); } else if( shapeCount == 1 ) { shape = (SHAPE*) (*aPadstack)[0]; DSN_T type = shape->shape->Type(); if( type != T_circle ) THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"), GetChars( GetTokenString( type ) ) ) ); CIRCLE* circle = (CIRCLE*) shape->shape; int viaDiam = scale( circle->diameter, routeResolution ); via = new ::VIA( sessionBoard ); via->SetPosition( mapPt( aPoint, routeResolution ) ); via->SetDrill( drill_diam_iu ); via->SetViaType( VIA_THROUGH ); via->SetWidth( viaDiam ); via->SetLayerPair( F_Cu, B_Cu ); } else if( shapeCount == copperLayerCount ) { shape = (SHAPE*) (*aPadstack)[0]; DSN_T type = shape->shape->Type(); if( type != T_circle ) THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"), GetChars( GetTokenString( type ) ) ) ); CIRCLE* circle = (CIRCLE*) shape->shape; int viaDiam = scale( circle->diameter, routeResolution ); via = new ::VIA( sessionBoard ); via->SetPosition( mapPt( aPoint, routeResolution ) ); via->SetDrill( drill_diam_iu ); via->SetViaType( VIA_THROUGH ); via->SetWidth( viaDiam ); via->SetLayerPair( F_Cu, B_Cu ); } else // VIA_MICROVIA or VIA_BLIND_BURIED { int topLayerNdx = -1; // session layer detectors int botLayerNdx = INT_MAX; int viaDiam = -1; for( int i=0; i<shapeCount; ++i ) { shape = (SHAPE*) (*aPadstack)[i]; DSN_T type = shape->shape->Type(); if( type != T_circle ) THROW_IO_ERROR( wxString::Format( _( "Unsupported via shape: %s"), GetChars( GetTokenString( type ) ) ) ); CIRCLE* circle = (CIRCLE*) shape->shape; int layerNdx = findLayerName( circle->layer_id ); if( layerNdx == -1 ) { wxString layerName = FROM_UTF8( circle->layer_id.c_str() ); THROW_IO_ERROR( wxString::Format( _("Session file uses invalid layer id \"%s\""), GetChars( layerName ) ) ); } if( layerNdx > topLayerNdx ) topLayerNdx = layerNdx; if( layerNdx < botLayerNdx ) botLayerNdx = layerNdx; if( viaDiam == -1 ) viaDiam = scale( circle->diameter, routeResolution ); } via = new ::VIA( sessionBoard ); via->SetPosition( mapPt( aPoint, routeResolution ) ); via->SetDrill( drill_diam_iu ); if( (topLayerNdx==0 && botLayerNdx==1) || (topLayerNdx==copperLayerCount-2 && botLayerNdx==copperLayerCount-1)) via->SetViaType( VIA_MICROVIA ); else via->SetViaType( VIA_BLIND_BURIED ); via->SetWidth( viaDiam ); LAYER_ID topLayer = pcbLayer2kicad[topLayerNdx]; LAYER_ID botLayer = pcbLayer2kicad[botLayerNdx]; via->SetLayerPair( topLayer, botLayer ); } if( via ) via->SetNetCode( aNetCode ); return via; }
void PCB_PAD::AddToBoard() { PCB_PAD_SHAPE* padShape; int i; int width = 0; int height = 0; if( m_objType == wxT( 'V' ) ) // via { // choose one of the shapes for( i = 0; i < (int) m_shapes.GetCount(); i++ ) { padShape = m_shapes[i]; if( padShape->m_width > 0 && padShape->m_height > 0 ) { if( padShape->m_KiCadLayer == F_Cu || padShape->m_KiCadLayer == B_Cu ) { width = padShape->m_width; height = padShape->m_height; break; } } } if( width == 0 || height == 0 ) THROW_IO_ERROR( wxT( "pad or via with zero size" ) ); if( IsCopperLayer( m_KiCadLayer ) ) { VIA* via = new VIA( m_board ); m_board->m_Track.Append( via ); via->SetTimeStamp( 0 ); via->SetPosition( wxPoint( m_positionX, m_positionY ) ); via->SetEnd( wxPoint( m_positionX, m_positionY ) ); via->SetWidth( height ); via->SetViaType( VIA_THROUGH ); via->SetLayerPair( F_Cu, B_Cu ); via->SetDrill( m_hole ); via->SetLayer( m_KiCadLayer ); via->SetNetCode( m_netCode ); } } else // pad { MODULE* module = new MODULE( m_board ); m_board->Add( module, ADD_APPEND ); m_name.text = m_defaultPinDes; module->SetPosition( wxPoint( m_positionX, m_positionY ) ); AddToModule( module, 0, true ); } }
KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad ) { // Since this will be called from python, cannot assume that code will // not pass a bad aFaceId. if( unsigned( aFaceId ) >= DIM( m_kiface ) ) { // @todo : throw an exception here for python's benefit, at least that // way it gets some explanatory text. wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFaceId" ) ); return NULL; } // return the previously loaded KIFACE, if it was. if( m_kiface[aFaceId] ) return m_kiface[aFaceId]; // DSO with KIFACE has not been loaded yet, does caller want to load it? if( doLoad ) { wxString dname = dso_full_path( aFaceId ); wxDynamicLibrary dso; void* addr = NULL; if( !dso.Load( dname, wxDL_VERBATIM | wxDL_NOW | wxDL_GLOBAL ) ) { // Failure: error reporting UI was done via wxLogSysError(). // No further reporting required here. } else if( ( addr = dso.GetSymbol( wxT( KIFACE_INSTANCE_NAME_AND_VERSION ) ) ) == NULL ) { // Failure: error reporting UI was done via wxLogSysError(). // No further reporting required here. } else { KIFACE_GETTER_FUNC* getter = (KIFACE_GETTER_FUNC*) addr; KIFACE* kiface = getter( &m_kiface_version[aFaceId], KIFACE_VERSION, m_program ); // KIFACE_GETTER_FUNC function comment (API) says the non-NULL is unconditional. wxASSERT_MSG( kiface, wxT( "attempted DSO has a bug, failed to return a KIFACE*" ) ); // Give the DSO a single chance to do its "process level" initialization. // "Process level" specifically means stay away from any projects in there. if( kiface->OnKifaceStart( m_program, m_ctl ) ) { // Tell dso's wxDynamicLibrary destructor not to Unload() the program image. (void) dso.Detach(); return m_kiface[aFaceId] = kiface; } } // In any of the failure cases above, dso.Unload() should be called here // by dso destructor. // However: // There is a file installation bug. We only look for KIFACE_I's which we know // to exist, and we did not find one. If we do not find one, this is an // installation bug. wxString msg = wxString::Format( wxT( "Fatal Installation Bug. File:\n" "'%s'\ncould not be loaded\n" ), GetChars( dname ) ); if( ! wxFileExists( dname ) ) msg << wxT( "It is missing.\n" ); else msg << wxT( "Perhaps a shared library (.dll or .so) file is missing.\n" ); msg << wxT( "From command line: argv[0]:\n'" ); msg << wxStandardPaths::Get().GetExecutablePath() << wxT( "'\n" ); // This is a fatal error, one from which we cannot recover, nor do we want // to protect against in client code which would require numerous noisy // tests in numerous places. So we inform the user that the installation // is bad. This exception will likely not get caught until way up in the // wxApp derivative, at which point the process will exit gracefully. THROW_IO_ERROR( msg ); } return NULL; }
void SCH_EDIT_FRAME::backAnnotateFootprints( const std::string& aChangedSetOfReferences ) throw( IO_ERROR, boost::bad_pointer ) { // Build a flat list of components in schematic: SCH_REFERENCE_LIST refs; SCH_SHEET_LIST sheets( g_RootSheet ); bool isChanged = false; sheets.GetComponents( Prj().SchLibs(), refs, false ); DSNLEXER lexer( aChangedSetOfReferences, FROM_UTF8( __func__ ) ); PTREE doc; try { Scan( &doc, &lexer ); #if defined(DEBUG) && 0 STRING_FORMATTER sf; Format( &sf, 0, 0, doc ); printf( "%s: '%s'\n", __func__, sf.GetString().c_str() ); #endif CPTREE& back_anno = doc.get_child( "back_annotation" ); wxString footprint; for( PTREE::const_iterator ref = back_anno.begin(); ref != back_anno.end(); ++ref ) { wxASSERT( ref->first == "ref" ); wxString reference = (UTF8&) ref->second.front().first; // Ensure the "fpid" node contains a footprint name, // and get it if exists if( ref->second.get_child( "fpid" ).size() ) { wxString tmp = (UTF8&) ref->second.get_child( "fpid" ).front().first; footprint = tmp; } else footprint.Empty(); // DBG( printf( "%s: ref:%s fpid:%s\n", __func__, TO_UTF8( reference ), TO_UTF8( footprint ) ); ) // Search the component in the flat list for( unsigned ii = 0; ii < refs.GetCount(); ++ii ) { if( reference == refs[ii].GetRef() ) { // We have found a candidate. // Note: it can be not unique (multiple parts per package) // So we *do not* stop the search here SCH_COMPONENT* component = refs[ii].GetComp(); SCH_FIELD* fpfield = component->GetField( FOOTPRINT ); const wxString& oldfp = fpfield->GetText(); if( !oldfp && fpfield->IsVisible() ) { fpfield->SetVisible( false ); } // DBG( printf("%s: ref:%s fpid:%s\n", __func__, TO_UTF8( refs[ii].GetRef() ), TO_UTF8( footprint ) );) if( oldfp != footprint ) isChanged = true; fpfield->SetText( footprint ); } } } } catch( const PTREE_ERROR& ex ) { // remap the exception to something the caller is likely to understand. THROW_IO_ERROR( ex.what() ); } if( isChanged ) OnModify(); }
void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IO_ERROR ) { sessionBoard = aBoard; // not owned here if( !session ) THROW_IO_ERROR( _("Session file is missing the \"session\" section") ); /* Dick 16-Jan-2012: session need not have a placement section. if( !session->placement ) THROW_IO_ERROR( _("Session file is missing the \"placement\" section") ); */ if( !session->route ) THROW_IO_ERROR( _("Session file is missing the \"routes\" section") ); if( !session->route->library ) THROW_IO_ERROR( _("Session file is missing the \"library_out\" section") ); // delete all the old tracks and vias aBoard->m_Track.DeleteAll(); aBoard->DeleteMARKERs(); buildLayerMaps( aBoard ); if( session->placement ) { // Walk the PLACEMENT object's COMPONENTs list, and for each PLACE within // each COMPONENT, reposition and re-orient each component and put on // correct side of the board. COMPONENTS& components = session->placement->components; for( COMPONENTS::iterator comp=components.begin(); comp!=components.end(); ++comp ) { PLACES& places = comp->places; for( unsigned i=0; i<places.size(); ++i ) { PLACE* place = &places[i]; // '&' even though places[] holds a pointer! wxString reference = FROM_UTF8( place->component_id.c_str() ); MODULE* module = aBoard->FindModuleByReference( reference ); if( !module ) { THROW_IO_ERROR( wxString::Format( _("Session file has 'reference' to non-existent component \"%s\""), GetChars( reference ) ) ); } if( !place->hasVertex ) continue; UNIT_RES* resolution = place->GetUnits(); wxASSERT( resolution ); wxPoint newPos = mapPt( place->vertex, resolution ); module->SetPosition( newPos ); if( place->side == T_front ) { // convert from degrees to tenths of degrees used in KiCad. int orientation = KiROUND( place->rotation * 10.0 ); if( module->GetLayer() != F_Cu ) { // module is on copper layer (back) module->Flip( module->GetPosition() ); } module->SetOrientation( orientation ); } else if( place->side == T_back ) { int orientation = KiROUND( (place->rotation + 180.0) * 10.0 ); if( module->GetLayer() != B_Cu ) { // module is on component layer (front) module->Flip( module->GetPosition() ); } module->SetOrientation( orientation ); } else { // as I write this, the PARSER *is* catching this, so we should never see below: wxFAIL_MSG( wxT("DSN::PARSER did not catch an illegal side := 'back|front'") ); } } } } routeResolution = session->route->GetUnits(); // Walk the NET_OUTs and create tracks and vias anew. NET_OUTS& net_outs = session->route->net_outs; for( NET_OUTS::iterator net = net_outs.begin(); net!=net_outs.end(); ++net ) { int netCode = 0; // page 143 of spec says wire's net_id is optional if( net->net_id.size() ) { wxString netName = FROM_UTF8( net->net_id.c_str() ); NETINFO_ITEM* netinfo = aBoard->FindNet( netName ); if( netinfo ) netCode = netinfo->GetNet(); else // else netCode remains 0 { // int breakhere = 1; } } WIRES& wires = net->wires; for( unsigned i = 0; i<wires.size(); ++i ) { WIRE* wire = &wires[i]; DSN_T shape = wire->shape->Type(); if( shape != T_path ) { /* shape == T_polygon is expected from freerouter if you have a zone on a non "power" type layer, i.e. a T_signal layer and the design does a round trip back in as session here. We kept our own zones in the BOARD, so ignore this so called 'wire'. wxString netId = FROM_UTF8( wire->net_id.c_str() ); THROW_IO_ERROR( wxString::Format( _("Unsupported wire shape: \"%s\" for net: \"%s\""), DLEX::GetTokenString(shape).GetData(), netId.GetData() ) ); */ } else { PATH* path = (PATH*) wire->shape; for( unsigned pt=0; pt<path->points.size()-1; ++pt ) { /* a debugging aid, may come in handy if( path->points[pt].x == 547800 && path->points[pt].y == -380250 ) { int breakhere = 1; } */ TRACK* track = makeTRACK( path, pt, netCode ); aBoard->Add( track ); } } } WIRE_VIAS& wire_vias = net->wire_vias; LIBRARY& library = *session->route->library; for( unsigned i=0; i<wire_vias.size(); ++i ) { int netCode = 0; // page 144 of spec says wire_via's net_id is optional if( net->net_id.size() ) { wxString netName = FROM_UTF8( net->net_id.c_str() ); NETINFO_ITEM* net = aBoard->FindNet( netName ); if( net ) netCode = net->GetNet(); // else netCode remains 0 } WIRE_VIA* wire_via = &wire_vias[i]; // example: (via Via_15:8_mil 149000 -71000 ) PADSTACK* padstack = library.FindPADSTACK( wire_via->GetPadstackId() ); if( !padstack ) { // Dick Feb 29, 2008: // Freerouter has a bug where it will not round trip all vias. // Vias which have a (use_via) element will be round tripped. // Vias which do not, don't come back in in the session library, // even though they may be actually used in the pre-routed, // protected wire_vias. So until that is fixed, create the // padstack from its name as a work around. // Could use a STRING_FORMATTER here and convert the entire // wire_via to text and put that text into the exception. wxString psid( FROM_UTF8( wire_via->GetPadstackId().c_str() ) ); THROW_IO_ERROR( wxString::Format( _("A wire_via references a missing padstack \"%s\""), GetChars( psid ) ) ); } NETCLASSPTR netclass = aBoard->GetDesignSettings().m_NetClasses.GetDefault(); int via_drill_default = netclass->GetViaDrill(); for( unsigned v=0; v<wire_via->vertexes.size(); ++v ) { ::VIA* via = makeVIA( padstack, wire_via->vertexes[v], netCode, via_drill_default ); aBoard->Add( via ); } } } }
bool CMP_READER::Load( NETLIST* aNetlist ) throw( IO_ERROR, PARSE_ERROR ) { wxCHECK_MSG( aNetlist != NULL,true, wxT( "No netlist passed to CMP_READER::Load()" ) ); wxString reference; // Stores value read from line like Reference = BUS1; wxString timestamp; // Stores value read from line like TimeStamp = /32307DE2/AA450F67; wxString footprint; // Stores value read from line like IdModule = CP6; wxString buffer; wxString value; bool ok = true; while( m_lineReader->ReadLine() ) { buffer = FROM_UTF8( m_lineReader->Line() ); if( !buffer.StartsWith( wxT( "BeginCmp" ) ) ) continue; // Begin component description. reference.Empty(); footprint.Empty(); timestamp.Empty(); while( m_lineReader->ReadLine() ) { buffer = FROM_UTF8( m_lineReader->Line() ); if( buffer.StartsWith( wxT( "EndCmp" ) ) ) break; // store string value, stored between '=' and ';' delimiters. value = buffer.AfterFirst( '=' ); value = value.BeforeLast( ';' ); value.Trim( true ); value.Trim( false ); if( buffer.StartsWith( wxT( "Reference" ) ) ) { reference = value; continue; } if( buffer.StartsWith( wxT( "IdModule =" ) ) ) { footprint = value; continue; } if( buffer.StartsWith( wxT( "TimeStamp =" ) ) ) { timestamp = value; continue; } } // Find the corresponding item in component list: COMPONENT* component = aNetlist->GetComponentByReference( reference ); // The corresponding component could no longer existing in the netlist. This // can happen when it is removed from schematic and still exists in footprint // assignment list. This is an usual case during the life of a design. if( component ) { FPID fpid; if( !footprint.IsEmpty() && fpid.Parse( footprint ) >= 0 ) { wxString error; error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d" ), GetChars( m_lineReader->GetSource() ), m_lineReader->LineNumber() ); THROW_IO_ERROR( error ); } // For checking purpose, store the existing FPID (if any) in the alternate fpid copy // if this existing FPID differs from the FPID read from the .cmp file. // CvPcb can ask for user to chose the right FPID. // It happens if the FPID was modified outside CvPcb. if( fpid != component->GetFPID() && !component->GetFPID().empty() ) component->SetAltFPID( component->GetFPID() ); component->SetFPID( fpid ); } else { ok = false; // can be used to display a warning in Pcbnew. } } return ok; }
void PCB_PAD::Parse( XNODE* aNode, wxString aDefaultMeasurementUnit, wxString aActualConversion ) { XNODE* lNode, *cNode; long num; wxString propValue, str, emsg; PCB_PAD_SHAPE* padShape; m_rotation = 0; lNode = FindNode( aNode, wxT( "padNum" ) ); if( lNode ) { lNode->GetNodeContent().ToLong( &num ); m_number = (int) num; } lNode = FindNode( aNode, wxT( "padStyleRef" ) ); if( lNode ) { lNode->GetAttribute( wxT( "Name" ), &propValue ); propValue.Trim( false ); m_name.text = propValue; } lNode = FindNode( aNode, wxT( "pt" ) ); if( lNode ) SetPosition( lNode->GetNodeContent(), aDefaultMeasurementUnit, &m_positionX, &m_positionY, aActualConversion ); lNode = FindNode( aNode, wxT( "rotation" ) ); if( lNode ) { str = lNode->GetNodeContent(); str.Trim( false ); m_rotation = StrToInt1Units( str ); } lNode = FindNode( aNode, wxT( "netNameRef" ) ); if( lNode ) { lNode->GetAttribute( wxT( "Name" ), &propValue ); propValue.Trim( false ); propValue.Trim( true ); m_net = propValue; m_netCode = GetNetCode( m_net ); } lNode = FindNode( aNode, wxT( "defaultPinDes" ) ); if( lNode ) { lNode->GetAttribute( wxT( "Name" ), &propValue ); //propValue.Trim( false ); m_defaultPinDes = propValue; } lNode = aNode; while( lNode && lNode->GetName() != wxT( "www.lura.sk" ) ) lNode = lNode->GetParent(); lNode = FindNode( lNode, wxT( "library" ) ); if ( !lNode ) THROW_IO_ERROR( wxT( "Unable to find library section" ) ); lNode = FindNode( lNode, wxT( "padStyleDef" ) ); while( lNode ) { lNode->GetAttribute( wxT( "Name" ), &propValue ); if( propValue.IsSameAs( m_name.text, false) ) break; lNode = lNode->GetNext(); } if ( !lNode ) THROW_IO_ERROR( wxString::Format( wxT( "Unable to find padStyleDef " ) + m_name.text ) ); cNode = FindNode( lNode, wxT( "holeDiam" ) ); if( cNode ) SetWidth( cNode->GetNodeContent(), aDefaultMeasurementUnit, &m_hole, aActualConversion ); if( FindNodeGetContent( lNode, wxT( "isHolePlated" ) ) == wxT( "False" ) ) m_isHolePlated = false; cNode = FindNode( lNode, wxT( "padShape" ) ); while( cNode ) { if( cNode->GetName() == wxT( "padShape" ) ) { // we support only Pads on specific layers...... // we do not support pads on "Plane", "NonSignal" , "Signal" ... layerr if( FindNode( cNode, wxT( "layerNumRef" ) ) ) { padShape = new PCB_PAD_SHAPE( m_callbacks, m_board ); padShape->Parse( cNode, aDefaultMeasurementUnit, aActualConversion ); m_shapes.Add( padShape ); } } cNode = cNode->GetNext(); } }