/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012-2023 KiCad Developers, see AUTHORS.txt for contributors. * * 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 */ #ifndef PCB_IO_EAGLE_H_ #define PCB_IO_EAGLE_H_ #include #include #include #include #include #include #include #include #include #include class PAD; class PCB_TEXT; class ZONE; typedef std::map FOOTPRINT_MAP; typedef std::vector ZONES; typedef std::map NET_MAP; typedef NET_MAP::const_iterator NET_MAP_CITER; /// subset of eagle.drawing.board.designrules in the XML document struct ERULES { ERULES() : psElongationLong ( 100 ), psElongationOffset ( 0 ), mvStopFrame ( 1.0 ), mvCreamFrame ( 0.0 ), mlMinStopFrame ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 4.0 ) ), mlMaxStopFrame ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 4.0 ) ), mlMinCreamFrame ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 0.0 ) ), mlMaxCreamFrame ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 0.0 ) ), psTop ( EPAD::UNDEF ), psBottom ( EPAD::UNDEF ), psFirst ( EPAD::UNDEF ), srRoundness ( 0.0 ), srMinRoundness ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 0.0 ) ), srMaxRoundness ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 0.0 ) ), rvPadTop ( 0.25 ), // rvPadBottom ( 0.25 ), rlMinPadTop ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 10 ) ), rlMaxPadTop ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 20 ) ), rvViaOuter ( 0.25 ), rlMinViaOuter ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 10 ) ), rlMaxViaOuter ( EDA_UNIT_UTILS::Mils2IU( pcbIUScale, 20 ) ), mdWireWire ( 0 ) {} void parse( wxXmlNode* aRules, std::function aCheckpoint ); ///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall ///< Goes into making a scaling factor for "long" pads. int psElongationLong; int psElongationOffset; ///< the offset of the hole within the "long" pad. ///< solder mask, expressed as percentage of the smaller pad/via dimension double mvStopFrame; ///< solderpaste mask, expressed as percentage of the smaller pad/via dimension double mvCreamFrame; int mlMinStopFrame; ///< solder mask, minimum size (Eagle mils, here nanometers) int mlMaxStopFrame; ///< solder mask, maximum size (Eagle mils, here nanometers) int mlMinCreamFrame; ///< solder paste mask, minimum size (Eagle mils, here nanometers) int mlMaxCreamFrame; ///< solder paste mask, maximum size (Eagle mils, here nanometers) int psTop; ///< Shape of the top pads int psBottom; ///< Shape of the bottom pads int psFirst; ///< Shape of the first pads double srRoundness; ///< corner rounding ratio for SMD pads (percentage) ///< corner rounding radius, minimum size (Eagle mils, here nanometers) int srMinRoundness; ///< corner rounding radius, maximum size (Eagle mils, here nanometers) int srMaxRoundness; double rvPadTop; ///< top pad size as percent of drill size // double rvPadBottom; ///< bottom pad size as percent of drill size double rlMinPadTop; ///< minimum copper annulus on through hole pads double rlMaxPadTop; ///< maximum copper annulus on through hole pads double rvViaOuter; ///< copper annulus is this percent of via hole double rlMinViaOuter; ///< minimum copper annulus on via double rlMaxViaOuter; ///< maximum copper annulus on via double mdWireWire; ///< wire to wire spacing I presume. }; /** * Works with Eagle 6.x XML board files and footprints to implement the Pcbnew #PLUGIN API * or a portion of it. */ class PCB_IO_EAGLE : public PCB_IO, public LAYER_REMAPPABLE_PLUGIN { public: const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override { return IO_BASE::IO_FILE_DESC( _HKI( "Eagle ver. 6.x XML PCB files" ), { "brd" } ); } const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override { return IO_BASE::IO_FILE_DESC( _HKI( "Eagle ver. 6.x XML library files" ), { "lbr" } ); } bool CanReadBoard( const wxString& aFileName ) const override; bool CanReadLibrary( const wxString& aFileName ) const override; bool CanReadFootprint( const wxString& aFileName ) const override; BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe, const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr ) override; std::vector GetImportedCachedLibraryFootprints() override; void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, bool aBestEfforts, const STRING_UTF8_MAP* aProperties = nullptr) override; FOOTPRINT* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName, bool aKeepUUID = false, const STRING_UTF8_MAP* aProperties = nullptr ) override; long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override { return getModificationTime( aLibraryPath ).GetValue().GetValue(); } bool IsLibraryWritable( const wxString& aLibraryPath ) override { return false; // until someone writes others like FootprintSave(), etc. } typedef int BIU; PCB_IO_EAGLE(); ~PCB_IO_EAGLE(); /** * Return the automapped layers. * * The callback needs to have the context of the current board so it can * correctly determine copper layer mapping. Thus, it is not static and is * expected to be bind to an instance of PCB_IO_EAGLE. * * @param aInputLayerDescriptionVector * @return Auto-mapped layers */ std::map DefaultLayerMappingCallback( const std::vector& aInputLayerDescriptionVector ); private: /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. void init( const STRING_UTF8_MAP* aProperties ); bool checkHeader( const wxString& aFileName ) const; void checkpoint(); void clear_cu_map(); /// Convert an Eagle distance to a KiCad distance. int kicad_y( const ECOORD& y ) const { return -y.ToPcbUnits(); } int kicad_x( const ECOORD& x ) const { return x.ToPcbUnits(); } /// create a font size (fontz) from an eagle font size scalar and KiCad font thickness VECTOR2I kicad_fontsize( const ECOORD& d, int aTextThickness ) const; /** * Generate mapping between Eagle and KiCad layers. * * @warning It is imperative that this gets called correctly because footprint libraries * do not get remapped by the user on load. Otherwise, Pcbnew will crash when * attempting to load footprint libraries that contain layers that do not exist * in the #EAGLE_LAYER definitions. * * @param aIsLibraryCache is the flag to indicate when mapping the footprint library cache * layers rather than the board layers. */ void mapEagleLayersToKicad( bool aIsLibraryCache = false ); /// Convert an Eagle layer to a KiCad layer. PCB_LAYER_ID kicad_layer( int aLayer ) const; /** * Get the default KiCad layer corresponding to an Eagle layer of the board, * a set of sensible layer mapping options and required flag * * @note The Eagle MILLING, TTEST, BTEST, and HOLES layers are set to #UNDEFINED_LAYER * for historical purposes. All other Eagle layers that do not directly map to * KiCad layers will be set to #UNDEFINED_LAYER when loading Eagle footprint * libraries. This should be addressed in the future because in some cases this * will cause data loss. * * @see #EAGLE_LAYER and defaultKiCadLayer(). * * @param aEagleLayer is the Eagle layer to map. * @param aIsLibraryCache is a flag to indicate if the mapping is for board or footprint * library cache objects. * @return a tuple containing the mapped layer. */ std::tuple defaultKicadLayer( int aEagleLayer, bool aIsLibraryCache = false ) const; /// Get Eagle layer name by its number const wxString& eagle_layer_name( int aLayer ) const; /// Get Eagle layer number by its name int eagle_layer_id( const wxString& aLayerName ) const; void setKeepoutSettingsToZone( ZONE* aZone, int aLayer ) const; /// This PLUGIN only caches one footprint library, this determines which one. void cacheLib( const wxString& aLibraryPath ); /// get a file's or dir's modification time. static wxDateTime getModificationTime( const wxString& aPath ); /// Determines the minimum copper layer stackup count that includes all mapped layers. int getMinimumCopperLayerCount() const; // all these loadXXX() throw IO_ERROR or ptree_error exceptions: void loadAllSections( wxXmlNode* aDocument ); void loadDesignRules( wxXmlNode* aDesignRules ); void loadLayerDefs( wxXmlNode* aLayers ); void loadPlain( wxXmlNode* aPlain ); void loadClasses( wxXmlNode* aClasses ); void loadSignals( wxXmlNode* aSignals ); /** * Load the Eagle "library" XML element, which can occur either under a "libraries" * element (if a *.brd file) or under a "drawing" element if a *.lbr file. * * @param aLib is the portion of the loaded XML document tree that is the "library" * element. * @param aLibName is a pointer to the library name or NULL. If NULL this means * we are loading a *.lbr not a *.brd file and the key used in m_templates * is to exclude the library name. */ void loadLibrary( wxXmlNode* aLib, const wxString* aLibName ); void loadLibraries( wxXmlNode* aLibs ); void loadElements( wxXmlNode* aElements ); /** * Load a copper or keepout polygon and adds it to the board. * * @return The loaded zone or nullptr if was not processed. */ ZONE* loadPolygon( wxXmlNode* aPolyNode ); void orientFootprintAndText( FOOTPRINT* aFootprint, const EELEMENT& e, const EATTR* aNameAttr, const EATTR* aValueAttr ); void orientFPText( FOOTPRINT* aFootprint, const EELEMENT& e, PCB_TEXT* aFPText, const EATTR* aAttr ); /// move the BOARD into the center of the page void centerBoard(); /** * Create a FOOTPRINT from an Eagle package. */ FOOTPRINT* makeFootprint( wxXmlNode* aPackage, const wxString& aPkgName ); void packageWire( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; void packagePad( FOOTPRINT* aFootprint, wxXmlNode* aTree ); void packageText( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; void packageRectangle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; void packagePolygon( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; void packageCircle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; /** * @param aFootprint The KiCad footprint to which to assign the hole. * @param aTree The Eagle XML node that is of type "hole". * @param aCenter If true, center the hole in the footprint and offset the footprint position. */ void packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aCenter ) const; void packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const; ///< Handles common pad properties void transferPad( const EPAD_COMMON& aEaglePad, PAD* aPad ) const; ///< Deletes the footprint templates list void deleteTemplates(); typedef std::vector ELAYERS; typedef ELAYERS::const_iterator EITER; int m_cu_map[17]; ///< map eagle to KiCad, cu layers only. std::map m_eagleLayers; ///< Eagle layer data stored by layer number std::map m_eagleLayersIds; ///< Eagle layer ids stored by layer name std::map m_layer_map; ///< Map of Eagle layers to KiCad layers ///< Eagle class number to KiCad netclass std::map> m_classMap; wxString m_customRules; ERULES* m_rules; ///< Eagle design rules. XPATH* m_xpath; ///< keeps track of what we are working on within ///< XML document during a Load(). int m_hole_count; ///< generates unique footprint names from eagle "hole"s. NET_MAP m_pads_to_nets; ///< net list std::map m_templates; ///< is part of a FOOTPRINT factory that operates ///< using copy construction. ///< lookup key is either libname.packagename or ///< simply packagename if FootprintLoad() or ///< FootprintEnumberate() PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr unsigned m_doneCount; unsigned m_lastProgressCount; unsigned m_totalCount; ///< for progress reporting int m_min_trace; ///< smallest trace we find on Load(), in BIU. int m_min_hole; ///< smallest diameter hole we find on Load(), in BIU. int m_min_via; ///< smallest via we find on Load(), in BIU. int m_min_annulus; ///< smallest via annulus we find on Load(), in BIU. wxString m_lib_path; wxDateTime m_mod_time; }; #endif // PCB_IO_EAGLE_H_