KiCad Plugin System
Copyright
This document is Copyright © 2016 by it’s contributors as listed below. You may distribute it and/or modify it under the terms of either the GNU General Public License (http://www.gnu.org/licenses/gpl.html), version 3 or later, or the Creative Commons Attribution License (http://creativecommons.org/licenses/by/3.0/), version 3.0 or later.
All trademarks within this guide belong to their legitimate owners.
Contributors
Cirilo Bernardo
Feedback
Please direct any bug reports, suggestions or new versions to here:
-
About KiCad document: https://github.com/KiCad/kicad-doc/issues
-
About KiCad software: https://bugs.launchpad.net/kicad
-
About KiCad software i18n: https://github.com/KiCad/kicad-i18n/issues
Publication date and software version
Published on January 29, 2016.
1. Introduction to the KiCad plugin system
The KiCad plugin system is a framework for extending the capabilities of KiCad using shared libraries. One of the main advantages of using a plugin is that it is not necessary to rebuild the KiCad suite while developing a plugin; in fact, plugins can be built with the aid of a very small set of headers from the KiCad source tree. Removing the requirement to build KiCad during plugin development greatly increases productivity by ensuring that the developer only compiles code directly related to the plugin which is being developed and thus reducing the time required for each build and test cycle.
Plugins were initially developed for the 3D model viewer to make it possible to support more types of 3D models without requiring major changes to the KiCad source for each new model type supported. The plugin framework was later generalized so that in the future developers can create different classes of plugins. Currently only 3D plugins are implemented within KiCad but it is envisioned that a PCB plugin will eventually be developed to make it possible for users to implement data Importers and Exporters.
1.1. Plugin Classes
Plugins are divided into Plugin Classes since each plugin addresses problems in a specific domain and therefore requires an interface unique to that domain. For example, the 3D model plugins load 3D model data from files and translate that data into a format which can be displayed by the 3D viewer. A PCB Import/Export plugin would take PCB data and export to other electrical or mechanical data formats, or translate a foreign format into a KiCad PCB. At the moment only the 3D Plugin Class has been developed and it will be the focus of this document.
Implementing a Plugin Class requires creating code within the KiCad source tree which manages the loading of plugin code. Within the KiCad source tree, the file plugins/ldr/pluginldr.h declares the base class for all plugin loaders. This class declares the most basic functions which we would expect to find in any KiCad plugin (boilerplate code) and its implementation provides basic checks on version compatibility between the plugin loader and the available plugins. The header plugins/ldr/3d/pluginldr3D.h declares a loader for the 3D Plugin Class. The loader is responsible for loading a given plugin and making its functions available to KiCad. Each instance of a plugin loader represents an actual plugin implementation and acts as a transparent bridge between KiCad and the plugin’s features. The loader is not the only code required within KiCad to support plugins: we also need code to discover the plugins and code to invoke the functions of the plugins via the plugin loader. In the case of the 3D plugins the discovery and invocation functions are all contained within the S3D_CACHE class.
Plugin developers do not need to be concerned with the details of KiCad’s internal code for managing plugins unless a new Plugin Class is being developed; a plugin only needs to define the functions declared by their specific plugin class.
The header include/plugins/kicad_plugin.h declares the generic functions required of all KiCad plugins; these functions identify the Plugin Class, provide the name of the specific plugin, provide version information for the Plugin Class API, provide version information for the specific plugin, and provide a basic version compatibility check on the Plugin Class API. In brief, these functions are:
1.1.1. Plugin Class: PLUGIN_3D
The header include/plugins/3d/3d_plugin.h declares the functions which must be implemented by all 3D plugins and defines a number of functions which are required by the plugin and which the user must not reimplement. The defined functions which the user must not reimplement are:
The functions which the user must implement are as follows:
2. Tutorials: 3D Plugin Class
This section contains a description of two very simple plugins of the PLUGIN_3D class and walks the user through the setup and building of the code.
2.1. Basic 3D Plugin
This tutorial walks the user through the development of a very basic 3D plugin named "PLUGIN_3D_DEMO1". The purpose of this tutorial is only to demonstrate the construction of a very basic 3D plugin which does nothing other than provide a few filter strings which permit the KiCad user to filter file names while browsing for 3D models. The code demonstrated here is the absolute minimum requirement for any 3D plugin and can be used as a template for creating more advanced plugins.
In order to build the demo project we require the following:
-
KiCad plugin headers
-
KiCad Scene Graph library kicad_3dsg
To automatically detect the KiCad headers and library we shall use a CMake FindPackage script; the script supplied in this tutorial should work on Linux and Windows if the relevant header files are installed to ${KICAD_ROOT_DIR}/kicad and the KiCad Scene Graph library is installed in ${KICAD_ROOT_DIR}/lib.
To start let’s create a project directory and the FindPackage script:
Kicad and its plugin headers must be installed; if they are installed to a user directory or under /opt on Linux, or you are using Windows, you will need to set the KICAD_ROOT_DIR environment variable to point to the directory containing the KiCad include and lib directories. For OS X the FindPackage script presented here may require some adjustments.
To configure and build the tutorial code we will use CMake and create a CMakeLists.txt script file:
The first demo project is very basic; it consists of a single file with no external link dependencies other than the compiler defaults. We start by creating a source directory:
Now we create the plugin source itself:
This source file meets all the minimum requirements to implement a 3D plugin. The plugin does not produce any data for rendering models but it can provide KiCad with a list of supported model file extensions and file extension filters to enhance the 3D model file selection dialog. Within KiCad the extension strings are used to select the plugins which may be used to load a specified model; for example, if the plugin is wrl then KiCad will invoke each plugin which claims to support the extension wrl until a plugin returns visualization data. The file filters provided by each plugin are passed to the 3D file selector dialog to improve the browsing UI.
To build the plugin:
The plugin will be built but not installed; you must copy the plugin file to KiCad’s plugin directory if you wish to load the plugin.
2.2. Advanced 3D Plugin
This tutorial walks the user through the development of a 3D plugin named "PLUGIN_3D_DEMO2". The purpose of this tutorial is to demonstrate the construction of a very basic scene graph which the KiCad previewer can render. The plugin claims to handle files of type txt. Although the file must exist in order for the cache manager to invoke the plugin, the file contents are not processed by this plugin; instead, the plugin simply creates a scene graph containing a pair of tetrahedra. This tutorial assumes that the first tutorial had been completed and that the CMakeLists.txt and FindKICAD.cmake script files have been created.
Place the new source file in the same directory as the previous tutorial’s source file and we will extend the previous tutorial’s CMakeLists.txt file to build this tutorial. Since this plugin will create a scene graph for KiCad we need to link to KiCad’s scene graph library kicad_3dsg. KiCad’s Scene Graph Library provides a set of classes which can be used to build the Scene Graph Object; the Scene Graph Object is an intermediate data visualization format used by the 3D Cache Manager. All plugins which support model visualization must translate the model data into a scene graph via this library.
The first step is to extend CMakeLists.txt to build this tutorial project:
Now we change to the source directory and create the source file:
3. Application Programming Interface (API)
Plugins are implemented via Application Programming Interface (API) implementations. Each Plugin Class has its specific API and in the 3D Plugin tutorials we have seen examples of the implementation of the 3D Plugin API as declared by the header 3d_plugin.h. Plugins may also rely on other APIs defined within the KiCad source tree; in the case of 3D plugins, all plugins which support visualization of models must interact with the Scene Graph API as declared in the header ifsg_all.h and its included headers.
This section describes the details of available Plugin Class APIs and other KiCad APIs which may be required for implementations of plugin classes.
3.1. Plugin Class APIs
There is currently only one plugin class declared for KiCad: the 3D Plugin Class. All KiCad plugin classes must implement a basic set of functions declared in the header file kicad_plugin.h; these declarations are referred to as the Base Kicad Plugin Class. No implementation of the Base Kicad Plugin Class exists; the header file exists purely to ensure that plugin developers implement these defined functions in each plugin implementation.
Within KiCad, each instance of a Plugin Loader implements the API presented by a plugin as though the Plugin Loader is a class providing the plugin’s services. This is achieved by the Plugin Loader class providing a public interface containing function names which are similar to those implemented by the plugin; the argument lists may vary to accommodate the need to inform the user of any problems which may be encountered if, for example, no plugin is loaded. Internally the Plugin Loader uses a stored pointer to each API function to invoke each function on behalf of the user.
3.1.1. API: Base Kicad Plugin Class
The Base Kicad Plugin Class is defined by the header file kicad_plugin.h. This header must be included in the declaration of all other plugin classes; for an example see the 3D Plugin Class declaration in the header file 3d_plugin.h. The prototypes for these functions were briefly described in Plugin Classes. The API is implemented by the base plugin loader as defined in pluginldr.cpp.
To help make sense of the functions required by the base KiCad plugin header we must look at what happens in the base Plugin Loader class. The Plugin Loader class declares a virtual function Open() which takes the full path to the plugin to be loaded. The implementation of the Open() function within a specific plugin class loader will initially invoke the protected open() function of the base plugin loader; this base open() function attempts to find the address of each of the required basic plugin functions; once the addresses of each function have been retrieved, a number of checks are enforced:
-
Plugin GetKicadPluginClass() is invoked and the result is compared to the Plugin Class string provided by the Plugin Loader implementation; if these strings do not match then the opened plugin is not intended for the Plugin Loader instance.
-
Plugin GetClassVersion() is invoked to retrieve the Plugin Class API Version implemented by the plugin.
-
Plugin Loader virtual GetLoaderVersion() function is invoked to retrieve the Plugin Class API Version implemented by the loader.
-
The Plugin Class API Version reported by the plugin and the loader are required to have the same Major Version number, otherwise they are considered incompatible. This is the most basic version test and it is enforced by the base plugin loader.
-
Plugin CheckClassVersion() is invoked with the Plugin Class API Version information of the Plugin Loader; if the Plugin supports the given version then it returns true to indicate success. If successful the loader creates a PluginInfo string based on the results of GetKicadPluginName() and GetPluginVersion(), and the plugin loading procedure continues within the Plugin Loader’s Open() implementation.
3.1.2. API: 3D Plugin Class
The 3D Plugin Class is declared by the header file 3d_plugin.h and it extends the required plugin functions as described in Plugin Class: PLUGIN_3D. The corresponding Plugin Loader is defined in pluginldr3D.cpp and the loader implements the following public functions in addition to the required API functions:
The required 3D Plugin Class functions are exposed via the following functions:
In typical situations, the user would do the following:
-
Create an instance of KICAD_PLUGIN_LDR_3D.
-
Invoke Open( "/path/to/myplugin.so" ) to open a specific plugin. The return value must be checked to ensure that the plugin loaded as desired.
-
Invoke any of the 3D Plugin Class calls as exposed by KICAD_PLUGIN_LDR_3D.
-
Invoke Close() to close (unlink) the plugin.
-
Destroy the KICAD_PLUGIN_LDR_3D instance.
3.2. Scenegraph Class APIs
The Scenegraph Class API is defined by the header ifsg_all.h and its included headers. The API consists of a number of helper routines with the namespace S3D as defined in ifsg_api.h and wrapper classes defined by the various ifsg_*.h headers; the wrappers support the underlying scene graph classes which, taken together, form a scene graph structure which is compatible with VRML2.0 static scene graphs. The headers, structures, classes and their public functions are as follows:
The sg_base.h header contains declarations of basic data types used by the scenegraph classes.
The IFSG_NODE class is the base class for all scenegraph nodes. All scenegraph objects implement the public functions of this class but in some cases a particular function may have no meaning for a specific class.
IFSG_TRANSFORM is similar to a VRML2.0 Transform node; it may contain any number of child IFSG_SHAPE and IFSG_TRANSFORM nodes and any number of referenced IFSG_SHAPE and IFSG_TRANSFORM nodes. A valid scenegraph must have a single IFSG_TRANSFORM object as a root.
IFSG_SHAPE is similar to a VRML2.0 Shape node; it must contain a single child or reference FACESET node and may contain a single child or reference APPEARANCE node.
IFSG_APPEARANCE is similar to a VRML2.0 Appearance node, however, at the moment it only represents the equivalent of an Appearance node containing a Material node.
IFSG_FACESET is similar to a VRML2.0 Geometry node which contains an IndexedFaceSet node. It must contain a single child or reference COORDS node, a single child COORDINDEX node, and a single child or reference NORMALS node; in addition there may be a single child or reference COLORS node. A simplistic normals calculation function is provided to aid the user in assigning normal values to surfaces. The deviations from the VRML2.0 analogue are as follows:
-
Normals are always per-vertex.
-
Colors are always per vertex.
-
The coordinate index set must describe triangular faces only.
IFSG_COORDINDEX is similar to a VRML2.0 coordIdx[] set except it must exclusively describe triangular faces, which implies that the total number of indices is divisible by 3.
IFSG_NORMALS is equivalent to a VRML2.0 Normals node.
IFSG_COLORS is similar to a VRML2.0 colors[] set.
The remaining API functions are defined in ifsg_api.h as follows:
For actual usage examples of the Scenegraph API see the Advanced 3D Plugin tutorial above and the KiCad VRML1, VRML2, and X3D parsers.