ADD: layer stack manager: support of multilayer dielectric between 2 copper layers
This feature is useful for advanced microwave applications. This is the last missing feature in the board stackup management.
This commit is contained in:
parent
39ef514ff9
commit
544867cf2a
|
@ -25,6 +25,7 @@
|
|||
# These are the keywords for the Pcbnew s-expression file format.
|
||||
|
||||
add_net
|
||||
addsublayer
|
||||
allowed
|
||||
anchor
|
||||
angle
|
||||
|
|
|
@ -42,58 +42,76 @@ wxString BuildStackupReport( BOARD_STACKUP& aStackup, EDA_UNITS_T aUnits )
|
|||
wxString report;
|
||||
|
||||
wxString txt;
|
||||
int row = 0;
|
||||
LOCALE_IO toggle; // toggles on the C locale to write floating values, then off.
|
||||
|
||||
for( const auto item : aStackup.GetList() )
|
||||
for( const BOARD_STACKUP_ITEM* item : aStackup.GetList() )
|
||||
{
|
||||
// Skip stackup items useless for the current board
|
||||
if( !item->IsEnabled() )
|
||||
{
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
|
||||
txt.Printf( "layer \"%s\" type \"%s\"", item->GetLayerName(), item->GetTypeName() );
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
||||
{
|
||||
wxString sublayer_text;
|
||||
|
||||
if( item->GetSublayersCount() )
|
||||
sublayer_text.Printf( "\n sublayer \"1/%d\"", item->GetSublayersCount() );
|
||||
|
||||
txt.Printf( "layer \"%s\" type \"%s\"%s",
|
||||
item->FormatDielectricLayerName(),
|
||||
item->GetTypeName(), sublayer_text );
|
||||
}
|
||||
else
|
||||
txt.Printf( "layer \"%s\" type \"%s\"", item->GetLayerName(),
|
||||
item->GetTypeName() );
|
||||
|
||||
report << txt;
|
||||
|
||||
if( item->IsMaterialEditable() )
|
||||
{
|
||||
txt.Printf( " Material \"%s\"", item->GetMaterial() );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->HasEpsilonRValue() )
|
||||
{
|
||||
txt.Printf( " EpsilonR %s", item->FormatEpsilonR() );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->HasLossTangentValue() )
|
||||
{
|
||||
txt.Printf( " LossTg %s", item->FormatLossTangent() );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->IsThicknessEditable() )
|
||||
{
|
||||
txt.Printf( " Thickness %s",
|
||||
StringFromValue( aUnits, item->GetThickness(), true, true ) );
|
||||
report << txt;
|
||||
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked() )
|
||||
{
|
||||
txt.Printf( " Locked" );
|
||||
report << txt;
|
||||
}
|
||||
}
|
||||
|
||||
if( item->IsColorEditable() )
|
||||
{
|
||||
txt.Printf( " Color \"%s\"", item->GetColor() );
|
||||
report << txt;
|
||||
}
|
||||
row++;
|
||||
|
||||
for( int idx = 0; idx < item->GetSublayersCount(); idx++ )
|
||||
{
|
||||
if( idx ) // not printed for the main (first) layer.
|
||||
{
|
||||
txt.Printf( "\n sublayer \"%d/%d\"", idx+1, item->GetSublayersCount() );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->IsThicknessEditable() )
|
||||
{
|
||||
txt.Printf( " Thickness %s",
|
||||
StringFromValue( aUnits, item->GetThickness( idx ), true, true ) );
|
||||
report << txt;
|
||||
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked( idx ) )
|
||||
{
|
||||
txt.Printf( " Locked" );
|
||||
report << txt;
|
||||
}
|
||||
}
|
||||
|
||||
if( item->IsMaterialEditable() )
|
||||
{
|
||||
txt.Printf( " Material \"%s\"", item->GetMaterial( idx ) );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->HasEpsilonRValue() )
|
||||
{
|
||||
txt.Printf( " EpsilonR %s", item->FormatEpsilonR( idx ) );
|
||||
report << txt;
|
||||
}
|
||||
|
||||
if( item->HasLossTangentValue() )
|
||||
{
|
||||
txt.Printf( " LossTg %s", item->FormatLossTangent( idx ) );
|
||||
report << txt;
|
||||
}
|
||||
}
|
||||
|
||||
report << '\n';
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType )
|
|||
m_DielectricPrmsList.emplace_back( item_prms );
|
||||
m_LayerId = UNDEFINED_LAYER;
|
||||
m_Type = aType;
|
||||
SetDielectricLayerId( 1 );
|
||||
SetEnabled( true );
|
||||
|
||||
// Initialize parameters to a usual value for allowed types:
|
||||
|
@ -48,7 +49,6 @@ BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType )
|
|||
case BS_ITEM_TYPE_DIELECTRIC:
|
||||
m_TypeName = KEY_CORE; // or prepreg
|
||||
SetMaterial( "FR4" ); // or other dielectric name
|
||||
SetDielectricLayerId( 1 );
|
||||
SetLossTangent( 0.02 ); // for FR4
|
||||
SetEpsilonR( 4.5 ); // for FR4
|
||||
break;
|
||||
|
@ -81,6 +81,7 @@ BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType )
|
|||
BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM& aOther )
|
||||
{
|
||||
m_LayerId = aOther.m_LayerId;
|
||||
m_DielectricLayerId = aOther.m_DielectricLayerId;
|
||||
m_Type = aOther.m_Type;
|
||||
m_enabled = aOther.m_enabled;
|
||||
m_DielectricPrmsList = aOther.m_DielectricPrmsList;
|
||||
|
@ -90,6 +91,28 @@ BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM& aOther )
|
|||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::AddDielectricPrms( int aDielectricPrmsIdx )
|
||||
{
|
||||
// add a DIELECTRIC_PRMS item to m_DielectricPrmsList
|
||||
DIELECTRIC_PRMS new_prms;
|
||||
|
||||
m_DielectricPrmsList.emplace( m_DielectricPrmsList.begin() + aDielectricPrmsIdx,
|
||||
new_prms );
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::RemoveDielectricPrms( int aDielectricPrmsIdx )
|
||||
{
|
||||
// Remove a DIELECTRIC_PRMS item from m_DielectricPrmsList if possible
|
||||
|
||||
if( GetSublayersCount() < 2 || aDielectricPrmsIdx < 0 || aDielectricPrmsIdx >= GetSublayersCount() )
|
||||
return;
|
||||
|
||||
m_DielectricPrmsList.erase( m_DielectricPrmsList.begin() + aDielectricPrmsIdx );
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BOARD_STACKUP_ITEM::GetCopperDefaultThickness()
|
||||
{
|
||||
// A reasonable thickness for copper layers:
|
||||
|
@ -104,38 +127,42 @@ int BOARD_STACKUP_ITEM::GetMaskDefaultThickness()
|
|||
}
|
||||
|
||||
// Getters:
|
||||
int BOARD_STACKUP_ITEM::GetThickness( int aDielectricSubLayer )
|
||||
int BOARD_STACKUP_ITEM::GetThickness( int aDielectricSubLayer ) const
|
||||
{
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_Thickness;
|
||||
}
|
||||
|
||||
|
||||
double BOARD_STACKUP_ITEM::GetLossTangent( int aDielectricSubLayer )
|
||||
double BOARD_STACKUP_ITEM::GetLossTangent( int aDielectricSubLayer ) const
|
||||
{
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_LossTangent;
|
||||
}
|
||||
|
||||
|
||||
double BOARD_STACKUP_ITEM::GetEpsilonR( int aDielectricSubLayer )
|
||||
double BOARD_STACKUP_ITEM::GetEpsilonR( int aDielectricSubLayer ) const
|
||||
{
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_EpsilonR;
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::IsThicknessLocked( int aDielectricSubLayer )
|
||||
bool BOARD_STACKUP_ITEM::IsThicknessLocked( int aDielectricSubLayer ) const
|
||||
{
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_ThicknessLocked;
|
||||
}
|
||||
|
||||
|
||||
int BOARD_STACKUP_ITEM::GetDielectricLayerId( int aDielectricSubLayer )
|
||||
wxString BOARD_STACKUP_ITEM::GetMaterial( int aDielectricSubLayer ) const
|
||||
{
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_DielectricLayerId;
|
||||
}
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
|
||||
wxString BOARD_STACKUP_ITEM::GetMaterial( int aDielectricSubLayer )
|
||||
{
|
||||
return m_DielectricPrmsList[aDielectricSubLayer].m_Material;
|
||||
}
|
||||
|
||||
|
@ -143,41 +170,50 @@ wxString BOARD_STACKUP_ITEM::GetMaterial( int aDielectricSubLayer )
|
|||
// Setters:
|
||||
void BOARD_STACKUP_ITEM::SetThickness( int aThickness, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_Thickness = aThickness;
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_Thickness = aThickness;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::SetLossTangent( double aTg, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_LossTangent = aTg;
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_LossTangent = aTg;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::SetEpsilonR( double aEpsilon, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_EpsilonR = aEpsilon;
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_EpsilonR = aEpsilon;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::SetThicknessLocked( bool aLocked, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_ThicknessLocked = aLocked;
|
||||
}
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::SetDielectricLayerId( int aLayerId, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_DielectricLayerId = aLayerId;
|
||||
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_ThicknessLocked = aLocked;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_STACKUP_ITEM::SetMaterial( const wxString& aName, int aDielectricSubLayer )
|
||||
{
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_Material = aName;
|
||||
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||
|
||||
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||
m_DielectricPrmsList[aDielectricSubLayer].m_Material = aName;
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::HasEpsilonRValue()
|
||||
bool BOARD_STACKUP_ITEM::HasEpsilonRValue() const
|
||||
{
|
||||
return m_Type == BS_ITEM_TYPE_DIELECTRIC
|
||||
|| m_Type == BS_ITEM_TYPE_SOLDERMASK
|
||||
|
@ -186,23 +222,21 @@ bool BOARD_STACKUP_ITEM::HasEpsilonRValue()
|
|||
};
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::HasLossTangentValue()
|
||||
bool BOARD_STACKUP_ITEM::HasLossTangentValue() const
|
||||
{
|
||||
return m_Type == BS_ITEM_TYPE_DIELECTRIC
|
||||
|| m_Type == BS_ITEM_TYPE_SOLDERMASK
|
||||
//|| m_Type == BS_ITEM_TYPE_SILKSCREEN
|
||||
;
|
||||
|| m_Type == BS_ITEM_TYPE_SOLDERMASK;
|
||||
};
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::HasMaterialValue()
|
||||
bool BOARD_STACKUP_ITEM::HasMaterialValue( int aDielectricSubLayer ) const
|
||||
{
|
||||
// return true if the material is specified
|
||||
return IsMaterialEditable() && IsPrmSpecified( GetMaterial() );
|
||||
return IsMaterialEditable() && IsPrmSpecified( GetMaterial( aDielectricSubLayer ) );
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::IsMaterialEditable()
|
||||
bool BOARD_STACKUP_ITEM::IsMaterialEditable() const
|
||||
{
|
||||
// The material is editable only for dielectric
|
||||
return m_Type == BS_ITEM_TYPE_DIELECTRIC ||
|
||||
|
@ -211,13 +245,13 @@ bool BOARD_STACKUP_ITEM::IsMaterialEditable()
|
|||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::IsColorEditable()
|
||||
bool BOARD_STACKUP_ITEM::IsColorEditable() const
|
||||
{
|
||||
return m_Type == BS_ITEM_TYPE_SOLDERMASK || m_Type == BS_ITEM_TYPE_SILKSCREEN;
|
||||
}
|
||||
|
||||
|
||||
bool BOARD_STACKUP_ITEM::IsThicknessEditable()
|
||||
bool BOARD_STACKUP_ITEM::IsThicknessEditable() const
|
||||
{
|
||||
switch( m_Type )
|
||||
{
|
||||
|
@ -244,25 +278,25 @@ bool BOARD_STACKUP_ITEM::IsThicknessEditable()
|
|||
}
|
||||
|
||||
|
||||
wxString BOARD_STACKUP_ITEM::FormatEpsilonR()
|
||||
wxString BOARD_STACKUP_ITEM::FormatEpsilonR( int aDielectricSubLayer ) const
|
||||
{
|
||||
// return a wxString to print/display Epsilon R
|
||||
wxString txt;
|
||||
txt.Printf( "%.1f", GetEpsilonR() );
|
||||
txt.Printf( "%.1f", GetEpsilonR( aDielectricSubLayer ) );
|
||||
return txt;
|
||||
}
|
||||
|
||||
|
||||
wxString BOARD_STACKUP_ITEM::FormatLossTangent()
|
||||
wxString BOARD_STACKUP_ITEM::FormatLossTangent( int aDielectricSubLayer ) const
|
||||
{
|
||||
// return a wxString to print/display Loss Tangent
|
||||
wxString txt;
|
||||
txt.Printf( "%g", GetLossTangent() );
|
||||
txt.Printf( "%g", GetLossTangent( aDielectricSubLayer ) );
|
||||
return txt;
|
||||
}
|
||||
|
||||
|
||||
wxString BOARD_STACKUP_ITEM::FormatDielectricLayerName()
|
||||
wxString BOARD_STACKUP_ITEM::FormatDielectricLayerName() const
|
||||
{
|
||||
// return a wxString to print/display a dielectriv name
|
||||
wxString lname;
|
||||
|
@ -364,17 +398,31 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
|
|||
BOARD_STACKUP stackup;
|
||||
stackup.BuildDefaultStackupList( aSettings );
|
||||
|
||||
// First test for removed layers:
|
||||
for( BOARD_STACKUP_ITEM* old_item: m_list )
|
||||
// First, find removed layers:
|
||||
for( BOARD_STACKUP_ITEM* curr_item: m_list )
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for( BOARD_STACKUP_ITEM* item: stackup.GetList() )
|
||||
{
|
||||
if( item->GetBrdLayerId() == old_item->GetBrdLayerId() )
|
||||
if( curr_item->GetBrdLayerId() != UNDEFINED_LAYER )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
if( item->GetBrdLayerId() == curr_item->GetBrdLayerId() )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // curr_item = dielectric layer
|
||||
{
|
||||
if( item->GetBrdLayerId() != UNDEFINED_LAYER )
|
||||
continue;
|
||||
|
||||
if( item->GetDielectricLayerId() == curr_item->GetDielectricLayerId() )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,6 +451,10 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
|
|||
}
|
||||
else // dielectric layer: see m_DielectricLayerId for identification
|
||||
{
|
||||
// Compare dielectric layer with dielectric layer
|
||||
if( initial_item->GetBrdLayerId() != UNDEFINED_LAYER )
|
||||
continue;
|
||||
|
||||
if( item->GetDielectricLayerId() == initial_item->GetDielectricLayerId() )
|
||||
{
|
||||
*item = *initial_item;
|
||||
|
@ -413,7 +465,9 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
|
|||
}
|
||||
|
||||
if( !found )
|
||||
{
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer other stackup settings from aSettings
|
||||
|
@ -586,31 +640,40 @@ void BOARD_STACKUP::FormatBoardStackup( OUTPUTFORMATTER* aFormatter,
|
|||
aFormatter->Quotew( layer_name ).c_str(),
|
||||
aFormatter->Quotew( item->GetTypeName() ).c_str() );
|
||||
|
||||
if( item->IsThicknessEditable() )
|
||||
{
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked() )
|
||||
aFormatter->Print( 0, " (thickness %s locked)",
|
||||
FormatInternalUnits( item->GetThickness() ).c_str() );
|
||||
else
|
||||
aFormatter->Print( 0, " (thickness %s)",
|
||||
FormatInternalUnits( item->GetThickness() ).c_str() );
|
||||
}
|
||||
|
||||
if( item->HasMaterialValue() )
|
||||
aFormatter->Print( 0, " (material %s)",
|
||||
aFormatter->Quotew( item->GetMaterial() ).c_str() );
|
||||
|
||||
if( item->HasEpsilonRValue() && item->HasMaterialValue() )
|
||||
aFormatter->Print( 0, " (epsilon_r %g)", item->GetEpsilonR() );
|
||||
|
||||
if( item->HasLossTangentValue() && item->HasMaterialValue() )
|
||||
aFormatter->Print( 0, " (loss_tangent %s)",
|
||||
Double2Str(item->GetLossTangent() ).c_str() );
|
||||
|
||||
if( item->IsColorEditable() && IsPrmSpecified( item->GetColor() ) )
|
||||
aFormatter->Print( 0, " (color %s)",
|
||||
aFormatter->Quotew( item->GetColor() ).c_str() );
|
||||
|
||||
for( int idx = 0; idx < item->GetSublayersCount(); idx++ )
|
||||
{
|
||||
if( idx ) // not for the main (first) layer.
|
||||
{
|
||||
aFormatter->Print( 0, "\n" );
|
||||
aFormatter->Print( nest_level+1, "addsublayer" );
|
||||
}
|
||||
|
||||
if( item->IsThicknessEditable() )
|
||||
{
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked( idx ) )
|
||||
aFormatter->Print( 0, " (thickness %s locked)",
|
||||
FormatInternalUnits( item->GetThickness( idx ) ).c_str() );
|
||||
else
|
||||
aFormatter->Print( 0, " (thickness %s)",
|
||||
FormatInternalUnits( item->GetThickness( idx ) ).c_str() );
|
||||
}
|
||||
|
||||
if( item->HasMaterialValue( idx ) )
|
||||
aFormatter->Print( 0, " (material %s)",
|
||||
aFormatter->Quotew( item->GetMaterial( idx ) ).c_str() );
|
||||
|
||||
if( item->HasEpsilonRValue() && item->HasMaterialValue( idx ) )
|
||||
aFormatter->Print( 0, " (epsilon_r %g)", item->GetEpsilonR( idx ) );
|
||||
|
||||
if( item->HasLossTangentValue() && item->HasMaterialValue( idx ) )
|
||||
aFormatter->Print( 0, " (loss_tangent %s)",
|
||||
Double2Str(item->GetLossTangent( idx ) ).c_str() );
|
||||
}
|
||||
|
||||
aFormatter->Print( 0, ")\n" );
|
||||
}
|
||||
|
||||
|
|
|
@ -58,15 +58,13 @@ enum BS_EDGE_CONNECTOR_CONSTRAINTS
|
|||
|
||||
|
||||
/**
|
||||
* A helper class to manage a dielectric parameters
|
||||
* A helper class to manage a dielectric layer set of parameters
|
||||
*/
|
||||
class DIELECTRIC_PRMS
|
||||
{
|
||||
friend class BOARD_STACKUP_ITEM;
|
||||
|
||||
private:
|
||||
int m_DielectricLayerId;/// the "layer" id for dielectric layers,
|
||||
/// from 1 (top) to 31 (bottom)
|
||||
wxString m_Material; /// type of material (for dielectric and solder mask)
|
||||
int m_Thickness; /// the physical layer thickness in internal units
|
||||
bool m_ThicknessLocked; /// true for dielectric layers with a fixed thickness
|
||||
|
@ -76,7 +74,6 @@ private:
|
|||
|
||||
public:
|
||||
DIELECTRIC_PRMS() :
|
||||
m_DielectricLayerId(-1),
|
||||
m_Thickness(0), m_ThicknessLocked( false ),
|
||||
m_EpsilonR( 1.0 ), m_LossTangent( 0.0 )
|
||||
{}
|
||||
|
@ -102,6 +99,9 @@ private:
|
|||
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
|
||||
int m_DielectricLayerId;/// the "layer" id for dielectric layers,
|
||||
/// from 1 (top) to 31 (bottom)
|
||||
/// (only 31 dielectric layers for 32 copper layers)
|
||||
/// List of dielectric parameters
|
||||
/// usually only one item, but in complex (microwave) boards, one can have
|
||||
/// more than one dielectic layer between 2 copper layers, and therfore
|
||||
|
@ -112,25 +112,40 @@ private:
|
|||
/// false to ignore it. Mainly used in dialog stackup editor.
|
||||
|
||||
public:
|
||||
/**
|
||||
* add (insert) a DIELECTRIC_PRMS item to m_DielectricPrmsList
|
||||
* all values are set to default
|
||||
* @param aDielectricPrmsIdx is a index in m_DielectricPrmsList
|
||||
* the new item will be inserted at this position
|
||||
*/
|
||||
void AddDielectricPrms( int aDielectricPrmsIdx );
|
||||
|
||||
/**
|
||||
* Remove a DIELECTRIC_PRMS item from m_DielectricPrmsList
|
||||
* @param aDielectricPrmsIdx is the index of the parameters set
|
||||
* to remove in m_DielectricPrmsList
|
||||
*/
|
||||
void RemoveDielectricPrms( int aDielectricPrmsIdx );
|
||||
|
||||
/// @return true if the layer has a meaningfull Epsilon R parameter
|
||||
/// namely dielectric layers: dielectric and solder mask
|
||||
bool HasEpsilonRValue();
|
||||
bool HasEpsilonRValue() const;
|
||||
|
||||
/// @return true if the layer has a meaningfull Dielectric Loss parameter
|
||||
/// namely dielectric layers: dielectric and solder mask
|
||||
bool HasLossTangentValue();
|
||||
bool HasLossTangentValue() const;
|
||||
|
||||
/// @return true if the material is specified
|
||||
bool HasMaterialValue();
|
||||
bool HasMaterialValue( int aDielectricSubLayer = 0 ) const;
|
||||
|
||||
/// @return true if the material is editable
|
||||
bool IsMaterialEditable();
|
||||
bool IsMaterialEditable() const;
|
||||
|
||||
/// @return true if the color is editable
|
||||
bool IsColorEditable();
|
||||
bool IsColorEditable() const;
|
||||
|
||||
/// @return true if Thickness is editable
|
||||
bool IsThicknessEditable();
|
||||
bool IsThicknessEditable() const;
|
||||
|
||||
/// @return a reasonable default value for a copper layer thickness
|
||||
static int GetCopperDefaultThickness();
|
||||
|
@ -138,30 +153,34 @@ public:
|
|||
/// @return a reasonable default value for a solder mask layer thickness
|
||||
static int GetMaskDefaultThickness();
|
||||
|
||||
/// @return a the number of sublayers in a dielectric layer.
|
||||
/// the count is >= 1 (there is at least one layer)
|
||||
int GetSublayersCount() const { return m_DielectricPrmsList.size(); }
|
||||
|
||||
/// @return a wxString to print/display Epsilon R
|
||||
wxString FormatEpsilonR();
|
||||
wxString FormatEpsilonR( int aDielectricSubLayer = 0 ) const;
|
||||
|
||||
/// @return a wxString to print/display Loss Tangent
|
||||
wxString FormatLossTangent();
|
||||
wxString FormatLossTangent( int aDielectricSubLayer = 0 ) const;
|
||||
|
||||
/// @return a wxString to print/display a dielectric name
|
||||
wxString FormatDielectricLayerName();
|
||||
wxString FormatDielectricLayerName() const;
|
||||
|
||||
// Getters:
|
||||
bool IsEnabled() {return m_enabled; }
|
||||
bool IsEnabled() const {return m_enabled; }
|
||||
|
||||
BOARD_STACKUP_ITEM_TYPE GetType() { return m_Type; }
|
||||
PCB_LAYER_ID GetBrdLayerId() { return m_LayerId; }
|
||||
wxString GetColor(){ return m_Color; }
|
||||
wxString GetLayerName() { return m_LayerName; }
|
||||
wxString GetTypeName() { return m_TypeName; }
|
||||
BOARD_STACKUP_ITEM_TYPE GetType() const { return m_Type; }
|
||||
PCB_LAYER_ID GetBrdLayerId() const { return m_LayerId; }
|
||||
wxString GetColor() const { return m_Color; }
|
||||
wxString GetLayerName() const { return m_LayerName; }
|
||||
wxString GetTypeName() const { return m_TypeName; }
|
||||
int GetDielectricLayerId() const { return m_DielectricLayerId; }
|
||||
|
||||
int GetThickness( int aDielectricSubLayer = 0 );
|
||||
bool IsThicknessLocked( int aDielectricSubLayer = 0 );
|
||||
double GetEpsilonR( int aDielectricSubLayer = 0 );
|
||||
double GetLossTangent( int aDielectricSubLayer = 0 );
|
||||
int GetDielectricLayerId( int aDielectricSubLayer = 0 );
|
||||
wxString GetMaterial( int aDielectricSubLayer = 0 );
|
||||
int GetThickness( int aDielectricSubLayer = 0 ) const;
|
||||
bool IsThicknessLocked( int aDielectricSubLayer = 0 ) const;
|
||||
double GetEpsilonR( int aDielectricSubLayer = 0 ) const;
|
||||
double GetLossTangent( int aDielectricSubLayer = 0 ) const;
|
||||
wxString GetMaterial( int aDielectricSubLayer = 0 ) const;
|
||||
|
||||
// Setters:
|
||||
void SetEnabled( bool aEnable) { m_enabled = aEnable; }
|
||||
|
@ -169,12 +188,12 @@ public:
|
|||
void SetColor( const wxString& aColorName ){ m_Color = aColorName; }
|
||||
void SetLayerName( const wxString& aName ) { m_LayerName = aName; }
|
||||
void SetTypeName( const wxString& aName ) { m_TypeName = aName; }
|
||||
void SetDielectricLayerId( int aLayerId ) { m_DielectricLayerId = aLayerId; }
|
||||
|
||||
void SetThickness( int aThickness, int aDielectricSubLayer = 0 );
|
||||
void SetThicknessLocked( bool aLocked, int aDielectricSubLayer = 0 );
|
||||
void SetEpsilonR( double aEpsilon, int aDielectricSubLayer = 0 );
|
||||
void SetLossTangent( double aTg, int aDielectricSubLayer = 0 );
|
||||
void SetDielectricLayerId( int aLayerId, int aDielectricSubLayer = 0 );
|
||||
void SetMaterial( const wxString& aName, int aDielectricSubLayer = 0 );
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,6 +49,9 @@ class PANEL_SETUP_LAYERS;
|
|||
struct BOARD_STACKUP_ROW_UI_ITEM
|
||||
{
|
||||
BOARD_STACKUP_ITEM* m_Item; // The BOARD_STACKUP_ITEM managed by this BOARD_STACKUP_ROW_UI_ITEM
|
||||
int m_SubItem; // For multilayer dielectric, the index in sublayer list.
|
||||
// Must be >= 0 and < m_Item sublayer count. Used only for dielectic
|
||||
// 0 is the base list of parameters (always existing)
|
||||
bool m_isEnabled; // True if the row is in board
|
||||
// false if not (this row is not shown on the panel)
|
||||
wxStaticBitmap* m_Icon; // Color icon in first column (column 1)
|
||||
|
@ -62,8 +65,8 @@ struct BOARD_STACKUP_ROW_UI_ITEM
|
|||
wxControl* m_EpsilonCtrl; // control shown in column 8
|
||||
wxControl* m_LossTgCtrl; // control shown in column 9
|
||||
|
||||
BOARD_STACKUP_ROW_UI_ITEM( BOARD_STACKUP_ITEM* aItem ) :
|
||||
m_Item( aItem ),
|
||||
BOARD_STACKUP_ROW_UI_ITEM( BOARD_STACKUP_ITEM* aItem, int aSubItem = 1 ) :
|
||||
m_Item( aItem ), m_SubItem( aSubItem ),
|
||||
m_isEnabled( true ), m_Icon( nullptr ), m_LayerName( nullptr ),
|
||||
m_LayerTypeCtrl( nullptr ),
|
||||
m_MaterialCtrl( nullptr ),m_MaterialButt( nullptr ),
|
||||
|
@ -92,13 +95,16 @@ public:
|
|||
*/
|
||||
void OnLayersOptionsChanged( LSET aNewLayerSet );
|
||||
|
||||
BOARD_STACKUP_ITEM* GetStackupItem( int aIndex );
|
||||
/// @return the BOARD_STACKUP_ITEM managed by the row aRow
|
||||
BOARD_STACKUP_ITEM* GetStackupItem( int aRow );
|
||||
/// @return the BOARD_STACKUP_ITEM sublayermanaged by the row aRow
|
||||
int GetSublayerId( int aRow );
|
||||
|
||||
/// Return the color currently selected for the row aRow
|
||||
wxColor GetSelectedColor( int aRow ) const;
|
||||
|
||||
BOARD_STACKUP& GetStackup() { return m_stackup; }
|
||||
int GetPcbTickness();
|
||||
int GetPcbThickness();
|
||||
|
||||
// Called by wxWidgets: transfer current settings stored in m_stackup to the board
|
||||
bool TransferDataFromWindow() override;
|
||||
|
@ -106,6 +112,18 @@ public:
|
|||
std::vector<wxColor> m_UserColors; // the list of user colors for each grid row
|
||||
// other colors are defined colors, and are not stored
|
||||
private:
|
||||
/** Creates a BOARD_STACKUP_ROW_UI_ITEM relative to the aStackupItem.
|
||||
* @return a BOARD_STACKUP_ROW_UI_ITEM filled with corresponding widgets
|
||||
* @param aRow is the row index in the row list
|
||||
* @param aStackupItem is the stackup item controlled by the created
|
||||
* BOARD_STACKUP_ROW_UI_ITEM.
|
||||
* @param aSublayerIdx is used only for BS_ITEM_TYPE_DIELECTRIC stackup items.
|
||||
* this is the index of the sublayer to used inside aStackupItem
|
||||
* (from 0 to sub layer count - 1)
|
||||
*/
|
||||
BOARD_STACKUP_ROW_UI_ITEM createRowData( int aRow, BOARD_STACKUP_ITEM* aStackupItem,
|
||||
int aSublayerIdx );
|
||||
|
||||
/** add a Spacer in m_fgGridSizer when a empty cell is needed
|
||||
*/
|
||||
wxControl* addSpacer();
|
||||
|
@ -124,20 +142,31 @@ private:
|
|||
* all copper layers and all tech layers that are supported by the stackup
|
||||
* items not in the current board stackup will be not shown, but they are
|
||||
* existing in list
|
||||
* @param aCreatedInitialStackup = true to create a initial stackup list for the dialog
|
||||
* false to build the stackup panel from the existing stackup list.
|
||||
*/
|
||||
void buildLayerStackPanel();
|
||||
void buildLayerStackPanel( bool aCreatedInitialStackup );
|
||||
|
||||
/** Show or do not show items in m_fgGridSizer according to the stackup of the
|
||||
/** Synchronize the full stackup shown in m_fgGridSizer according to the stackup of the
|
||||
* current board and optionally update the stackup params (thickness, color ... )
|
||||
* @param aFullSync = true to update stackup params, false to only update the list
|
||||
* of shown items
|
||||
*/
|
||||
void synchronizeWithBoard( bool aFullSync );
|
||||
|
||||
/** Show or do not show items in m_fgGridSizer according to the stackup of the
|
||||
* current board.
|
||||
* The panel stackup stores all posible layers (because the number of layers is set
|
||||
* from an other panel), but only some of them must be actually shown on screen
|
||||
*/
|
||||
void showOnlyActiveLayers();
|
||||
|
||||
/** Populate m_fgGridSizer with items to handle stackup parameters
|
||||
* If previous items are in list, remove old items
|
||||
* New prms are added
|
||||
* must be called after adding or deleting a dielectric parameter set
|
||||
*/
|
||||
void RebuildLayerStackPanel();
|
||||
void rebuildLayerStackPanel();
|
||||
|
||||
/** Transfer current UI settings to m_stackup but not to the board
|
||||
*/
|
||||
|
|
|
@ -614,150 +614,173 @@ void GERBER_JOBFILE_WRITER::addJSONMaterialStackup()
|
|||
for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
|
||||
{
|
||||
BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( ii );
|
||||
double thickness = item->GetThickness()*m_conversionUnits; // layer thickness is always in mm
|
||||
wxString layer_type;
|
||||
std::string layer_name; // for comment
|
||||
|
||||
switch( item->GetType() )
|
||||
int sub_layer_count = item->GetType() == BS_ITEM_TYPE_DIELECTRIC
|
||||
? item->GetSublayersCount() : 1;
|
||||
|
||||
for( int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
|
||||
{
|
||||
case BS_ITEM_TYPE_COPPER:
|
||||
layer_type = "Copper";
|
||||
layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
|
||||
last_copper_layer = item->GetBrdLayerId();
|
||||
break;
|
||||
// layer thickness is always in mm
|
||||
double thickness = item->GetThickness( sub_idx )*m_conversionUnits;
|
||||
wxString layer_type;
|
||||
std::string layer_name; // for comment
|
||||
|
||||
case BS_ITEM_TYPE_SILKSCREEN:
|
||||
layer_type = "Legend";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_SOLDERMASK:
|
||||
layer_type = "SolderMask";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_SOLDERPASTE:
|
||||
layer_type = "SolderPaste";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_DIELECTRIC:
|
||||
layer_type = "Dielectric";
|
||||
// The option core or prepreg is not added here, as it creates constraints
|
||||
// in build process, not necessary wanted.
|
||||
layer_name = formatStringFromUTF32( wxString::Format( "dielectric layer %d",
|
||||
item->GetDielectricLayerId() ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
openBlock();
|
||||
addJSONObject( wxString::Format( "\"Type\": \"%s\",\n", layer_type ) );
|
||||
|
||||
if( item->IsColorEditable() && uptodate )
|
||||
{
|
||||
if( IsPrmSpecified( item->GetColor() ) )
|
||||
switch( item->GetType() )
|
||||
{
|
||||
wxString colorName = item->GetColor();
|
||||
case BS_ITEM_TYPE_COPPER:
|
||||
layer_type = "Copper";
|
||||
layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
|
||||
last_copper_layer = item->GetBrdLayerId();
|
||||
break;
|
||||
|
||||
if( colorName.StartsWith( "#" ) ) // This is a user defined color.
|
||||
case BS_ITEM_TYPE_SILKSCREEN:
|
||||
layer_type = "Legend";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_SOLDERMASK:
|
||||
layer_type = "SolderMask";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_SOLDERPASTE:
|
||||
layer_type = "SolderPaste";
|
||||
layer_name = formatStringFromUTF32( item->GetTypeName() );
|
||||
break;
|
||||
|
||||
case BS_ITEM_TYPE_DIELECTRIC:
|
||||
layer_type = "Dielectric";
|
||||
// The option core or prepreg is not added here, as it creates constraints
|
||||
// in build process, not necessary wanted.
|
||||
if( sub_layer_count > 1 )
|
||||
{
|
||||
// In job file a color can be given by its RGB values (0...255)
|
||||
wxColor color( colorName );
|
||||
colorName.Printf( "R%dG%dB%d", color.Red(), color.Green(), color.Blue() );
|
||||
layer_name = formatStringFromUTF32(
|
||||
wxString::Format( "dielectric layer %d - %d/%d",
|
||||
item->GetDielectricLayerId(),
|
||||
sub_idx+1, sub_layer_count ) );
|
||||
}
|
||||
else
|
||||
layer_name = formatStringFromUTF32(
|
||||
wxString::Format( "dielectric layer %d",
|
||||
item->GetDielectricLayerId() ) );
|
||||
break;
|
||||
|
||||
addJSONObject( wxString::Format( "\"Color\": \"%s\",\n", colorName ) );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( item->IsThicknessEditable() && uptodate )
|
||||
addJSONObject( wxString::Format( "\"Thickness\": %.3f,\n", thickness ) );
|
||||
openBlock();
|
||||
addJSONObject( wxString::Format( "\"Type\": \"%s\",\n", layer_type ) );
|
||||
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
||||
{
|
||||
if( item->HasMaterialValue() )
|
||||
if( item->IsColorEditable() && uptodate )
|
||||
{
|
||||
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
||||
|
||||
// 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 )
|
||||
if( IsPrmSpecified( item->GetColor() ) )
|
||||
{
|
||||
// Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetEpsilonR() > 1.0 )
|
||||
addJSONObject( wxString::Format( "\"DielectricConstant\": %s,\n",
|
||||
item->FormatEpsilonR() ) );
|
||||
wxString colorName = item->GetColor();
|
||||
|
||||
// Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetLossTangent() > 0.0 )
|
||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
||||
item->FormatLossTangent() ) );
|
||||
if( colorName.StartsWith( "#" ) ) // This is a user defined color.
|
||||
{
|
||||
// In job file a color can be given by its RGB values (0...255)
|
||||
wxColor color( colorName );
|
||||
colorName.Printf( "R%dG%dB%d", color.Red(), color.Green(), color.Blue() );
|
||||
}
|
||||
|
||||
addJSONObject( wxString::Format( "\"Color\": \"%s\",\n", colorName ) );
|
||||
}
|
||||
}
|
||||
|
||||
PCB_LAYER_ID next_copper_layer = (PCB_LAYER_ID) (last_copper_layer+1);
|
||||
if( item->IsThicknessEditable() && uptodate )
|
||||
addJSONObject( wxString::Format( "\"Thickness\": %.3f,\n", thickness ) );
|
||||
|
||||
// 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;
|
||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
||||
{
|
||||
if( item->HasMaterialValue() )
|
||||
{
|
||||
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n",
|
||||
item->GetMaterial( sub_idx ) ) );
|
||||
|
||||
// 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 )
|
||||
{
|
||||
// Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetEpsilonR() > 1.0 )
|
||||
addJSONObject( wxString::Format( "\"DielectricConstant\": %s,\n",
|
||||
item->FormatEpsilonR( sub_idx ) ) );
|
||||
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s/%s\",\n",
|
||||
// Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetLossTangent() > 0.0 )
|
||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
||||
item->FormatLossTangent( sub_idx ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
wxString subLayerName;
|
||||
|
||||
if( sub_layer_count > 1 )
|
||||
subLayerName.Printf( " (%d/%d)",sub_idx+1, sub_layer_count );
|
||||
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s/%s%s\",\n",
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ),
|
||||
subLayerName )
|
||||
);
|
||||
|
||||
// Add a comment ("Notes"):
|
||||
wxString note = "\"Notes\": ";
|
||||
|
||||
note << wxString::Format( " \"Type: %s", layer_name.c_str() );
|
||||
|
||||
note << wxString::Format( " (from %s to %s)\"\n",
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) )
|
||||
);
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
|
||||
|
||||
// Add a comment ("Notes"):
|
||||
wxString note = "\"Notes\": ";
|
||||
|
||||
note << wxString::Format( " \"Type: %s", layer_name.c_str() );
|
||||
|
||||
note << wxString::Format( " (from %s to %s)\"\n",
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( last_copper_layer ) ),
|
||||
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
|
||||
|
||||
addJSONObject( note );
|
||||
}
|
||||
else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
|
||||
{
|
||||
if( item->HasMaterialValue() )
|
||||
addJSONObject( note );
|
||||
}
|
||||
else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
|
||||
{
|
||||
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
||||
|
||||
// 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 )
|
||||
if( item->HasMaterialValue() )
|
||||
{
|
||||
// Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetEpsilonR() > 1.0 )
|
||||
addJSONObject( wxString::Format( "\"DielectricConstant\": %s,\n",
|
||||
item->FormatEpsilonR() ) );
|
||||
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
||||
|
||||
// Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetLossTangent() > 0.0 )
|
||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
||||
item->FormatLossTangent() ) );
|
||||
// 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 )
|
||||
{
|
||||
// Generate Epsilon R if > 1.0 (value <= 1.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetEpsilonR() > 1.0 )
|
||||
addJSONObject( wxString::Format( "\"DielectricConstant\": %s,\n",
|
||||
item->FormatEpsilonR() ) );
|
||||
|
||||
// Generate LossTangent > 0.0 (value <= 0.0 means not specified: it is not
|
||||
// a possible value
|
||||
if( item->GetLossTangent() > 0.0 )
|
||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
||||
item->FormatLossTangent() ) );
|
||||
}
|
||||
}
|
||||
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s\",\n", layer_name.c_str() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s\",\n", layer_name.c_str() ) );
|
||||
}
|
||||
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s\",\n", layer_name.c_str() ) );
|
||||
removeJSONSepararator();
|
||||
closeBlockWithSep();
|
||||
}
|
||||
else
|
||||
{
|
||||
addJSONObject( wxString::Format( "\"Name\": \"%s\",\n", layer_name.c_str() ) );
|
||||
}
|
||||
|
||||
removeJSONSepararator();
|
||||
closeBlockWithSep();
|
||||
}
|
||||
|
||||
removeJSONSepararator();
|
||||
|
|
|
@ -1075,72 +1075,90 @@ void PCB_PARSER::parseBoardStackup()
|
|||
else
|
||||
Expecting( "layer_name" );
|
||||
|
||||
// Dielectric thickness can be locked (for impedance controled layers)
|
||||
bool thickness_locked = false;
|
||||
bool has_next_sublayer = true;
|
||||
int sublayer_idx = 0; // the index of dielectric sub layers
|
||||
// sublayer 0 is always existing (main sublayer)
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
while( has_next_sublayer )
|
||||
{
|
||||
if( token == T_LEFT )
|
||||
has_next_sublayer = false;
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
if( token == T_addsublayer )
|
||||
{
|
||||
case T_type:
|
||||
NeedSYMBOL();
|
||||
item->SetTypeName( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
has_next_sublayer = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case T_thickness:
|
||||
item->SetThickness( parseBoardUnits( T_thickness ) );
|
||||
if( token == T_LEFT )
|
||||
{
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_LEFT )
|
||||
switch( token )
|
||||
{
|
||||
case T_type:
|
||||
NeedSYMBOL();
|
||||
item->SetTypeName( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
if( token == T_locked )
|
||||
{
|
||||
thickness_locked = true;
|
||||
case T_thickness:
|
||||
item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
|
||||
token = NextTok();
|
||||
|
||||
if( token == T_LEFT )
|
||||
break;
|
||||
|
||||
if( token == T_locked )
|
||||
{
|
||||
// Dielectric thickness can be locked (for impedance controled layers)
|
||||
if( type == BS_ITEM_TYPE_DIELECTRIC )
|
||||
item->SetThicknessLocked( true, sublayer_idx );
|
||||
|
||||
NeedRIGHT();
|
||||
}
|
||||
break;
|
||||
|
||||
case T_material:
|
||||
NeedSYMBOL();
|
||||
item->SetMaterial( FromUTF8(), sublayer_idx );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_epsilon_r:
|
||||
NextTok();
|
||||
item->SetEpsilonR( parseDouble(), sublayer_idx );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_loss_tangent:
|
||||
NextTok();
|
||||
item->SetLossTangent( parseDouble(), sublayer_idx );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_color:
|
||||
NeedSYMBOL();
|
||||
item->SetColor( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Currently, skip this item if not defined, because the stackup def
|
||||
// is a moving target
|
||||
//Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
|
||||
skipCurrent();
|
||||
}
|
||||
break;
|
||||
|
||||
case T_material:
|
||||
NeedSYMBOL();
|
||||
item->SetMaterial( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_epsilon_r:
|
||||
NextTok();
|
||||
item->SetEpsilonR( parseDouble() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_loss_tangent:
|
||||
NextTok();
|
||||
item->SetLossTangent( parseDouble() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_color:
|
||||
NeedSYMBOL();
|
||||
item->SetColor( FromUTF8() );
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Currently, skip this item if not defined, because the stackup def
|
||||
// is a moving target
|
||||
//Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
|
||||
skipCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( type == BS_ITEM_TYPE_DIELECTRIC && thickness_locked )
|
||||
item->SetThicknessLocked( true );
|
||||
if( has_next_sublayer ) // Prepare reading the next sublayer description
|
||||
{
|
||||
sublayer_idx++;
|
||||
item->AddDielectricPrms( sublayer_idx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( token != T_RIGHT )
|
||||
|
|
Loading…
Reference in New Issue