7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 20:59:17 +00:00

Add QA tests and expand serialization for API

This commit is contained in:
Jon Evans 2024-01-20 18:35:29 -05:00
parent 6bd02cae6d
commit 1dbe78c68b
106 changed files with 9643 additions and 736 deletions
api
common
eeschema
include
pcbnew
qa
scripting

View File

@ -22,11 +22,19 @@ set( KIAPI_PROTO_SRCS
common/envelope.proto
common/types/base_types.proto
common/types/enums.proto
common/types/project_settings.proto
common/commands/base_commands.proto
common/commands/editor_commands.proto
common/commands/project_commands.proto
board/board.proto
board/board_commands.proto
board/board_types.proto
schematic/schematic_types.proto
schematic/schematic_commands.proto
)
# Generated C++ code must be in the build dir; it is dependent on the version of protoc installed
@ -101,18 +109,3 @@ target_include_directories( kiapi INTERFACE
# Because when building internally, the generated files do not include the "api" base path
target_include_directories( kiapi PUBLIC ${KIAPI_CPP_BASEPATH} )
option( KICAD_BUILD_ENUM_EXPORTER
"Build the enum exporter used as part of generating the IPC APIs"
OFF )
if( KICAD_BUILD_ENUM_EXPORTER )
add_subdirectory( enums )
add_custom_target( enum_definitions
COMMAND $<TARGET_FILE:enum_exporter> ${CMAKE_CURRENT_BINARY_DIR}/enums.json
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API definitions from KiCad enums..."
DEPENDS enum_exporter
)
endif()

View File

@ -1,91 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <filesystem>
#include <iostream>
#include <string>
#include <argparse/argparse.hpp>
#include <fmt.h>
#include <nlohmann/json.hpp>
#define MAGIC_ENUM_RANGE_MAX 1024
#include <magic_enum.hpp>
#include <layer_ids.h>
#include <eda_shape.h>
#include <core/typeinfo.h>
template<typename T>
nlohmann::json FormatEnum()
{
nlohmann::json js;
js["type"] = magic_enum::enum_type_name<T>();
js["values"] = nlohmann::json::array();
for( const std::pair<T, std::string_view>& entry : magic_enum::enum_entries<T>() )
{
js["values"].emplace_back( nlohmann::json( {
{ "key", entry.second },
{ "value", static_cast<int>( entry.first ) }
} ) );
}
return js;
}
int main( int argc, char* argv[] )
{
argparse::ArgumentParser args( "enum_exporter" );
args.add_argument( "output_dir" ).default_value( std::string() );
try
{
args.parse_args( argc, argv );
}
catch( const std::runtime_error& err )
{
std::cerr << err.what() << std::endl;
std::cerr << args;
std::exit( 1 );
}
std::filesystem::path path( args.get<std::string>( "output_dir" ) );
std::ofstream outfile;
if( !path.empty() )
{
path = std::filesystem::absolute( path );
outfile.open( path );
}
std::ostream& out = outfile.is_open() ? outfile : std::cout;
nlohmann::json js = nlohmann::json::array();
js += FormatEnum<PCB_LAYER_ID>();
js += FormatEnum<SHAPE_T>();
js += FormatEnum<KICAD_T>();
out << js.dump( 4 ) << std::endl;
}

116
api/proto/board/board.proto Normal file
View File

@ -0,0 +1,116 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Jon Evans <jon@craftyjon.com>
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
syntax = "proto3";
package kiapi.board;
import "common/types/base_types.proto";
import "board/board_types.proto";
message BoardFinish
{
string type_name = 1;
}
message BoardImpedanceControl
{
bool is_controlled = 1;
}
message BoardEdgeConnector
{
}
message Castellation
{
bool has_castellated_pads = 1;
}
message EdgePlating
{
bool has_edge_plating = 1;
}
message BoardEdgeSettings
{
BoardEdgeConnector connector = 1;
Castellation castellation = 2;
EdgePlating plating = 3;
}
message BoardStackupCopperLayer
{
}
message BoardStackupLayer
{
kiapi.common.types.Distance thickness = 1;
kiapi.board.types.BoardLayer layer = 2;
bool enabled = 3;
oneof item {
BoardStackupCopperLayer copper = 4;
}
}
message BoardStackup
{
BoardFinish finish = 1;
BoardImpedanceControl impedance = 2;
// NOTE: m_HasThicknessConstrains appears to be unused
BoardEdgeSettings edge = 3;
repeated BoardStackupLayer layers = 4;
}
// LAYER_CLASS_* in BOARD_DESIGN_SETTINGS -- needs to become an enum class
enum BoardLayerClass
{
BLC_UNKNOWN = 0;
BLC_SILKSCREEN = 1;
BLC_COPPER = 2;
BLC_EDGES = 3;
BLC_COURTYARD = 4;
BLC_FABRICATION = 5;
BLC_OTHER = 6;
}
message BoardLayerGraphicsDefaults
{
BoardLayerClass layer = 1;
kiapi.common.types.TextAttributes text = 2;
kiapi.common.types.Distance line_thickness = 3;
}
message GraphicsDefaults
{
repeated BoardLayerGraphicsDefaults layers = 1;
}
// Anything that isn't stackup or design rules
message BoardSettings
{
GraphicsDefaults graphics_defaults = 1;
// Dimension default settings
}
message BoardDesignRules
{
}

View File

@ -0,0 +1,151 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Jon Evans <jon@craftyjon.com>
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
syntax = "proto3";
package kiapi.board.commands;
import "common/types/base_types.proto";
import "common/types/enums.proto";
import "board/board.proto";
import "board/board_types.proto";
/*
* Board stackup and properties
*/
message GetBoardStackup
{
kiapi.common.types.DocumentSpecifier board = 1;
}
message BoardStackupResponse
{
kiapi.board.BoardStackup stackup = 1;
}
message UpdateBoardStackup
{
kiapi.common.types.DocumentSpecifier board = 1;
kiapi.board.BoardStackup stackup = 2;
}
message GetGraphicsDefaults
{
kiapi.common.types.DocumentSpecifier board = 1;
}
message GraphicsDefaultsResponse
{
kiapi.board.GraphicsDefaults defaults = 1;
}
/*
* Net management
*/
message GetNets
{
kiapi.common.types.DocumentSpecifier board = 1;
// If provided, will only return nets that belong to the given netclass.
// If more than one netclass_filter is given, nets belonging to any of the given classes will
// be returned.
repeated string netclass_filter = 2;
}
message NetsResponse
{
repeated kiapi.board.types.Net nets = 1;
}
// Retrieve all the copper items belonging to a certain net or set of nets
// returns kiapi.common.commands.GetItemsResponse
message GetItemsByNet
{
// Specifies which document to query, which fields to return, etc.
kiapi.common.types.ItemHeader header = 1;
// List of one or more types of items to retreive
repeated kiapi.common.types.KiCadObjectType types = 2;
// A list of net codes to filter items by
repeated kiapi.board.types.NetCode net_codes = 3;
}
// Retrieve all the copper items belonging to a certain net class or set of net classes
// returns kiapi.common.commands.GetItemsResponse
message GetItemsByNetClass
{
// Specifies which document to query, which fields to return, etc.
kiapi.common.types.ItemHeader header = 1;
// List of one or more types of items to retreive
repeated kiapi.common.types.KiCadObjectType types = 2;
// A list of net class names to filter items by
repeated string net_classes = 3;
}
/*
* Blocking operations
*/
// Refills some or all zones on the board.
// This is a blocking operation; it will return Empty immediately, but KiCad will return
// ApiStatusCode.AS_BUSY to all future API requests until the zone fill has completed.
message RefillZones
{
kiapi.common.types.DocumentSpecifier board = 1;
// A list of zones to refill. If empty, all zones are refilled.
repeated kiapi.common.types.KIID zones = 2;
}
/*
* Utilities
*/
// returns kiapi.common.commands.BoundingBoxResponse
message GetTextExtents
{
// A temporary text item to calculate the bounding box for
kiapi.board.types.Text text = 1;
}
//// Interactive commands ////
// These commands begin an interactive operation in the editor.
// They return a response immediately, but the editor will become busy
// and will not reply to further API commands until the user has finished
// the operation.
// These commands will return an error if received in a non-interactive context.
// Selects and begins an interactive move of the given item(s).
// NOTE: Takes ownership of the active commit, if one exists:
// the move tool will push the commit when the user confirms the move,
// or roll back the commit if the user cancels the move. Keep this in
// mind if using this command in combination with commands that create
// or modify items using an explicit commit.
message InteractiveMoveItems
{
kiapi.common.types.DocumentSpecifier board = 1;
repeated kiapi.common.types.KIID items = 2;
}

View File

@ -21,90 +21,467 @@ syntax = "proto3";
package kiapi.board.types;
import "google/protobuf/any.proto";
import "common/types/base_types.proto";
/// Represents a track segment on a board
enum BoardLayer
{
BL_UNKNOWN = 0;
BL_UNDEFINED = 1;
BL_UNSELECTED = 2;
BL_F_Cu = 3;
BL_In1_Cu = 4;
BL_In2_Cu = 5;
BL_In3_Cu = 6;
BL_In4_Cu = 7;
BL_In5_Cu = 8;
BL_In6_Cu = 9;
BL_In7_Cu = 10;
BL_In8_Cu = 11;
BL_In9_Cu = 12;
BL_In10_Cu = 13;
BL_In11_Cu = 14;
BL_In12_Cu = 15;
BL_In13_Cu = 16;
BL_In14_Cu = 17;
BL_In15_Cu = 18;
BL_In16_Cu = 19;
BL_In17_Cu = 20;
BL_In18_Cu = 21;
BL_In19_Cu = 22;
BL_In20_Cu = 23;
BL_In21_Cu = 24;
BL_In22_Cu = 25;
BL_In23_Cu = 26;
BL_In24_Cu = 27;
BL_In25_Cu = 28;
BL_In26_Cu = 29;
BL_In27_Cu = 30;
BL_In28_Cu = 31;
BL_In29_Cu = 32;
BL_In30_Cu = 33;
BL_B_Cu = 34;
BL_B_Adhes = 35;
BL_F_Adhes = 36;
BL_B_Paste = 37;
BL_F_Paste = 38;
BL_B_SilkS = 39;
BL_F_SilkS = 40;
BL_B_Mask = 41;
BL_F_Mask = 42;
BL_Dwgs_User = 43;
BL_Cmts_User = 44;
BL_Eco1_User = 45;
BL_Eco2_User = 46;
BL_Edge_Cuts = 47;
BL_Margin = 48;
BL_B_CrtYd = 49;
BL_F_CrtYd = 50;
BL_B_Fab = 51;
BL_F_Fab = 52;
BL_User_1 = 53;
BL_User_2 = 54;
BL_User_3 = 55;
BL_User_4 = 56;
BL_User_5 = 57;
BL_User_6 = 58;
BL_User_7 = 59;
BL_User_8 = 60;
BL_User_9 = 61;
}
message NetCode
{
int32 value = 1;
}
// Describes a copper item's net
message Net
{
// A unique code representing this net
NetCode code = 1;
// Human-readable net name
string name = 2;
}
// Represents a track segment on a board
message Track
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Point2D start = 2;
kiapi.common.types.Point2D end = 3;
kiapi.common.types.Vector2 start = 2;
kiapi.common.types.Vector2 end = 3;
kiapi.common.types.Distance width = 4;
kiapi.common.types.LockedState locked = 5;
kiapi.common.types.BoardLayer layer = 6;
kiapi.common.types.Net net = 7;
BoardLayer layer = 6;
Net net = 7;
}
/// Represents an arc track (not a PCB_SHAPE in arc shape)
/// Arc tracks in KiCad store start, midpoint, and end.
/// All other values (center point, angles, etc) are inferred.
// Represents an arc track (not a PCB_SHAPE in arc shape)
// Arc tracks in KiCad store start, midpoint, and end.
// All other values (center point, angles, etc) are inferred.
message Arc
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Point2D start = 2;
kiapi.common.types.Point2D mid = 3; /// Arc midpoint
kiapi.common.types.Point2D end = 4;
kiapi.common.types.Vector2 start = 2;
kiapi.common.types.Vector2 mid = 3; // Arc midpoint
kiapi.common.types.Vector2 end = 4;
kiapi.common.types.Distance width = 5;
kiapi.common.types.LockedState locked = 6;
kiapi.common.types.BoardLayer layer = 7;
kiapi.common.types.Net net = 8;
BoardLayer layer = 7;
Net net = 8;
}
enum PadStackType
{
PST_UNKNOWN = 0;
PST_THROUGH = 1; /// Through all layers; same shape on all layers
PST_BLIND_BURIED = 2; /// From a start layer to end layer (inclusive); same shape on all included layers
PST_THROUGH = 1; // Through all layers; same shape on all layers
PST_BLIND_BURIED = 2; // From a start layer to end layer (inclusive); same shape on all included layers
}
enum UnconnectedLayerRemoval
{
ULR_UNKNOWN = 0;
/// Keep annular rings on all layers
// Keep annular rings on all layers
ULR_KEEP = 1;
/// Remove annular rings on unconnected layers, including start and end layers.
// Remove annular rings on unconnected layers, including start and end layers.
ULR_REMOVE = 2;
/// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected.
// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected.
ULR_REMOVE_EXCEPT_START_AND_END = 3;
}
/// A pad stack definition for a multilayer pad or via.
// The shape of a pad on a given layer
enum PadStackShape
{
PSS_UNKNOWN = 0;
PSS_CIRCLE = 1;
PSS_RECTANGLE = 2;
PSS_OVAL = 3;
PSS_TRAPEZOID = 4;
PSS_ROUNDRECT = 5;
PSS_CHAMFEREDRECT = 6;
PSS_CUSTOM = 7;
}
// Which corners are chamfered in a PSS_CHAMFEREDRECT
message ChamferedRectCorners
{
bool top_left = 1;
bool top_right = 2;
bool bottom_left = 3;
bool bottom_right = 4;
}
// The defintion of a padstack on a single layer
message PadStackLayer
{
// The board layers of this padstack entry
repeated BoardLayer layers = 1;
// The shape of the pad on this layer
PadStackShape shape = 2;
// The size (x and y) of the shape on this layer
kiapi.common.types.Vector2 size = 3;
// How much to round the corners of the shape by, as a fraction of min(size.x, size.y)
// Only used for PSS_ROUNDRECT or PSS_CHAMFEREDRECT
float corner_rounding_ratio = 4;
// How much to round the corners of the shape by, as a fraction of min(size.x, size.y)
// Only used for PSS_CHAMFEREDRECT
float chamfer_ratio = 5;
ChamferedRectCorners chamfered_corners = 6;
repeated GraphicShape custom_shapes = 7;
}
// A pad stack definition for a multilayer pad or via.
message PadStack
{
/// What type of pad stack this represents.
// What type of pad stack this represents.
PadStackType type = 1;
/// Lowest (closest to F_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
kiapi.common.types.BoardLayer start_layer = 2;
// Lowest (closest to F_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
BoardLayer start_layer = 2;
/// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
kiapi.common.types.BoardLayer end_layer = 3;
// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH.
BoardLayer end_layer = 3;
/// How to treat annular rings on unconnected layers.
// How to treat pad shapes on unconnected layers.
UnconnectedLayerRemoval unconnected_layer_removal = 4;
// The diameter, in x and y, of the pad's drilled hole, if this pad has a hole.
// x and y will be the same value if the hole is round.
kiapi.common.types.Vector2 drill_diameter = 5;
repeated PadStackLayer layers = 6;
// The overall rotation of this padstack (affects all layers)
kiapi.common.types.Angle angle = 7;
}
/// Represents a via
// Represents a via
message Via
{
/// The unique identifier of the via
// The unique identifier of the via
kiapi.common.types.KIID id = 1;
/// The location of the via's center point
kiapi.common.types.Point2D position = 2;
// The location of the via's center point
kiapi.common.types.Vector2 position = 2;
/// The diameter of the via's circular copper pad
kiapi.common.types.Distance pad_diameter = 4;
// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this.
PadStack pad_stack = 3;
/// The diameter of the via's drilled hole
kiapi.common.types.Distance drill_diameter = 5;
kiapi.common.types.LockedState locked = 4;
/// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this.
Net net = 5;
}
message GraphicSegmentAttributes
{
kiapi.common.types.Vector2 start = 1;
kiapi.common.types.Vector2 end = 2;
}
message GraphicRectangleAttributes
{
kiapi.common.types.Vector2 top_left = 1;
kiapi.common.types.Vector2 bottom_right = 2;
}
message GraphicArcAttributes
{
kiapi.common.types.Vector2 start = 1;
kiapi.common.types.Vector2 mid = 2;
kiapi.common.types.Vector2 end = 3;
}
message GraphicCircleAttributes
{
kiapi.common.types.Vector2 center = 1;
// A point on the radius of the circle. This is stored instead of just a radius so that the point
// by which the user can adjust the circle radius is persisted.
kiapi.common.types.Vector2 radius_point = 2;
}
message GraphicBezierAttributes
{
kiapi.common.types.Vector2 start = 1;
kiapi.common.types.Vector2 control1 = 2;
kiapi.common.types.Vector2 control2 = 3;
kiapi.common.types.Vector2 end = 4;
}
message GraphicShape
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.LockedState locked = 2;
BoardLayer layer = 3;
Net net = 4;
kiapi.common.types.GraphicAttributes attributes = 5;
oneof geometry {
GraphicSegmentAttributes segment = 6;
GraphicRectangleAttributes rectangle = 7;
GraphicArcAttributes arc = 8;
GraphicCircleAttributes circle = 9;
kiapi.common.types.PolySet polygon = 10;
GraphicBezierAttributes bezier = 11;
}
}
// A board-specific text object, existing on a board layer
message Text
{
kiapi.common.types.Text text = 1;
BoardLayer layer = 2;
}
// A board-specific textbox, existing on a board layer
message TextBox
{
kiapi.common.types.TextBox textbox = 1;
BoardLayer layer = 2;
}
// NOTE: There has been some discussion about what to do with pad attributes and properties.
// This may be considered somewhat unstable until we decide what to do with the KiCad side.
// It is not clear what the set of mutually-exclusive pad types will be at the end of the day,
// versus what will be non-exclusive attributes/properties.
// For now, this maps to PAD_ATTRIB in KiCad.
enum PadType
{
PT_UNKNOWN = 0;
PT_PTH = 1;
PT_SMD = 2;
PT_EDGE_CONNECTOR = 3;
PT_NPTH = 4;
}
enum CustomPadShapeZoneFillStrategy
{
CPSZ_UNKNOWN = 0;
CPSZ_OUTLINE = 1;
CPSZ_CONVEXHULL = 2;
}
message ThermalSpokeSettings
{
int64 width = 1;
kiapi.common.types.Angle angle = 2;
int64 gap = 3;
}
message Pad
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.LockedState locked = 2;
string number = 3;
Net net = 4;
PadType type = 5;
PadStack pad_stack = 6;
kiapi.common.types.LockedState locked = 7;
kiapi.common.types.Net net = 8;
// A pad's position is always relative to the parent footprint's origin
kiapi.common.types.Vector2 position = 7;
DesignRuleOverrides overrides = 8;
ThermalSpokeSettings thermal_spokes = 9;
}
// Copper zone, non-copper zone, or rule area
message Zone
{
// TODO
}
message Dimension
{
// TODO
}
message ReferenceImage
{
// TODO
}
message Group
{
// TODO
}
message FieldId
{
int32 id = 1;
}
message Field
{
FieldId id = 1;
string name = 2;
Text text = 3;
}
message Model3D
{
// TODO
}
enum FootprintMountingStyle
{
FMS_UNKNOWN = 0;
FMS_THROUGH_HOLE = 1;
FMS_SMD = 2;
FMS_UNSPECIFIED = 3;
}
message FootprintAttributes
{
string description = 1;
string keywords = 2;
bool not_in_schematic = 3;
bool exclude_from_position_files = 4;
bool exclude_from_bill_of_materials = 5;
bool exempt_from_courtyard_requirement = 6;
bool do_not_populate = 7;
FootprintMountingStyle mounting_style = 8;
}
// enum class ZONE_CONNECTION
enum ZoneConnectionStyle
{
ZCS_UNKNOWN = 0;
ZCS_INHERITED = 1;
ZCS_NONE = 2;
ZCS_THERMAL = 3;
ZCS_FULL = 4;
ZCS_PTH_THERMAL = 5; // Thermal reliefs for plated through holes, solid for SMD pads
}
message DesignRuleOverrides
{
// Copper-to-copper clearance override
kiapi.common.types.Distance clearance = 1;
// Solder mask expansion/contraction
kiapi.common.types.Distance solder_mask_margin = 2;
// Solder paste expansion/contraction
kiapi.common.types.Distance solder_paste_margin = 3;
// Solder paste expansion/contraction ratio
kiapi.common.types.Ratio solder_paste_margin_ratio = 4;
ZoneConnectionStyle zone_connection = 5;
}
message NetTieDefinition
{
repeated string pad_number = 1;
}
// A footprint definition (i.e. what would be in a library)
message Footprint
{
kiapi.common.types.LibraryIdentifier id = 1;
kiapi.common.types.Vector2 anchor = 2;
FootprintAttributes attributes = 3;
DesignRuleOverrides overrides = 4;
repeated NetTieDefinition net_ties = 5;
repeated BoardLayer private_layers = 6;
Field reference_field = 7;
Field value_field = 8;
Field datasheet_field = 9;
Field description_field = 10;
// All footprint items except for mandatory fields
repeated google.protobuf.Any items = 11;
}
// An instance of a footprint on a board
message FootprintInstance
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
kiapi.common.types.Angle orientation = 3;
BoardLayer layer = 4;
kiapi.common.types.LockedState locked = 5;
Footprint definition = 6;
Field reference_field = 7;
Field value_field = 8;
Field datasheet_field = 9;
Field description_field = 10;
FootprintAttributes attributes = 11;
DesignRuleOverrides overrides = 12;
}

