API: Add CheckPadstackPresenceOnLayers

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20587
This commit is contained in:
Jon Evans 2025-05-26 21:46:21 -04:00
parent 9466cab585
commit d1e4b03ec1
3 changed files with 108 additions and 0 deletions

View File

@ -189,6 +189,42 @@ message PadShapeAsPolygonResponse
repeated kiapi.common.types.PolygonWithHoles polygons = 2; repeated kiapi.common.types.PolygonWithHoles polygons = 2;
} }
// Tests if the given set of items with padstacks (pads or vias) has content on the given set of layers.
// This is a dynamic call rather than a property of the padstack because pads and vias can be set to only include
// shapes on connected copper layers, and whether or not the pad is connected can't be determined in isolation.
// To optimize API call performance, multiple items and multiple layers to test may be passed in with this
// command message. The return will include the results for each valid item on each valid layer.
// Note that not all layers make sense for a given item (for example, testing against BL_UNDEFINED never makes
// sense). In general, the internal KiCad APIs will not return an error when testing non-sensical layers for a given
// item, and instead will return a default of "true" for any such layers.
message CheckPadstackPresenceOnLayers
{
kiapi.common.types.DocumentSpecifier board = 1;
repeated kiapi.common.types.KIID items = 2;
repeated kiapi.board.types.BoardLayer layers = 3;
}
enum PadstackPresence
{
PSP_UNKNOWN = 0;
PSP_PRESENT = 1; // The padstack has a shape on a given layer (is flashed)
PSP_NOT_PRESENT = 2; // The padstack has no shape on a given layer (is not flashed)
}
message PadstackPresenceEntry
{
kiapi.common.types.KIID item = 1;
kiapi.board.types.BoardLayer layer = 2;
PadstackPresence presence = 3;
}
message PadstackPresenceResponse
{
repeated PadstackPresenceEntry entries = 1;
}
// PCB editor commands // PCB editor commands
// returns BoardLayers // returns BoardLayers

View File

@ -78,6 +78,8 @@ API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) :
&API_HANDLER_PCB::handleGetBoundingBox ); &API_HANDLER_PCB::handleGetBoundingBox );
registerHandler<GetPadShapeAsPolygon, PadShapeAsPolygonResponse>( registerHandler<GetPadShapeAsPolygon, PadShapeAsPolygonResponse>(
&API_HANDLER_PCB::handleGetPadShapeAsPolygon ); &API_HANDLER_PCB::handleGetPadShapeAsPolygon );
registerHandler<CheckPadstackPresenceOnLayers, PadstackPresenceResponse>(
&API_HANDLER_PCB::handleCheckPadstackPresenceOnLayers );
registerHandler<GetTitleBlockInfo, types::TitleBlockInfo>( registerHandler<GetTitleBlockInfo, types::TitleBlockInfo>(
&API_HANDLER_PCB::handleGetTitleBlockInfo ); &API_HANDLER_PCB::handleGetTitleBlockInfo );
registerHandler<ExpandTextVariables, ExpandTextVariablesResponse>( registerHandler<ExpandTextVariables, ExpandTextVariablesResponse>(
@ -1056,6 +1058,73 @@ HANDLER_RESULT<PadShapeAsPolygonResponse> API_HANDLER_PCB::handleGetPadShapeAsPo
} }
HANDLER_RESULT<PadstackPresenceResponse> API_HANDLER_PCB::handleCheckPadstackPresenceOnLayers(
const HANDLER_CONTEXT<CheckPadstackPresenceOnLayers>& aCtx )
{
using board::types::BoardLayer;
if( HANDLER_RESULT<bool> documentValidation = validateDocument( aCtx.Request.board() );
!documentValidation )
{
return tl::unexpected( documentValidation.error() );
}
PadstackPresenceResponse response;
LSET layers;
for( const int layer : aCtx.Request.layers() )
layers.set( FromProtoEnum<PCB_LAYER_ID, BoardLayer>( static_cast<BoardLayer>( layer ) ) );
for( const types::KIID& padRequest : aCtx.Request.items() )
{
KIID id( padRequest.value() );
std::optional<BOARD_ITEM*> optItem = getItemById( id );
if( !optItem )
continue;
switch( ( *optItem )->Type() )
{
case PCB_PAD_T:
{
PAD* pad = static_cast<PAD*>( *optItem );
for( PCB_LAYER_ID layer : layers )
{
PadstackPresenceEntry* entry = response.add_entries();
entry->mutable_item()->set_value( pad->m_Uuid.AsStdString() );
entry->set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( layer ) );
entry->set_presence( pad->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
}
break;
}
case PCB_VIA_T:
{
PCB_VIA* via = static_cast<PCB_VIA*>( *optItem );
for( PCB_LAYER_ID layer : layers )
{
PadstackPresenceEntry* entry = response.add_entries();
entry->mutable_item()->set_value( via->m_Uuid.AsStdString() );
entry->set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( layer ) );
entry->set_presence( via->FlashLayer( layer ) ? PSP_PRESENT : PSP_NOT_PRESENT );
}
break;
}
default:
break;
}
}
return response;
}
HANDLER_RESULT<types::TitleBlockInfo> API_HANDLER_PCB::handleGetTitleBlockInfo( HANDLER_RESULT<types::TitleBlockInfo> API_HANDLER_PCB::handleGetTitleBlockInfo(
const HANDLER_CONTEXT<GetTitleBlockInfo>& aCtx ) const HANDLER_CONTEXT<GetTitleBlockInfo>& aCtx )
{ {

View File

@ -103,6 +103,9 @@ private:
HANDLER_RESULT<PadShapeAsPolygonResponse> handleGetPadShapeAsPolygon( HANDLER_RESULT<PadShapeAsPolygonResponse> handleGetPadShapeAsPolygon(
const HANDLER_CONTEXT<GetPadShapeAsPolygon>& aCtx ); const HANDLER_CONTEXT<GetPadShapeAsPolygon>& aCtx );
HANDLER_RESULT<PadstackPresenceResponse> handleCheckPadstackPresenceOnLayers(
const HANDLER_CONTEXT<CheckPadstackPresenceOnLayers>& aCtx );
HANDLER_RESULT<types::TitleBlockInfo> handleGetTitleBlockInfo( HANDLER_RESULT<types::TitleBlockInfo> handleGetTitleBlockInfo(
const HANDLER_CONTEXT<commands::GetTitleBlockInfo>& aCtx ); const HANDLER_CONTEXT<commands::GetTitleBlockInfo>& aCtx );