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 + +/** + * @brief Represents a floating value in E notation + */ +struct CPA_EVALUE +{ + long Base = 0; + long Exponent = 0; + + void Parse( XNODE* aNode ); + double GetDouble(); +}; + + +typedef wxString CPA_MATERIAL_ID; + +typedef wxString CPA_LAYER_ID; + +/** + * @brief subset of CPA_LAYER_TYPE - for materials only +*/ +enum class CPA_MATERIAL_LAYER_TYPE +{ + CONSTRUCTION, + ELECTRICAL, + NON_ELECTRICAL +}; + +struct CPA_MATERIAL +{ + CPA_MATERIAL_ID ID; + wxString Name; + CPA_MATERIAL_LAYER_TYPE Type; // Materials; + std::map Layers; + std::vector LayerStack; + + void Parse( XNODE* aNode ); +}; + +struct CPA_ASSIGNMENTS +{ + CPA_LAYERDEFS Layerdefs; + //Todo Add codedefs, technology, grids, etc. +}; + +/** + * @brief Represents a CADSTAR PCB Archive (CPA) file + */ +class CPA_FILE +{ +public: + explicit CPA_FILE( wxString aFilename ) : Filename( aFilename ) + { + } + + /** + * @brief Parses the file + * @throw IO_ERROR if file could not be opened or there was + * an error while parsing + */ + void Parse(); + + wxString Filename; + + CPA_ASSIGNMENTS Assignments; + //Todo Add Header, Library, Defaults, etc.. +}; + +//Helper Functions +void CPAParseEValue( XNODE* aNode, CPA_EVALUE& aValue, wxString location ); +void CPAParseNameAndID( XNODE* aNode, wxString& aName, wxString& aID ); + + +#endif // CADSTAR_PCB_ARCHIVE_PARSER_H_ \ No newline at end of file diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.cpp b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.cpp new file mode 100644 index 0000000000..33f89ffb0f --- /dev/null +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.cpp @@ -0,0 +1,70 @@ +/* + * 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_plugin.cpp + * @brief Pcbnew PLUGIN for CADSTAR PCB Archive (*.cpa) format: an ASCII format + * based on S-expressions. + */ + +#include +#include +#include +#include +#include + + +CADSTAR_PCB_ARCHIVE_PLUGIN::CADSTAR_PCB_ARCHIVE_PLUGIN() +{ + m_board = nullptr; + m_props = nullptr; +} + + +CADSTAR_PCB_ARCHIVE_PLUGIN::~CADSTAR_PCB_ARCHIVE_PLUGIN() +{ +} + + +const wxString CADSTAR_PCB_ARCHIVE_PLUGIN::PluginName() const +{ + return wxT( "CADSTAR PCB Archive" ); +} + + +const wxString CADSTAR_PCB_ARCHIVE_PLUGIN::GetFileExtension() const +{ + return wxT( "cpa" ); +} + + +BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( + const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties ) +{ + m_props = aProperties; + m_board = aAppendToMe ? aAppendToMe : new BOARD(); + + CADSTAR_PCB tempPCB( m_board ); + CPA_FILE theFile( aFileName ); + theFile.Parse(); + tempPCB.Load( &theFile ); + + return m_board; +} diff --git a/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.h b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.h new file mode 100644 index 0000000000..ce3c295b72 --- /dev/null +++ b/pcbnew/cadstar2kicadpcb_plugin/cadstar_pcb_archive_plugin.h @@ -0,0 +1,61 @@ +/* + * 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_plugin.h + * @brief Pcbnew PLUGIN for CADSTAR PCB Archive (*.cpa) format: an ASCII format + * based on S-expressions. + */ + +#ifndef CADSTAR_ARCHIVE_PLUGIN_H_ +#define CADSTAR_ARCHIVE_PLUGIN_H_ + + +#include + +class CADSTAR_PCB_ARCHIVE_PLUGIN : public PLUGIN +{ +public: + // ------------------------------------------------------- + + const wxString PluginName() const override; + + BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, + const PROPERTIES* aProperties = NULL ) override; + + const wxString GetFileExtension() const override; + + long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override + { + // No support for libraries.... + return 0; + } + + // ------------------------------------------------------ + + CADSTAR_PCB_ARCHIVE_PLUGIN(); + ~CADSTAR_PCB_ARCHIVE_PLUGIN(); + +private: + const PROPERTIES* m_props; + BOARD* m_board; +}; + +#endif // CADSTAR_ARCHIVE_PLUGIN_H_ diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index c68dcaf04c..f29f77d48d 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -89,6 +89,7 @@ bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bo { AltiumDesignerPcbFileWildcard(), IO_MGR::ALTIUM_DESIGNER }, // Import Altium Designer board files { AltiumCircuitStudioPcbFileWildcard(), IO_MGR::ALTIUM_CIRCUIT_STUDIO }, // Import Altium Circuit Studio board files { AltiumCircuitMakerPcbFileWildcard(), IO_MGR::ALTIUM_CIRCUIT_MAKER }, // Import Altium Circuit Maker board files + { CadstarArchivePcbFileWildcard(), IO_MGR::CADSTAR_ARCHIVE }, // Import Cadstar PCB Archive board files }; // clang-format on @@ -388,6 +389,10 @@ IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl ) { pluginType = IO_MGR::ALTIUM_CIRCUIT_MAKER; } + else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::CADSTAR_ARCHIVE ) ) == 0 ) + { + pluginType = IO_MGR::CADSTAR_ARCHIVE; + } else { pluginType = IO_MGR::KICAD_SEXP; diff --git a/pcbnew/io_mgr.cpp b/pcbnew/io_mgr.cpp index ca35d887ec..430b841775 100644 --- a/pcbnew/io_mgr.cpp +++ b/pcbnew/io_mgr.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -215,6 +216,8 @@ static IO_MGR::REGISTER_PLUGIN registerAltiumCircuitStudioPlugin( IO_MGR::ALTIUM static IO_MGR::REGISTER_PLUGIN registerAltiumCircuitMakerPlugin( IO_MGR::ALTIUM_CIRCUIT_MAKER, wxT( "Altium Circuit Maker" ), []() -> PLUGIN* { return new ALTIUM_CIRCUIT_MAKER_PLUGIN; } ); +static IO_MGR::REGISTER_PLUGIN registerCadstarArchivePlugin( IO_MGR::CADSTAR_ARCHIVE, + wxT( "CADSTAR PCB Archive" ), []() -> PLUGIN* { return new CADSTAR_PCB_ARCHIVE_PLUGIN; } ); #ifdef BUILD_GITHUB_PLUGIN static IO_MGR::REGISTER_PLUGIN registerGithubPlugin( IO_MGR::GITHUB, wxT("Github"), []() -> PLUGIN* { return new GITHUB_PLUGIN; } ); #endif /* BUILD_GITHUB_PLUGIN */ diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index a2f865636e..b950b895eb 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -60,6 +60,7 @@ public: ALTIUM_DESIGNER, ALTIUM_CIRCUIT_STUDIO, ALTIUM_CIRCUIT_MAKER, + CADSTAR_ARCHIVE, GEDA_PCB, ///< Geda PCB file formats. //N.B. This needs to be commented out to ensure compile-type errors diff --git a/qa/gal/gal_pixel_alignment/CMakeLists.txt b/qa/gal/gal_pixel_alignment/CMakeLists.txt index db3af56240..a4d246fc02 100644 --- a/qa/gal/gal_pixel_alignment/CMakeLists.txt +++ b/qa/gal/gal_pixel_alignment/CMakeLists.txt @@ -71,6 +71,7 @@ target_link_libraries( test_gal_pixel_alignment kimath pnsrouter pcbcommon + cadstar2kicadpcb bitmaps 3d-viewer gal diff --git a/qa/pcbnew/CMakeLists.txt b/qa/pcbnew/CMakeLists.txt index 81fd08d2d5..65763cc4ac 100644 --- a/qa/pcbnew/CMakeLists.txt +++ b/qa/pcbnew/CMakeLists.txt @@ -73,6 +73,7 @@ target_link_libraries( qa_pcbnew connectivity pcbcommon pnsrouter + cadstar2kicadpcb gal common gal diff --git a/qa/pcbnew_tools/CMakeLists.txt b/qa/pcbnew_tools/CMakeLists.txt index 376438aebb..48237e9d8a 100644 --- a/qa/pcbnew_tools/CMakeLists.txt +++ b/qa/pcbnew_tools/CMakeLists.txt @@ -53,6 +53,7 @@ target_link_libraries( qa_pcbnew_tools connectivity pcbcommon pnsrouter + cadstar2kicadpcb gal dxflib_qcad tinyspline_lib