View File

@ -31,3 +31,8 @@ message GetVersionResponse
{
kiapi.common.types.KiCadVersion version = 1;
}
// A command to check if the connection to KiCad is OK
message Ping
{
}

View File

@ -27,17 +27,18 @@ package kiapi.common.commands;
import "google/protobuf/any.proto";
import "common/types/base_types.proto";
import "common/types/enums.proto";
/// Refreshes the given frame, if that frame is open
// Refreshes the given frame, if that frame is open
message RefreshEditor
{
kiapi.common.types.FrameType frame = 1;
}
/// Retrieves a list of open documents of the given type
// Retrieves a list of open documents of the given type
message GetOpenDocuments
{
/// Which type of documents to query
// Which type of documents to query
kiapi.common.types.DocumentType type = 1;
}
@ -86,140 +87,150 @@ message BeginCommit
message BeginCommitResponse
{
// Opaque identifier tracking a commit
kiapi.common.types.KIID id = 1;
}
enum CommitResult
enum CommitAction
{
CR_UNKNOWN = 0;
CR_OK = 1; // Commit was pushed successfully
CR_NO_COMMIT = 2; // There was no commit started
CMA_UNKNOWN = 0;
CMA_COMMIT = 1; // Commit the changes to the design
CMA_DROP = 2; // Cancel this commit
}
message EndCommit
{
// The ID that was given by BeginCommit
kiapi.common.types.KIID id = 1;
// What to do with this commit
CommitAction action = 2;
// Optional message describing this changeset
string message = 1;
string message = 3;
}
message EndCommitResponse
{
CommitResult result = 1;
}
/// Creates new items on a given document
// Creates new items on a given document
message CreateItems
{
/// Specifies which document to create on, which fields are included, etc.
// Specifies which document to create on, which fields are included, etc.
kiapi.common.types.ItemHeader header = 1;
/// List of items to create
// List of items to create
repeated google.protobuf.Any items = 2;
/// Items may be created on a top-level document (sheet, board, etc) or inside a container
/// (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint
/// that the items should be added to. This ID must be an existing symbol (for schematic
/// documents) or footprint (for board documents). If the given container does not exist or is
/// not the correct item type, the CreateItems call will fail.
// Items may be created on a top-level document (sheet, board, etc) or inside a container
// (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint
// that the items should be added to. This ID must be an existing symbol (for schematic
// documents) or footprint (for board documents). If the given container does not exist or is
// not the correct item type, the CreateItems call will fail.
kiapi.common.types.KIID container = 3;
}
enum ItemCreationStatus
enum ItemStatusCode
{
ICS_UNKNOWN = 0;
ICS_OK = 1; /// The item was created
ICS_INVALID_TYPE = 2; /// The item's type is not valid for the given document
ICS_EXISTING = 3; /// The item had a specified KIID and that KIID was already in use
ISC_UNKNOWN = 0;
ISC_OK = 1; // The item was created or updated
ISC_INVALID_TYPE = 2; // The item's type is not valid for the given document
ISC_EXISTING = 3; // The item to be created had a specified KIID and that KIID was already in use
ISC_NONEXISTENT = 4; // The item to be updated did not exist in the given document
ISC_IMMUTABLE = 5; // The item to be updated is not allowed to be modified by the API
ISC_INVALID_DATA = 7; // The item to be created does not have valid data for the given document
}
// Per-item status feedback for creation and update calls
message ItemStatus
{
ItemStatusCode code = 1;
string error_message = 2;
}
message ItemCreationResult
{
ItemCreationStatus status = 1;
ItemStatus status = 1;
/// The created version of the item, including an updated KIID as applicable
// The created version of the item, including an updated KIID as applicable
google.protobuf.Any item = 2;
}
message CreateItemsResponse
{
/// Specifies which document was modified, which fields are included in created_items, etc.
// Specifies which document was modified, which fields are included in created_items, etc.
kiapi.common.types.ItemHeader header = 1;
/// Status of the overall request; may return IRS_OK even if no items were created
// Status of the overall request; may return IRS_OK even if no items were created
kiapi.common.types.ItemRequestStatus status = 2;
/// Status of each item to be created
// Status of each item to be created
repeated ItemCreationResult created_items = 3;
}
message GetItems
{
/// Specifies which document to query, which fields to return, etc.
// Specifies which document to query, which fields to return, etc.
kiapi.common.types.ItemHeader header = 1;
/// List of one or more types of items to retreive
repeated kiapi.common.types.ItemType types = 2;
// List of one or more types of items to retreive
repeated kiapi.common.types.KiCadObjectType types = 2;
}
message GetItemsResponse
{
/// Specifies which document was modified, which fields are included in items, etc.
// Specifies which document was modified, which fields are included in items, etc.
kiapi.common.types.ItemHeader header = 1;
/// Status of the overall request; may return IRS_OK even if no items were retrieved
// Status of the overall request; may return IRS_OK even if no items were retrieved
kiapi.common.types.ItemRequestStatus status = 2;
repeated google.protobuf.Any items = 3;
}
/// Updates items in a given document
// Updates items in a given document
message UpdateItems
{
/// Specifies which document to modify, which fields are included, etc.
// Specifies which document to modify, which fields are included, etc.
kiapi.common.types.ItemHeader header = 1;
/// List of items to modify
// List of items to modify
repeated google.protobuf.Any items = 2;
}
enum ItemUpdateStatus
{
IUS_UNKNOWN = 0;
IUS_OK = 1; /// The item was updated
IUS_INVALID_TYPE = 2; /// The item's type is not valid for the given document
IUS_NONEXISTENT = 3; /// The item did not exist in the given document
IUS_IMMUTABLE = 4; /// The item is not allowed to be modified by the API
}
message ItemUpdateResult
{
ItemUpdateStatus status = 1;
ItemStatus status = 1;
/// The update version of the item
// The update version of the item
google.protobuf.Any item = 2;
}
message UpdateItemsResponse
{
/// Specifies which document was modified, which fields are included in updated_items, etc.
// Specifies which document was modified, which fields are included in updated_items, etc.
kiapi.common.types.ItemHeader header = 1;
/// Status of the overall request; may return IRS_OK even if no items were modified
// Status of the overall request; may return IRS_OK even if no items were modified
kiapi.common.types.ItemRequestStatus status = 2;
/// Status of each item to be created
// Status of each item to be created
repeated ItemUpdateResult updated_items = 3;
}
/// Deletes items in a given document
// Deletes items in a given document
message DeleteItems
{
/// Specifies which document to modify
// Specifies which document to modify
kiapi.common.types.ItemHeader header = 1;
/// List of item KIIDs to delete
// List of item KIIDs to delete
repeated kiapi.common.types.KIID item_ids = 2;
}
@ -227,8 +238,8 @@ enum ItemDeletionStatus
{
IDS_UNKNOWN = 0;
IDS_OK = 1;
IDS_NONEXISTENT = 2; /// The item did not exist in the given document
IDS_IMMUTABLE = 3; /// The item is not allowed to be modified by the API
IDS_NONEXISTENT = 2; // The item did not exist in the given document
IDS_IMMUTABLE = 3; // The item is not allowed to be modified by the API
}
message ItemDeletionResult
@ -240,12 +251,49 @@ message ItemDeletionResult
message DeleteItemsResponse
{
/// Specifies which document was modified, etc.
// Specifies which document was modified, etc.
kiapi.common.types.ItemHeader header = 1;
/// Status of the overall request; may return IRS_OK even if no items were deleted
// Status of the overall request; may return IRS_OK even if no items were deleted
kiapi.common.types.ItemRequestStatus status = 2;
/// Status of each item requested to be deleted
// Status of each item requested to be deleted
repeated ItemDeletionResult deleted_items = 3;
}
message GetItemBoundingBox
{
kiapi.common.types.ItemHeader header = 1;
kiapi.common.types.KIID id = 2;
}
message BoundingBoxResponse
{
kiapi.common.types.Vector2 position = 1;
kiapi.common.types.Vector2 size = 2;
}
// Tests if a certain point falls within tolerance of an item's geometry
message HitTest
{
kiapi.common.types.ItemHeader header = 1;
kiapi.common.types.KIID id = 2;
kiapi.common.types.Vector2 position = 3;
int32 tolerance = 4;
}
enum HitTestResult
{
HTR_UNKNOWN = 0;
HTR_NO_HIT = 1;
HTR_HIT = 2;
}
message HitTestResponse
{
HitTestResult result = 1;
}

