356 lines
13 KiB
C++
356 lines
13 KiB
C++
/**
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef PCB_IO_IPC2581_H_
|
|
#define PCB_IO_IPC2581_H_
|
|
|
|
#include <pcb_io/pcb_io.h>
|
|
#include <pcb_io/pcb_io_mgr.h>
|
|
#include <pcb_io/common/plugin_common_layer_mapping.h>
|
|
|
|
#include <eda_shape.h>
|
|
#include <layer_ids.h> // PCB_LAYER_ID
|
|
#include <font/font.h>
|
|
#include <geometry/shape_segment.h>
|
|
#include <stroke_params.h>
|
|
|
|
#include <wx/xml/xml.h>
|
|
#include <memory>
|
|
|
|
class BOARD;
|
|
class BOARD_ITEM;
|
|
class EDA_TEXT;
|
|
class FOOTPRINT;
|
|
class PROGRESS_REPORTER;
|
|
class NETINFO_ITEM;
|
|
class PAD;
|
|
class PCB_SHAPE;
|
|
class PCB_VIA;
|
|
class PROGRESS_REPORTER;
|
|
class SHAPE_POLY_SET;
|
|
class SHAPE_SEGMENT;
|
|
|
|
class PCB_IO_IPC2581 : public PCB_IO, public LAYER_REMAPPABLE_PLUGIN
|
|
{
|
|
public:
|
|
/**
|
|
* @brief PCB_IO_IPC2581
|
|
*
|
|
*/
|
|
PCB_IO_IPC2581() : PCB_IO( wxS( "IPC-2581" ) )
|
|
{
|
|
m_show_layer_mapping_warnings = false;
|
|
m_total_bytes = 0;
|
|
m_scale = 1.0;
|
|
m_sigfig = 3;
|
|
m_version = 'B';
|
|
m_enterpriseNode = nullptr;
|
|
m_board = nullptr;
|
|
m_props = nullptr;
|
|
m_shape_user_node = nullptr;
|
|
m_shape_std_node = nullptr;
|
|
m_line_node = nullptr;
|
|
m_last_padstack = nullptr;
|
|
m_progress_reporter = nullptr;
|
|
m_xml_doc = nullptr;
|
|
m_xml_root = nullptr;
|
|
}
|
|
|
|
~PCB_IO_IPC2581() override;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
// BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
|
|
// const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr ) override;
|
|
|
|
void SaveBoard( const wxString& aFileName, BOARD* aBoard,
|
|
const STRING_UTF8_MAP* aProperties = nullptr ) override;
|
|
|
|
const IO_BASE::IO_FILE_DESC GetBoardFileDesc() const override
|
|
{
|
|
return IO_BASE::IO_FILE_DESC( _HKI( "IPC-2581 Production File" ), { "xml" } );
|
|
}
|
|
|
|
const IO_BASE::IO_FILE_DESC GetLibraryDesc() const override
|
|
{
|
|
// No library description for this plugin
|
|
return IO_BASE::IO_FILE_DESC( wxEmptyString, {} );
|
|
}
|
|
|
|
std::vector<FOOTPRINT*> GetImportedCachedLibraryFootprints() override;
|
|
|
|
long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Reading currently disabled
|
|
bool CanReadBoard( const wxString& aFileName ) const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Reading currently disabled
|
|
bool CanReadFootprint( const wxString& aFileName ) const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Reading currently disabled
|
|
bool CanReadLibrary( const wxString& aFileName ) const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the automapped layers.
|
|
*
|
|
* @param aInputLayerDescriptionVector
|
|
* @return Auto-mapped layers
|
|
*/
|
|
// static std::map<wxString, PCB_LAYER_ID> DefaultLayerMappingCallback(
|
|
// const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector );
|
|
|
|
/**
|
|
* Register a different handler to be called when mapping of IPC2581 to KiCad layers occurs.
|
|
*
|
|
* @param aLayerMappingHandler
|
|
*/
|
|
// void RegisterLayerMappingCallback( LAYER_MAPPING_HANDLER aLayerMappingHandler ) override
|
|
// {};
|
|
|
|
private:
|
|
|
|
/**
|
|
* Frees the memory allocated for the loaded footprints in #m_loaded_footprints.
|
|
*
|
|
*/
|
|
void clearLoadedFootprints();
|
|
|
|
/**
|
|
* Creates the XML header for IPC-2581
|
|
*
|
|
*/
|
|
wxXmlNode* generateXmlHeader();
|
|
|
|
/**
|
|
* Creates the Content section of the XML file. This holds the overview of
|
|
* the rest of the board data. Includes references to the step, bom, and layers
|
|
* as well as the content dictionaries
|
|
*/
|
|
wxXmlNode* generateContentSection();
|
|
|
|
/**
|
|
* Creates the logistical data header. This section defines the organization and person
|
|
* creating the file. Can be used for contact information and config management
|
|
*/
|
|
wxXmlNode* generateLogisticSection();
|
|
|
|
/**
|
|
* Creates the history section. This section defines the history of the file, the revision
|
|
* number, and the date of the revision as well as software used to create the file. Optionally,
|
|
* the data could include information about the git revision and tag
|
|
*/
|
|
wxXmlNode* generateHistorySection();
|
|
|
|
/**
|
|
* Creates the BOM section. This section defines the BOM data for the board. This includes
|
|
* the part number, manufacturer, and distributor information for each component on the board.
|
|
*/
|
|
wxXmlNode* generateBOMSection( wxXmlNode* aEcadNode );
|
|
|
|
/**
|
|
* Creates the ECAD section. This describes the layout, layers, and design as well as
|
|
* component placement and netlist information
|
|
*/
|
|
wxXmlNode* generateEcadSection();
|
|
|
|
/**
|
|
* Creates the Approved Vendor List section. If the user chooses, this will associate
|
|
* BOM items with vendor numbers and names.
|
|
*/
|
|
wxXmlNode* generateAvlSection();
|
|
|
|
void generateCadLayers( wxXmlNode* aCadLayerNode );
|
|
|
|
void generateDrillLayers( wxXmlNode* aCadLayerNode );
|
|
|
|
void generateStepSection( wxXmlNode* aCadNode );
|
|
|
|
void generateProfile( wxXmlNode* aStepNode );
|
|
|
|
void generateLogicalNets( wxXmlNode* aStepNode );
|
|
|
|
void generatePhyNetGroup( wxXmlNode* aStepNode );
|
|
|
|
void generateLayerFeatures( wxXmlNode* aStepNode );
|
|
|
|
void generateLayerSetDrill( wxXmlNode* aStepNode );
|
|
|
|
void generateLayerSetNet( wxXmlNode* aLayerNode, PCB_LAYER_ID aLayer, std::vector<BOARD_ITEM*>& aItems );
|
|
|
|
wxXmlNode* generateContentStackup( wxXmlNode* aContentNode );
|
|
|
|
void generateComponents( wxXmlNode* aStepNode );
|
|
|
|
void addCadHeader( wxXmlNode* aEcadNode );
|
|
|
|
wxXmlNode* addPackage( wxXmlNode* aStepNode, FOOTPRINT* aFootprint );
|
|
|
|
void addPad( wxXmlNode* aContentNode, const PAD* aPad, PCB_LAYER_ID aLayer );
|
|
|
|
void addVia( wxXmlNode* aContentNode, const PCB_VIA* aVia, PCB_LAYER_ID aLayer );
|
|
|
|
void addPadStack( wxXmlNode* aContentNode, const PAD* aPad );
|
|
|
|
void addPadStack( wxXmlNode* aContentNode, const PCB_VIA* aVia );
|
|
|
|
void addLocationNode( wxXmlNode* aContentNode, double aX, double aY );
|
|
|
|
void addLocationNode( wxXmlNode* aContentNode, const PAD& aPad, bool aRelative );
|
|
|
|
void addLocationNode( wxXmlNode* aContentNode, const PCB_SHAPE& aShape );
|
|
|
|
void addShape( wxXmlNode* aContentNode, const PCB_SHAPE& aShape );
|
|
|
|
void addShape( wxXmlNode* aContentNode, const PAD& aPad, PCB_LAYER_ID aLayer );
|
|
|
|
void addSlotCavity( wxXmlNode* aContentNode, const PAD& aPad, const wxString& aName );
|
|
|
|
void addText( wxXmlNode* aContentNode, EDA_TEXT* aShape, const KIFONT::METRICS& aFontMetrics );
|
|
|
|
void addLineDesc( wxXmlNode* aNode, int aWidth, LINE_STYLE aDashType, bool aForce = false );
|
|
|
|
void addFillDesc( wxXmlNode* aNode, FILL_T aFillType, bool aForce = false );
|
|
|
|
bool addPolygonNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET::POLYGON& aPolygon,
|
|
FILL_T aFillType = FILL_T::FILLED_SHAPE, int aWidth = 0,
|
|
LINE_STYLE aDashType = LINE_STYLE::SOLID );
|
|
|
|
bool addPolygonCutouts( wxXmlNode* aParentNode, const SHAPE_POLY_SET::POLYGON& aPolygon );
|
|
|
|
bool addOutlineNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET& aPolySet, int aWidth = 0,
|
|
LINE_STYLE aDashType = LINE_STYLE::SOLID );
|
|
|
|
bool addContourNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET& aPolySet, int aOutline = 0,
|
|
FILL_T aFillType = FILL_T::FILLED_SHAPE, int aWidth = 0,
|
|
LINE_STYLE aDashType = LINE_STYLE::SOLID );
|
|
|
|
size_t lineHash( int aWidth, LINE_STYLE aDashType );
|
|
|
|
size_t shapeHash( const PCB_SHAPE& aShape );
|
|
|
|
wxString genString( const wxString& aStr, const char* aPrefix = nullptr ) const;
|
|
|
|
wxString floatVal( double aVal );
|
|
|
|
wxString pinName( const PAD* aPad ) const;
|
|
|
|
wxString componentName( FOOTPRINT* aFootprint );
|
|
|
|
void addXY( wxXmlNode* aNode, const VECTOR2I& aVec, const char* aXName = nullptr,
|
|
const char* aYName = nullptr );
|
|
|
|
void addAttribute( wxXmlNode* aNode, const wxString& aName, const wxString& aValue );
|
|
|
|
wxXmlNode* insertNode( wxXmlNode* aParent, const wxString& aName );
|
|
|
|
wxXmlNode* appendNode( wxXmlNode* aParent, const wxString& aName );
|
|
|
|
void appendNode( wxXmlNode* aParent, wxXmlNode* aNode );
|
|
|
|
void insertNode( wxXmlNode* aParent, wxXmlNode* aNode );
|
|
|
|
void insertNodeAfter( wxXmlNode* aPrev, wxXmlNode* aNode );
|
|
|
|
void addLayerAttributes( wxXmlNode* aNode, PCB_LAYER_ID aLayer );
|
|
|
|
bool isValidLayerFor2581( PCB_LAYER_ID aLayer );
|
|
private:
|
|
LAYER_MAPPING_HANDLER m_layerMappingHandler;
|
|
bool m_show_layer_mapping_warnings;
|
|
|
|
size_t m_total_bytes; //<! Total number of bytes to be written
|
|
|
|
wxString m_units_str; //<! Output string for units
|
|
double m_scale; //<! Scale factor from IU to IPC2581 units (mm, micron, in)
|
|
int m_sigfig; //<! Max number of digits past the decimal point
|
|
char m_version; //<! Currently, either 'B' or 'C' for the IPC2581 version
|
|
wxString m_OEMRef; //<! If set, field name containing the internal ID of parts
|
|
wxString m_mpn; //<! If set, field name containing the manufacturer part number
|
|
wxString m_mfg; //<! If set, field name containing the part manufacturer
|
|
wxString m_distpn; //<! If set, field name containing the distributor part number
|
|
wxString m_dist; //<! If set, field name containing the distributor name
|
|
|
|
// Node pointer to the main enterprise node to be used for adding
|
|
// enterprises later when forming the AVL
|
|
wxXmlNode* m_enterpriseNode;
|
|
|
|
BOARD* m_board;
|
|
std::vector<FOOTPRINT*> m_loaded_footprints;
|
|
const STRING_UTF8_MAP* m_props;
|
|
|
|
std::map<size_t, wxString> m_user_shape_dict; //<! Map between shape hash values and reference id string
|
|
wxXmlNode* m_shape_user_node; //<! Output XML node for reference shapes in UserDict
|
|
|
|
std::map<size_t, wxString> m_std_shape_dict; //<! Map between shape hash values and reference id string
|
|
wxXmlNode* m_shape_std_node; //<! Output XML node for reference shapes in StandardDict
|
|
|
|
std::map<size_t, wxString> m_line_dict; //<! Map between line hash values and reference id string
|
|
wxXmlNode* m_line_node; //<! Output XML node for reference lines in LineDict
|
|
|
|
std::map<size_t, wxString> m_padstack_dict; //<! Map between padstack hash values and reference id string (PADSTACK_##)
|
|
std::vector<wxXmlNode*> m_padstacks; //<! Holding vector for padstacks. These need to be inserted prior to the components
|
|
wxXmlNode* m_last_padstack; //<! Pointer to padstack list where we can insert the VIA padstacks once we process tracks
|
|
|
|
std::map<size_t, wxString>
|
|
m_footprint_dict; //<! Map between the footprint hash values and reference id string (<fpid>_##)
|
|
|
|
std::map<wxString, FOOTPRINT*>
|
|
m_footprint_refdes_dict; //<! Map between sanitized refdes and footprint pointer
|
|
|
|
std::map<FOOTPRINT*, wxString>
|
|
m_footprint_refdes_reverse_dict; //<! Reverse lookup for
|
|
|
|
std::map<FOOTPRINT*, wxString>
|
|
m_OEMRef_dict; //<! Reverse map from the footprint pointer to the reference id string assigned for components
|
|
|
|
std::map<int, std::vector<std::pair<wxString, wxString>>>
|
|
m_net_pin_dict; //<! Map from netcode to the component/pin pairs in the net
|
|
|
|
std::map<PCB_LAYER_ID, wxString>
|
|
m_layer_name_map; //<! Mapping layer name in 2581 to the internal layer id
|
|
|
|
std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<BOARD_ITEM*>>
|
|
m_drill_layers; //<! Drill sets are output as layers (to/from pairs)
|
|
|
|
std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>, std::vector<PAD*>>
|
|
m_slot_holes; //<! Storage vector of slotted holes that need to be output as cutouts
|
|
|
|
PROGRESS_REPORTER* m_progress_reporter;
|
|
|
|
std::set<wxUniChar> m_acceptable_chars; //<! IPC2581B and C have differing sets of allowed characters in names
|
|
|
|
wxXmlDocument* m_xml_doc;
|
|
wxXmlNode* m_xml_root;
|
|
};
|
|
|
|
#endif // PCB_IO_IPC2581_H_
|