Prepare changes to support a better board stack management in .gbrjob file.

In .gbrjob file, one can specify the thickness and color of some layers.
Currently, there is no way to enter these parameters.
This commit prepare a better support of .gbrjob files.
This commit is contained in:
jean-pierre charras 2019-06-23 13:20:22 +02:00
parent 31c254d8c1
commit c1eee56785
10 changed files with 999 additions and 104 deletions

View File

@ -447,6 +447,7 @@ set( PCB_COMMON_SRCS
../pcbnew/class_pad.cpp
../pcbnew/class_pcb_target.cpp
../pcbnew/class_pcb_text.cpp
../pcbnew/board_stackup_manager/class_board_stackup.cpp
../pcbnew/class_text_mod.cpp
../pcbnew/class_track.cpp
../pcbnew/class_zone.cpp

View File

@ -29,6 +29,7 @@
#include <class_track.h>
#include <netclass.h>
#include <config_params.h>
#include <board_stackup_manager/class_board_stackup.h>
#define DEFAULT_SILK_LINE_WIDTH 0.12
#define DEFAULT_COPPER_LINE_WIDTH 0.20
@ -250,6 +251,15 @@ public:
D_PAD m_Pad_Master; ///< A dummy pad to store all default parameters
// when importing values or create a new pad
/** Set to true if the board has a stackup management.
* if m_hasStackup is false, a default basic stackup witll be used to
* generate the ;gbrjob file.
* if m_hasStackup is true, the stackup defined for the board is used.
* if not up to date, a error message will be set
* Could be removed later, or at least always set to true
*/
bool m_HasStackup;
private:
// Indicies into the trackWidth, viaSizes and diffPairDimensions lists.
// The 0 index is always the current netclass value(s)
@ -278,9 +288,17 @@ private:
/// This is also the last used netclass after starting a track.
wxString m_currentNetClassName;
/** the description of layers stackup, for board fabrication
* only physical layers are in layers stackup.
* It includes not only layers enabled for the board edition, but also dielectic layers
*/
BOARD_STACKUP m_stackup;
public:
BOARD_DESIGN_SETTINGS();
BOARD_STACKUP& GetStackupDescriptor() { return m_stackup; }
/**
* Function GetDefault
* @return the default netclass.

View File

@ -180,6 +180,10 @@ if( KICAD_SCRIPTING AND KICAD_SCRIPTING_ACTION_MENU )
)
endif()
set( PCBNEW_BRDSTACKUP_MGR
board_stackup_manager/stackup_predefined_prms.cpp
)
set( PCBNEW_IMPORT_GFX
import_gfx/dialog_import_gfx_base.cpp
import_gfx/dialog_import_gfx.cpp
@ -192,6 +196,7 @@ set( PCBNEW_IMPORT_GFX
import_gfx/nanosvg.cpp
)
set( PCBNEW_EXPORTERS
exporters/export_hyperlynx.cpp
exporters/export_d356.cpp
@ -222,6 +227,7 @@ set( PCBNEW_CLASS_SRCS
${PCBNEW_EXPORTERS}
${PCBNEW_IMPORT_GFX}
${PCBNEW_DRC_SRCS}
${PCBNEW_BRDSTACKUP_MGR}
autorouter/rect_placement/rect_placement.cpp
autorouter/spread_footprints.cpp

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2019 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
@ -423,8 +423,9 @@ public:
BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
m_Pad_Master( NULL )
{
LSET all_set = LSET().set();
m_HasStackup = false; // no stackup defined by default
LSET all_set = LSET().set();
m_enabledLayers = all_set; // All layers enabled at first.
// SetCopperLayerCount() will adjust this.
SetVisibleLayers( all_set );
@ -433,7 +434,6 @@ BOARD_DESIGN_SETTINGS::BOARD_DESIGN_SETTINGS() :
m_visibleElements = ~( 1 << GAL_LAYER_INDEX( LAYER_MOD_TEXT_INVISIBLE ) );
SetCopperLayerCount( 2 ); // Default design is a double sided board
m_CurrentViaType = VIA_THROUGH;
// if true, when creating a new track starting on an existing track, use this track width

View File

@ -0,0 +1,484 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2019 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/>.
*/
#include "class_board_stackup.h"
#include <convert_to_biu.h>
#include <base_units.h>
#include <layers_id_colors_and_visibility.h>
#include <board_design_settings.h>
#include <class_board.h>
#include "stackup_predefined_prms.h"
// A reasonable thickness for copper layers:
const int copperDefaultThickness = Millimeter2iu( 0.035 );
// A reasonable thickness for solder mask:
const int maskDefaultThickness = Millimeter2iu( 0.01 );
BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType )
{
m_LayerId = UNDEFINED_LAYER;
m_Type = aType;
m_DielectricLayerId = 0;
m_EpsilonR = 0;
m_LossTangent = 0.0;
// Initialize parameters to a usual value for allowed types:
switch( m_Type )
{
case BS_ITEM_TYPE_COPPER:
m_TypeName = "copper";
m_Thickness = copperDefaultThickness;
break;
case BS_ITEM_TYPE_DIELECTRIC:
m_TypeName = "core"; // or prepreg
m_Material = "FR4"; // or other dielectric name
m_DielectricLayerId = 1;
m_Thickness = 0; // will be set later
m_LossTangent = 0.02; // for FR4
m_EpsilonR = 4.5; // for FR4
break;
case BS_ITEM_TYPE_SOLDERPASTE:
m_TypeName = "solderpaste";
m_Thickness = 0.0; // Not used
break;
case BS_ITEM_TYPE_SOLDERMASK:
m_TypeName = "soldermask";
m_Color = NOT_SPECIFIED;
m_Thickness = maskDefaultThickness;
m_EpsilonR = 3.5;
m_LossTangent = 0.0;
break;
case BS_ITEM_TYPE_SILKSCREEN:
m_TypeName = "silkscreen";
m_Color = NOT_SPECIFIED;
m_Thickness = 0.0; // Not used
break;
case BS_ITEM_TYPE_UNDEFINED:
m_Thickness = 0.0;
break;
}
}
BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM& aOther )
{
m_LayerId = aOther.m_LayerId;
m_Type = aOther.m_Type;
m_DielectricLayerId = aOther.m_DielectricLayerId;
m_TypeName = aOther.m_TypeName;
m_Material = aOther.m_Material;
m_Color = aOther.m_Color;
m_Thickness = aOther.m_Thickness;
m_EpsilonR = aOther.m_EpsilonR;
m_LossTangent = aOther.m_LossTangent;
}
bool BOARD_STACKUP_ITEM::HasEpsilonRValue()
{
return m_Type == BS_ITEM_TYPE_DIELECTRIC || m_Type == BS_ITEM_TYPE_SOLDERMASK;
};
bool BOARD_STACKUP_ITEM::HasLossTangentValue()
{
return m_Type == BS_ITEM_TYPE_DIELECTRIC || m_Type == BS_ITEM_TYPE_SOLDERMASK;
};
bool BOARD_STACKUP_ITEM::IsMaterialEditable()
{
// The material is editable only for dielectric
return m_Type == BS_ITEM_TYPE_DIELECTRIC;
}
bool BOARD_STACKUP_ITEM::IsColorEditable()
{
return m_Type == BS_ITEM_TYPE_SOLDERMASK || m_Type == BS_ITEM_TYPE_SILKSCREEN;
}
bool BOARD_STACKUP_ITEM::IsThicknessEditable()
{
switch( m_Type )
{
case BS_ITEM_TYPE_COPPER:
return true;
case BS_ITEM_TYPE_DIELECTRIC:
return true;
case BS_ITEM_TYPE_SOLDERMASK:
return true;
case BS_ITEM_TYPE_SOLDERPASTE:
return false;
case BS_ITEM_TYPE_SILKSCREEN:
return false;
default:
break;
}
return false;
}
BOARD_STACKUP::BOARD_STACKUP()
{
m_HasDielectricConstrains = false; // True if some dielectric layers have constrains
// (Loss tg and Epison R)
m_HasThicknessConstrains = false; // True if some dielectric or copper layers have constrains
m_EdgeConnectorConstraints = BS_EDGE_CONNECTOR_NONE;
m_CastellatedPads = false; // True if some castellated pads exist
m_EdgePlating = false; // True if edge board is plated
m_FinishType = "None"; // undefined finish type
}
BOARD_STACKUP::BOARD_STACKUP( BOARD_STACKUP& aOther )
{
m_HasDielectricConstrains = aOther.m_HasDielectricConstrains;
m_EdgeConnectorConstraints = aOther.m_EdgeConnectorConstraints;
m_CastellatedPads = aOther.m_CastellatedPads;
m_EdgePlating = aOther.m_EdgePlating;
m_FinishType = aOther.m_FinishType;
// All items in aOther.m_list have to be duplicated, because aOther.m_list
// manage pointers to these items
for( auto item : aOther.m_list )
{
BOARD_STACKUP_ITEM* dup_item = new BOARD_STACKUP_ITEM( *item );
Add( dup_item );
}
}
BOARD_STACKUP& BOARD_STACKUP::operator=( const BOARD_STACKUP& aOther )
{
m_HasDielectricConstrains = aOther.m_HasDielectricConstrains;
m_EdgeConnectorConstraints = aOther.m_EdgeConnectorConstraints;
m_CastellatedPads = aOther.m_CastellatedPads;
m_EdgePlating = aOther.m_EdgePlating;
m_FinishType = aOther.m_FinishType;
RemoveAll();
// All items in aOther.m_list have to be duplicated, because aOther.m_list
// manage pointers to these items
for( auto item : aOther.m_list )
{
BOARD_STACKUP_ITEM* dup_item = new BOARD_STACKUP_ITEM( *item );
Add( dup_item );
}
return *this;
}
void BOARD_STACKUP::RemoveAll()
{
for( auto item : m_list )
delete item;
m_list.clear();
}
BOARD_STACKUP_ITEM* BOARD_STACKUP::GetStackupLayer( int aIndex )
{
if( aIndex < 0 || aIndex >= GetCount() )
return nullptr;
return GetList()[aIndex];
}
int BOARD_STACKUP::BuildBoardTicknessFromStackup() const
{
// return the board thickness from the thickness of BOARD_STACKUP_ITEM list
int thickness = 0;
for( auto item : m_list )
{
if( item->IsThicknessEditable() )
thickness += item->m_Thickness;
}
return thickness;
}
bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
{
bool change = false;
// Build the suitable stackup:
BOARD_STACKUP stackup;
stackup.BuildDefaultStackupList( aSettings );
// First test for removed layers:
for( BOARD_STACKUP_ITEM* old_item: m_list )
{
bool found = false;
for( BOARD_STACKUP_ITEM* item: stackup.GetList() )
{
if( item->m_LayerId == old_item->m_LayerId )
{
found = true;
break;
}
}
if( !found ) // a layer was removed: a change is found
{
change = true;
break;
}
}
// Now initialize all stackup items to the initial values, when exist
for( BOARD_STACKUP_ITEM* item: stackup.GetList() )
{
bool found = false;
// Search for initial settings:
for( BOARD_STACKUP_ITEM* initial_item: m_list )
{
if( item->m_LayerId != UNDEFINED_LAYER )
{
if( item->m_LayerId == initial_item->m_LayerId )
{
*item = *initial_item;
found = true;
break;
}
}
else // dielectric layer: see m_DielectricLayerId for identification
{
if( item->m_DielectricLayerId == initial_item->m_DielectricLayerId )
{
*item = *initial_item;
found = true;
break;
}
}
}
if( !found )
change = true;
}
// Transfer other stackup settings from aSettings
BOARD_STACKUP& source_stackup = aSettings->GetStackupDescriptor();
m_HasDielectricConstrains = source_stackup.m_HasDielectricConstrains;
m_EdgeConnectorConstraints = source_stackup.m_EdgeConnectorConstraints;
m_CastellatedPads = source_stackup.m_CastellatedPads;
m_EdgePlating = source_stackup.m_EdgePlating;
m_FinishType = source_stackup.m_FinishType;
*this = stackup;
return change;
}
void BOARD_STACKUP::BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings )
{
// Creates a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
LSET enabledLayer = aSettings->GetEnabledLayers();
int copperLayerCount = aSettings->GetCopperLayerCount();
double diel_thickness = aSettings->GetBoardThickness()
- (copperDefaultThickness * copperLayerCount);
diel_thickness /= copperLayerCount - 1;
int dielectric_idx = 0;
// Add silk screen, solder mask and solder paste layers on top
if( enabledLayer[F_SilkS] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN );
item->m_LayerId = F_SilkS;
item->m_TypeName = _( "Top Silk Screen" );
Add( item );
}
if( enabledLayer[F_Paste] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE );
item->m_LayerId = F_Paste;
item->m_TypeName = _( "Top Solder Paste" );
Add( item );
}
if( enabledLayer[F_Mask] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK );
item->m_LayerId = F_Mask;
item->m_TypeName = _( "Top Solder Mask" );
Add( item );
}
// Add copper and dielectric layers
for( int ii = 0; ii < copperLayerCount; ii++ )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_COPPER );
item->m_LayerId = ( PCB_LAYER_ID )ii;
Add( item );
if( ii == copperLayerCount-1 )
{
item->m_LayerId = B_Cu;
break;
}
// Add the dielectric layer:
item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_DIELECTRIC );
item->m_Thickness = diel_thickness;
item->m_DielectricLayerId = dielectric_idx + 1;
// Display a dielectric default layer name:
if( (dielectric_idx & 1) == 0 )
{
item->m_TypeName = _( "core" );
item->m_Material = "FR4";
}
else
{
item->m_TypeName = _( "prepreg" );
item->m_Material = "FR4";
}
Add( item );
dielectric_idx++;
}
// Add silk screen, solder mask and solder paste layers on bottom
if( enabledLayer[B_Mask] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERMASK );
item->m_LayerId = B_Mask;
item->m_TypeName = _( "Bottom Solder Mask" );
Add( item );
}
if( enabledLayer[B_Paste] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SOLDERPASTE );
item->m_LayerId = B_Paste;
item->m_TypeName = _( "Bottom Solder Paste" );
Add( item );
}
if( enabledLayer[B_SilkS] )
{
BOARD_STACKUP_ITEM* item = new BOARD_STACKUP_ITEM( BS_ITEM_TYPE_SILKSCREEN );
item->m_LayerId = B_SilkS;
item->m_TypeName = _( "Bottom Silk Screen" );
Add( item );
}
// Transfer other stackup settings from aSettings
BOARD_STACKUP& source_stackup = aSettings->GetStackupDescriptor();
m_HasDielectricConstrains = source_stackup.m_HasDielectricConstrains;
m_EdgeConnectorConstraints = source_stackup.m_EdgeConnectorConstraints;
m_CastellatedPads = source_stackup.m_CastellatedPads;
m_EdgePlating = source_stackup.m_EdgePlating;
m_FinishType = source_stackup.m_FinishType;
}
void BOARD_STACKUP::FormatBoardStackup( OUTPUTFORMATTER* aFormatter,
BOARD* aBoard, int aNestLevel ) const
{
// Board stackup is the ordered list from top to bottom of
// physical layers and substrate used to build the board.
if( m_list.empty() )
return;
aFormatter->Print( aNestLevel, "(board_stackup\n" );
int nest_level = aNestLevel+1;
for( BOARD_STACKUP_ITEM* item: m_list )
{
wxString layer_name;
if( item->m_LayerId == UNDEFINED_LAYER )
{
layer_name.Printf( "dielectric %d", item->m_DielectricLayerId );
}
else
layer_name = aBoard->GetLayerName( item->m_LayerId );
aFormatter->Print( nest_level, "(layer %s (type %s)",
aFormatter->Quotew( layer_name ).c_str(),
aFormatter->Quotew( item->m_TypeName ).c_str() );
if( item->IsThicknessEditable() )
aFormatter->Print( 0, " (thickness %s)",
FormatInternalUnits( (int)item->m_Thickness ).c_str() );
if( item->m_Type == BS_ITEM_TYPE_DIELECTRIC )
aFormatter->Print( 0, " (material %s)",
aFormatter->Quotew( item->m_Material ).c_str() );
if( item->HasEpsilonRValue() )
aFormatter->Print( 0, " (epsilon_r %g)", item->m_EpsilonR );
if( item->HasLossTangentValue() )
aFormatter->Print( 0, " (loss %s)",
Double2Str(item->m_LossTangent ).c_str() );
if( item->IsColorEditable() && !item->m_Color.IsEmpty()
&& item->m_Color != NOT_SPECIFIED )
aFormatter->Print( 0, " (color %s)",
aFormatter->Quotew( item->m_Color ).c_str() );
aFormatter->Print( 0, ")\n" );
}
// Other infos about board, related to layers and other fabrication specifications
if( !m_FinishType.IsEmpty() && m_FinishType != NOT_SPECIFIED )
aFormatter->Print( nest_level, "(copper_finish %s)\n",
aFormatter->Quotew( m_FinishType ).c_str() );
aFormatter->Print( nest_level, "(dielectric_constrains %s)\n",
m_HasDielectricConstrains ? "yes" : "no" );
if( m_EdgeConnectorConstraints > 0 )
aFormatter->Print( nest_level, "(edge_connector %s)\n",
m_EdgeConnectorConstraints > 1 ? "bevelled": "yes" );
if( m_CastellatedPads )
aFormatter->Print( nest_level, "(castellated_pads yes)\n" );
if( m_EdgePlating )
aFormatter->Print( nest_level, "(edge_plating yes)\n" );
aFormatter->Print( aNestLevel, ")\n" );
}