View File

@ -0,0 +1,34 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
syntax = "proto3";
package kiapi.common.commands;
import "common/types/project_settings.proto";
message GetNetClasses
{
}
message NetClassesResponse
{
repeated kiapi.common.project.NetClass net_classes = 1;
}

View File

@ -29,9 +29,11 @@ enum ApiStatusCode
AS_OK = 1; // Request succeeded
AS_TIMEOUT = 2; // Request timed out
AS_BAD_REQUEST = 3; // The request had invalid parameters or otherwise was illegal
AS_NOT_READY = 4; // KiCad was not (yet) in a state where it could handle API requests
AS_NOT_READY = 4; // KiCad has recently started and cannot handle API requests yet
AS_UNHANDLED = 5; // The request was not handled by KiCad
AS_TOKEN_MISMATCH = 6; // The kicad_token in the request didn't match this KiCad's token
AS_BUSY = 7; // KiCad is busy performing an operation and can't accept API commands
AS_UNIMPLEMENTED = 8; // The requested API call has not yet been implemented
}
/*

View File

@ -27,6 +27,7 @@ syntax = "proto3";
package kiapi.common.types;
import "google/protobuf/field_mask.proto";
import "common/types/enums.proto";
enum CommandStatus
{
@ -95,10 +96,10 @@ enum DocumentType
*/
message LibraryIdentifier
{
/// The library portion of the LIB_ID
// The library portion of the LIB_ID
string library_nickname = 1;
/// The symbol or footprint name
// The symbol or footprint name
string entry_name = 2;
}
@ -107,13 +108,25 @@ message LibraryIdentifier
*/
message SheetPath
{
/// The canonical path to the sheet. The first KIID will be the root sheet, etc.
// The canonical path to the sheet. The first KIID will be the root sheet, etc.
repeated KIID path = 1;
/// The path converted to a human readable form such as "/", "/child", or "/child/grandchild"
// The path converted to a human readable form such as "/", "/child", or "/child/grandchild"
string path_human_readable = 2;
}
/**
* Describes a KiCad project
*/
message ProjectSpecifier
{
// The name of the project (without the kicad_pro extension)
string name = 1;
// The path to the project directory
string path = 2;
}
/**
* Describes a document that will be the target of a request
*/
@ -123,24 +136,17 @@ message DocumentSpecifier
oneof identifier
{
/// If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry
// If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry
LibraryIdentifier lib_id = 2;
/// If type == DT_SCHEMATIC, identifies a sheet with a given path
// If type == DT_SCHEMATIC, identifies a sheet with a given path
SheetPath sheet_path = 3;
/// If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb"
// If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb"
string board_filename = 4;
}
}
/**
* Describes the type of a KiCad item (wrapper for KICAD_T)
*/
message ItemType
{
/// Must be a valid value in the KICAD_T C++ enum (see typeinfo.h)
int32 type = 1;
ProjectSpecifier project = 5;
}
/**
@ -148,11 +154,15 @@ message ItemType
*/
message ItemHeader
{
/// Which document is this request targeting?
// Which document is this request targeting?
DocumentSpecifier document = 1;
/// Which fields on the item(s) are included with this request or response
google.protobuf.FieldMask field_mask = 2;
// Which container within the document is this request targeting?
// If container is omitted or empty, the document is used as the container.
KIID container = 2;
// Which fields on the item(s) are included with this request or response
google.protobuf.FieldMask field_mask = 3;
}
/**
@ -162,32 +172,93 @@ enum ItemRequestStatus
{
IRS_UNKNOWN = 0;
IRS_OK = 1;
IRS_DOCUMENT_NOT_FOUND = 2; /// The given document is not open in KiCad
IRS_FIELD_MASK_INVALID = 3; /// The given field_mask contains invalid specifiers
IRS_DOCUMENT_NOT_FOUND = 2; // The given document is not open in KiCad
IRS_FIELD_MASK_INVALID = 3; // The given field_mask contains invalid specifiers
}
/// Describes a point in 2D space. All coordinates are in nanometers.
message Point2D
// Describes a point or distance in 2D space. All coordinates are in nanometers.
message Vector2
{
int64 x_nm = 1;
int64 y_nm = 2;
}
/// Describes a point in 3D space. All coordinates are in nanometers.
message Point3D
// Describes a point or distance in 3D space. All coordinates are in nanometers.
message Vector3
{
int64 x_nm = 1;
int64 y_nm = 2;
int64 z_nm = 3;
}
/// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers.
// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers.
message Distance
{
int64 value_nm = 1;
}
/// Describes whether or not an item is locked for editing or movement
// Corresponds to EDA_ANGLE, where the underlying storage is degrees
message Angle
{
double value_degrees = 1;
}
// Represents a value from 0.0 to 1.0
message Ratio
{
double value = 1;
}
// Corresponds to COLOR4D. Each color channel is a double from 0.0 to 1.0.
message Color
{
double r = 1;
double g = 2;
double b = 3;
double a = 4;
}
// The formulation of arc that is used in KiCad core geometry code.
// Start, midpoint (on the arc) and end are stored. Angle, center point, etc are calculated.
message ArcStartMidEnd
{
Vector2 start = 1;
Vector2 mid = 2;
Vector2 end = 3;
}
message PolyLineNode
{
oneof geometry {
Vector2 point = 1;
ArcStartMidEnd arc = 2;
}
}
// Corresponds to class SHAPE_LINE_CHAIN: A closed or open polyline that can include arcs.
// For non-arc cases, each node is a point along the line. An implicit line segment exists
// between the last and first node if closed is true. When arcs are present, the arc start and
// end points are not duplicated by point nodes (meaning, for example, a rectangle with rounded
// corners could be represented with four arc nodes and no point nodes).
message PolyLine
{
repeated PolyLineNode nodes = 1;
bool closed = 2;
}
message PolygonWithHoles
{
PolyLine outline = 1;
repeated PolyLine holes = 2;
}
// Corresponds to SHAPE_POLY_SET: a set of polygons or polylines
message PolySet
{
repeated PolygonWithHoles polygons = 1;
}
// Describes whether or not an item is locked for editing or movement
enum LockedState
{
LS_UNKNOWN = 0;
@ -195,23 +266,69 @@ enum LockedState
LS_LOCKED = 2;
}
message BoardLayer
message TextAttributes
{
int32 layer_id = 1; /// From PCB_LAYER_T
string font_name = 1;
HorizontalAlignment horizontal_alignment = 2;
VerticalAlignment vertical_alignment = 3;
kiapi.common.types.Angle angle = 4;
double line_spacing = 5;
kiapi.common.types.Distance stroke_width = 6;
bool italic = 7;
bool bold = 8;
bool underlined = 9;
bool visible = 10;
bool mirrored = 11;
bool multiline = 12;
bool keep_upright = 13;
kiapi.common.types.Vector2 size = 14;
}
/// Describes a copper item's net
message Net
message Text
{
/// A unique code representing this net
int32 code = 1;
/// Human-readable net name
string name = 2;
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
kiapi.common.types.TextAttributes attributes = 3;
kiapi.common.types.LockedState locked = 4;
string text = 5;
string hyperlink = 6;
bool knockout = 7;
}
/// Describes a net class (a grouping of nets)
message NetClass
message TextBox
{
string name = 1;
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 top_left = 2;
kiapi.common.types.Vector2 bottom_right = 3;
kiapi.common.types.TextAttributes attributes = 4;
kiapi.common.types.LockedState locked = 5;
string text = 6;
}
message StrokeAttributes
{
Distance width = 1;
StrokeLineStyle style = 2;
Color color = 3;
}
enum GraphicFillType
{
GFT_UNKNOWN = 0;
GFT_UNFILLED = 1;
GFT_FILLED = 2;
}
message GraphicFillAttributes
{
GraphicFillType fill_type = 1;
// Color of the fill (not used in board and footprints)
Color color = 2;
}
message GraphicAttributes
{
StrokeAttributes stroke = 1;
GraphicFillAttributes fill = 2;
}

View File

@ -0,0 +1,119 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* enums.proto
* Includes protobuf versions of common KiCad enums
*/
syntax = "proto3";
package kiapi.common.types;
// The set of object types (from KICAD_T) that are exposed to the API.
enum KiCadObjectType
{
KOT_UNKNOWN = 0;
KOT_PCB_FOOTPRINT = 1;
KOT_PCB_PAD = 2;
KOT_PCB_SHAPE = 3;
KOT_PCB_REFERENCE_IMAGE = 4;
KOT_PCB_FIELD = 5;
KOT_PCB_GENERATOR = 6;
KOT_PCB_TEXT = 7;
KOT_PCB_TEXTBOX = 8;
KOT_PCB_TABLE = 9;
KOT_PCB_TABLECELL = 10;
KOT_PCB_TRACE = 11;
KOT_PCB_VIA = 12;
KOT_PCB_ARC = 13;
KOT_PCB_MARKER = 14;
KOT_PCB_DIMENSION = 15;
KOT_PCB_ZONE = 16;
KOT_PCB_GROUP = 17;
KOT_SCH_MARKER = 18;
KOT_SCH_JUNCTION = 19;
KOT_SCH_NO_CONNECT = 20;
KOT_SCH_BUS_WIRE_ENTRY = 21;
KOT_SCH_BUS_BUS_ENTRY = 22;
KOT_SCH_LINE = 23;
KOT_SCH_SHAPE = 24;
KOT_SCH_BITMAP = 25;
KOT_SCH_TEXTBOX = 26;
KOT_SCH_TEXT = 27;
KOT_SCH_TABLE = 28;
KOT_SCH_TABLECELL = 29;
KOT_SCH_LABEL = 30;
KOT_SCH_GLOBAL_LABEL = 31;
KOT_SCH_HIER_LABEL = 32;
KOT_SCH_DIRECTIVE_LABEL = 33;
KOT_SCH_FIELD = 34;
KOT_SCH_SYMBOL = 35;
KOT_SCH_SHEET_PIN = 36;
KOT_SCH_SHEET = 37;
KOT_SCH_PIN = 38;
KOT_LIB_SYMBOL = 39;
KOT_LIB_SHAPE = 40;
KOT_LIB_TEXT = 41;
KOT_LIB_TEXTBOX = 42;
KOT_LIB_PIN = 43;
KOT_LIB_FIELD = 44;
KOT_WSG_LINE = 45;
KOT_WSG_RECT = 46;
KOT_WSG_POLY = 47;
KOT_WSG_TEXT = 48;
KOT_WSG_BITMAP = 49;
KOT_WSG_PAGE = 50;
}
// Mapped to GR_TEXT_H_ALIGN_T
enum HorizontalAlignment
{
HA_UNKNOWN = 0;
HA_LEFT = 1;
HA_CENTER = 2;
HA_RIGHT = 3;
HA_INDETERMINATE = 4;
}
// Mapped to GR_TEXT_V_ALIGN_T
enum VerticalAlignment
{
VA_UNKNOWN = 0;
VA_TOP = 1;
VA_CENTER = 2;
VA_BOTTOM = 3;
VA_INDETERMINATE = 4;
}
// Mapped to LINE_STYLE
enum StrokeLineStyle
{
SLS_UNKNOWN = 0;
SLS_DEFAULT = 1;
SLS_SOLID = 2;
SLS_DASH = 3;
SLS_DOT = 4;
SLS_DASHDOT = 5;
SLS_DASHDOTDOT = 6;
}

