Altium: Handle footprint vias

These are treated as pads in KiCad

Fixes https://gitlab.com/kicad/code/kicad/-/issues/18194
This commit is contained in:
Seth Hillbrand 2024-06-14 16:48:41 -07:00
parent 021f251efd
commit 7ea013b96c
4 changed files with 121 additions and 3 deletions

View File

@ -883,7 +883,6 @@ AVIA6::AVIA6( ALTIUM_BINARY_PARSER& aReader )
size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
aReader.Skip( 1 );
uint8_t flags1 = aReader.Read<uint8_t>();
is_test_fab_top = ( flags1 & 0x80 ) != 0;
is_tent_bottom = ( flags1 & 0x40 ) != 0;
@ -908,8 +907,41 @@ AVIA6::AVIA6( ALTIUM_BINARY_PARSER& aReader )
}
else
{
aReader.Skip( 43 );
uint8_t temp_byte = aReader.Read<uint8_t>(); // Unknown.
thermal_relief_airgap = aReader.ReadKicadUnit();
thermal_relief_conductorcount = aReader.Read<uint8_t>();
aReader.Skip( 1 ); // Unknown.
thermal_relief_conductorwidth = aReader.ReadKicadUnit();
aReader.ReadKicadUnit(); // Unknown. 20mil?
aReader.ReadKicadUnit(); // Unknown. 20mil?
aReader.Skip( 4 );
soldermask_expansion_front = aReader.ReadKicadUnit();
aReader.Skip( 8 );
temp_byte = aReader.Read<uint8_t>();
soldermask_expansion_manual = temp_byte & 0x02;
aReader.Skip( 7 );
viamode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
for( int ii = 0; ii < 32; ++ii )
{
diameter_by_layer[ii] = aReader.ReadKicadUnit();
}
aReader.Skip( 38 );
soldermask_expansion_linked = aReader.Read<uint8_t>() & 0x01;
soldermask_expansion_back = aReader.ReadKicadUnit();
aReader.Skip( 45 );
pos_tolerance = aReader.ReadKicadUnit();
neg_tolerance = aReader.ReadKicadUnit();
}
aReader.SkipSubrecord();

View File

@ -670,13 +670,29 @@ struct AVIA6
uint16_t net;
VECTOR2I position;
uint32_t pos_tolerance; // 2147483640 is N/A
uint32_t neg_tolerance; // 2147483640 is N/A
uint32_t diameter;
uint32_t holesize;
int32_t thermal_relief_airgap;
uint32_t thermal_relief_conductorcount;
uint32_t thermal_relief_conductorwidth;
int32_t soldermask_expansion_front;
int32_t soldermask_expansion_back;
bool soldermask_expansion_manual;
bool soldermask_expansion_linked;
ALTIUM_LAYER layer_start;
ALTIUM_LAYER layer_end;
ALTIUM_PAD_MODE viamode;
// In PAD_MODE::SIMPLE, this is the same as the diameter
// In PAD_MODE::TOP_MIDDLE_BOTTOM, layer 0 is top, layer 1 is middle, layer 31 is bottom
// In PAD_MODE::FULL_STACK, layers correspond to the layer number
uint32_t diameter_by_layer[32];
explicit AVIA6( ALTIUM_BINARY_PARSER& aReader );
};

View File

@ -771,7 +771,7 @@ FOOTPRINT* ALTIUM_PCB::ParseFootprint( ALTIUM_COMPOUND_FILE& altiumLibFile,
case ALTIUM_RECORD::VIA:
{
AVIA6 via( parser );
// TODO: implement
ConvertVias6ToFootprintItem( footprint.get(), via );
break;
}
case ALTIUM_RECORD::TRACK:
@ -3019,6 +3019,75 @@ void ALTIUM_PCB::ConvertPads6ToBoardItem( const APAD6& aElem )
}
void ALTIUM_PCB::ConvertVias6ToFootprintItem( FOOTPRINT* aFootprint, const AVIA6& aElem )
{
std::unique_ptr<PAD> pad = std::make_unique<PAD>( aFootprint );
pad->SetNumber( "" );
pad->SetNetCode( GetNetCode( aElem.net ) );
pad->SetPosition( aElem.position );
pad->SetSize( VECTOR2I( aElem.diameter, aElem.diameter ) );
pad->SetDrillSize( VECTOR2I( aElem.holesize, aElem.holesize ) );
pad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
pad->SetShape( PAD_SHAPE::CIRCLE );
pad->SetAttribute( PAD_ATTRIB::PTH );
// Pads are always through holes in KiCad
pad->SetLayerSet( LSET().AllCuMask() );
if( aElem.viamode == ALTIUM_PAD_MODE::SIMPLE )
pad->Padstack().SetMode( PADSTACK::MODE::NORMAL );
else if( aElem.viamode == ALTIUM_PAD_MODE::TOP_MIDDLE_BOTTOM )
{
pad->Padstack().SetMode( PADSTACK::MODE::TOP_INNER_BOTTOM );
pad->Padstack().Size( In2_Cu ) = VECTOR2I( aElem.diameter_by_layer[1], aElem.diameter_by_layer[1] );
}
else
{
pad->Padstack().SetMode( PADSTACK::MODE::CUSTOM );
for( int ii = 0; ii < 32; ++ii )
{
VECTOR2I size( aElem.diameter_by_layer[ii], aElem.diameter_by_layer[ii] );
pad->Padstack().Size( static_cast<PCB_LAYER_ID>( F_Cu + ii ) ) = size;
}
}
if( aElem.is_tent_top )
{
pad->Padstack().FrontOuterLayers().has_solder_mask = true;
}
else
{
pad->Padstack().FrontOuterLayers().has_solder_mask = false;
pad->SetLayerSet( pad->GetLayerSet().set( F_Mask ) );
}
if( aElem.is_tent_bottom )
{
pad->Padstack().BackOuterLayers().has_solder_mask = true;
}
else
{
pad->Padstack().BackOuterLayers().has_solder_mask = false;
pad->SetLayerSet( pad->GetLayerSet().set( B_Mask ) );
}
if( aElem.is_locked )
pad->SetLocked( true );
if( aElem.soldermask_expansion_manual )
{
pad->Padstack().FrontOuterLayers().solder_mask_margin = aElem.soldermask_expansion_front;
pad->Padstack().BackOuterLayers().solder_mask_margin = aElem.soldermask_expansion_back;
}
aFootprint->Add( pad.release(), ADD_MODE::APPEND );
}
void ALTIUM_PCB::ConvertPads6ToFootprintItem( FOOTPRINT* aFootprint, const APAD6& aElem )
{
// It is possible to place altium pads on non-copper layers -> we need to interpolate them using drawings!

View File

@ -172,6 +172,7 @@ private:
void ConvertPads6ToFootprintItemOnNonCopper( FOOTPRINT* aFootprint, const APAD6& aElem );
void ParseVias6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ConvertVias6ToFootprintItem( FOOTPRINT* aFootprint, const AVIA6& aElem );
void ParseTracks6Data( const ALTIUM_COMPOUND_FILE& aAltiumPcbFile,
const CFB::COMPOUND_FILE_ENTRY* aEntry );
void ConvertTracks6ToBoardItem( const ATRACK6& aElem, const int aPrimitiveIndex );