View File

@ -0,0 +1,191 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2019 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/>.
*/
/**
* @file class_board_stackup.h
*/
#ifndef CLASS_BOARD_STACKUP_H
#define CLASS_BOARD_STACKUP_H
#include <vector>
#include <wx/string.h>
#include <layers_id_colors_and_visibility.h>
class BOARD_DESIGN_SETTINGS;
class OUTPUTFORMATTER;
// A enum to manage the different layers inside the stackup layers.
// Note the stackup layers include both dielectric and some layers handled by the board editor
// Therfore a stackup layer item is not exactely like a board layer
enum BOARD_STACKUP_ITEM_TYPE
{
BS_ITEM_TYPE_UNDEFINED, // For not yet initialized BOARD_STACKUP_ITEM item
BS_ITEM_TYPE_COPPER, // A initialized BOARD_STACKUP_ITEM item for copper layers
BS_ITEM_TYPE_DIELECTRIC, // A initialized BOARD_STACKUP_ITEM item for the
// dielectric between copper layers
BS_ITEM_TYPE_SOLDERPASTE, // A initialized BOARD_STACKUP_ITEM item for solder paste layers
BS_ITEM_TYPE_SOLDERMASK, // A initialized BOARD_STACKUP_ITEM item for solder mask layers
BS_ITEM_TYPE_SILKSCREEN, // A initialized BOARD_STACKUP_ITEM item for silkscreen layers
};
// A enum to manage edge connector fab info
enum BS_EDGE_CONNECTOR_CONSTRAINTS
{
BS_EDGE_CONNECTOR_NONE, // No edge connector in board
BS_EDGE_CONNECTOR_IN_USE, // some edge connector in board
BS_EDGE_CONNECTOR_BEVELLED // Some connector in board, and the connector must be bevelled
};
/**
* this class manage one layer needed to make a physical board
* it can be a solder mask, silk screen, copper or a dielectric
*/
class BOARD_STACKUP_ITEM
{
public:
BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType );
BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM& aOther );
BOARD_STACKUP_ITEM_TYPE m_Type;
wxString m_TypeName; /// type name of layer (copper, silk screen, core, prepreg ...)
wxString m_Material; /// type of material (has meaning only for dielectric
int m_DielectricLayerId;/// the "layer" id for dielectric layers, from 1 (top) to 32 (bottom)
wxString m_Color; /// mainly for silkscreen and solder mask
int m_Thickness; /// the physical layer thickness in internal units
double m_EpsilonR; /// For dielectric (and solder mask) the dielectric constant
double m_LossTangent; /// For dielectric (and solder mask) the dielectric loss
PCB_LAYER_ID m_LayerId; /// the layer id (F.Cu to B.Cu, F.Silk, B.silk, F.Mask, B.Mask)
/// and UNDEFINED_LAYER (-1) for dielectic layers that are not
/// really layers for the board editor
/// @return true if the layer has a meaningfull Epsilon R parameter
/// namely dielectric layers: dielectric and solder mask
bool HasEpsilonRValue();
/// @return true if the layer has a meaningfull Dielectric Loss parameter
/// namely dielectric layers: dielectric and solder mask
bool HasLossTangentValue();
/// @return true if the material is editable
bool IsMaterialEditable();
/// @return true if the color is editable
bool IsColorEditable();
/// @return true if Thickness is editable
bool IsThicknessEditable();
};
/**
* this class manage the layers needed to make a physical board
* they are solder mask, silk screen, copper and dielectric
* Some other layers, used in fabrication, are not managed here because they
* are not used to make a physical board itself
* Note also there are a few other parameters realed to the physical stackup,
* like finish type, impedance control and a few others
*/
class BOARD_STACKUP
{
// The list of items describing the stackup for fabrication.
// this is not just copper layers, but also mask dielectric layers
std::vector<BOARD_STACKUP_ITEM*> m_list;
public:
/** The name of external copper finish
*/
wxString m_FinishType;
/** True if some layers have impedance controlled tracks or have specific
* constrains for micro-wave applications
* If the board has dielectric constrains, the .gbrjob will contain
* info about dielectric constrains: loss tangent and Epsilon rel.
* If not, these values will be not specified in job file.
*/
bool m_HasDielectricConstrains;
/** True if some layers (copper and/or dielectric) have specific thickness
*/
bool m_HasThicknessConstrains;
/** If the board has edge connector cards, some constrains can be specifed
* in job file:
* BS_EDGE_CONNECTOR_NONE = no edge connector
* BS_EDGE_CONNECTOR_IN_USE = board has edge connectors
* BS_EDGE_CONNECTOR_BEVELLED = edge connectors are bevelled
*/
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints;
bool m_CastellatedPads; ///< True if castellated pads exist
bool m_EdgePlating; ///< True if the edge board is plated
public:
BOARD_STACKUP();
BOARD_STACKUP( BOARD_STACKUP& aOther );
BOARD_STACKUP& operator=( const BOARD_STACKUP& aOther );
~BOARD_STACKUP() { RemoveAll(); }
std::vector<BOARD_STACKUP_ITEM*>& GetList() { return m_list; }
/// @return a reference to the layer aIndex, or nullptr if not exists
BOARD_STACKUP_ITEM* GetStackupLayer( int aIndex );
/// Delete all items in list and clear the list
void RemoveAll();
/// @return the number of layers in the stackup
int GetCount() { return (int) m_list.size(); }
/// @return the board thickness ( in UI) from the thickness of BOARD_STACKUP_ITEM list
int BuildBoardTicknessFromStackup() const;
/// Add a new item in stackup layer
void Add( BOARD_STACKUP_ITEM* aItem ) { m_list.push_back( aItem ); }
/**
* Synchronize the BOARD_STACKUP_ITEM* list with the board.
* Not enabled layers are removed
* Missing layers are added
* @param aSettings, is the current board setting.
* @return true if changes are made
*/
bool SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings );
/**
* Creates a default stackup, according to the current BOARD_DESIGN_SETTINGS settings.
* @param aSettings is the current board setting.
*/
void BuildDefaultStackupList( BOARD_DESIGN_SETTINGS* aSettings );
/**
* Writes the stackup info on board file
* @param aFormatter is the OUTPUTFORMATTER used to create the file
* @param aBoard is the board
* @param aNestLevel is the index to nest level to indent the lines in file
*/
void FormatBoardStackup( OUTPUTFORMATTER* aFormatter,
BOARD* aBoard, int aNestLevel ) const;
};
#endif // #ifndef CLASS_BOARD_STACKUP_H