View File

@ -0,0 +1,35 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* project_settings.proto
* Messages that describes project settings shared between schematics and boards
*/
syntax = "proto3";
package kiapi.common.project;
message NetClass
{
// The name of the netclass (the literal string "Default" for the default netclass)
string name = 1;
}

View File

@ -0,0 +1,24 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
syntax = "proto3";
package kiapi.schematic.types;

View File

@ -0,0 +1,75 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
syntax = "proto3";
package kiapi.schematic.types;
import "common/types/base_types.proto";
enum SchematicLayer
{
SL_UNKNOWN = 0;
}
/// Represents a schematic line segment, which may be a wire, bus, or graphical line
message Line
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 start = 2;
kiapi.common.types.Vector2 end = 3;
/**
* One of: LAYER_BUS, LAYER_WIRE, LAYER_NOTES
*/
SchematicLayer layer = 4;
}
message Text
{
kiapi.common.types.Text text = 1;
}
message LocalLabel
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
Text text = 3;
}
message GlobalLabel
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
Text text = 3;
}
message HierarchicalLabel
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
Text text = 3;
}
message DirectiveLabel
{
kiapi.common.types.KIID id = 1;
kiapi.common.types.Vector2 position = 2;
Text text = 3;
}

View File

@ -41,8 +41,7 @@ add_custom_target(
-DSRC_PATH=${PROJECT_SOURCE_DIR}
-DKICAD_CMAKE_MODULE_PATH=${KICAD_CMAKE_MODULE_PATH}
-P ${KICAD_CMAKE_MODULE_PATH}/BuildSteps/WriteVersionHeader.cmake
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
BYPRODUCTS ${CMAKE_BINARY_DIR}/kicad_build_version.h
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} BYPRODUCTS ${CMAKE_BINARY_DIR}/kicad_build_version.h
DEPENDS ${KICAD_CMAKE_MODULE_PATH}/BuildSteps/WriteVersionHeader.cmake
COMMENT "Generating version string header"
)
@ -632,14 +631,14 @@ set( COMMON_SRCS
http_lib/http_lib_connection.cpp
http_lib/http_lib_settings.cpp
api/api_enums.cpp
api/api_utils.cpp
)
if( KICAD_IPC_API )
set( COMMON_SRCS
${COMMON_SRCS}
api/api_server.cpp
api/api_handler.cpp
api/api_handler_common.cpp
api/api_handler_editor.cpp
)
endif()
@ -693,6 +692,7 @@ target_include_directories( common
.
${CMAKE_BINARY_DIR}
$<TARGET_PROPERTY:argparse::argparse,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:kiapi,INTERFACE_INCLUDE_DIRECTORIES>
)
# text markup support
@ -794,6 +794,12 @@ set( PCB_COMMON_SRCS
widgets/net_selector.cpp
)
set( PCB_COMMON_SRCS
${PCB_COMMON_SRCS}
${CMAKE_SOURCE_DIR}/pcbnew/api/api_pcb_enums.cpp
${CMAKE_SOURCE_DIR}/pcbnew/api/api_pcb_utils.cpp
)
# add -DPCBNEW to compilation of these PCBNEW sources
set_source_files_properties( ${PCB_COMMON_SRCS} PROPERTIES
COMPILE_DEFINITIONS "PCBNEW"

436
common/api/api_enums.cpp Normal file
View File

@ -0,0 +1,436 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <api/api_enums.h>
#include <import_export.h>
#include <api/common/types/enums.pb.h>
#include <api/board/board_types.pb.h>
#include <api/schematic/schematic_types.pb.h>
#include <core/typeinfo.h>
#include <font/text_attributes.h>
#include <layer_ids.h>
#include <stroke_params.h>
using namespace kiapi;
using namespace kiapi::common;
template<>
KICAD_T FromProtoEnum( types::KiCadObjectType aValue )
{
switch( aValue )
{
case types::KiCadObjectType::KOT_PCB_FOOTPRINT: return PCB_FOOTPRINT_T;
case types::KiCadObjectType::KOT_PCB_PAD: return PCB_PAD_T;
case types::KiCadObjectType::KOT_PCB_SHAPE: return PCB_SHAPE_T;
case types::KiCadObjectType::KOT_PCB_REFERENCE_IMAGE: return PCB_REFERENCE_IMAGE_T;
case types::KiCadObjectType::KOT_PCB_FIELD: return PCB_FIELD_T;
case types::KiCadObjectType::KOT_PCB_GENERATOR: return PCB_GENERATOR_T;
case types::KiCadObjectType::KOT_PCB_TEXT: return PCB_TEXT_T;
case types::KiCadObjectType::KOT_PCB_TEXTBOX: return PCB_TEXTBOX_T;
case types::KiCadObjectType::KOT_PCB_TABLE: return PCB_TABLE_T;
case types::KiCadObjectType::KOT_PCB_TABLECELL: return PCB_TABLECELL_T;
case types::KiCadObjectType::KOT_PCB_TRACE: return PCB_TRACE_T;
case types::KiCadObjectType::KOT_PCB_VIA: return PCB_VIA_T;
case types::KiCadObjectType::KOT_PCB_ARC: return PCB_ARC_T;
case types::KiCadObjectType::KOT_PCB_MARKER: return PCB_MARKER_T;
case types::KiCadObjectType::KOT_PCB_DIMENSION: return PCB_DIMENSION_T;
case types::KiCadObjectType::KOT_PCB_ZONE: return PCB_ZONE_T;
case types::KiCadObjectType::KOT_PCB_GROUP: return PCB_GROUP_T;
case types::KiCadObjectType::KOT_SCH_MARKER: return SCH_MARKER_T;
case types::KiCadObjectType::KOT_SCH_JUNCTION: return SCH_JUNCTION_T;
case types::KiCadObjectType::KOT_SCH_NO_CONNECT: return SCH_NO_CONNECT_T;
case types::KiCadObjectType::KOT_SCH_BUS_WIRE_ENTRY: return SCH_BUS_WIRE_ENTRY_T;
case types::KiCadObjectType::KOT_SCH_BUS_BUS_ENTRY: return SCH_BUS_BUS_ENTRY_T;
case types::KiCadObjectType::KOT_SCH_LINE: return SCH_LINE_T;
case types::KiCadObjectType::KOT_SCH_SHAPE: return SCH_SHAPE_T;
case types::KiCadObjectType::KOT_SCH_BITMAP: return SCH_BITMAP_T;
case types::KiCadObjectType::KOT_SCH_TEXTBOX: return SCH_TEXTBOX_T;
case types::KiCadObjectType::KOT_SCH_TEXT: return SCH_TEXT_T;
case types::KiCadObjectType::KOT_SCH_TABLE: return SCH_TABLE_T;
case types::KiCadObjectType::KOT_SCH_TABLECELL: return SCH_TABLECELL_T;
case types::KiCadObjectType::KOT_SCH_LABEL: return SCH_LABEL_T;
case types::KiCadObjectType::KOT_SCH_GLOBAL_LABEL: return SCH_GLOBAL_LABEL_T;
case types::KiCadObjectType::KOT_SCH_HIER_LABEL: return SCH_HIER_LABEL_T;
case types::KiCadObjectType::KOT_SCH_DIRECTIVE_LABEL: return SCH_DIRECTIVE_LABEL_T;
case types::KiCadObjectType::KOT_SCH_FIELD: return SCH_FIELD_T;
case types::KiCadObjectType::KOT_SCH_SYMBOL: return SCH_SYMBOL_T;
case types::KiCadObjectType::KOT_SCH_SHEET_PIN: return SCH_SHEET_PIN_T;
case types::KiCadObjectType::KOT_SCH_SHEET: return SCH_SHEET_T;
case types::KiCadObjectType::KOT_SCH_PIN: return SCH_PIN_T;
case types::KiCadObjectType::KOT_LIB_SYMBOL: return LIB_SYMBOL_T;
case types::KiCadObjectType::KOT_LIB_SHAPE: return LIB_SHAPE_T;
case types::KiCadObjectType::KOT_LIB_TEXT: return LIB_TEXT_T;
case types::KiCadObjectType::KOT_LIB_TEXTBOX: return LIB_TEXTBOX_T;
case types::KiCadObjectType::KOT_LIB_PIN: return LIB_PIN_T;
case types::KiCadObjectType::KOT_LIB_FIELD: return LIB_FIELD_T;
case types::KiCadObjectType::KOT_WSG_LINE: return WSG_LINE_T;
case types::KiCadObjectType::KOT_WSG_RECT: return WSG_RECT_T;
case types::KiCadObjectType::KOT_WSG_POLY: return WSG_POLY_T;
case types::KiCadObjectType::KOT_WSG_TEXT: return WSG_TEXT_T;
case types::KiCadObjectType::KOT_WSG_BITMAP: return WSG_BITMAP_T;
case types::KiCadObjectType::KOT_WSG_PAGE: return WSG_PAGE_T;
case types::KiCadObjectType::KOT_UNKNOWN: return TYPE_NOT_INIT;
default:
wxCHECK_MSG( false, TYPE_NOT_INIT,
"Unhandled case in FromProtoEnum<types::KiCadObjectType>" );
}
}
template<>
types::KiCadObjectType ToProtoEnum( KICAD_T aValue )
{
switch( aValue )
{
case PCB_FOOTPRINT_T: return types::KiCadObjectType::KOT_PCB_FOOTPRINT;
case PCB_PAD_T: return types::KiCadObjectType::KOT_PCB_PAD;
case PCB_SHAPE_T: return types::KiCadObjectType::KOT_PCB_SHAPE;
case PCB_REFERENCE_IMAGE_T: return types::KiCadObjectType::KOT_PCB_REFERENCE_IMAGE;
case PCB_FIELD_T: return types::KiCadObjectType::KOT_PCB_FIELD;
case PCB_GENERATOR_T: return types::KiCadObjectType::KOT_PCB_GENERATOR;
case PCB_TEXT_T: return types::KiCadObjectType::KOT_PCB_TEXT;
case PCB_TEXTBOX_T: return types::KiCadObjectType::KOT_PCB_TEXTBOX;
case PCB_TABLE_T: return types::KiCadObjectType::KOT_PCB_TABLE;
case PCB_TABLECELL_T: return types::KiCadObjectType::KOT_PCB_TABLECELL;
case PCB_TRACE_T: return types::KiCadObjectType::KOT_PCB_TRACE;
case PCB_VIA_T: return types::KiCadObjectType::KOT_PCB_VIA;
case PCB_ARC_T: return types::KiCadObjectType::KOT_PCB_ARC;
case PCB_MARKER_T: return types::KiCadObjectType::KOT_PCB_MARKER;
case PCB_DIMENSION_T: return types::KiCadObjectType::KOT_PCB_DIMENSION;
case PCB_ZONE_T: return types::KiCadObjectType::KOT_PCB_ZONE;
case PCB_GROUP_T: return types::KiCadObjectType::KOT_PCB_GROUP;
case SCH_MARKER_T: return types::KiCadObjectType::KOT_SCH_MARKER;
case SCH_JUNCTION_T: return types::KiCadObjectType::KOT_SCH_JUNCTION;
case SCH_NO_CONNECT_T: return types::KiCadObjectType::KOT_SCH_NO_CONNECT;
case SCH_BUS_WIRE_ENTRY_T: return types::KiCadObjectType::KOT_SCH_BUS_WIRE_ENTRY;
case SCH_BUS_BUS_ENTRY_T: return types::KiCadObjectType::KOT_SCH_BUS_BUS_ENTRY;
case SCH_LINE_T: return types::KiCadObjectType::KOT_SCH_LINE;
case SCH_SHAPE_T: return types::KiCadObjectType::KOT_SCH_SHAPE;
case SCH_BITMAP_T: return types::KiCadObjectType::KOT_SCH_BITMAP;
case SCH_TEXTBOX_T: return types::KiCadObjectType::KOT_SCH_TEXTBOX;
case SCH_TEXT_T: return types::KiCadObjectType::KOT_SCH_TEXT;
case SCH_TABLE_T: return types::KiCadObjectType::KOT_SCH_TABLE;
case SCH_TABLECELL_T: return types::KiCadObjectType::KOT_SCH_TABLECELL;
case SCH_LABEL_T: return types::KiCadObjectType::KOT_SCH_LABEL;
case SCH_GLOBAL_LABEL_T: return types::KiCadObjectType::KOT_SCH_GLOBAL_LABEL;
case SCH_HIER_LABEL_T: return types::KiCadObjectType::KOT_SCH_HIER_LABEL;
case SCH_DIRECTIVE_LABEL_T: return types::KiCadObjectType::KOT_SCH_DIRECTIVE_LABEL;
case SCH_FIELD_T: return types::KiCadObjectType::KOT_SCH_FIELD;
case SCH_SYMBOL_T: return types::KiCadObjectType::KOT_SCH_SYMBOL;
case SCH_SHEET_PIN_T: return types::KiCadObjectType::KOT_SCH_SHEET_PIN;
case SCH_SHEET_T: return types::KiCadObjectType::KOT_SCH_SHEET;
case SCH_PIN_T: return types::KiCadObjectType::KOT_SCH_PIN;
case LIB_SYMBOL_T: return types::KiCadObjectType::KOT_LIB_SYMBOL;
case LIB_SHAPE_T: return types::KiCadObjectType::KOT_LIB_SHAPE;
case LIB_TEXT_T: return types::KiCadObjectType::KOT_LIB_TEXT;
case LIB_TEXTBOX_T: return types::KiCadObjectType::KOT_LIB_TEXTBOX;
case LIB_PIN_T: return types::KiCadObjectType::KOT_LIB_PIN;
case LIB_FIELD_T: return types::KiCadObjectType::KOT_LIB_FIELD;
case WSG_LINE_T: return types::KiCadObjectType::KOT_WSG_LINE;
case WSG_RECT_T: return types::KiCadObjectType::KOT_WSG_RECT;
case WSG_POLY_T: return types::KiCadObjectType::KOT_WSG_POLY;
case WSG_TEXT_T: return types::KiCadObjectType::KOT_WSG_TEXT;
case WSG_BITMAP_T: return types::KiCadObjectType::KOT_WSG_BITMAP;
case WSG_PAGE_T: return types::KiCadObjectType::KOT_WSG_PAGE;
default:
wxCHECK_MSG( false, types::KiCadObjectType::KOT_UNKNOWN,
"Unhandled case in ToProtoEnum<KICAD_T>");
}
}
template<>
PCB_LAYER_ID FromProtoEnum( board::types::BoardLayer aValue )
{
switch( aValue )
{
case board::types::BoardLayer::BL_UNDEFINED: return UNDEFINED_LAYER;
case board::types::BoardLayer::BL_UNSELECTED: return UNSELECTED_LAYER;
case board::types::BoardLayer::BL_F_Cu: return F_Cu;
case board::types::BoardLayer::BL_In1_Cu: return In1_Cu;
case board::types::BoardLayer::BL_In2_Cu: return In2_Cu;
case board::types::BoardLayer::BL_In3_Cu: return In3_Cu;
case board::types::BoardLayer::BL_In4_Cu: return In4_Cu;
case board::types::BoardLayer::BL_In5_Cu: return In5_Cu;
case board::types::BoardLayer::BL_In6_Cu: return In6_Cu;
case board::types::BoardLayer::BL_In7_Cu: return In7_Cu;
case board::types::BoardLayer::BL_In8_Cu: return In8_Cu;
case board::types::BoardLayer::BL_In9_Cu: return In9_Cu;
case board::types::BoardLayer::BL_In10_Cu: return In10_Cu;
case board::types::BoardLayer::BL_In11_Cu: return In11_Cu;
case board::types::BoardLayer::BL_In12_Cu: return In12_Cu;
case board::types::BoardLayer::BL_In13_Cu: return In13_Cu;
case board::types::BoardLayer::BL_In14_Cu: return In14_Cu;
case board::types::BoardLayer::BL_In15_Cu: return In15_Cu;
case board::types::BoardLayer::BL_In16_Cu: return In16_Cu;
case board::types::BoardLayer::BL_In17_Cu: return In17_Cu;
case board::types::BoardLayer::BL_In18_Cu: return In18_Cu;
case board::types::BoardLayer::BL_In19_Cu: return In19_Cu;
case board::types::BoardLayer::BL_In20_Cu: return In20_Cu;
case board::types::BoardLayer::BL_In21_Cu: return In21_Cu;
case board::types::BoardLayer::BL_In22_Cu: return In22_Cu;
case board::types::BoardLayer::BL_In23_Cu: return In23_Cu;
case board::types::BoardLayer::BL_In24_Cu: return In24_Cu;
case board::types::BoardLayer::BL_In25_Cu: return In25_Cu;
case board::types::BoardLayer::BL_In26_Cu: return In26_Cu;
case board::types::BoardLayer::BL_In27_Cu: return In27_Cu;
case board::types::BoardLayer::BL_In28_Cu: return In28_Cu;
case board::types::BoardLayer::BL_In29_Cu: return In29_Cu;
case board::types::BoardLayer::BL_In30_Cu: return In30_Cu;
case board::types::BoardLayer::BL_B_Cu: return B_Cu;
case board::types::BoardLayer::BL_B_Adhes: return B_Adhes;
case board::types::BoardLayer::BL_F_Adhes: return F_Adhes;
case board::types::BoardLayer::BL_B_Paste: return B_Paste;
case board::types::BoardLayer::BL_F_Paste: return F_Paste;
case board::types::BoardLayer::BL_B_SilkS: return B_SilkS;
case board::types::BoardLayer::BL_F_SilkS: return F_SilkS;
case board::types::BoardLayer::BL_B_Mask: return B_Mask;
case board::types::BoardLayer::BL_F_Mask: return F_Mask;
case board::types::BoardLayer::BL_Dwgs_User: return Dwgs_User;
case board::types::BoardLayer::BL_Cmts_User: return Cmts_User;
case board::types::BoardLayer::BL_Eco1_User: return Eco1_User;
case board::types::BoardLayer::BL_Eco2_User: return Eco2_User;
case board::types::BoardLayer::BL_Edge_Cuts: return Edge_Cuts;
case board::types::BoardLayer::BL_Margin: return Margin;
case board::types::BoardLayer::BL_B_CrtYd: return B_CrtYd;
case board::types::BoardLayer::BL_F_CrtYd: return F_CrtYd;
case board::types::BoardLayer::BL_B_Fab: return B_Fab;
case board::types::BoardLayer::BL_F_Fab: return F_Fab;
case board::types::BoardLayer::BL_User_1: return User_1;
case board::types::BoardLayer::BL_User_2: return User_2;
case board::types::BoardLayer::BL_User_3: return User_3;
case board::types::BoardLayer::BL_User_4: return User_4;
case board::types::BoardLayer::BL_User_5: return User_5;
case board::types::BoardLayer::BL_User_6: return User_6;
case board::types::BoardLayer::BL_User_7: return User_7;
case board::types::BoardLayer::BL_User_8: return User_8;
case board::types::BoardLayer::BL_User_9: return User_9;
case board::types::BoardLayer::BL_UNKNOWN: return UNDEFINED_LAYER;
default:
wxCHECK_MSG( false, UNDEFINED_LAYER,
"Unhandled case in FromProtoEnum<board::types::BoardLayer>" );
}
}
template<>
board::types::BoardLayer ToProtoEnum( PCB_LAYER_ID aValue )
{
switch( aValue )
{
case UNDEFINED_LAYER: return board::types::BoardLayer::BL_UNDEFINED;
case UNSELECTED_LAYER: return board::types::BoardLayer::BL_UNSELECTED;
case F_Cu: return board::types::BoardLayer::BL_F_Cu;
case In1_Cu: return board::types::BoardLayer::BL_In1_Cu;
case In2_Cu: return board::types::BoardLayer::BL_In2_Cu;
case In3_Cu: return board::types::BoardLayer::BL_In3_Cu;
case In4_Cu: return board::types::BoardLayer::BL_In4_Cu;
case In5_Cu: return board::types::BoardLayer::BL_In5_Cu;
case In6_Cu: return board::types::BoardLayer::BL_In6_Cu;
case In7_Cu: return board::types::BoardLayer::BL_In7_Cu;
case In8_Cu: return board::types::BoardLayer::BL_In8_Cu;
case In9_Cu: return board::types::BoardLayer::BL_In9_Cu;
case In10_Cu: return board::types::BoardLayer::BL_In10_Cu;
case In11_Cu: return board::types::BoardLayer::BL_In11_Cu;
case In12_Cu: return board::types::BoardLayer::BL_In12_Cu;
case In13_Cu: return board::types::BoardLayer::BL_In13_Cu;
case In14_Cu: return board::types::BoardLayer::BL_In14_Cu;
case In15_Cu: return board::types::BoardLayer::BL_In15_Cu;
case In16_Cu: return board::types::BoardLayer::BL_In16_Cu;
case In17_Cu: return board::types::BoardLayer::BL_In17_Cu;
case In18_Cu: return board::types::BoardLayer::BL_In18_Cu;
case In19_Cu: return board::types::BoardLayer::BL_In19_Cu;
case In20_Cu: return board::types::BoardLayer::BL_In20_Cu;
case In21_Cu: return board::types::BoardLayer::BL_In21_Cu;
case In22_Cu: return board::types::BoardLayer::BL_In22_Cu;
case In23_Cu: return board::types::BoardLayer::BL_In23_Cu;
case In24_Cu: return board::types::BoardLayer::BL_In24_Cu;
case In25_Cu: return board::types::BoardLayer::BL_In25_Cu;
case In26_Cu: return board::types::BoardLayer::BL_In26_Cu;
case In27_Cu: return board::types::BoardLayer::BL_In27_Cu;
case In28_Cu: return board::types::BoardLayer::BL_In28_Cu;
case In29_Cu: return board::types::BoardLayer::BL_In29_Cu;
case In30_Cu: return board::types::BoardLayer::BL_In30_Cu;
case B_Cu: return board::types::BoardLayer::BL_B_Cu;
case B_Adhes: return board::types::BoardLayer::BL_B_Adhes;
case F_Adhes: return board::types::BoardLayer::BL_F_Adhes;
case B_Paste: return board::types::BoardLayer::BL_B_Paste;
case F_Paste: return board::types::BoardLayer::BL_F_Paste;
case B_SilkS: return board::types::BoardLayer::BL_B_SilkS;
case F_SilkS: return board::types::BoardLayer::BL_F_SilkS;
case B_Mask: return board::types::BoardLayer::BL_B_Mask;
case F_Mask: return board::types::BoardLayer::BL_F_Mask;
case Dwgs_User: return board::types::BoardLayer::BL_Dwgs_User;
case Cmts_User: return board::types::BoardLayer::BL_Cmts_User;
case Eco1_User: return board::types::BoardLayer::BL_Eco1_User;
case Eco2_User: return board::types::BoardLayer::BL_Eco2_User;
case Edge_Cuts: return board::types::BoardLayer::BL_Edge_Cuts;
case Margin: return board::types::BoardLayer::BL_Margin;
case B_CrtYd: return board::types::BoardLayer::BL_B_CrtYd;
case F_CrtYd: return board::types::BoardLayer::BL_F_CrtYd;
case B_Fab: return board::types::BoardLayer::BL_B_Fab;
case F_Fab: return board::types::BoardLayer::BL_F_Fab;
case User_1: return board::types::BoardLayer::BL_User_1;
case User_2: return board::types::BoardLayer::BL_User_2;
case User_3: return board::types::BoardLayer::BL_User_3;
case User_4: return board::types::BoardLayer::BL_User_4;
case User_5: return board::types::BoardLayer::BL_User_5;
case User_6: return board::types::BoardLayer::BL_User_6;
case User_7: return board::types::BoardLayer::BL_User_7;
case User_8: return board::types::BoardLayer::BL_User_8;
case User_9: return board::types::BoardLayer::BL_User_9;
default:
wxCHECK_MSG( false, board::types::BoardLayer::BL_UNKNOWN,
"Unhandled case in ToProtoEnum<PCB_LAYER_ID>");
}
}
template<>
SCH_LAYER_ID FromProtoEnum( schematic::types::SchematicLayer aValue )
{
switch( aValue )
{
default:
wxCHECK_MSG( false, SCH_LAYER_ID_START,
"Unhandled case in FromProtoEnum<schematic::types::SchematicLayer>" );
}
}
template<>
schematic::types::SchematicLayer ToProtoEnum( SCH_LAYER_ID aValue )
{
switch( aValue )
{
default:
wxCHECK_MSG( false, schematic::types::SchematicLayer::SL_UNKNOWN,
"Unhandled case in ToProtoEnum<SCH_LAYER_ID>");
}
}
template<>
GR_TEXT_H_ALIGN_T FromProtoEnum( types::HorizontalAlignment aValue )
{
switch( aValue )
{
case types::HorizontalAlignment::HA_LEFT: return GR_TEXT_H_ALIGN_LEFT;
case types::HorizontalAlignment::HA_CENTER: return GR_TEXT_H_ALIGN_CENTER;
case types::HorizontalAlignment::HA_RIGHT: return GR_TEXT_H_ALIGN_RIGHT;
case types::HorizontalAlignment::HA_INDETERMINATE: return GR_TEXT_H_ALIGN_INDETERMINATE;
case types::HorizontalAlignment::HA_UNKNOWN: return GR_TEXT_H_ALIGN_CENTER;
default:
wxCHECK_MSG( false, GR_TEXT_H_ALIGN_CENTER,
"Unhandled case in FromProtoEnum<types::HorizontalAlignment>" );
}
}
template<>
types::HorizontalAlignment ToProtoEnum( GR_TEXT_H_ALIGN_T aValue )
{
switch( aValue )
{
case GR_TEXT_H_ALIGN_LEFT: return types::HorizontalAlignment::HA_LEFT;
case GR_TEXT_H_ALIGN_CENTER: return types::HorizontalAlignment::HA_CENTER;
case GR_TEXT_H_ALIGN_RIGHT: return types::HorizontalAlignment::HA_RIGHT;
case GR_TEXT_H_ALIGN_INDETERMINATE: return types::HorizontalAlignment::HA_INDETERMINATE;
default:
wxCHECK_MSG( false, types::HorizontalAlignment::HA_UNKNOWN,
"Unhandled case in ToProtoEnum<GR_TEXT_H_ALIGN_T>");
}
}
template<>
GR_TEXT_V_ALIGN_T FromProtoEnum( types::VerticalAlignment aValue )
{
switch( aValue )
{
case types::VerticalAlignment::VA_TOP: return GR_TEXT_V_ALIGN_TOP;
case types::VerticalAlignment::VA_CENTER: return GR_TEXT_V_ALIGN_CENTER;
case types::VerticalAlignment::VA_BOTTOM: return GR_TEXT_V_ALIGN_BOTTOM;
case types::VerticalAlignment::VA_INDETERMINATE: return GR_TEXT_V_ALIGN_INDETERMINATE;
case types::VerticalAlignment::VA_UNKNOWN: return GR_TEXT_V_ALIGN_CENTER;
default:
wxCHECK_MSG( false, GR_TEXT_V_ALIGN_CENTER,
"Unhandled case in FromProtoEnum<types::VerticalAlignment>" );
}
}
template<>
types::VerticalAlignment ToProtoEnum( GR_TEXT_V_ALIGN_T aValue )
{
switch( aValue )
{
case GR_TEXT_V_ALIGN_TOP: return types::VerticalAlignment::VA_TOP;
case GR_TEXT_V_ALIGN_CENTER: return types::VerticalAlignment::VA_CENTER;
case GR_TEXT_V_ALIGN_BOTTOM: return types::VerticalAlignment::VA_BOTTOM;
case GR_TEXT_V_ALIGN_INDETERMINATE: return types::VerticalAlignment::VA_INDETERMINATE;
default:
wxCHECK_MSG( false, types::VerticalAlignment::VA_UNKNOWN,
"Unhandled case in ToProtoEnum<GR_TEXT_V_ALIGN_T>");
}
}
template<>
LINE_STYLE FromProtoEnum( types::StrokeLineStyle aValue )
{
switch( aValue )
{
case types::StrokeLineStyle::SLS_DEFAULT: return LINE_STYLE::DEFAULT;
case types::StrokeLineStyle::SLS_SOLID: return LINE_STYLE::SOLID;
case types::StrokeLineStyle::SLS_DASH: return LINE_STYLE::DASH;
case types::StrokeLineStyle::SLS_DOT: return LINE_STYLE::DOT;
case types::StrokeLineStyle::SLS_DASHDOT: return LINE_STYLE::DASHDOT;
case types::StrokeLineStyle::SLS_DASHDOTDOT: return LINE_STYLE::DASHDOTDOT;
case types::StrokeLineStyle::SLS_UNKNOWN:
default:
wxCHECK_MSG( false, LINE_STYLE::DEFAULT,
"Unhandled case in FromProtoEnum<types::StrokeLineStyle>" );
}
}
template<>
types::StrokeLineStyle ToProtoEnum( LINE_STYLE aValue )
{
switch( aValue )
{
case LINE_STYLE::DEFAULT: return types::StrokeLineStyle::SLS_DEFAULT;
case LINE_STYLE::SOLID: return types::StrokeLineStyle::SLS_SOLID;
case LINE_STYLE::DASH: return types::StrokeLineStyle::SLS_DASH;
case LINE_STYLE::DOT: return types::StrokeLineStyle::SLS_DOT;
case LINE_STYLE::DASHDOT: return types::StrokeLineStyle::SLS_DASHDOT;
case LINE_STYLE::DASHDOTDOT: return types::StrokeLineStyle::SLS_DASHDOTDOT;
default:
wxCHECK_MSG( false, types::StrokeLineStyle::SLS_UNKNOWN,
"Unhandled case in ToProtoEnum<LINE_STYLE>");
}
}

View File

@ -19,10 +19,14 @@
*/
#include <api/api_handler.h>
#include <wx/wx.h>
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiResponseStatus;
const wxString API_HANDLER::m_defaultCommitMessage = _( "Modification from API" );
API_RESULT API_HANDLER::Handle( ApiRequest& aMsg )
{
ApiResponseStatus status;
@ -55,20 +59,3 @@ API_RESULT API_HANDLER::Handle( ApiRequest& aMsg )
// This response is used internally; no need for an error message
return tl::unexpected( status );
}
std::optional<KICAD_T> API_HANDLER::TypeNameFromAny( const google::protobuf::Any& aMessage )
{
static const std::map<std::string, KICAD_T> s_types = {
{ "type.googleapis.com/kiapi.board.types.Track", PCB_TRACE_T },
{ "type.googleapis.com/kiapi.board.types.Arc", PCB_ARC_T },
{ "type.googleapis.com/kiapi.board.types.Via", PCB_VIA_T },
};
auto it = s_types.find( aMessage.type_url() );
if( it != s_types.end() )
return it->second;
return std::nullopt;
}

View File

@ -22,7 +22,11 @@
#include <api/api_handler_common.h>
#include <build_version.h>
#include <google/protobuf/empty.pb.h>
#include <pgm_base.h>
#include <project/net_settings.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <wx/string.h>
using namespace kiapi::common::commands;
@ -34,10 +38,13 @@ API_HANDLER_COMMON::API_HANDLER_COMMON() :
API_HANDLER()
{
registerHandler<GetVersion, GetVersionResponse>( &API_HANDLER_COMMON::handleGetVersion );
registerHandler<GetNetClasses, NetClassesResponse>( &API_HANDLER_COMMON::handleGetNetClasses );
registerHandler<Ping, Empty>( &API_HANDLER_COMMON::handlePing );
}
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion& aMsg )
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion&,
const HANDLER_CONTEXT& )
{
GetVersionResponse reply;
@ -50,3 +57,26 @@ HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVers
return reply;
}
HANDLER_RESULT<NetClassesResponse> API_HANDLER_COMMON::handleGetNetClasses( GetNetClasses& aMsg,
const HANDLER_CONTEXT& aCtx )
{
NetClassesResponse reply;
std::shared_ptr<NET_SETTINGS>& netSettings =
Pgm().GetSettingsManager().Prj().GetProjectFile().m_NetSettings;
for( const auto& [name, netClass] : netSettings->m_NetClasses )
{
reply.add_net_classes()->set_name( name.ToStdString() );
}
return reply;
}
HANDLER_RESULT<Empty> API_HANDLER_COMMON::handlePing( Ping& aMsg, const HANDLER_CONTEXT& aCtx )
{
return Empty();
}

