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.
|
# These are the keywords for the Pcbnew s-expression file format.
|
||||||
|
|
||||||
add_net
|
add_net
|
||||||
|
addsublayer
|
||||||
allowed
|
allowed
|
||||||
anchor
|
anchor
|
||||||
angle
|
angle
|
||||||
|
|
|
@ -42,58 +42,76 @@ wxString BuildStackupReport( BOARD_STACKUP& aStackup, EDA_UNITS_T aUnits )
|
||||||
wxString report;
|
wxString report;
|
||||||
|
|
||||||
wxString txt;
|
wxString txt;
|
||||||
int row = 0;
|
|
||||||
LOCALE_IO toggle; // toggles on the C locale to write floating values, then off.
|
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
|
// Skip stackup items useless for the current board
|
||||||
if( !item->IsEnabled() )
|
if( !item->IsEnabled() )
|
||||||
{
|
|
||||||
row++;
|
|
||||||
continue;
|
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;
|
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() )
|
if( item->IsColorEditable() )
|
||||||
{
|
{
|
||||||
txt.Printf( " Color \"%s\"", item->GetColor() );
|
txt.Printf( " Color \"%s\"", item->GetColor() );
|
||||||
report << txt;
|
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';
|
report << '\n';
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM_TYPE aType )
|
||||||
m_DielectricPrmsList.emplace_back( item_prms );
|
m_DielectricPrmsList.emplace_back( item_prms );
|
||||||
m_LayerId = UNDEFINED_LAYER;
|
m_LayerId = UNDEFINED_LAYER;
|
||||||
m_Type = aType;
|
m_Type = aType;
|
||||||
|
SetDielectricLayerId( 1 );
|
||||||
SetEnabled( true );
|
SetEnabled( true );
|
||||||
|
|
||||||
// Initialize parameters to a usual value for allowed types:
|
// 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:
|
case BS_ITEM_TYPE_DIELECTRIC:
|
||||||
m_TypeName = KEY_CORE; // or prepreg
|
m_TypeName = KEY_CORE; // or prepreg
|
||||||
SetMaterial( "FR4" ); // or other dielectric name
|
SetMaterial( "FR4" ); // or other dielectric name
|
||||||
SetDielectricLayerId( 1 );
|
|
||||||
SetLossTangent( 0.02 ); // for FR4
|
SetLossTangent( 0.02 ); // for FR4
|
||||||
SetEpsilonR( 4.5 ); // for FR4
|
SetEpsilonR( 4.5 ); // for FR4
|
||||||
break;
|
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 )
|
BOARD_STACKUP_ITEM::BOARD_STACKUP_ITEM( BOARD_STACKUP_ITEM& aOther )
|
||||||
{
|
{
|
||||||
m_LayerId = aOther.m_LayerId;
|
m_LayerId = aOther.m_LayerId;
|
||||||
|
m_DielectricLayerId = aOther.m_DielectricLayerId;
|
||||||
m_Type = aOther.m_Type;
|
m_Type = aOther.m_Type;
|
||||||
m_enabled = aOther.m_enabled;
|
m_enabled = aOther.m_enabled;
|
||||||
m_DielectricPrmsList = aOther.m_DielectricPrmsList;
|
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()
|
int BOARD_STACKUP_ITEM::GetCopperDefaultThickness()
|
||||||
{
|
{
|
||||||
// A reasonable thickness for copper layers:
|
// A reasonable thickness for copper layers:
|
||||||
|
@ -104,38 +127,42 @@ int BOARD_STACKUP_ITEM::GetMaskDefaultThickness()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters:
|
// 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;
|
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;
|
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;
|
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;
|
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;
|
return m_DielectricPrmsList[aDielectricSubLayer].m_Material;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,41 +170,50 @@ wxString BOARD_STACKUP_ITEM::GetMaterial( int aDielectricSubLayer )
|
||||||
// Setters:
|
// Setters:
|
||||||
void BOARD_STACKUP_ITEM::SetThickness( int aThickness, int aDielectricSubLayer )
|
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 )
|
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 )
|
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 )
|
void BOARD_STACKUP_ITEM::SetThicknessLocked( bool aLocked, int aDielectricSubLayer )
|
||||||
{
|
{
|
||||||
m_DielectricPrmsList[aDielectricSubLayer].m_ThicknessLocked = aLocked;
|
wxASSERT( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() );
|
||||||
}
|
|
||||||
|
|
||||||
|
if( aDielectricSubLayer >= 0 && aDielectricSubLayer < GetSublayersCount() )
|
||||||
void BOARD_STACKUP_ITEM::SetDielectricLayerId( int aLayerId, int aDielectricSubLayer )
|
m_DielectricPrmsList[aDielectricSubLayer].m_ThicknessLocked = aLocked;
|
||||||
{
|
|
||||||
m_DielectricPrmsList[aDielectricSubLayer].m_DielectricLayerId = aLayerId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BOARD_STACKUP_ITEM::SetMaterial( const wxString& aName, int aDielectricSubLayer )
|
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
|
return m_Type == BS_ITEM_TYPE_DIELECTRIC
|
||||||
|| m_Type == BS_ITEM_TYPE_SOLDERMASK
|
|| 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
|
return m_Type == BS_ITEM_TYPE_DIELECTRIC
|
||||||
|| m_Type == BS_ITEM_TYPE_SOLDERMASK
|
|| m_Type == BS_ITEM_TYPE_SOLDERMASK;
|
||||||
//|| m_Type == BS_ITEM_TYPE_SILKSCREEN
|
|
||||||
;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool BOARD_STACKUP_ITEM::HasMaterialValue()
|
bool BOARD_STACKUP_ITEM::HasMaterialValue( int aDielectricSubLayer ) const
|
||||||
{
|
{
|
||||||
// return true if the material is specified
|
// 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
|
// The material is editable only for dielectric
|
||||||
return m_Type == BS_ITEM_TYPE_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;
|
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 )
|
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
|
// return a wxString to print/display Epsilon R
|
||||||
wxString txt;
|
wxString txt;
|
||||||
txt.Printf( "%.1f", GetEpsilonR() );
|
txt.Printf( "%.1f", GetEpsilonR( aDielectricSubLayer ) );
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString BOARD_STACKUP_ITEM::FormatLossTangent()
|
wxString BOARD_STACKUP_ITEM::FormatLossTangent( int aDielectricSubLayer ) const
|
||||||
{
|
{
|
||||||
// return a wxString to print/display Loss Tangent
|
// return a wxString to print/display Loss Tangent
|
||||||
wxString txt;
|
wxString txt;
|
||||||
txt.Printf( "%g", GetLossTangent() );
|
txt.Printf( "%g", GetLossTangent( aDielectricSubLayer ) );
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxString BOARD_STACKUP_ITEM::FormatDielectricLayerName()
|
wxString BOARD_STACKUP_ITEM::FormatDielectricLayerName() const
|
||||||
{
|
{
|
||||||
// return a wxString to print/display a dielectriv name
|
// return a wxString to print/display a dielectriv name
|
||||||
wxString lname;
|
wxString lname;
|
||||||
|
@ -364,17 +398,31 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
|
||||||
BOARD_STACKUP stackup;
|
BOARD_STACKUP stackup;
|
||||||
stackup.BuildDefaultStackupList( aSettings );
|
stackup.BuildDefaultStackupList( aSettings );
|
||||||
|
|
||||||
// First test for removed layers:
|
// First, find removed layers:
|
||||||
for( BOARD_STACKUP_ITEM* old_item: m_list )
|
for( BOARD_STACKUP_ITEM* curr_item: m_list )
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for( BOARD_STACKUP_ITEM* item: stackup.GetList() )
|
for( BOARD_STACKUP_ITEM* item: stackup.GetList() )
|
||||||
{
|
{
|
||||||
if( item->GetBrdLayerId() == old_item->GetBrdLayerId() )
|
if( curr_item->GetBrdLayerId() != UNDEFINED_LAYER )
|
||||||
{
|
{
|
||||||
found = true;
|
if( item->GetBrdLayerId() == curr_item->GetBrdLayerId() )
|
||||||
break;
|
{
|
||||||
|
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
|
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() )
|
if( item->GetDielectricLayerId() == initial_item->GetDielectricLayerId() )
|
||||||
{
|
{
|
||||||
*item = *initial_item;
|
*item = *initial_item;
|
||||||
|
@ -413,7 +465,9 @@ bool BOARD_STACKUP::SynchronizeWithBoard( BOARD_DESIGN_SETTINGS* aSettings )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !found )
|
if( !found )
|
||||||
|
{
|
||||||
change = true;
|
change = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer other stackup settings from aSettings
|
// Transfer other stackup settings from aSettings
|
||||||
|
@ -586,31 +640,40 @@ void BOARD_STACKUP::FormatBoardStackup( OUTPUTFORMATTER* aFormatter,
|
||||||
aFormatter->Quotew( layer_name ).c_str(),
|
aFormatter->Quotew( layer_name ).c_str(),
|
||||||
aFormatter->Quotew( item->GetTypeName() ).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() ) )
|
if( item->IsColorEditable() && IsPrmSpecified( item->GetColor() ) )
|
||||||
aFormatter->Print( 0, " (color %s)",
|
aFormatter->Print( 0, " (color %s)",
|
||||||
aFormatter->Quotew( item->GetColor() ).c_str() );
|
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" );
|
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
|
class DIELECTRIC_PRMS
|
||||||
{
|
{
|
||||||
friend class BOARD_STACKUP_ITEM;
|
friend class BOARD_STACKUP_ITEM;
|
||||||
|
|
||||||
private:
|
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)
|
wxString m_Material; /// type of material (for dielectric and solder mask)
|
||||||
int m_Thickness; /// the physical layer thickness in internal units
|
int m_Thickness; /// the physical layer thickness in internal units
|
||||||
bool m_ThicknessLocked; /// true for dielectric layers with a fixed thickness
|
bool m_ThicknessLocked; /// true for dielectric layers with a fixed thickness
|
||||||
|
@ -76,7 +74,6 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DIELECTRIC_PRMS() :
|
DIELECTRIC_PRMS() :
|
||||||
m_DielectricLayerId(-1),
|
|
||||||
m_Thickness(0), m_ThicknessLocked( false ),
|
m_Thickness(0), m_ThicknessLocked( false ),
|
||||||
m_EpsilonR( 1.0 ), m_LossTangent( 0.0 )
|
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)
|
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
|
/// and UNDEFINED_LAYER (-1) for dielectic layers that are not
|
||||||
/// really layers for the board editor
|
/// 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
|
/// List of dielectric parameters
|
||||||
/// usually only one item, but in complex (microwave) boards, one can have
|
/// usually only one item, but in complex (microwave) boards, one can have
|
||||||
/// more than one dielectic layer between 2 copper layers, and therfore
|
/// 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.
|
/// false to ignore it. Mainly used in dialog stackup editor.
|
||||||
|
|
||||||
public:
|
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
|
/// @return true if the layer has a meaningfull Epsilon R parameter
|
||||||
/// namely dielectric layers: dielectric and solder mask
|
/// namely dielectric layers: dielectric and solder mask
|
||||||
bool HasEpsilonRValue();
|
bool HasEpsilonRValue() const;
|
||||||
|
|
||||||
/// @return true if the layer has a meaningfull Dielectric Loss parameter
|
/// @return true if the layer has a meaningfull Dielectric Loss parameter
|
||||||
/// namely dielectric layers: dielectric and solder mask
|
/// namely dielectric layers: dielectric and solder mask
|
||||||
bool HasLossTangentValue();
|
bool HasLossTangentValue() const;
|
||||||
|
|
||||||
/// @return true if the material is specified
|
/// @return true if the material is specified
|
||||||
bool HasMaterialValue();
|
bool HasMaterialValue( int aDielectricSubLayer = 0 ) const;
|
||||||
|
|
||||||
/// @return true if the material is editable
|
/// @return true if the material is editable
|
||||||
bool IsMaterialEditable();
|
bool IsMaterialEditable() const;
|
||||||
|
|
||||||
/// @return true if the color is editable
|
/// @return true if the color is editable
|
||||||
bool IsColorEditable();
|
bool IsColorEditable() const;
|
||||||
|
|
||||||
/// @return true if Thickness is editable
|
/// @return true if Thickness is editable
|
||||||
bool IsThicknessEditable();
|
bool IsThicknessEditable() const;
|
||||||
|
|
||||||
/// @return a reasonable default value for a copper layer thickness
|
/// @return a reasonable default value for a copper layer thickness
|
||||||
static int GetCopperDefaultThickness();
|
static int GetCopperDefaultThickness();
|
||||||
|
@ -138,30 +153,34 @@ public:
|
||||||
/// @return a reasonable default value for a solder mask layer thickness
|
/// @return a reasonable default value for a solder mask layer thickness
|
||||||
static int GetMaskDefaultThickness();
|
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
|
/// @return a wxString to print/display Epsilon R
|
||||||
wxString FormatEpsilonR();
|
wxString FormatEpsilonR( int aDielectricSubLayer = 0 ) const;
|
||||||
|
|
||||||
/// @return a wxString to print/display Loss Tangent
|
/// @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
|
/// @return a wxString to print/display a dielectric name
|
||||||
wxString FormatDielectricLayerName();
|
wxString FormatDielectricLayerName() const;
|
||||||
|
|
||||||
// Getters:
|
// Getters:
|
||||||
bool IsEnabled() {return m_enabled; }
|
bool IsEnabled() const {return m_enabled; }
|
||||||
|
|
||||||
BOARD_STACKUP_ITEM_TYPE GetType() { return m_Type; }
|
BOARD_STACKUP_ITEM_TYPE GetType() const { return m_Type; }
|
||||||
PCB_LAYER_ID GetBrdLayerId() { return m_LayerId; }
|
PCB_LAYER_ID GetBrdLayerId() const { return m_LayerId; }
|
||||||
wxString GetColor(){ return m_Color; }
|
wxString GetColor() const { return m_Color; }
|
||||||
wxString GetLayerName() { return m_LayerName; }
|
wxString GetLayerName() const { return m_LayerName; }
|
||||||
wxString GetTypeName() { return m_TypeName; }
|
wxString GetTypeName() const { return m_TypeName; }
|
||||||
|
int GetDielectricLayerId() const { return m_DielectricLayerId; }
|
||||||
|
|
||||||
int GetThickness( int aDielectricSubLayer = 0 );
|
int GetThickness( int aDielectricSubLayer = 0 ) const;
|
||||||
bool IsThicknessLocked( int aDielectricSubLayer = 0 );
|
bool IsThicknessLocked( int aDielectricSubLayer = 0 ) const;
|
||||||
double GetEpsilonR( int aDielectricSubLayer = 0 );
|
double GetEpsilonR( int aDielectricSubLayer = 0 ) const;
|
||||||
double GetLossTangent( int aDielectricSubLayer = 0 );
|
double GetLossTangent( int aDielectricSubLayer = 0 ) const;
|
||||||
int GetDielectricLayerId( int aDielectricSubLayer = 0 );
|
wxString GetMaterial( int aDielectricSubLayer = 0 ) const;
|
||||||
wxString GetMaterial( int aDielectricSubLayer = 0 );
|
|
||||||
|
|
||||||
// Setters:
|
// Setters:
|
||||||
void SetEnabled( bool aEnable) { m_enabled = aEnable; }
|
void SetEnabled( bool aEnable) { m_enabled = aEnable; }
|
||||||
|
@ -169,12 +188,12 @@ public:
|
||||||
void SetColor( const wxString& aColorName ){ m_Color = aColorName; }
|
void SetColor( const wxString& aColorName ){ m_Color = aColorName; }
|
||||||
void SetLayerName( const wxString& aName ) { m_LayerName = aName; }
|
void SetLayerName( const wxString& aName ) { m_LayerName = aName; }
|
||||||
void SetTypeName( const wxString& aName ) { m_TypeName = aName; }
|
void SetTypeName( const wxString& aName ) { m_TypeName = aName; }
|
||||||
|
void SetDielectricLayerId( int aLayerId ) { m_DielectricLayerId = aLayerId; }
|
||||||
|
|
||||||
void SetThickness( int aThickness, int aDielectricSubLayer = 0 );
|
void SetThickness( int aThickness, int aDielectricSubLayer = 0 );
|
||||||
void SetThicknessLocked( bool aLocked, int aDielectricSubLayer = 0 );
|
void SetThicknessLocked( bool aLocked, int aDielectricSubLayer = 0 );
|
||||||
void SetEpsilonR( double aEpsilon, int aDielectricSubLayer = 0 );
|
void SetEpsilonR( double aEpsilon, int aDielectricSubLayer = 0 );
|
||||||
void SetLossTangent( double aTg, 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 );
|
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
|
struct BOARD_STACKUP_ROW_UI_ITEM
|
||||||
{
|
{
|
||||||
BOARD_STACKUP_ITEM* m_Item; // The BOARD_STACKUP_ITEM managed by this 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
|
bool m_isEnabled; // True if the row is in board
|
||||||
// false if not (this row is not shown on the panel)
|
// false if not (this row is not shown on the panel)
|
||||||
wxStaticBitmap* m_Icon; // Color icon in first column (column 1)
|
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_EpsilonCtrl; // control shown in column 8
|
||||||
wxControl* m_LossTgCtrl; // control shown in column 9
|
wxControl* m_LossTgCtrl; // control shown in column 9
|
||||||
|
|
||||||
BOARD_STACKUP_ROW_UI_ITEM( BOARD_STACKUP_ITEM* aItem ) :
|
BOARD_STACKUP_ROW_UI_ITEM( BOARD_STACKUP_ITEM* aItem, int aSubItem = 1 ) :
|
||||||
m_Item( aItem ),
|
m_Item( aItem ), m_SubItem( aSubItem ),
|
||||||
m_isEnabled( true ), m_Icon( nullptr ), m_LayerName( nullptr ),
|
m_isEnabled( true ), m_Icon( nullptr ), m_LayerName( nullptr ),
|
||||||
m_LayerTypeCtrl( nullptr ),
|
m_LayerTypeCtrl( nullptr ),
|
||||||
m_MaterialCtrl( nullptr ),m_MaterialButt( nullptr ),
|
m_MaterialCtrl( nullptr ),m_MaterialButt( nullptr ),
|
||||||
|
@ -92,13 +95,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void OnLayersOptionsChanged( LSET aNewLayerSet );
|
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
|
/// Return the color currently selected for the row aRow
|
||||||
wxColor GetSelectedColor( int aRow ) const;
|
wxColor GetSelectedColor( int aRow ) const;
|
||||||
|
|
||||||
BOARD_STACKUP& GetStackup() { return m_stackup; }
|
BOARD_STACKUP& GetStackup() { return m_stackup; }
|
||||||
int GetPcbTickness();
|
int GetPcbThickness();
|
||||||
|
|
||||||
// Called by wxWidgets: transfer current settings stored in m_stackup to the board
|
// Called by wxWidgets: transfer current settings stored in m_stackup to the board
|
||||||
bool TransferDataFromWindow() override;
|
bool TransferDataFromWindow() override;
|
||||||
|
@ -106,6 +112,18 @@ public:
|
||||||
std::vector<wxColor> m_UserColors; // the list of user colors for each grid row
|
std::vector<wxColor> m_UserColors; // the list of user colors for each grid row
|
||||||
// other colors are defined colors, and are not stored
|
// other colors are defined colors, and are not stored
|
||||||
private:
|
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
|
/** add a Spacer in m_fgGridSizer when a empty cell is needed
|
||||||
*/
|
*/
|
||||||
wxControl* addSpacer();
|
wxControl* addSpacer();
|
||||||
|
@ -124,20 +142,31 @@ private:
|
||||||
* all copper layers and all tech layers that are supported by the stackup
|
* 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
|
* items not in the current board stackup will be not shown, but they are
|
||||||
* existing in list
|
* 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 ... )
|
* current board and optionally update the stackup params (thickness, color ... )
|
||||||
* @param aFullSync = true to update stackup params, false to only update the list
|
* @param aFullSync = true to update stackup params, false to only update the list
|
||||||
* of shown items
|
* of shown items
|
||||||
*/
|
*/
|
||||||
void synchronizeWithBoard( bool aFullSync );
|
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
|
/** Populate m_fgGridSizer with items to handle stackup parameters
|
||||||
* If previous items are in list, remove old items
|
* 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
|
/** 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 )
|
for( int ii = 0; ii < brd_stackup.GetCount(); ++ii )
|
||||||
{
|
{
|
||||||
BOARD_STACKUP_ITEM* item = brd_stackup.GetStackupLayer( 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 thickness is always in mm
|
||||||
layer_type = "Copper";
|
double thickness = item->GetThickness( sub_idx )*m_conversionUnits;
|
||||||
layer_name = formatStringFromUTF32( m_pcb->GetLayerName( item->GetBrdLayerId() ) );
|
wxString layer_type;
|
||||||
last_copper_layer = item->GetBrdLayerId();
|
std::string layer_name; // for comment
|
||||||
break;
|
|
||||||
|
|
||||||
case BS_ITEM_TYPE_SILKSCREEN:
|
switch( item->GetType() )
|
||||||
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() ) )
|
|
||||||
{
|
{
|
||||||
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)
|
layer_name = formatStringFromUTF32(
|
||||||
wxColor color( colorName );
|
wxString::Format( "dielectric layer %d - %d/%d",
|
||||||
colorName.Printf( "R%dG%dB%d", color.Red(), color.Green(), color.Blue() );
|
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 )
|
openBlock();
|
||||||
addJSONObject( wxString::Format( "\"Thickness\": %.3f,\n", thickness ) );
|
addJSONObject( wxString::Format( "\"Type\": \"%s\",\n", layer_type ) );
|
||||||
|
|
||||||
if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
if( item->IsColorEditable() && uptodate )
|
||||||
{
|
|
||||||
if( item->HasMaterialValue() )
|
|
||||||
{
|
{
|
||||||
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
if( IsPrmSpecified( item->GetColor() ) )
|
||||||
|
|
||||||
// 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
|
wxString colorName = item->GetColor();
|
||||||
// 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
|
if( colorName.StartsWith( "#" ) ) // This is a user defined color.
|
||||||
// a possible value
|
{
|
||||||
if( item->GetLossTangent() > 0.0 )
|
// In job file a color can be given by its RGB values (0...255)
|
||||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
wxColor color( colorName );
|
||||||
item->FormatLossTangent() ) );
|
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( item->GetType() == BS_ITEM_TYPE_DIELECTRIC )
|
||||||
if( next_copper_layer >= m_pcb->GetCopperLayerCount()-1 )
|
{
|
||||||
next_copper_layer = B_Cu;
|
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( last_copper_layer ) ),
|
||||||
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) )
|
formatStringFromUTF32( m_pcb->GetLayerName( next_copper_layer ) ) );
|
||||||
);
|
|
||||||
|
|
||||||
// Add a comment ("Notes"):
|
addJSONObject( note );
|
||||||
wxString note = "\"Notes\": ";
|
}
|
||||||
|
else if( item->GetType() == BS_ITEM_TYPE_SOLDERMASK || item->GetType() == BS_ITEM_TYPE_SILKSCREEN )
|
||||||
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( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
if( item->HasMaterialValue() )
|
||||||
|
|
||||||
// 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
|
addJSONObject( wxString::Format( "\"Material\": \"%s\",\n", item->GetMaterial() ) );
|
||||||
// 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
|
// These constrains are only written if the board has impedance controlled tracks.
|
||||||
// a possible value
|
// If the board is not impedance controlled, they are useless.
|
||||||
if( item->GetLossTangent() > 0.0 )
|
// Do not add constrains that create more expensive boards.
|
||||||
addJSONObject( wxString::Format( "\"LossTangent\": %s,\n",
|
if( brd_stackup.m_HasDielectricConstrains )
|
||||||
item->FormatLossTangent() ) );
|
{
|
||||||
|
// 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();
|
removeJSONSepararator();
|
||||||
|
|
|
@ -1075,72 +1075,90 @@ void PCB_PARSER::parseBoardStackup()
|
||||||
else
|
else
|
||||||
Expecting( "layer_name" );
|
Expecting( "layer_name" );
|
||||||
|
|
||||||
// Dielectric thickness can be locked (for impedance controled layers)
|
bool has_next_sublayer = true;
|
||||||
bool thickness_locked = false;
|
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();
|
if( token == T_addsublayer )
|
||||||
|
|
||||||
switch( token )
|
|
||||||
{
|
{
|
||||||
case T_type:
|
has_next_sublayer = true;
|
||||||
NeedSYMBOL();
|
|
||||||
item->SetTypeName( FromUTF8() );
|
|
||||||
NeedRIGHT();
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case T_thickness:
|
if( token == T_LEFT )
|
||||||
item->SetThickness( parseBoardUnits( T_thickness ) );
|
{
|
||||||
token = NextTok();
|
token = NextTok();
|
||||||
|
|
||||||
if( token == T_LEFT )
|
switch( token )
|
||||||
|
{
|
||||||
|
case T_type:
|
||||||
|
NeedSYMBOL();
|
||||||
|
item->SetTypeName( FromUTF8() );
|
||||||
|
NeedRIGHT();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if( token == T_locked )
|
case T_thickness:
|
||||||
{
|
item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
|
||||||
thickness_locked = true;
|
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();
|
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 )
|
if( has_next_sublayer ) // Prepare reading the next sublayer description
|
||||||
item->SetThicknessLocked( true );
|
{
|
||||||
|
sublayer_idx++;
|
||||||
|
item->AddDielectricPrms( sublayer_idx );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( token != T_RIGHT )
|
if( token != T_RIGHT )
|
||||||
|
|
Loading…
Reference in New Issue