View File

@ -0,0 +1,115 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2019 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file stackup_predefined_prms.cpp
*/
#include "class_board_stackup.h"
#include <convert_to_biu.h>
#include <layers_id_colors_and_visibility.h>
#include <board_design_settings.h>
#include <i18n_utility.h> // _HKI definition
#include "stackup_predefined_prms.h"
// A list of copper finish standard type names
// They are standard names in .gbdjob files, so avoid changing them or
// ensure they are compatible with .gbrjob file spec.
static wxString CopperFinishType[] =
{
_HKI( NOT_SPECIFIED ), // Not specified, not in .gbrjob file
_HKI("ENIG"), // used in .gbrjob file
_HKI("ENEPIG"), // used in .gbrjob file
_HKI("HAL SnPb"), // used in .gbrjob file
_HKI("HAL lead-free"), // used in .gbrjob file
_HKI("Hard gold"), // used in .gbrjob file
_HKI("Immersion tin"), // used in .gbrjob file
_HKI("Immersion nickel"), // used in .gbrjob file
_HKI("Immersion silver"), // used in .gbrjob file
_HKI("Immersion gold"), // used in .gbrjob file
_HKI("HT_OSP"), // used in .gbrjob file
_HKI("OSP"), // used in .gbrjob file
_HKI("None"), // used in .gbrjob file
_HKI("User defined") // keep this option at end
};
// A list of available colors for solder mask and silkscreen
// These names are used in .gbrjob file, so they are not fully free.
// Use only what is allowed in .gbrjob files.
static FAB_LAYER_COLOR solderMaskColors[] =
{
{ _HKI( NOT_SPECIFIED ), wxColor( 0, 128, 0 ) }, // Not specified, not in .gbrjob file
{ _HKI( "Green" ), wxColor( 0, 128, 0 ) }, // used in .gbrjob file
{ _HKI( "Red" ), wxColor( 128, 0, 0 ) }, // used in .gbrjob file
{ _HKI( "Blue" ), wxColor( 0, 0, 128 ) }, // used in .gbrjob file
{ _HKI( "Black" ), wxColor( 20, 20, 20 ) }, // used in .gbrjob file
{ _HKI( "White" ), wxColor( 200, 200, 200 ) }, // used in .gbrjob file
{ _HKI( "Yellow" ), wxColor( 128, 128, 0 ) }, // used in .gbrjob file
{ _HKI( "Purple" ), wxColor( 100, 0, 100 ) }, // used in .gbrjob file
{ _HKI( "user defined" ), wxColor( 128, 128, 128 ) }, //free
{ "", wxColor( 0, 0, 0 ) } // Sentinel
};
// A list of available substrate material
// These names are used in .gbrjob file, so they are not fully free.
// Use only what is allowed in .gbrjob files.
static FAB_SUBSTRATE substrateMaterial[] =
{
{ _HKI( NOT_SPECIFIED ), 0.0, 0.0 }, // Not specified, not in .gbrjob file
{ _HKI( "FR4" ), 4.5, 0.02 }, // used in .gbrjob file
{ _HKI( "Polyimide" ), 1.0, 0.0 }, // used in .gbrjob file
{ _HKI( "Polyolefin" ), 1.0, 0.0 }, // used in .gbrjob file
{ _HKI( "Al" ), 8.7, 0.001 }, // used in .gbrjob file
{ _HKI( "PTFE" ), 2.1, 0.0002 }, // used in .gbrjob file
{ _HKI( "Teflon" ), 2.1, 0.0002 }, // used in .gbrjob file
{ _HKI( "Ceramic" ), 1.0, 0.0 }, // used in .gbrjob file
{ _HKI( "user defined" ), 1.0, 0.0 }, // Free
{ "", 0.0, 0.0 } // Sentinel
};
wxArrayString GetCopperFinishStandardList( bool aTranslate )
{
wxArrayString list;
for( unsigned ii = 0; ii < arrayDim( CopperFinishType ); ii++ )
list.Add( aTranslate ? wxGetTranslation( CopperFinishType[ii] ) : CopperFinishType[ii] );
return list;
}
const FAB_LAYER_COLOR* GetColorStandardList()
{
return solderMaskColors;
}
const FAB_SUBSTRATE* GetSubstrateMaterialStandardList()
{
return substrateMaterial;
}