View File

@ -0,0 +1,353 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Jon Evans <jon@craftyjon.com>
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <api/api_handler_editor.h>
#include <api/api_utils.h>
#include <eda_base_frame.h>
#include <eda_item.h>
#include <wx/wx.h>
using namespace kiapi::common::commands;
API_HANDLER_EDITOR::API_HANDLER_EDITOR( EDA_BASE_FRAME* aFrame ) :
API_HANDLER(),
m_frame( aFrame )
{
registerHandler<BeginCommit, BeginCommitResponse>( &API_HANDLER_EDITOR::handleBeginCommit );
registerHandler<EndCommit, EndCommitResponse>( &API_HANDLER_EDITOR::handleEndCommit );
registerHandler<CreateItems, CreateItemsResponse>( &API_HANDLER_EDITOR::handleCreateItems );
registerHandler<UpdateItems, UpdateItemsResponse>( &API_HANDLER_EDITOR::handleUpdateItems );
registerHandler<DeleteItems, DeleteItemsResponse>( &API_HANDLER_EDITOR::handleDeleteItems );
registerHandler<HitTest, HitTestResponse>( &API_HANDLER_EDITOR::handleHitTest );
}
HANDLER_RESULT<BeginCommitResponse> API_HANDLER_EDITOR::handleBeginCommit( BeginCommit& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
if( m_commits.count( aCtx.ClientName ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( fmt::format( "the client {} already has a commit in progress",
aCtx.ClientName ) );
return tl::unexpected( e );
}
wxASSERT( !m_activeClients.count( aCtx.ClientName ) );
BeginCommitResponse response;
KIID id;
m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
response.mutable_id()->set_value( id.AsStdString() );
m_activeClients.insert( aCtx.ClientName );
return response;
}
HANDLER_RESULT<EndCommitResponse> API_HANDLER_EDITOR::handleEndCommit( EndCommit& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
if( !m_commits.count( aCtx.ClientName ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( fmt::format( "the client {} does not has a commit in progress",
aCtx.ClientName ) );
return tl::unexpected( e );
}
wxASSERT( m_activeClients.count( aCtx.ClientName ) );
const std::pair<KIID, std::unique_ptr<COMMIT>>& pair = m_commits.at( aCtx.ClientName );
const KIID& id = pair.first;
const std::unique_ptr<COMMIT>& commit = pair.second;
EndCommitResponse response;
// Do not check IDs with drop; it is a safety net in case the id was lost on the client side
switch( aMsg.action() )
{
case kiapi::common::commands::CMA_DROP:
{
commit->Revert();
m_commits.erase( aCtx.ClientName );
m_activeClients.erase( aCtx.ClientName );
break;
}
case kiapi::common::commands::CMA_COMMIT:
{
if( aMsg.id().value().compare( id.AsStdString() ) != 0 )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( fmt::format( "the id {} does not match the commit in progress",
aMsg.id().value() ) );
return tl::unexpected( e );
}
pushCurrentCommit( aCtx, wxString( aMsg.message().c_str(), wxConvUTF8 ) );
break;
}
default:
break;
}
return response;
}
COMMIT* API_HANDLER_EDITOR::getCurrentCommit( const HANDLER_CONTEXT& aCtx )
{
if( !m_commits.count( aCtx.ClientName ) )
{
KIID id;
m_commits[aCtx.ClientName] = std::make_pair( id, createCommit() );
}
return m_commits.at( aCtx.ClientName ).second.get();
}
void API_HANDLER_EDITOR::pushCurrentCommit( const HANDLER_CONTEXT& aCtx, const wxString& aMessage )
{
auto it = m_commits.find( aCtx.ClientName );
if( it == m_commits.end() )
return;
it->second.second->Push( aMessage.IsEmpty() ? m_defaultCommitMessage : aMessage );
m_commits.erase( it );
m_activeClients.erase( aCtx.ClientName );
}
HANDLER_RESULT<bool> API_HANDLER_EDITOR::validateDocument(
const kiapi::common::types::DocumentSpecifier& aDocument )
{
if( !validateDocumentInternal( aDocument ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( fmt::format( "the requested document {} is not open",
aDocument.board_filename() ) );
return tl::unexpected( e );
}
return true;
}
HANDLER_RESULT<std::optional<KIID>> API_HANDLER_EDITOR::validateItemHeaderDocument(
const kiapi::common::types::ItemHeader& aHeader )
{
if( !aHeader.has_document() || aHeader.document().type() != thisDocumentType() )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_UNHANDLED );
// No error message, this is a flag that the server should try a different handler
return tl::unexpected( e );
}
HANDLER_RESULT<bool> documentValidation = validateDocument( aHeader.document() );
if( !documentValidation )
return tl::unexpected( documentValidation.error() );
if( !validateDocumentInternal( aHeader.document() ) )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( fmt::format( "the requested document {} is not open",
aHeader.document().board_filename() ) );
return tl::unexpected( e );
}
if( aHeader.has_container() )
{
return KIID( aHeader.container().value() );
}
// Valid header, but no container provided
return std::nullopt;
}
std::optional<ApiResponseStatus> API_HANDLER_EDITOR::checkForBusy()
{
if( !m_frame->CanAcceptApiCommands() )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BUSY );
e.set_error_message( "KiCad is busy and cannot respond to API requests right now" );
return e;
}
return std::nullopt;
}
HANDLER_RESULT<CreateItemsResponse> API_HANDLER_EDITOR::handleCreateItems( CreateItems& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
CreateItemsResponse response;
HANDLER_RESULT<ItemRequestStatus> result = handleCreateUpdateItemsInternal( true, aCtx,
aMsg.header(), aMsg.items(),
[&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
{
ItemCreationResult itemResult;
itemResult.mutable_status()->CopyFrom( aStatus );
itemResult.mutable_item()->CopyFrom( aItem );
response.mutable_created_items()->Add( std::move( itemResult ) );
} );
if( !result.has_value() )
return tl::unexpected( result.error() );
response.set_status( *result );
return response;
}
HANDLER_RESULT<UpdateItemsResponse> API_HANDLER_EDITOR::handleUpdateItems( UpdateItems& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
UpdateItemsResponse response;
HANDLER_RESULT<ItemRequestStatus> result = handleCreateUpdateItemsInternal( false, aCtx,
aMsg.header(), aMsg.items(),
[&]( const ItemStatus& aStatus, const google::protobuf::Any& aItem )
{
ItemUpdateResult itemResult;
itemResult.mutable_status()->CopyFrom( aStatus );
itemResult.mutable_item()->CopyFrom( aItem );
response.mutable_updated_items()->Add( std::move( itemResult ) );
} );
if( !result.has_value() )
return tl::unexpected( result.error() );
response.set_status( *result );
return response;
}
HANDLER_RESULT<DeleteItemsResponse> API_HANDLER_EDITOR::handleDeleteItems( DeleteItems& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
if( !validateItemHeaderDocument( aMsg.header() ) )
{
ApiResponseStatus e;
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
e.set_status( ApiStatusCode::AS_UNHANDLED );
return tl::unexpected( e );
}
std::map<KIID, ItemDeletionStatus> itemsToDelete;
for( const kiapi::common::types::KIID& kiidBuf : aMsg.item_ids() )
{
if( !kiidBuf.value().empty() )
{
KIID kiid( kiidBuf.value() );
itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT;
}
}
if( itemsToDelete.empty() )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( "no valid items to delete were given" );
return tl::unexpected( e );
}
deleteItemsInternal( itemsToDelete, aCtx );
DeleteItemsResponse response;
for( const auto& [id, status] : itemsToDelete )
{
ItemDeletionResult result;
result.mutable_id()->set_value( id.AsStdString() );
result.set_status( status );
}
response.set_status( kiapi::common::types::ItemRequestStatus::IRS_OK );
return response;
}
HANDLER_RESULT<HitTestResponse> API_HANDLER_EDITOR::handleHitTest( HitTest& aMsg,
const HANDLER_CONTEXT& aCtx )
{
if( std::optional<ApiResponseStatus> busy = checkForBusy() )
return tl::unexpected( *busy );
if( !validateItemHeaderDocument( aMsg.header() ) )
{
ApiResponseStatus e;
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
e.set_status( ApiStatusCode::AS_UNHANDLED );
return tl::unexpected( e );
}
HitTestResponse response;
std::optional<EDA_ITEM*> item = getItemFromDocument( aMsg.header().document(),
KIID( aMsg.id().value() ) );
if( !item )
{
ApiResponseStatus e;
e.set_status( ApiStatusCode::AS_BAD_REQUEST );
e.set_error_message( "the requested item ID is not present in the given document" );
return tl::unexpected( e );
}
if( ( *item )->HitTest( kiapi::common::UnpackVector2( aMsg.position() ), aMsg.tolerance() ) )
response.set_result( HitTestResult::HTR_HIT );
else
response.set_result( HitTestResult::HTR_NO_HIT );
return response;
}

