1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #ifndef EAGLE_PLUGIN_H
26 #define EAGLE_PLUGIN_H
27 
28 #include <convert_to_biu.h>
29 #include <io_mgr.h>
30 #include <layer_ids.h>
31 #include <netclass.h>
32 #include <plugins/eagle/eagle_parser.h>
33 #include <plugins/common/plugin_common_layer_mapping.h>
34 
35 #include <map>
36 #include <tuple>
37 #include <wx/xml/xml.h>
38 
39 class PAD;
40 class FP_TEXT;
41 class ZONE;
42 
43 typedef std::map<wxString, FOOTPRINT*> FOOTPRINT_MAP;
44 typedef std::vector<ZONE*>             ZONES;
45 typedef std::map<wxString, ENET>        NET_MAP;
46 typedef NET_MAP::const_iterator         NET_MAP_CITER;
47 
48 
49 /// subset of eagle.drawing.board.designrules in the XML document
50 struct ERULES
51 {
ERULESERULES52     ERULES() :
53         psElongationLong    ( 100 ),
54         psElongationOffset  ( 0 ),
55 
56         mvStopFrame         ( 1.0 ),
57         mvCreamFrame        ( 0.0 ),
58         mlMinStopFrame      ( Mils2iu( 4.0 ) ),
59         mlMaxStopFrame      ( Mils2iu( 4.0 ) ),
60         mlMinCreamFrame     ( Mils2iu( 0.0 ) ),
61         mlMaxCreamFrame     ( Mils2iu( 0.0 ) ),
62 
63         psTop               ( EPAD::UNDEF ),
64         psBottom            ( EPAD::UNDEF ),
65         psFirst             ( EPAD::UNDEF ),
66 
67         srRoundness         ( 0.0 ),
68         srMinRoundness      ( Mils2iu( 0.0 ) ),
69         srMaxRoundness      ( Mils2iu( 0.0 ) ),
70 
71         rvPadTop            ( 0.25 ),
72         // rvPadBottom      ( 0.25 ),
73         rlMinPadTop         ( Mils2iu( 10 ) ),
74         rlMaxPadTop         ( Mils2iu( 20 ) ),
75 
76         rvViaOuter          ( 0.25 ),
77         rlMinViaOuter       ( Mils2iu( 10 ) ),
78         rlMaxViaOuter       ( Mils2iu( 20 ) ),
79         mdWireWire          ( 0 )
80     {}
81 
82     void parse( wxXmlNode* aRules, std::function<void()> aCheckpoint );
83 
84     ///< percent over 100%.  0-> not elongated, 100->twice as wide as is tall
85     ///< Goes into making a scaling factor for "long" pads.
86     int    psElongationLong;
87 
88     int    psElongationOffset;  ///< the offset of the hole within the "long" pad.
89 
90     ///< solder mask, expressed as percentage of the smaller pad/via dimension
91     double mvStopFrame;
92 
93     ///< solderpaste mask, expressed as percentage of the smaller pad/via dimension
94     double mvCreamFrame;
95     int    mlMinStopFrame;      ///< solder mask, minimum size (Eagle mils, here nanometers)
96     int    mlMaxStopFrame;      ///< solder mask, maximum size (Eagle mils, here nanometers)
97     int    mlMinCreamFrame;     ///< solder paste mask, minimum size (Eagle mils, here nanometers)
98     int    mlMaxCreamFrame;     ///< solder paste mask, maximum size (Eagle mils, here nanometers)
99 
100     int    psTop;               ///< Shape of the top pads
101     int    psBottom;            ///< Shape of the bottom pads
102     int    psFirst;             ///< Shape of the first pads
103 
104     double srRoundness;         ///< corner rounding ratio for SMD pads (percentage)
105 
106     ///< corner rounding radius, minimum size (Eagle mils, here nanometers)
107     int    srMinRoundness;
108 
109     ///< corner rounding radius, maximum size (Eagle mils, here nanometers)
110     int    srMaxRoundness;
111 
112     double rvPadTop;            ///< top pad size as percent of drill size
113     // double   rvPadBottom;    ///< bottom pad size as percent of drill size
114 
115     double rlMinPadTop;         ///< minimum copper annulus on through hole pads
116     double rlMaxPadTop;         ///< maximum copper annulus on through hole pads
117 
118     double rvViaOuter;          ///< copper annulus is this percent of via hole
119     double rlMinViaOuter;       ///< minimum copper annulus on via
120     double rlMaxViaOuter;       ///< maximum copper annulus on via
121     double mdWireWire;          ///< wire to wire spacing I presume.
122 };
123 
124 
125 /**
126  * Works with Eagle 6.x XML board files and footprints to implement the Pcbnew #PLUGIN API
127  * or a portion of it.
128  */
129 class EAGLE_PLUGIN : public PLUGIN, public LAYER_REMAPPABLE_PLUGIN
130 {
131 public:
132     const wxString PluginName() const override;
133 
134     BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe,
135                  const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr,
136                  PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
137 
138     std::vector<FOOTPRINT*> GetImportedCachedLibraryFootprints() override;
139 
140     const wxString GetFileExtension() const override;
141 
142     void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
143                              bool aBestEfforts, const PROPERTIES* aProperties = nullptr) override;
144 
145     FOOTPRINT* FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
146                               bool  aKeepUUID = false,
147                               const PROPERTIES* aProperties = nullptr ) override;
148 
GetLibraryTimestamp(const wxString & aLibraryPath)149     long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
150     {
151         return getModificationTime( aLibraryPath ).GetValue().GetValue();
152     }
153 
IsFootprintLibWritable(const wxString & aLibraryPath)154     bool IsFootprintLibWritable( const wxString& aLibraryPath ) override
155     {
156         return false;   // until someone writes others like FootprintSave(), etc.
157     }
158 
159     void FootprintLibOptions( PROPERTIES* aProperties ) const override;
160 
161     typedef int BIU;
162 
163     EAGLE_PLUGIN();
164     ~EAGLE_PLUGIN();
165 
166     /**
167      * Return the automapped layers.
168      *
169      * The callback needs to have the context of the current board so it can
170      * correctly determine copper layer mapping. Thus, it is not static and is
171      * expected to be bind to an instance of EAGLE_PLUGIN.
172      *
173      * @param aInputLayerDescriptionVector
174      * @return Auto-mapped layers
175      */
176     std::map<wxString, PCB_LAYER_ID> DefaultLayerMappingCallback(
177             const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector );
178 
179 private:
180     /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed.
181     void init( const PROPERTIES* aProperties );
182 
183     void checkpoint();
184 
185     void clear_cu_map();
186 
187     /// Convert an Eagle distance to a KiCad distance.
kicad_y(const ECOORD & y)188     int kicad_y( const ECOORD& y ) const { return -y.ToPcbUnits(); }
kicad_x(const ECOORD & x)189     int kicad_x( const ECOORD& x ) const { return x.ToPcbUnits(); }
190 
191     /// create a font size (fontz) from an eagle font size scalar and KiCad font thickness
192     wxSize  kicad_fontz( const ECOORD& d, int aTextThickness ) const;
193 
194     /// Generate mapping between Eagle na KiCad layers
195     void mapEagleLayersToKicad();
196 
197     /// Convert an Eagle layer to a KiCad layer.
198     PCB_LAYER_ID kicad_layer( int aLayer ) const;
199 
200     /// Get default KiCad layer corresponding to an Eagle layer of the board,
201     /// a set of sensible layer mapping options and required flag
202     std::tuple<PCB_LAYER_ID, LSET, bool> defaultKicadLayer( int aEagleLayer ) const;
203 
204     /// Get Eagle layer name by its number
205     const wxString& eagle_layer_name( int aLayer ) const;
206 
207     /// Get Eagle layer number by its name
208     int eagle_layer_id( const wxString& aLayerName ) const;
209 
210     /// This PLUGIN only caches one footprint library, this determines which one.
211     void    cacheLib( const wxString& aLibraryPath );
212 
213     /// get a file's  or dir's modification time.
214     static wxDateTime getModificationTime( const wxString& aPath );
215 
216     // all these loadXXX() throw IO_ERROR or ptree_error exceptions:
217 
218     void loadAllSections( wxXmlNode* aDocument );
219     void loadDesignRules( wxXmlNode* aDesignRules );
220     void loadLayerDefs( wxXmlNode* aLayers );
221     void loadPlain( wxXmlNode* aPlain );
222     void loadClasses( wxXmlNode* aClasses );
223     void loadSignals( wxXmlNode* aSignals );
224 
225     /**
226      * Load the Eagle "library" XML element, which can occur either under a "libraries"
227      * element (if a *.brd file) or under a "drawing" element if a *.lbr file.
228      *
229      * @param aLib is the portion of the loaded XML document tree that is the "library"
230      *             element.
231      * @param aLibName is a pointer to the library name or NULL.  If NULL this means
232      *                 we are loading a *.lbr not a *.brd file and the key used in m_templates
233      *                 is to exclude the library name.
234      */
235     void loadLibrary( wxXmlNode* aLib, const wxString* aLibName );
236 
237     void loadLibraries( wxXmlNode* aLibs );
238     void loadElements( wxXmlNode* aElements );
239 
240     /**
241      * Load a copper or keepout polygon and adds it to the board.
242      *
243      * @return The loaded zone or nullptr if was not processed.
244      */
245     ZONE* loadPolygon( wxXmlNode* aPolyNode );
246 
247     void orientFootprintAndText( FOOTPRINT* aFootprint, const EELEMENT& e, const EATTR* aNameAttr,
248                                  const EATTR* aValueAttr );
249 
250     void orientFPText( FOOTPRINT* aFootprint, const EELEMENT& e, FP_TEXT* aFPText,
251                        const EATTR* aAttr );
252 
253 
254     /// move the BOARD into the center of the page
255     void centerBoard();
256 
257     /**
258      * Create a FOOTPRINT from an Eagle package.
259      */
260     FOOTPRINT* makeFootprint( wxXmlNode* aPackage, const wxString& aPkgName );
261 
262     void packageWire( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
263     void packagePad( FOOTPRINT* aFootprint, wxXmlNode* aTree );
264     void packageText( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
265     void packageRectangle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
266     void packagePolygon( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
267     void packageCircle( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
268 
269     /**
270      * @param aFootprint The KiCad footprint to which to assign the hole.
271      * @param aTree The Eagle XML node that is of type "hole".
272      * @param aCenter If true, center the hole in the footprint and offset the footprint position.
273      */
274     void packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aCenter ) const;
275     void packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const;
276 
277     ///< Handles common pad properties
278     void transferPad( const EPAD_COMMON& aEaglePad, PAD* aPad ) const;
279 
280     ///< Deletes the footprint templates list
281     void deleteTemplates();
282 
283     typedef std::vector<ELAYER>     ELAYERS;
284     typedef ELAYERS::const_iterator EITER;
285 
286     int                              m_cu_map[17];     ///< map eagle to KiCad, cu layers only.
287     std::map<int, ELAYER>            m_eagleLayers;    ///< Eagle layer data stored by layer number
288     std::map<wxString, int>          m_eagleLayersIds; ///< Eagle layer ids stored by layer name
289     std::map<wxString, PCB_LAYER_ID> m_layer_map;      ///< Map of Eagle layers to KiCad layers
290 
291     std::map<wxString, NETCLASSPTR>  m_classMap;       ///< Eagle class number to KiCad netclass
292     wxString                         m_customRules;
293 
294     ERULES*       m_rules;          ///< Eagle design rules.
295     XPATH*        m_xpath;          ///< keeps track of what we are working on within
296                                     ///< XML document during a Load().
297 
298     int           m_hole_count;     ///< generates unique footprint names from eagle "hole"s.
299 
300     NET_MAP       m_pads_to_nets;   ///< net list
301 
302     FOOTPRINT_MAP m_templates;      ///< is part of a FOOTPRINT factory that operates using copy
303                                     ///< construction.
304                                     ///< lookup key is either libname.packagename or simply
305                                     ///< packagename if FootprintLoad() or FootprintEnumberate()
306 
307     const PROPERTIES*   m_props;    ///< passed via Save() or Load(), no ownership, may be NULL.
308     BOARD*              m_board;    ///< which BOARD is being worked on, no ownership here
309 
310     PROGRESS_REPORTER*  m_progressReporter;  ///< optional; may be nullptr
311     unsigned            m_doneCount;
312     unsigned            m_lastProgressCount;
313     unsigned            m_totalCount;         ///< for progress reporting
314 
315     int         m_min_trace;        ///< smallest trace we find on Load(), in BIU.
316     int         m_min_hole;         ///< smallest diameter hole we find on Load(), in BIU.
317     int         m_min_via;          ///< smallest via we find on Load(), in BIU.
318     int         m_min_annulus;      ///< smallest via annulus we find on Load(), in BIU.
319 
320     wxString    m_lib_path;
321     wxDateTime  m_mod_time;
322 };
323 
324 #endif  // EAGLE_PLUGIN_H
325