View File

@ -0,0 +1,77 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2019 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file stackup_predefined_prms.h
*/
#ifndef STACKUP_PREDEFINED_PRMS_H
#define STACKUP_PREDEFINED_PRMS_H
#include <wx/string.h>
#include <layers_id_colors_and_visibility.h>
// Keyword used in file to identify the dielectric layer type
#define KEY_CORE "core"
#define KEY_PREPREG "prepreg"
// key string used for not specified parameters
#define NOT_SPECIFIED "Undefined"
// A minor struct to handle color in gerber job file and dialog
struct FAB_LAYER_COLOR
{
wxString m_ColorName; // the name (in job file) of the color
wxColor m_Color; // the color in r,g,b values (0..255)
};
// A minor struct to handle substrates prms in gerber job file and dialog
struct FAB_SUBSTRATE
{
wxString m_Name; // the name (in job file) of material
double m_EpsilonR; // the epsilon r of this material
double m_Loss; // the loss (tanD) of this material
};
/**
* @return a wxArray of standard copper finish names.
* @param aTranslate = false for the initial names, true for translated names
*/
wxArrayString GetCopperFinishStandardList( bool aTranslate );
/**
* @return a list of standard FAB_LAYER_COLOR items for silkscreen and solder mask.
*/
const FAB_LAYER_COLOR* GetColorStandardList();
/**
* @return a list of standard material items for dielectric.
*/
const FAB_SUBSTRATE* GetSubstrateMaterialStandardList();
#endif // #ifndef STACKUP_PREDEFINED_PRMS_H