View File

@ -312,7 +312,8 @@ std::optional<PLUGIN_ACTION> API_PLUGIN::createActionFromJson( const nlohmann::j
}
wxBitmap bmp;
bmp.LoadFile( iconFile.GetFullPath() );
// TODO: If necessary; support types other than PNG
bmp.LoadFile( iconFile.GetFullPath(), wxBITMAP_TYPE_PNG );
if( bmp.IsOk() )
bitmaps.push_back( bmp );

View File

@ -303,10 +303,15 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
return;
}
wxLogTrace( traceApi, wxString::Format( "Manager: begin processing; %zu jobs left in queue",
m_jobs.size() ) );
JOB& job = m_jobs.front();
if( job.type == JOB_TYPE::CREATE_ENV )
{
wxLogTrace( traceApi, "Manager: Python exe '%s'",
Pgm().GetCommonSettings()->m_Api.python_interpreter );
wxLogTrace( traceApi, wxString::Format( "Manager: creating Python env at %s",
job.env_path ) );
PYTHON_MANAGER manager( Pgm().GetCommonSettings()->m_Api.python_interpreter );
@ -330,6 +335,7 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
wxLogTrace( traceApi, wxString::Format( "Manager: installing dependencies for %s",
job.plugin_path ) );
std::optional<wxString> pythonHome = PYTHON_MANAGER::GetPythonEnvironment( job.identifier );
std::optional<wxString> python = PYTHON_MANAGER::GetVirtualPython( job.identifier );
wxFileName reqs = wxFileName( job.plugin_path, "requirements.txt" );
@ -337,28 +343,46 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
{
wxLogTrace( traceApi, wxString::Format( "Manager: error: python not found at %s",
job.env_path ) );
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED,
wxID_ANY );
QueueEvent( evt );
}
else if( !reqs.IsFileReadable() )
{
wxLogTrace( traceApi,
wxString::Format( "Manager: error: requirements.txt not found at %s",
job.plugin_path ) );
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED,
wxID_ANY );
QueueEvent( evt );
}
else
{
PYTHON_MANAGER manager( *python );
wxLogTrace( traceApi, "Manager: Python exe '%s'", *python );
wxString cmd = wxString::Format(
PYTHON_MANAGER manager( *python );
wxExecuteEnv env;
if( pythonHome )
env.env[wxS( "VIRTUAL_ENV" )] = *pythonHome;
wxString cmd = wxS( "-m ensurepip" );
wxLogTrace( traceApi, "Manager: calling python `%s`", cmd );
manager.Execute( cmd,
[=]( int aRetVal, const wxString& aOutput, const wxString& aError )
{
wxLogTrace( traceApi, wxString::Format( "Manager: ensurepip (%d): %s",
aRetVal, aOutput ) );
if( !aError.IsEmpty() )
{
wxLogTrace( traceApi,
wxString::Format( "Manager: ensurepip err: %s", aError ) );
}
}, &env );
cmd = wxString::Format(
wxS( "-m pip install --no-input --isolated --require-virtualenv "
"--exists-action i -r '%s'" ),
reqs.GetFullPath() );
wxLogTrace( traceApi, "Manager: calling python `%s`", cmd );
manager.Execute( cmd,
[=]( int aRetVal, const wxString& aOutput, const wxString& aError )
{
@ -382,10 +406,14 @@ void API_PLUGIN_MANAGER::processNextJob( wxCommandEvent& aEvent )
wxID_ANY );
QueueEvent( evt );
} );
}, &env );
}
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_PLUGIN_MANAGER_JOB_FINISHED, wxID_ANY );
QueueEvent( evt );
}
m_jobs.pop_front();
wxLogTrace( traceApi, wxString::Format( "Manager: %zu jobs left in queue", m_jobs.size() ) );
wxLogTrace( traceApi, wxString::Format( "Manager: done processing; %zu jobs left in queue",
m_jobs.size() ) );
}

