diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp
index 4f84c3e280..b05e8bff20 100644
--- a/common/wildcards_and_files_ext.cpp
+++ b/common/wildcards_and_files_ext.cpp
@@ -270,6 +270,10 @@ wxString EaglePcbFileWildcard()
return _( "Eagle ver. 6.x XML PCB files" ) + AddFileExtListToFilter( { "brd" } );
}
+wxString CadstarArchivePcbFileWildcard()
+{
+ return _( "CADSTAR PCB Archive files" ) + AddFileExtListToFilter( { "cpa" } );
+}
wxString PCadPcbFileWildcard()
{
diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt
index 689f016fc9..4a6fefecbf 100644
--- a/cvpcb/CMakeLists.txt
+++ b/cvpcb/CMakeLists.txt
@@ -67,6 +67,7 @@ set_target_properties( cvpcb_kiface PROPERTIES
)
target_link_libraries( cvpcb_kiface
pcbcommon
+ cadstar2kicadpcb
3d-viewer
gal
common
diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h
index 689c9be73c..eb520bcc3b 100644
--- a/include/wildcards_and_files_ext.h
+++ b/include/wildcards_and_files_ext.h
@@ -196,6 +196,7 @@ extern wxString AltiumSchematicFileWildcard();
extern wxString EagleSchematicFileWildcard();
extern wxString EagleFilesWildcard();
extern wxString PCadPcbFileWildcard();
+extern wxString CadstarArchivePcbFileWildcard();
extern wxString AltiumDesignerPcbFileWildcard();
extern wxString AltiumCircuitStudioPcbFileWildcard();
extern wxString AltiumCircuitMakerPcbFileWildcard();
diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index 41f85c8e92..1103ae19ae 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -596,6 +596,7 @@ endif()
add_subdirectory( pcad2kicadpcb_plugin )
add_subdirectory( plugins/altium )
+add_subdirectory( cadstar2kicadpcb_plugin )
set( PCBNEW_IO_LIBRARIES pcad2kicadpcb altium2pcbnew CACHE INTERNAL "")
@@ -692,6 +693,7 @@ set( PCBNEW_KIFACE_LIBRARIES
connectivity
pcbcommon
pnsrouter
+ cadstar2kicadpcb
kiplatform
common
gal
diff --git a/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt b/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt
new file mode 100644
index 0000000000..ae3136155b
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+# Sources for the pcbnew PLUGIN called CADSTAR_ARCHIVE_PLUGIN
+include_directories( . )
+
+set( CADSTAR2PCBNEW_SRCS
+ cadstar_pcb_archive_plugin.cpp
+ cadstar_pcb_archive_parser.cpp
+ cadstar_common.cpp
+ cadstar_pcb.cpp
+ )
+
+add_library( cadstar2kicadpcb STATIC ${CADSTAR2PCBNEW_SRCS} )
+
+target_link_libraries( cadstar2kicadpcb pcbcommon )
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp
new file mode 100644
index 0000000000..2dfe9453ad
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.cpp
@@ -0,0 +1,152 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_common.cpp
+ * @brief Helper functions and common defines
+ */
+
+#include
+
+XNODE* CADSTAR_COMMON::LoadArchiveFile( const wxString& aFileName, FILE_TYPE aType )
+{
+ KEYWORD emptyKeywords[1] = {};
+ XNODE * iNode = NULL, *cNode = NULL;
+ int tok;
+ bool cadstarFileCheckDone = false;
+ wxString str, fileIdentifier;
+ wxCSConv win1252( wxT( "windows-1252" ) );
+ wxMBConv* conv = &win1252; // Initial testing suggests file encoding to be Windows-1252
+ // More samples required.
+ FILE* fp = wxFopen( aFileName, wxT( "rt" ) );
+
+ if( !fp )
+ THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) );
+
+
+ switch( aType )
+ {
+ case FILE_TYPE::PCB_ARCHIVE:
+ fileIdentifier = wxT( "CADSTARPCB" );
+ break;
+
+ //add others here
+ // SCHEMATIC_ARCHIVE
+ // ...
+
+ default:
+ wxASSERT_MSG( true, "Unknown CADSTAR filetype specified" );
+ }
+
+ DSNLEXER lexer( emptyKeywords, 0, fp, aFileName );
+
+ while( ( tok = lexer.NextTok() ) != DSN_EOF )
+ {
+ if( tok == DSN_RIGHT )
+ {
+ cNode = iNode;
+ if( cNode )
+ {
+ iNode = cNode->GetParent();
+ }
+ else
+ {
+ //too many closing brackets
+ THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
+ }
+ }
+ else if( tok == DSN_LEFT )
+ {
+ tok = lexer.NextTok();
+ str = wxString( lexer.CurText(), *conv );
+ cNode = new XNODE( wxXML_ELEMENT_NODE, str );
+
+ if( iNode )
+ {
+ iNode->AddChild( cNode );
+ }
+ else if( !cadstarFileCheckDone )
+ {
+
+ if( cNode->GetName() != fileIdentifier )
+ {
+ THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
+ }
+ }
+
+ iNode = cNode;
+ }
+ else if( iNode )
+ {
+ str = wxString( lexer.CurText(), *conv );
+
+ if( !str.IsEmpty() )
+ {
+ wxString result, paramName = "attr0";
+ int i = 0;
+
+ while( iNode->GetAttribute( paramName, &result ) )
+ {
+ paramName = wxT( "attr" );
+ paramName << i++;
+ }
+
+ iNode->AddAttribute( paramName, str );
+ }
+ }
+ else
+ {
+ //not enough closing brackets
+ THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
+ }
+ }
+
+ if( iNode != NULL )
+ {
+ //not enough closing brackets
+ THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
+ }
+
+ if( cNode )
+ {
+ return cNode;
+ }
+ else
+ {
+ THROW_IO_ERROR( _( "The selected file is not valid or might be corrupt!" ) );
+ }
+
+ return NULL;
+}
+
+wxString CADSTAR_COMMON::GetAttributeID( XNODE* aNode, unsigned int aID )
+{
+ wxString attrName = "attr";
+ attrName << aID;
+ return aNode->GetAttribute( attrName, wxEmptyString );
+}
+
+void CADSTAR_COMMON::CheckNoChildNodes( XNODE* aNode, wxString aLocation )
+{
+ if( aNode->GetChildren() )
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), aLocation );
+ }
+}
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h
new file mode 100644
index 0000000000..3f4f3e66c3
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_common.h
@@ -0,0 +1,92 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_common.h
+ * @brief Helper functions and common defines
+ */
+
+#ifndef CADSTAR_COMMON_H_
+#define CADSTAR_COMMON_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define THROW_MISSING_NODE_IO_ERROR( nodename, location ) \
+ THROW_IO_ERROR( wxString::Format( _( "Missing node '%s' in '%s'" ), nodename, location ) )
+
+#define THROW_UNKNOWN_NODE_IO_ERROR( nodename, location ) \
+ THROW_IO_ERROR( wxString::Format( _( "Unknown node '%s' in '%s'" ), nodename, location ) )
+
+#define THROW_MISSING_PARAMETER_IO_ERROR( param, location ) \
+ THROW_IO_ERROR( wxString::Format( _( "Missing Parameter '%s' in '%s'" ), param, location ) )
+
+#define THROW_UNKNOWN_PARAMETER_IO_ERROR( param, location ) \
+ THROW_IO_ERROR( wxString::Format( _( "Unknown Parameter '%s' in '%s'" ), param, location ) )
+
+#define THROW_PARSING_IO_ERROR( param, location ) \
+ THROW_IO_ERROR( wxString::Format( _( "Unable to parse '%s' in '%s'" ), param, location ) )
+
+
+namespace CADSTAR_COMMON
+{
+enum class FILE_TYPE
+{
+ PCB_ARCHIVE,
+ SCHEMATIC_ARCHIVE //for future schematic importer
+ //cadstar libraries?
+ //etc.
+};
+
+
+/**
+ * @brief Reads a CADSTAR Archive file (S-parameter format)
+ * @param aFileName
+ * @param aType
+ * @return XNODE pointing to the top of the tree for further parsing. Each node has the first
+ element as the node's name and subsequent elements as node attributes ("attr0",
+ "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks.
+ * @throws IO_ERROR
+ */
+extern XNODE* LoadArchiveFile(
+ const wxString& aFileName, FILE_TYPE aType = FILE_TYPE::PCB_ARCHIVE );
+
+/**
+ * @brief
+ * @param aNode
+ * @param aID
+ * @return returns the value of attribute "attrX" in aNode where 'X' is aID
+ */
+extern wxString GetAttributeID( XNODE* aNode, unsigned int aID );
+
+/**
+ * @brief
+ * @param aNode
+ * @throw IO_ERROR if a child node was found
+ */
+extern void CheckNoChildNodes( XNODE* aNode, wxString aLocation );
+
+} // namespace CADSTAR_COMMON
+
+#endif // CADSTAR_COMMON_H_
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp
new file mode 100644
index 0000000000..148709b138
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.cpp
@@ -0,0 +1,329 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_pcb.cpp
+ * @brief Converts a CPA_FILE object into a KiCad BOARD object
+ */
+
+#include //KEY_COPPER, KEY_CORE, KEY_PREPREG
+#include
+
+
+void CADSTAR_PCB::Load( CPA_FILE* aCPAfile )
+{
+ loadBoardStackup( aCPAfile );
+
+ //TODO: process all other items
+}
+
+
+void CADSTAR_PCB::loadBoardStackup( CPA_FILE* aCPAfile )
+{
+ std::map& cpaLayers = aCPAfile->Assignments.Layerdefs.Layers;
+ std::map& cpaMaterials =
+ aCPAfile->Assignments.Layerdefs.Materials;
+ std::vector& cpaLayerStack = aCPAfile->Assignments.Layerdefs.LayerStack;
+ unsigned numElectricalAndPowerLayers = 0;
+ BOARD_DESIGN_SETTINGS& designSettings = mBoard->GetDesignSettings();
+ BOARD_STACKUP& stackup = designSettings.GetStackupDescriptor();
+ int noOfKiCadStackupLayers = 0;
+ int lastElectricalLayerIndex = 0;
+ int dielectricSublayer = 0;
+ int numDielectricLayers = 0;
+ bool prevWasDielectric = false;
+ BOARD_STACKUP_ITEM* tempKiCadLayer;
+ std::vector layerIDs;
+
+ //Remove all layers except required ones
+ stackup.RemoveAll();
+ layerIDs.push_back( PCB_LAYER_ID::F_CrtYd );
+ layerIDs.push_back( PCB_LAYER_ID::B_CrtYd );
+ layerIDs.push_back( PCB_LAYER_ID::Margin );
+ layerIDs.push_back( PCB_LAYER_ID::Edge_Cuts );
+ designSettings.SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
+
+ for( auto it = cpaLayerStack.begin(); it != cpaLayerStack.end(); ++it )
+ {
+ CPA_LAYER curLayer = cpaLayers[*it];
+ BOARD_STACKUP_ITEM_TYPE kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_UNDEFINED;
+ LAYER_T copperType = LAYER_T::LT_UNDEFINED;
+ PCB_LAYER_ID kicadLayerID = PCB_LAYER_ID::UNDEFINED_LAYER;
+ wxString layerTypeName = wxEmptyString;
+
+ if( cpaLayers.count( *it ) == 0 )
+ wxASSERT_MSG( true, wxT( "Unable to find layer index" ) );
+
+ if( prevWasDielectric && ( curLayer.Type != CPA_LAYER_TYPE::CONSTRUCTION ) )
+ {
+ stackup.Add( tempKiCadLayer ); //only add dielectric layers here after all are done
+ dielectricSublayer = 0;
+ prevWasDielectric = false;
+ noOfKiCadStackupLayers++;
+ }
+
+ switch( curLayer.Type )
+ {
+ case CPA_LAYER_TYPE::ALLDOC:
+ case CPA_LAYER_TYPE::ALLELEC:
+ case CPA_LAYER_TYPE::ALLLAYER:
+ case CPA_LAYER_TYPE::ASSCOMPCOPP:
+ case CPA_LAYER_TYPE::NOLAYER:
+ //Shouldn't be here if CPA file is correctly parsed and not corrupt
+ THROW_IO_ERROR( wxString::Format(
+ _( "Unexpected layer '%s' in layer stack." ), curLayer.Name ) );
+ continue;
+ case CPA_LAYER_TYPE::JUMPERLAYER:
+ copperType = LAYER_T::LT_JUMPER;
+ kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ );
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER;
+ layerTypeName = KEY_COPPER;
+ break;
+ case CPA_LAYER_TYPE::ELEC:
+ copperType = LAYER_T::LT_SIGNAL;
+ kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ );
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER;
+ layerTypeName = KEY_COPPER;
+ break;
+ case CPA_LAYER_TYPE::POWER:
+ copperType = LAYER_T::LT_POWER;
+ kicadLayerID = getKiCadCopperLayerID( numElectricalAndPowerLayers++ );
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_COPPER;
+ layerTypeName = KEY_COPPER;
+ break;
+ case CPA_LAYER_TYPE::CONSTRUCTION:
+ kicadLayerID = PCB_LAYER_ID::UNDEFINED_LAYER;
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_DIELECTRIC;
+ prevWasDielectric = true;
+ layerTypeName = KEY_PREPREG;
+ //TODO handle KEY_CORE and KEY_PREPREG
+ //will need to look at CADSTAR layer embedding (CPA_LAYER->Embedding)
+ //check electrical layers above and below to decide if current layer is prepreg
+ // or core
+ break;
+ case CPA_LAYER_TYPE::DOC:
+ //TODO find out a suitable KiCad Layer alternative for this CADSTAR type
+ continue; //ignore
+ case CPA_LAYER_TYPE::NONELEC:
+ switch( curLayer.SubType )
+ {
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY:
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_NONE:
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT:
+ //TODO find out a suitable KiCad Layer alternative for these CADSTAR types
+ continue; //ignore these layer types for now
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PASTE:
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SOLDERPASTE;
+ if( numElectricalAndPowerLayers > 0 )
+ {
+ kicadLayerID = PCB_LAYER_ID::F_Paste;
+ layerTypeName = _HKI( "Top Solder Paste" );
+ }
+ else
+ {
+ kicadLayerID = PCB_LAYER_ID::B_Paste;
+ layerTypeName = _HKI( "Bottom Solder Paste" );
+ }
+ break;
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN:
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SILKSCREEN;
+ if( numElectricalAndPowerLayers > 0 )
+ {
+ kicadLayerID = PCB_LAYER_ID::F_SilkS;
+ layerTypeName = _HKI( "Top Silk Screen" );
+ }
+ else
+ {
+ kicadLayerID = PCB_LAYER_ID::B_SilkS;
+ layerTypeName = _HKI( "Bottom Silk Screen" );
+ }
+ break;
+ case CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST:
+ kicadLayerType = BOARD_STACKUP_ITEM_TYPE::BS_ITEM_TYPE_SOLDERMASK;
+ if( numElectricalAndPowerLayers > 0 )
+ {
+ kicadLayerID = PCB_LAYER_ID::F_Mask;
+ layerTypeName = _HKI( "Top Solder Mask" );
+ }
+ else
+ {
+ kicadLayerID = PCB_LAYER_ID::B_Mask;
+ layerTypeName = _HKI( "Bottom Solder Mask" );
+ }
+ break;
+ default:
+ wxASSERT_MSG( true, wxT( "Unknown CADSTAR Layer Sub-type" ) );
+ break;
+ }
+ break;
+ default:
+ wxASSERT_MSG( true, wxT( "Unknown CADSTAR Layer Type" ) );
+ break;
+ }
+
+ if( dielectricSublayer == 0 )
+ tempKiCadLayer = new BOARD_STACKUP_ITEM( kicadLayerType );
+
+ tempKiCadLayer->SetLayerName( curLayer.Name );
+ tempKiCadLayer->SetBrdLayerId( kicadLayerID );
+
+ if( prevWasDielectric )
+ {
+ wxASSERT_MSG( kicadLayerID == PCB_LAYER_ID::UNDEFINED_LAYER,
+ wxT( "Error Processing Dielectric Layer. "
+ "Expected to have undefined layer type" ) );
+
+ if( dielectricSublayer == 0 )
+ tempKiCadLayer->SetDielectricLayerId( ++numDielectricLayers );
+ else
+ tempKiCadLayer->AddDielectricPrms( dielectricSublayer );
+ }
+
+ if( !curLayer.MaterialId.IsEmpty() )
+ {
+ tempKiCadLayer->SetMaterial(
+ cpaMaterials[curLayer.MaterialId].Name, dielectricSublayer );
+ tempKiCadLayer->SetEpsilonR( cpaMaterials[curLayer.MaterialId].Permittivity.GetDouble(),
+ dielectricSublayer );
+ tempKiCadLayer->SetLossTangent(
+ cpaMaterials[curLayer.MaterialId].LossTangent.GetDouble(), dielectricSublayer );
+ //TODO add Resistivity when KiCad supports it
+ }
+
+ int unitMultiplier = 10; //assume CPA_FILE uses HUNDREDTH MICRON as its unit
+ //TODO: read units from CPA_FILE header and change unitMultiplier
+ // Also, add unitMultiplier somewhere in CPA_FILE
+ tempKiCadLayer->SetThickness( curLayer.Thickness * unitMultiplier, dielectricSublayer );
+
+ wxASSERT( layerTypeName != wxEmptyString );
+ tempKiCadLayer->SetTypeName( layerTypeName );
+
+ if( !prevWasDielectric )
+ {
+ stackup.Add( tempKiCadLayer ); //only add non-dielectric layers here
+ ++noOfKiCadStackupLayers;
+ layerIDs.push_back( tempKiCadLayer->GetBrdLayerId() );
+ designSettings.SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
+ }
+ else
+ ++dielectricSublayer;
+
+ if( copperType != LAYER_T::LT_UNDEFINED )
+ {
+ wxASSERT( mBoard->SetLayerType( tempKiCadLayer->GetBrdLayerId(),
+ copperType ) ); //move to outside, need to enable layer in board first
+ lastElectricalLayerIndex = noOfKiCadStackupLayers - 1;
+ wxASSERT( mBoard->SetLayerName(
+ tempKiCadLayer->GetBrdLayerId(), tempKiCadLayer->GetLayerName() ) );
+ //TODO set layer names for other CADSTAR layers when KiCad supports custom
+ //layer names on non-copper layers
+ }
+ //TODO map kicad layer to CADSTAR layer in mLayermap
+ }
+
+ //change last copper layer to be B_Cu instead of an inner layer
+ PCB_LAYER_ID lastElecBrdId =
+ stackup.GetStackupLayer( lastElectricalLayerIndex )->GetBrdLayerId();
+ std::remove( layerIDs.begin(), layerIDs.end(), lastElecBrdId );
+ layerIDs.push_back( PCB_LAYER_ID::B_Cu );
+ tempKiCadLayer = stackup.GetStackupLayer( lastElectricalLayerIndex );
+ tempKiCadLayer->SetBrdLayerId( PCB_LAYER_ID::B_Cu );
+ wxASSERT( mBoard->SetLayerName(
+ tempKiCadLayer->GetBrdLayerId(), tempKiCadLayer->GetLayerName() ) );
+
+ //make all layers enabled and visible
+ mBoard->SetEnabledLayers( LSET( &layerIDs[0], layerIDs.size() ) );
+ mBoard->SetVisibleLayers( LSET( &layerIDs[0], layerIDs.size() ) );
+
+ mBoard->SetCopperLayerCount( numElectricalAndPowerLayers );
+}
+
+
+PCB_LAYER_ID CADSTAR_PCB::getKiCadCopperLayerID( unsigned int aLayerNum )
+{
+ switch( aLayerNum )
+ {
+ case 0:
+ return PCB_LAYER_ID::F_Cu;
+ case 1:
+ return PCB_LAYER_ID::In1_Cu;
+ case 2:
+ return PCB_LAYER_ID::In2_Cu;
+ case 3:
+ return PCB_LAYER_ID::In3_Cu;
+ case 4:
+ return PCB_LAYER_ID::In4_Cu;
+ case 5:
+ return PCB_LAYER_ID::In5_Cu;
+ case 6:
+ return PCB_LAYER_ID::In6_Cu;
+ case 7:
+ return PCB_LAYER_ID::In7_Cu;
+ case 8:
+ return PCB_LAYER_ID::In8_Cu;
+ case 9:
+ return PCB_LAYER_ID::In9_Cu;
+ case 10:
+ return PCB_LAYER_ID::In10_Cu;
+ case 11:
+ return PCB_LAYER_ID::In11_Cu;
+ case 12:
+ return PCB_LAYER_ID::In12_Cu;
+ case 13:
+ return PCB_LAYER_ID::In13_Cu;
+ case 14:
+ return PCB_LAYER_ID::In14_Cu;
+ case 15:
+ return PCB_LAYER_ID::In15_Cu;
+ case 16:
+ return PCB_LAYER_ID::In16_Cu;
+ case 17:
+ return PCB_LAYER_ID::In17_Cu;
+ case 18:
+ return PCB_LAYER_ID::In18_Cu;
+ case 19:
+ return PCB_LAYER_ID::In19_Cu;
+ case 20:
+ return PCB_LAYER_ID::In20_Cu;
+ case 21:
+ return PCB_LAYER_ID::In21_Cu;
+ case 22:
+ return PCB_LAYER_ID::In22_Cu;
+ case 23:
+ return PCB_LAYER_ID::In23_Cu;
+ case 24:
+ return PCB_LAYER_ID::In24_Cu;
+ case 25:
+ return PCB_LAYER_ID::In25_Cu;
+ case 26:
+ return PCB_LAYER_ID::In26_Cu;
+ case 27:
+ return PCB_LAYER_ID::In27_Cu;
+ case 28:
+ return PCB_LAYER_ID::In28_Cu;
+ case 29:
+ return PCB_LAYER_ID::In29_Cu;
+ case 30:
+ return PCB_LAYER_ID::In30_Cu;
+ case 31:
+ return PCB_LAYER_ID::B_Cu;
+ }
+ return PCB_LAYER_ID::UNDEFINED_LAYER;
+}
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h
new file mode 100644
index 0000000000..a8ace12202
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb.h
@@ -0,0 +1,54 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_pcb.h
+ * @brief Converts a CPA_FILE object into a KiCad BOARD object
+ */
+
+#ifndef CADSTAR_PCB_H_
+#define CADSTAR_PCB_H_
+
+#include
+
+class BOARD;
+
+class CADSTAR_PCB
+{
+public:
+ explicit CADSTAR_PCB( BOARD* aBoard ) : mBoard( aBoard )
+ {
+ }
+
+ /**
+ * @brief Loads a CADSTAR PCB Archive into the KiCad BOARD
+ * @param aCPAfile
+ */
+ void Load( CPA_FILE* aCPAfile );
+
+private:
+ BOARD* mBoard;
+ std::map mLayermap;
+ void loadBoardStackup( CPA_FILE* aCPAfile );
+ PCB_LAYER_ID getKiCadCopperLayerID( unsigned int aLayerNum );
+};
+
+
+#endif // CADSTAR_PCB_H_
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp
new file mode 100644
index 0000000000..0341d7eb64
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.cpp
@@ -0,0 +1,429 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_pcb_archive_parser.cpp
+ * @brief Parses a CADSTAR PCB Archive file
+ */
+
+#include
+#include // pow()
+
+
+void CPA_FILE::Parse()
+{
+ XNODE* fileRootNode =
+ CADSTAR_COMMON::LoadArchiveFile( Filename, CADSTAR_COMMON::FILE_TYPE::PCB_ARCHIVE );
+
+ XNODE* tempNode = fileRootNode->GetChildren();
+
+ for( ; tempNode && ( tempNode->GetName() != wxT( "ASSIGNMENTS" ) );
+ tempNode = tempNode->GetNext() )
+ ;
+
+ if( !tempNode )
+ THROW_MISSING_NODE_IO_ERROR( wxT( "ASSIGNMENTS" ), wxT( "CADSTARPCB" ) );
+
+ tempNode = tempNode->GetChildren();
+
+ for( ; tempNode && ( tempNode->GetName() != wxT( "LAYERDEFS" ) );
+ tempNode = tempNode->GetNext() )
+ ;
+
+ if( !tempNode )
+ THROW_MISSING_NODE_IO_ERROR( wxT( "LAYERDEFS" ), wxT( "ASSIGNMENTS" ) );
+
+ Assignments.Layerdefs.Parse( tempNode );
+
+ //Todo - This is just for testing. Remove this block & delete fileRootNode.
+ {
+ wxXmlDocument doc;
+ doc.SetRoot( fileRootNode );
+ doc.Save( Filename + wxT( ".xml" ) );
+ }
+
+ //delete fileRootNode;
+
+ //TODO need to parse everything else!
+}
+
+void CPA_LAYERDEFS::Parse( XNODE* aNode )
+{
+ wxASSERT( aNode->GetName() == wxT( "LAYERDEFS" ) );
+ XNODE * iNode, *cNode;
+ wxXmlAttribute* xmlAttribute = NULL;
+
+ iNode = aNode->GetChildren();
+
+ if( !iNode )
+ THROW_MISSING_PARAMETER_IO_ERROR( wxT( "LAYERSTACK" ), wxT( "LAYERDEFS" ) );
+
+ for( ; iNode; iNode = iNode->GetNext() )
+ {
+ wxString nodeName = iNode->GetName();
+
+ if( nodeName == wxT( "LAYERSTACK" ) )
+ {
+ xmlAttribute = iNode->GetAttributes();
+
+ for( ; xmlAttribute; xmlAttribute = xmlAttribute->GetNext() )
+ {
+ LayerStack.push_back( xmlAttribute->GetValue() );
+ }
+
+ if( cNode = iNode->GetChildren() ) //Shouldn't have any children
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), nodeName );
+ }
+ }
+ else if( nodeName == wxT( "MATERIAL" ) )
+ {
+ CPA_MATERIAL material;
+ material.Parse( iNode );
+ Materials.insert( std::make_pair( material.ID, material ) );
+ }
+ else if( nodeName == wxT( "LAYER" ) )
+ {
+ CPA_LAYER layer;
+ layer.Parse( iNode );
+ Layers.insert( std::make_pair( layer.ID, layer ) );
+ }
+ else if( nodeName == wxT( "SWAPPAIR" ) )
+ {
+ wxString layerId = CADSTAR_COMMON::GetAttributeID( iNode, 0 );
+ wxString swapLayerId = CADSTAR_COMMON::GetAttributeID( iNode, 1 );
+
+ if( layerId.IsEmpty() || swapLayerId.IsEmpty() )
+ {
+ THROW_MISSING_PARAMETER_IO_ERROR(
+ wxT( "ID" ), wxString::Format( "SWAPPAIR %s,%s", layerId, swapLayerId ) );
+ }
+
+ Layers[layerId].SwapLayerID = swapLayerId;
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( nodeName, aNode->GetName() );
+ }
+ }
+}
+
+
+void CPAParseEValue( XNODE* aNode, CPA_EVALUE& aValue, wxString location )
+{
+ if( aNode->GetChildren()->GetName() == wxT( "E" ) )
+ {
+ aValue.Parse( aNode->GetChildren() );
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( aNode->GetChildren()->GetName(), location );
+ }
+}
+
+
+void CPAParseNameAndID( XNODE* aNode, wxString& aName, wxString& aID )
+{
+ aID = CADSTAR_COMMON::GetAttributeID( aNode, 0 );
+ aName = CADSTAR_COMMON::GetAttributeID( aNode, 1 );
+
+ if( aID.IsEmpty() )
+ THROW_MISSING_PARAMETER_IO_ERROR(
+ wxT( "ID" ), wxString::Format( "%s %s", aNode->GetName(), aName ) );
+
+ if( aName.IsEmpty() )
+ THROW_MISSING_PARAMETER_IO_ERROR(
+ wxT( "Name" ), wxString::Format( "%s %s", aNode->GetName(), aID ) );
+}
+
+void CPA_MATERIAL::Parse( XNODE* aNode )
+{
+ wxASSERT( aNode->GetName() == wxT( "MATERIAL" ) );
+
+ //Process Name & ID
+ CPAParseNameAndID( aNode, Name, ID );
+
+ //Process Type
+ wxString sType = CADSTAR_COMMON::GetAttributeID( aNode, 2 );
+
+ if( sType == wxT( "CONSTRUCTION" ) )
+ {
+ Type = CPA_MATERIAL_LAYER_TYPE::CONSTRUCTION;
+ }
+ else if( sType == wxT( "ELECTRICAL" ) )
+ {
+ Type = CPA_MATERIAL_LAYER_TYPE::ELECTRICAL;
+ }
+ else if( sType == wxT( "NONELEC" ) )
+ {
+ Type = CPA_MATERIAL_LAYER_TYPE::NON_ELECTRICAL;
+ }
+ else
+ {
+ THROW_UNKNOWN_PARAMETER_IO_ERROR( sType, wxString::Format( "MATERIAL %s", Name ) );
+ }
+
+ //Process electrical values
+ XNODE* iNode = aNode->GetChildren();
+
+ if( !iNode )
+ THROW_MISSING_PARAMETER_IO_ERROR(
+ wxT( "RESISTIVITY" ), wxString::Format( "MATERIAL %s", Name ) );
+
+ for( ; iNode; iNode = iNode->GetNext() )
+ {
+ wxString nodeName = iNode->GetName();
+ wxString location = wxString::Format( "MATERIAL %s->%s", Name, nodeName );
+
+ if( nodeName == wxT( "RELPERMIT" ) )
+ {
+ CPAParseEValue( iNode, Permittivity, location );
+ }
+ else if( nodeName == wxT( "LOSSTANGENT" ) )
+ {
+ CPAParseEValue( iNode, LossTangent, location );
+ }
+ else if( nodeName == wxT( "RESISTIVITY" ) )
+ {
+ CPAParseEValue( iNode, Resistivity, location );
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( nodeName, wxString::Format( "MATERIAL %s", Name ) );
+ }
+ }
+}
+
+void CPA_LAYER::Parse( XNODE* aNode )
+{
+ wxASSERT( aNode->GetName() == wxT( "LAYER" ) );
+
+ //Process Name & ID
+ CPAParseNameAndID( aNode, Name, ID );
+
+ XNODE* cNode = aNode->GetChildren();
+ auto processLayerMaterialDetails = [&]() {
+ XNODE* tempNode = cNode->GetChildren();
+ for( ; tempNode; tempNode = tempNode->GetNext() )
+ {
+ wxString tempNodeName = tempNode->GetName();
+
+ if( tempNodeName == wxT( "MAKE" ) )
+ {
+ //Process material ID and layer width
+ MaterialId = CADSTAR_COMMON::GetAttributeID( tempNode, 0 );
+
+ if( MaterialId.IsEmpty() )
+ THROW_PARSING_IO_ERROR(
+ wxT( "Material ID" ), wxString::Format( "LAYER %s->MAKE", Name ) );
+
+ if( !CADSTAR_COMMON::GetAttributeID( tempNode, 1 ).ToLong( &Thickness ) )
+ THROW_PARSING_IO_ERROR(
+ wxT( "Thickness" ), wxString::Format( "LAYER %s->MAKE", Name ) );
+
+ XNODE* childOfTempNode = tempNode->GetChildren();
+
+ if( childOfTempNode )
+ {
+ if( childOfTempNode->GetName() == wxT( "EMBEDS" ) )
+ {
+ // if( UPWARDS
+ wxString embedsValue = CADSTAR_COMMON::GetAttributeID( childOfTempNode, 0 );
+
+ if( embedsValue == wxT( "UPWARDS" ) )
+ {
+ Embedding = CPA_EMBEDDING::ABOVE;
+ }
+ else if( embedsValue == wxT( "DOWNWARDS" ) )
+ {
+ Embedding = CPA_EMBEDDING::BELOW;
+ }
+ else
+ {
+ THROW_UNKNOWN_PARAMETER_IO_ERROR(
+ embedsValue, wxString::Format( "LAYER %s -> EMBEDS", Name ) );
+ }
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( childOfTempNode->GetName(),
+ wxString::Format( "LAYER %s->MAKE", Name ) );
+ }
+ }
+ }
+ else if( tempNodeName == wxT( "BIAS" ) )
+ {
+ wxString bias = CADSTAR_COMMON::GetAttributeID( tempNode, 0 );
+
+ if( bias == wxT( "X_BIASED" ) )
+ {
+ RoutingBias = CPA_ROUTING_BIAS::X;
+ }
+ else if( bias == wxT( "Y_BIASED" ) )
+ {
+ RoutingBias = CPA_ROUTING_BIAS::Y;
+ }
+ else if( bias == wxT( "ANTITRACK" ) )
+ {
+ RoutingBias = CPA_ROUTING_BIAS::ANTI_ROUTE;
+ }
+ else if( bias == wxT( "OBSTACLE" ) )
+ {
+ RoutingBias = CPA_ROUTING_BIAS::OBSTACLE;
+ }
+ else if( bias == wxT( "UNBIASED" ) )
+ {
+ RoutingBias = CPA_ROUTING_BIAS::UNBIASED;
+ }
+ else
+ {
+ THROW_UNKNOWN_PARAMETER_IO_ERROR(
+ bias, wxString::Format( "LAYER %s -> BIAS", Name ) );
+ }
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( tempNodeName, wxString::Format( "LAYER %s", Name ) );
+ }
+ }
+ };
+
+ for( ; cNode; cNode = cNode->GetNext() )
+ {
+ //TODO ADD CHECK TO MAKE SURE THERE ARE NO CHILD NODES
+
+ wxString cNodeName = cNode->GetName();
+
+ if( cNodeName == wxT( "ALLDOC" ) )
+ {
+ Type = CPA_LAYER_TYPE::ALLDOC;
+ }
+ else if( cNodeName == wxT( "ALLELEC" ) )
+ {
+ Type = CPA_LAYER_TYPE::ALLELEC;
+ }
+ else if( cNodeName == wxT( "ALLLAYER" ) )
+ {
+ Type = CPA_LAYER_TYPE::ALLLAYER;
+ }
+ else if( cNodeName == wxT( "ASSCOMPCOPP" ) )
+ {
+ Type = CPA_LAYER_TYPE::ASSCOMPCOPP;
+ }
+ else if( cNodeName == wxT( "JUMPERLAYER" ) )
+ {
+ Type = CPA_LAYER_TYPE::JUMPERLAYER;
+ }
+ else if( cNodeName == wxT( "NOLAYER" ) )
+ {
+ Type = CPA_LAYER_TYPE::NOLAYER;
+ }
+ else if( cNodeName == wxT( "POWER" ) )
+ {
+ Type = CPA_LAYER_TYPE::POWER;
+
+ if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) )
+ THROW_PARSING_IO_ERROR(
+ wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) );
+
+ processLayerMaterialDetails();
+ }
+ else if( cNodeName == wxT( "DOC" ) )
+ {
+ Type = CPA_LAYER_TYPE::DOC;
+ }
+ else if( cNodeName == wxT( "CONSTRUCTION" ) )
+ {
+ Type = CPA_LAYER_TYPE::CONSTRUCTION;
+ processLayerMaterialDetails();
+ }
+ else if( cNodeName == wxT( "ELEC" ) )
+ {
+ Type = CPA_LAYER_TYPE::ELEC;
+
+ if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) )
+ THROW_PARSING_IO_ERROR(
+ wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) );
+
+ processLayerMaterialDetails();
+ }
+ else if( cNodeName == wxT( "NONELEC" ) )
+ {
+ Type = CPA_LAYER_TYPE::NONELEC;
+
+ if( !CADSTAR_COMMON::GetAttributeID( cNode, 0 ).ToLong( &PhysicalLayer ) )
+ THROW_PARSING_IO_ERROR(
+ wxT( "Physical Layer" ), wxString::Format( "LAYER %s", Name ) );
+
+ processLayerMaterialDetails();
+ }
+ else if( cNodeName == wxT( "LASUBTYP" ) )
+ {
+ //Process subtype
+ wxString sSubType = CADSTAR_COMMON::GetAttributeID( cNode, 0 );
+
+ if( sSubType == wxT( "LAYERSUBTYPE_ASSEMBLY" ) )
+ {
+ this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_ASSEMBLY;
+ }
+ else if( sSubType == wxT( "LAYERSUBTYPE_PASTE" ) )
+ {
+ this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PASTE;
+ }
+ else if( sSubType == wxT( "LAYERSUBTYPE_PLACEMENT" ) )
+ {
+ this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_PLACEMENT;
+ }
+ else if( sSubType == wxT( "LAYERSUBTYPE_SILKSCREEN" ) )
+ {
+ this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SILKSCREEN;
+ }
+ else if( sSubType == wxT( "LAYERSUBTYPE_SOLDERRESIST" ) )
+ {
+ this->SubType = CPA_LAYER_SUBTYPE::LAYERSUBTYPE_SOLDERRESIST;
+ }
+ else
+ {
+ THROW_UNKNOWN_PARAMETER_IO_ERROR(
+ sSubType, wxString::Format( "LAYER %s %s", Name, cNodeName ) );
+ }
+ }
+ else
+ {
+ THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, wxString::Format( "LAYER %s", Name ) );
+ }
+ }
+}
+
+void CPA_EVALUE::Parse( XNODE* aNode )
+{
+ wxASSERT( aNode->GetName() == wxT( "E" ) );
+
+ if( ( !CADSTAR_COMMON::GetAttributeID( aNode, 0 ).ToLong( &Base ) )
+ || ( !CADSTAR_COMMON::GetAttributeID( aNode, 1 ).ToLong( &Exponent ) ) )
+ THROW_PARSING_IO_ERROR( wxT( "Base and Exponent" ),
+ wxString::Format(
+ "%s->%s", aNode->GetParent()->GetName(), aNode->GetParent()->GetName() ) );
+}
+
+double CPA_EVALUE::GetDouble()
+{
+ return Base * std::pow( 10.0, Exponent );
+}
diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h
new file mode 100644
index 0000000000..2521129805
--- /dev/null
+++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_parser.h
@@ -0,0 +1,173 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2020 Roberto Fernandez Bautista <@Qbort>
+ * Copyright (C) 2020 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 .
+ */
+
+/**
+ * @file cadstar_pcb_archive_parser.cpp
+ * @brief Reads in a CADSTAR PCB Archive (*.cpa) file
+ */
+
+#ifndef CADSTAR_PCB_ARCHIVE_PARSER_H_
+#define CADSTAR_PCB_ARCHIVE_PARSER_H_
+
+#include
+#include