View File

@ -111,11 +111,8 @@ struct LAYER
*/
wxString m_name; ///< The name of the layer, there should be no spaces in this name.
LAYER_T m_type; ///< The type of the layer
bool m_visible;
int m_number;
/**

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean_Pierre Charras <jp.charras at wanadoo.fr>
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2019 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
@ -45,6 +45,7 @@
#include <wildcards_and_files_ext.h>
#include <reporter.h>
#include <gbr_metadata.h>
#include <board_stackup_manager/stackup_predefined_prms.h>
GERBER_JOBFILE_WRITER::GERBER_JOBFILE_WRITER( BOARD* aPcb, REPORTER* aReporter )
@ -280,6 +281,29 @@ void GERBER_JOBFILE_WRITER::addJSONGeneralSpecs()
addJSONObject( wxString::Format( "\"BoardThickness\": %.3f,\n",
m_pcb->GetDesignSettings().GetBoardThickness()*m_conversionUnits ) );
// Copper finish
BOARD_STACKUP brd_stackup = m_pcb->GetDesignSettings().GetStackupDescriptor();
if( !brd_stackup.m_FinishType.IsEmpty() )
addJSONObject( wxString::Format( "\"Finish\": \"%s\",\n", brd_stackup.m_FinishType ) );
if( brd_stackup.m_CastellatedPads )
addJSONObject( "\"Castellated\": \"true\",\n" );
if( brd_stackup.m_EdgePlating )
addJSONObject( "\"EdgePlating\": \"true\",\n" );
if( brd_stackup.m_EdgeConnectorConstraints )
{
addJSONObject( "\"EdgeConnector\": \"true\",\n" );
if( brd_stackup.m_EdgeConnectorConstraints == BS_EDGE_CONNECTOR_BEVELLED )
addJSONObject( "\"EdgeConnectorBevelled\": \"true\",\n" );
else
addJSONObject( "\"EdgeConnectorBevelled\": \"false\",\n" );
}
#if 0 // Not yet in use
/* The board type according to IPC-2221. There are six primary board types:
- Type 1 - Single-sided
@ -555,126 +579,108 @@ void GERBER_JOBFILE_WRITER::addJSONMaterialStackup()
addJSONObject( "\"MaterialStackup\":\n" );
openArrayBlock();
// Build the candidates: only layers on a board are candidates:
// Build the candidates list:
LSET maskLayer;
BOARD_STACKUP brd_stackup = m_pcb->GetDesignSettings().GetStackupDescriptor();
for( unsigned ii = 0; ii < m_params.m_GerberFileList.GetCount(); ii ++ )
{
PCB_LAYER_ID layer = m_params.m_LayerId[ii];
// Ensure brd_stackup is up to date (i.e. no change made by SynchronizeWithBoard() )
bool uptodate = not brd_stackup.SynchronizeWithBoard( &m_pcb->GetDesignSettings() );
if( layer <= B_Cu )
maskLayer.set( layer );
else
{
switch( layer )
{
case B_Paste:
case F_Paste:
case B_SilkS:
case F_SilkS:
case B_Mask:
case F_Mask:
maskLayer.set( layer );
break;
if( !uptodate && m_pcb->GetDesignSettings().m_HasStackup )
m_reporter->Report( _( "Board stackup settings not up to date\n"
"Please fix the stackup" ), REPORTER::RPT_ERROR );
case Edge_Cuts:
case B_Adhes:
case F_Adhes:
case B_Fab:
case F_Fab:
case Dwgs_User:
case Cmts_User:
case Eco1_User:
case Eco2_User:
case Margin:
case B_CrtYd:
case F_CrtYd:
break;
PCB_LAYER_ID last_copper_layer = F_Cu;
default:
m_reporter->Report(
wxString::Format( "Unexpected layer id %d in job file", layer ),
REPORTER::RPT_ERROR );
break;
}
}
}
// build a candidate list (in reverse order: bottom to top):
LSEQ list = maskLayer.SeqStackupBottom2Top();
// Generate the list (top to bottom):
for( int ii = list.size()-1; ii >= 0; --ii )
for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
{
PCB_LAYER_ID layer = list[ii];
BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( ii );
double thickness = item->m_Thickness*m_conversionUnits; // layer thickness is always in mm
wxString layer_type;
wxString color;
wxString dielectric;
double thickness = 0.0; // layer thickness in mm
std::string layer_name; // for comment
if( layer <= B_Cu )
switch( item->m_Type )
{
case BS_ITEM_TYPE_COPPER:
layer_type = "Copper";
//thickness = 0.035;
}
else
{
switch( layer )
{
case B_Paste:
case F_Paste:
layer_type = "SolderPaste";
break;
layer_name = formatStringToGerber( m_pcb->GetLayerName( item->m_LayerId ) );
last_copper_layer = item->m_LayerId;
break;
case B_SilkS:
case F_SilkS:
//color = "White";
layer_type = "Legend";
break;
case BS_ITEM_TYPE_SILKSCREEN:
layer_type = "Legend";
layer_name = formatStringToGerber( item->m_TypeName );
break;
case B_Mask:
case F_Mask:
//color = "Green";
//thickness = 0.025;
layer_type = "SolderMask";
break;
case BS_ITEM_TYPE_SOLDERMASK:
layer_type = "SolderMask";
layer_name = formatStringToGerber( item->m_TypeName );
break;
default:
break;
}
case BS_ITEM_TYPE_SOLDERPASTE:
layer_type = "SolderPaste";
layer_name = formatStringToGerber( item->m_TypeName );
break;
case BS_ITEM_TYPE_DIELECTRIC:
layer_type = "Dielectric";
layer_name = formatStringToGerber( wxString::Format( "dielectric layer %d (%s)",
item->m_DielectricLayerId, item->m_TypeName ) );
break;
default:
break;
}
openBlock();
addJSONObject( wxString::Format( "\"Type\": \"%s\",\n", layer_type ) );
if( !color.IsEmpty() )
addJSONObject( wxString::Format( "\"Color\": \"%s\",\n", color ) );
if( item->IsColorEditable() && uptodate )
{
if( !item->m_Color.IsEmpty() && item->m_Color != NOT_SPECIFIED )
addJSONObject( wxString::Format( "\"Color\": \"%s\",\n", item->m_Color ) );
}
if( thickness > 0.0 )
addJSONObject( wxString::Format( "\"Thickness\": %f,\n", thickness ) );
if( item->IsThicknessEditable() && uptodate )
addJSONObject( wxString::Format( "\"Thickness\": %.3f,\n", thickness ) );
if( item->m_Type == BS_ITEM_TYPE_DIELECTRIC )
{
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->m_Material ) );
// These constrains are only written if the board has impedance controlled tracks.
// If the board is not impedance controlled, they are useless.
// Do not add constrains that create more expensive boards.
if( brd_stackup.m_HasDielectricConstrains )
{
addJSONObject( wxString::Format( "\"DielectricConstant\": %.1f,\n", item->m_EpsilonR ) );
addJSONObject( wxString::Format( "\"LossTangent\": %f,\n", item->m_LossTangent ) );
}
PCB_LAYER_ID next_copper_layer = (PCB_LAYER_ID) (last_copper_layer+1);
// If the next_copper_layer is the last copper layer, the next layer id is B_Cu
if( next_copper_layer >= m_pcb->GetCopperLayerCount()-1 )
next_copper_layer = B_Cu;
// Add a comment ("Notes"):
wxString note = "\"Notes\": ";
if( uptodate ) // We can add the dielectric variant ("core" "prepreg" ...):
note << wxString::Format( " \"Type: %s", layer_name.c_str() );
note << wxString::Format( " (from %s to %s)\"\n",
formatStringToGerber( m_pcb->GetLayerName( last_copper_layer ) ),
formatStringToGerber( m_pcb->GetLayerName( next_copper_layer ) ) );
addJSONObject( note );
}
else
addJSONObject( wxString::Format( "\"Notes\": \"Layer: %s\",\n", layer_name.c_str() ) );
std::string strname = formatStringToGerber( m_pcb->GetLayerName( layer ) );
addJSONObject( wxString::Format( "\"Notes\": \"Layer %s\",\n", strname.c_str() ) );
removeJSONSepararator();
closeBlockWithSep();
if( layer < B_Cu ) // Add dielectric between copper layers
{
dielectric = "FR4"; // Temporary
openBlock();
addJSONObject( wxString::Format( "\"Type\": \"%s\",\n", "Dielectric" ) );
if( thickness > 0.0 )
addJSONObject( wxString::Format( "\"Thickness\": %f,\n", color ) );
if( !dielectric.IsEmpty() )
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", dielectric ) );
addJSONObject( wxString::Format( "\"Notes\": \"Layers L%d/L%d\",\n",
layer+1, layer+2 ) );
removeJSONSepararator();
closeBlockWithSep();
}
}
removeJSONSepararator();