View File

@ -95,9 +95,11 @@ KICAD_API_SERVER::KICAD_API_SERVER() :
m_logFilePath.SetName( s_logFileName );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
{
PATHS::EnsurePathExists( PATHS::GetLogsPath() );
log( fmt::format( "--- KiCad API server started at {} ---\n", SocketPath() ) );
}
log( fmt::format( "--- KiCad API server started at {} ---\n", SocketPath() ) );
wxLogTrace( traceApi, wxString::Format( "Server: listening at %s", SocketPath() ) );
Bind( API_REQUEST_EVENT, &KICAD_API_SERVER::handleApiEvent, this );
@ -168,10 +170,13 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
error.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
error.mutable_status()->set_error_message( "request could not be parsed" );
m_server->Reply( error.SerializeAsString() );
log( "Response (ERROR): " + error.Utf8DebugString() );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
log( "Response (ERROR): " + error.Utf8DebugString() );
}
log( "Request: " + request.Utf8DebugString() );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
log( "Request: " + request.Utf8DebugString() );
if( !request.header().kicad_token().empty() &&
request.header().kicad_token().compare( m_token ) != 0 )
@ -182,7 +187,9 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
error.mutable_status()->set_error_message(
"the provided kicad_token did not match this KiCad instance's token" );
m_server->Reply( error.SerializeAsString() );
log( "Response (ERROR): " + error.Utf8DebugString() );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
log( "Response (ERROR): " + error.Utf8DebugString() );
}
API_RESULT result;
@ -203,7 +210,9 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
{
result->mutable_header()->set_kicad_token( m_token );
m_server->Reply( result->SerializeAsString() );
log( "Response: " + result->Utf8DebugString() );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
log( "Response: " + result->Utf8DebugString() );
}
else
{
@ -220,16 +229,15 @@ void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent )
}
m_server->Reply( error.SerializeAsString() );
log( "Response (ERROR): " + error.Utf8DebugString() );
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging )
log( "Response (ERROR): " + error.Utf8DebugString() );
}
}
void KICAD_API_SERVER::log( const std::string& aOutput )
{
if( !ADVANCED_CFG::GetCfg().m_EnableAPILogging )
return;
FILE* fp = wxFopen( m_logFilePath.GetFullPath(), wxT( "a" ) );
if( !fp )

80
common/api/api_utils.cpp Normal file
View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com>
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <magic_enum.hpp>
#include <api/api_utils.h>
namespace kiapi::common
{
std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage )
{
static const std::map<std::string, KICAD_T> s_types = {
{ "type.googleapis.com/kiapi.board.types.Track", PCB_TRACE_T },
{ "type.googleapis.com/kiapi.board.types.Arc", PCB_ARC_T },
{ "type.googleapis.com/kiapi.board.types.Via", PCB_VIA_T },
{ "type.googleapis.com/kiapi.board.types.Text", PCB_TEXT_T },
{ "type.googleapis.com/kiapi.board.types.TextBox", PCB_TEXTBOX_T },
{ "type.googleapis.com/kiapi.board.types.GraphicShape", PCB_SHAPE_T },
{ "type.googleapis.com/kiapi.board.types.Pad", PCB_PAD_T },
{ "type.googleapis.com/kiapi.board.types.Zone", PCB_ZONE_T },
{ "type.googleapis.com/kiapi.board.types.Dimension", PCB_DIMENSION_T },
{ "type.googleapis.com/kiapi.board.types.ReferenceImage", PCB_REFERENCE_IMAGE_T },
{ "type.googleapis.com/kiapi.board.types.Group", PCB_GROUP_T },
{ "type.googleapis.com/kiapi.board.types.Field", PCB_FIELD_T },
{ "type.googleapis.com/kiapi.board.types.FootprintInstance", PCB_FOOTPRINT_T },
};
auto it = s_types.find( aMessage.type_url() );
if( it != s_types.end() )
return it->second;
return std::nullopt;
}
LIB_ID LibIdFromProto( const types::LibraryIdentifier& aId )
{
return LIB_ID( aId.library_nickname(), aId.entry_name() );
}
types::LibraryIdentifier LibIdToProto( const LIB_ID& aId )
{
types::LibraryIdentifier msg;
msg.set_library_nickname( aId.GetLibNickname() );
msg.set_entry_name( aId.GetLibItemName() );
return msg;
}
void PackVector2( kiapi::common::types::Vector2& aOutput, const VECTOR2I aInput )
{
aOutput.set_x_nm( aInput.x );
aOutput.set_y_nm( aInput.y );
}
VECTOR2I UnpackVector2( const types::Vector2& aInput )
{
return VECTOR2I( aInput.x_nm(), aInput.y_nm() );
}
} // namespace kiapi::common

