diff --git a/api/proto/common/commands/project_commands.proto b/api/proto/common/commands/project_commands.proto index 8117715a24..90c6fba931 100644 --- a/api/proto/common/commands/project_commands.proto +++ b/api/proto/common/commands/project_commands.proto @@ -35,6 +35,22 @@ message NetClassesResponse } +message SetNetClasses +{ + repeated kiapi.common.project.NetClass net_classes = 1; + + // Whether to merge or replace the existing netclasses with the contents of this message + // Note that this only happens at the level of netclass name: for example, if merge_mode is set to + // MMM_MERGE, the design has netclasses ["Default", "HV"], and this message has netclasses + // ["Default", "LV"], the resulting set will be ["Default", "HV", "LV"] -- the Default netclass + // will have its properties replaced with those in this message, the "LV" netclass will be added, + // and the "HV" netclass will be left alone. If merge_mode is set to MMM_REPLACE, the "HV" class + // will be erased. Note that there must always be a "Default" netclass, so it will not be erased + // even if merge_mode is MMM_REPLACE and there is no "Default" class specified in this message. + kiapi.common.types.MapMergeMode merge_mode = 3; +} + + message ExpandTextVariables { kiapi.common.types.DocumentSpecifier document = 1; diff --git a/api/proto/common/types/project_settings.proto b/api/proto/common/types/project_settings.proto index 179bebc5c4..ba2796a6b2 100644 --- a/api/proto/common/types/project_settings.proto +++ b/api/proto/common/types/project_settings.proto @@ -26,12 +26,48 @@ syntax = "proto3"; package kiapi.common.project; +import "common/types/base_types.proto"; +import "common/types/enums.proto"; +import "board/board_types.proto"; + +message NetClassBoardSettings +{ + optional kiapi.common.types.Distance clearance = 1; + optional kiapi.common.types.Distance track_width = 2; + optional kiapi.common.types.Distance diff_pair_track_width = 3; + optional kiapi.common.types.Distance diff_pair_gap = 4; + optional kiapi.common.types.Distance diff_pair_via_gap = 5; + + // The default padstack to use for vias belonging to this netclass + // Currently KiCad only supports specifying the drill diameter and annular size on all layers for + // netclass via stacks. Complex padstacks and other via features cannot be specified here. + optional kiapi.board.types.PadStack via_stack = 6; + + // The default padstack to use for microvias belonging to this netclass + // Currently KiCad only supports specifying the drill diameter and annular size on all layers for + // netclass via stacks. Complex padstacks and other via features cannot be specified here. + optional kiapi.board.types.PadStack microvia_stack = 7; + + optional kiapi.common.types.Color color = 8; +} + +message NetClassSchematicSettings +{ + optional kiapi.common.types.Distance wire_width = 1; + optional kiapi.common.types.Distance bus_width = 2; + optional kiapi.common.types.Color color = 3; + optional kiapi.common.types.StrokeLineStyle line_style = 4; +} message NetClass { // The name of the netclass (the literal string "Default" for the default netclass) string name = 1; + optional int32 priority = 2; + + optional NetClassBoardSettings board = 3; + optional NetClassSchematicSettings schematic = 4; } message TextVariables diff --git a/common/api/api_handler_common.cpp b/common/api/api_handler_common.cpp index d3c91d497e..5a2572b0f5 100644 --- a/common/api/api_handler_common.cpp +++ b/common/api/api_handler_common.cpp @@ -45,6 +45,7 @@ API_HANDLER_COMMON::API_HANDLER_COMMON() : { registerHandler( &API_HANDLER_COMMON::handleGetVersion ); registerHandler( &API_HANDLER_COMMON::handleGetNetClasses ); + registerHandler( &API_HANDLER_COMMON::handleSetNetClasses ); registerHandler( &API_HANDLER_COMMON::handlePing ); registerHandler( &API_HANDLER_COMMON::handleGetTextExtents ); registerHandler( @@ -85,15 +86,57 @@ HANDLER_RESULT API_HANDLER_COMMON::handleGetNetClasses( std::shared_ptr& netSettings = Pgm().GetSettingsManager().Prj().GetProjectFile().m_NetSettings; - for( const auto& [name, netClass] : netSettings->GetNetclasses() ) + google::protobuf::Any any; + + netSettings->GetDefaultNetclass()->Serialize( any ); + any.UnpackTo( reply.add_net_classes() ); + + for( const auto& netClass : netSettings->GetNetclasses() | std::views::values ) { - reply.add_net_classes()->set_name( name.ToStdString() ); + netClass->Serialize( any ); + any.UnpackTo( reply.add_net_classes() ); } return reply; } +HANDLER_RESULT API_HANDLER_COMMON::handleSetNetClasses( + const HANDLER_CONTEXT& aCtx ) +{ + std::shared_ptr& netSettings = + Pgm().GetSettingsManager().Prj().GetProjectFile().m_NetSettings; + + if( aCtx.Request.merge_mode() == MapMergeMode::MMM_REPLACE ) + netSettings->ClearNetclasses(); + + auto netClasses = netSettings->GetNetclasses(); + google::protobuf::Any any; + + for( const auto& ncProto : aCtx.Request.net_classes() ) + { + any.PackFrom( ncProto ); + wxString name = wxString::FromUTF8( ncProto.name() ); + + if( name == wxT( "Default" ) ) + { + netSettings->GetDefaultNetclass()->Deserialize( any ); + } + else + { + if( !netClasses.contains( name ) ) + netClasses.insert( { name, std::make_shared( name, false ) } ); + + netClasses[name]->Deserialize( any ); + } + } + + netSettings->SetNetclasses( netClasses ); + + return Empty(); +} + + HANDLER_RESULT API_HANDLER_COMMON::handlePing( const HANDLER_CONTEXT& aCtx ) { return Empty(); diff --git a/common/api/api_utils.cpp b/common/api/api_utils.cpp index 9ce17a65a0..ab2523fb5d 100644 --- a/common/api/api_utils.cpp +++ b/common/api/api_utils.cpp @@ -212,4 +212,24 @@ KICOMMON_API SHAPE_POLY_SET UnpackPolySet( const types::PolySet& aInput ) return sps; } + +KICOMMON_API void PackColor( types::Color& aOutput, const KIGFX::COLOR4D& aInput ) +{ + aOutput.set_r( aInput.r ); + aOutput.set_g( aInput.g ); + aOutput.set_b( aInput.b ); + aOutput.set_a( aInput.a ); +} + + +KICOMMON_API KIGFX::COLOR4D UnpackColor( const types::Color& aInput ) +{ + double r = std::clamp( aInput.r(), 0.0, 1.0 ); + double g = std::clamp( aInput.g(), 0.0, 1.0 ); + double b = std::clamp( aInput.b(), 0.0, 1.0 ); + double a = std::clamp( aInput.a(), 0.0, 1.0 ); + + return KIGFX::COLOR4D( r, g, b, a ); +} + } // namespace kiapi::common diff --git a/common/netclass.cpp b/common/netclass.cpp index 0c15ee47a3..e9583f5900 100644 --- a/common/netclass.cpp +++ b/common/netclass.cpp @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include // This will get mapped to "kicad_default" in the specctra_export. const char NETCLASS::Default[] = "Default"; @@ -126,6 +129,125 @@ bool NETCLASS::operator==( const NETCLASS& other ) const } +void NETCLASS::Serialize( google::protobuf::Any &aContainer ) const +{ + using namespace kiapi::common; + project::NetClass nc; + + nc.set_name( m_Name.ToUTF8() ); + nc.set_priority( m_Priority ); + + project::NetClassBoardSettings* board = nc.mutable_board(); + + if( m_Clearance ) + board->mutable_clearance()->set_value_nm( *m_Clearance ); + + if( m_TrackWidth ) + board->mutable_track_width()->set_value_nm( *m_TrackWidth ); + + if( m_diffPairWidth ) + board->mutable_diff_pair_track_width()->set_value_nm( *m_diffPairWidth ); + + if( m_diffPairGap ) + board->mutable_diff_pair_gap()->set_value_nm( *m_diffPairGap ); + + if( m_diffPairViaGap ) + board->mutable_diff_pair_via_gap()->set_value_nm( *m_diffPairViaGap ); + + if( m_ViaDia ) + { + kiapi::board::types::PadStackLayer* layer = board->mutable_via_stack()->add_copper_layers(); + layer->set_shape( kiapi::board::types::PSS_CIRCLE ); + layer->set_layer( kiapi::board::types::BoardLayer::BL_F_Cu ); + PackVector2( *layer->mutable_size(), { *m_ViaDia, *m_ViaDia } ); + } + + if( m_ViaDrill ) + { + PackVector2( *board->mutable_via_stack()->mutable_drill()->mutable_diameter(), + { *m_ViaDrill, *m_ViaDrill } ); + } + + if( m_pcbColor != COLOR4D::UNSPECIFIED ) + PackColor( *board->mutable_color(), m_pcbColor ); + + project::NetClassSchematicSettings* schematic = nc.mutable_schematic(); + + if( m_wireWidth ) + schematic->mutable_wire_width()->set_value_nm( *m_wireWidth ); + + if( m_busWidth ) + schematic->mutable_bus_width()->set_value_nm( *m_busWidth ); + + if( m_schematicColor != COLOR4D::UNSPECIFIED ) + PackColor( *schematic->mutable_color(), m_schematicColor ); + + if( m_lineStyle ) + { + // TODO(JE) resolve issues with moving to kicommon + // schematic->set_line_style( ToProtoEnum( + // static_cast( *m_lineStyle ) ) ); + } + + aContainer.PackFrom( nc ); +} + + +bool NETCLASS::Deserialize( const google::protobuf::Any &aContainer ) +{ + using namespace kiapi::common; + project::NetClass nc; + + if( !aContainer.UnpackTo( &nc ) ) + return false; + + m_Name = wxString::FromUTF8( nc.name() ); + m_Priority = nc.priority(); + + if( nc.board().has_clearance() ) + m_Clearance = nc.board().clearance().value_nm(); + + if( nc.board().has_track_width() ) + m_TrackWidth = nc.board().track_width().value_nm(); + + if( nc.board().has_diff_pair_track_width() ) + m_diffPairWidth = nc.board().diff_pair_track_width().value_nm(); + + if( nc.board().has_diff_pair_gap() ) + m_diffPairGap = nc.board().diff_pair_gap().value_nm(); + + if( nc.board().has_diff_pair_via_gap() ) + m_diffPairViaGap = nc.board().diff_pair_via_gap().value_nm(); + + if( nc.board().has_via_stack() ) + { + if( nc.board().via_stack().copper_layers_size() > 0 ) + m_ViaDia = nc.board().via_stack().copper_layers().at( 0 ).size().x_nm(); + + if( nc.board().via_stack().has_drill() ) + m_ViaDrill = nc.board().via_stack().drill().diameter().x_nm(); + } + + if( nc.board().has_color() ) + m_pcbColor = UnpackColor( nc.board().color() ); + + if( nc.schematic().has_wire_width() ) + m_wireWidth = nc.schematic().wire_width().value_nm(); + + if( nc.schematic().has_bus_width() ) + m_busWidth = nc.schematic().bus_width().value_nm(); + + if( nc.schematic().has_color() ) + m_schematicColor = UnpackColor( nc.schematic().color() ); + + // TODO(JE) resolve issues with moving to kicommon + // if( nc.schematic().has_line_style() ) + // m_lineStyle = static_cast( FromProtoEnum( nc.schematic().line_style() ) ); + + return true; +} + + const std::vector& NETCLASS::GetConstituentNetclasses() const { return m_constituents; diff --git a/include/api/api_handler_common.h b/include/api/api_handler_common.h index 06f14e5128..8b782b840e 100644 --- a/include/api/api_handler_common.h +++ b/include/api/api_handler_common.h @@ -44,6 +44,9 @@ private: HANDLER_RESULT handleGetNetClasses( const HANDLER_CONTEXT& aCtx ); + HANDLER_RESULT handleSetNetClasses( + const HANDLER_CONTEXT& aCtx ); + HANDLER_RESULT handlePing( const HANDLER_CONTEXT& aCtx ); HANDLER_RESULT handleGetTextExtents( diff --git a/include/api/api_utils.h b/include/api/api_utils.h index 8cd4897113..18e0587af4 100644 --- a/include/api/api_utils.h +++ b/include/api/api_utils.h @@ -31,6 +31,7 @@ #include #include #include +#include class SHAPE_LINE_CHAIN; @@ -72,6 +73,10 @@ KICOMMON_API void PackPolySet( types::PolySet& aOutput, const SHAPE_POLY_SET& aI KICOMMON_API SHAPE_POLY_SET UnpackPolySet( const types::PolySet& aInput ); +KICOMMON_API void PackColor( types::Color& aOutput, const KIGFX::COLOR4D& aInput ); + +KICOMMON_API KIGFX::COLOR4D UnpackColor( const types::Color& aInput ); + } // namespace kiapi::common #endif //KICAD_API_UTILS_H diff --git a/include/netclass.h b/include/netclass.h index 78e6b2e15b..a4c9b14bcd 100644 --- a/include/netclass.h +++ b/include/netclass.h @@ -32,6 +32,7 @@ #include #include #include +#include using KIGFX::COLOR4D; @@ -40,7 +41,7 @@ DECL_SET_FOR_SWIG( STRINGSET, wxString ) /** * A collection of nets and the parameters used to route or test these nets. */ -class KICOMMON_API NETCLASS +class KICOMMON_API NETCLASS : public SERIALIZABLE { public: static const char Default[]; ///< the name of the default NETCLASS @@ -62,6 +63,9 @@ public: return wxT( "NETCLASS" ); } + void Serialize( google::protobuf::Any &aContainer ) const override; + bool Deserialize( const google::protobuf::Any &aContainer ) override; + /// @brief Resets all parent fields to point to this netclass void ResetParents();