View File

@ -97,6 +97,7 @@ void PANEL_PLUGIN_SETTINGS::OnEnableApiChecked( wxCommandEvent& aEvent )
void PANEL_PLUGIN_SETTINGS::updateApiStatusText()
{
#ifdef KICAD_IPC_API
if( m_cbEnableApi->GetValue() && Pgm().GetApiServer().Running() )
{
m_stApiStatus->SetLabel( wxString::Format( _( "Listening at %s" ),
@ -106,6 +107,9 @@ void PANEL_PLUGIN_SETTINGS::updateApiStatusText()
{
m_stApiStatus->SetLabel( wxEmptyString );
}
#else
m_stApiStatus->SetLabel( _( "This installation of KiCad does not have API support enabled." ) );
#endif
}

View File

@ -23,6 +23,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <api/api_plugin_manager.h>
#include <base_screen.h>
#include <bitmaps.h>
#include <confirm.h>
@ -35,6 +36,7 @@
#include <gal/graphics_abstraction_layer.h>
#include <id.h>
#include <kiface_base.h>
#include <kiplatform/ui.h>
#include <lockfile.h>
#include <macros.h>
#include <math/vector2wx.h>
@ -1343,3 +1345,45 @@ bool EDA_DRAW_FRAME::SaveCanvasImageToFile( const wxString& aFileName,
image.Destroy();
return retv;
}
void EDA_DRAW_FRAME::addApiPluginTools()
{
#ifdef KICAD_IPC_API
// TODO: Add user control over visibility and order
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
mgr.ButtonBindings().clear();
std::vector<const PLUGIN_ACTION*> actions = mgr.GetActionsForScope( PluginActionScope() );
for( auto& action : actions )
{
if( !action->show_button )
continue;
const wxBitmapBundle& icon = KIPLATFORM::UI::IsDarkTheme() && action->icon_dark.IsOk()
? action->icon_dark
: action->icon_light;
wxAuiToolBarItem* button = m_mainToolBar->AddTool( wxID_ANY, wxEmptyString, icon,
action->name );
Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler( EDA_DRAW_FRAME::OnApiPluginInvoke ) );
mgr.ButtonBindings().insert( { button->GetId(), action->identifier } );
}
#endif
}
void EDA_DRAW_FRAME::OnApiPluginInvoke( wxCommandEvent& aEvent )
{
#ifdef KICAD_IPC_API
API_PLUGIN_MANAGER& mgr = Pgm().GetPluginManager();
if( mgr.ButtonBindings().count( aEvent.GetId() ) )
mgr.InvokeAction( mgr.ButtonBindings().at( aEvent.GetId() ) );
#endif
}

Some files were not shown because too many files have changed in this diff Show More