aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-08-01 08:20:23 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2016-08-01 08:20:23 +0200
commitbfeeac6e4889d1e9a1083b3c7efc59652981b168 (patch)
treea937d844a59da7c509685dcd1ddd9933772e526f
parentc307e9f234e544386fa3ae53083c7510668e1716 (diff)
downloadkicad-utils-bfeeac6e4889d1e9a1083b3c7efc59652981b168.tar.gz
kicad-utils-bfeeac6e4889d1e9a1083b3c7efc59652981b168.tar.bz2
kicad-utils-bfeeac6e4889d1e9a1083b3c7efc59652981b168.tar.xz
kicad-utils-bfeeac6e4889d1e9a1083b3c7efc59652981b168.zip
o Moving the generation logic to Python, embedding a Python interpreter with the help of pybind11.
o Adding install configuration to CMake to make it easier to reuse the project later on. o Splitting out the examples into its own project to make it easier to test the whole installation setup and python/template loading. o Trying to reorganize the code a bit, not very much better yet.
-rw-r--r--.gitmodules5
-rw-r--r--CMakeLists.txt21
-rw-r--r--cli/CMakeLists.txt29
-rw-r--r--cli/generate-header.cpp (renamed from generate-header.cpp)285
-rw-r--r--cmake/KicadUtilsConfig.cmake2
-rw-r--r--cmake/kicad_generate_header.cmake (renamed from kicad.cmake)24
-rwxr-xr-xconfigure51
-rw-r--r--core/CMakeLists.txt22
-rw-r--r--core/KicadNetLexer.g4 (renamed from KicadNetLexer.g4)0
-rw-r--r--core/KicadNetParser.g4 (renamed from KicadNetParser.g4)0
-rw-r--r--core/include-priv/trygvis/antlr.h (renamed from include-priv/trygvis/antlr.h)0
-rw-r--r--core/include-priv/trygvis/string_utils.h (renamed from include-priv/trygvis/string_utils.h)0
-rw-r--r--core/include/trygvis/kicad.h (renamed from include/trygvis/kicad.h)21
-rw-r--r--core/kicad.cpp (renamed from kicad.cpp)6
-rw-r--r--examples/CMakeLists.txt9
-rw-r--r--examples/arduino-led/CMakeLists.txt2
-rw-r--r--examples/intel-quark-d2000/CMakeLists.txt7
-rw-r--r--examples/intel-quark-d2000/intel-quark-d2000.py2
-rw-r--r--python/CMakeLists.txt13
-rw-r--r--python/GenerateHeaderPy.cpp40
-rw-r--r--python/include/trygvis/kicad/GenerateHeaderPy.h45
-rw-r--r--python/include/trygvis/kicad/python.h3
-rw-r--r--python/kicad_utils_py.cpp38
m---------python/pybind110
-rw-r--r--template/intel-quark-d2000.py69
25 files changed, 596 insertions, 98 deletions
diff --git a/.gitmodules b/.gitmodules
index a84f300..83b6a4d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,7 @@
[submodule "pybind11"]
- path = pybind11
+ path = python/pybind11
url = https://github.com/pybind/pybind11.git
branch = master
+[submodule "python/pybind11"]
+ path = python/pybind11
+ url = https://github.com/pybind/pybind11
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 926f7c0..e70bce4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,18 +1,13 @@
cmake_minimum_required(VERSION 3.5)
project(kicad_utils)
-find_package(Antlr4)
-antlr4_add_target(TARGET KicadNet LEXER KicadNetLexer.g4 PARSER KicadNetParser.g4 STATIC)
+add_compile_options(--std=c++14)
+add_compile_options(-Wall)
+add_compile_options(-Wextra)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+add_subdirectory(core)
+add_subdirectory(python)
+add_subdirectory(cli)
+#add_subdirectory(examples)
-set(SOURCE_FILES generate-header.cpp kicad.cpp include/trygvis/kicad.h include-priv/trygvis/antlr.h include-priv/trygvis/string_utils.h)
-add_executable(generate-header ${SOURCE_FILES})
-target_include_directories(generate-header PUBLIC include PRIVATE include-priv)
-target_link_libraries(generate-header KicadNet Antlr4::antlr4_shared)
-target_compile_options(generate-header PUBLIC --std=c++14)
-target_compile_options(generate-header PUBLIC -Wall -Wextra)
-
-include(kicad.cmake)
-add_custom_target(all_examples)
-add_subdirectory(examples)
+message(STATUS "The examples are not built as they depend on a full installation of kicad-utils. Do a make install first and then build the examples")
diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt
new file mode 100644
index 0000000..f3dd326
--- /dev/null
+++ b/cli/CMakeLists.txt
@@ -0,0 +1,29 @@
+set(SOURCE_FILES generate-header.cpp)
+add_executable(generate-header ${SOURCE_FILES})
+
+target_link_libraries(generate-header PUBLIC kicad-utils-core)
+
+get_target_property(kicad_utils_py_include_directories kicad_utils_py INCLUDE_DIRECTORIES)
+target_include_directories(generate-header PRIVATE ${kicad_utils_py_include_directories})
+target_link_libraries(generate-header PUBLIC ${PYTHON_LIBRARIES} stdc++fs)
+
+add_dependencies(generate-header kicad_utils_py)
+
+install(TARGETS generate-header
+ EXPORT kicad_utils_export
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+
+install(DIRECTORY ../template/
+ DESTINATION share/kicad-utils/template
+ FILES_MATCHING PATTERN *.py
+ PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
+
+install(DIRECTORY ../cmake/
+ DESTINATION lib/cmake/KicadUtils)
+
+install(EXPORT kicad_utils_export
+ FILE KicadUtilsTargets.cmake
+ NAMESPACE KicadUtils::
+ DESTINATION lib/cmake/KicadUtils)
diff --git a/generate-header.cpp b/cli/generate-header.cpp
index d134d47..1033fc3 100644
--- a/generate-header.cpp
+++ b/cli/generate-header.cpp
@@ -1,21 +1,34 @@
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <err.h>
-#include <sysexits.h>
-#include <getopt.h>
-#include <cstring>
-#include <memory>
-#include <map>
#include "trygvis/kicad.h"
-using namespace std;
using namespace trygvis::kicad;
-
using trygvis::kicad::netlist::component;
using trygvis::kicad::netlist::kicad_net_loader;
using trygvis::kicad::netlist::kicad_parse_exception;
using trygvis::kicad::netlist::net;
+using nl = trygvis::kicad::netlist::netlist;
+
+#include "pybind11/pybind11.h"
+#include "pybind11/stl.h"
+#include "pybind11/eval.h"
+
+namespace py = pybind11;
+
+#include <fstream>
+#include <sstream>
+#include <err.h>
+#include <sysexits.h>
+#include <map>
+#include <cstring>
+#include <experimental/filesystem>
+
+#ifdef _WIN32
+static const char PATH_SEPARATOR = ';';
+#else
+static const char PATH_SEPARATOR = ':';
+#endif
+
+using namespace std;
+namespace fs = std::experimental::filesystem;
char *program;
@@ -24,18 +37,20 @@ void usage(const char *reason = nullptr) {
if (reason) {
fprintf(stderr, "%s\n", reason);
}
- fprintf(stderr, "usage: %s -n <net file> -r <ref> [-o <out file>]\n", program);
+ fprintf(stderr, "usage: %s -n <net file> -r <ref> [-o <out file>] [-t <python template>]\n", program);
exit(EX_USAGE);
}
-void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **ref, char **out_filename) {
+void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **ref, char **py_template,
+ vector<fs::path> &template_libs, char **out_filename) {
*debug = false;
*ref = nullptr;
*out_filename = nullptr;
+ *py_template = nullptr;
*ref = nullptr;
int c;
- while ((c = getopt(argc, argv, "Dn:r:o:")) != -1) {
+ while ((c = getopt(argc, argv, "Dn:r:o:t:l:")) != -1) {
switch (c) {
case 'D':
*debug = true;
@@ -46,6 +61,12 @@ void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **
case 'r':
*ref = optarg;
break;
+ case 't':
+ *py_template = optarg;
+ break;
+ case 'l':
+ template_libs.push_back(fs::path(optarg));
+ break;
case 'o':
if (strcmp("-", optarg) != 0) {
*out_filename = optarg;
@@ -56,7 +77,7 @@ void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **
}
}
- if (!*net_filename && !*ref) {
+ if (!*net_filename || !*ref) {
usage();
}
}
@@ -76,7 +97,7 @@ public:
class arduino_uno : public part {
public:
- arduino_uno() : part("ARDUINO_UNO") { }
+ arduino_uno() : part("ARDUINO_UNO") {}
~arduino_uno() {
}
@@ -100,7 +121,7 @@ public:
class intel_quark_d2000 : public part {
public:
- intel_quark_d2000() : part("INTEL_QUARK_D2000") { }
+ intel_quark_d2000() : part("INTEL_QUARK_D2000") {}
~intel_quark_d2000() {
}
@@ -177,52 +198,74 @@ public:
}
};
-class library {
-public:
- library(const string &name) : name(name) { }
-
- library(library &&l) : name(std::move(l.name)), parts(std::move(l.parts)) { }
-
- const string name;
- vector<unique_ptr<part>> parts;
-
- opt<part *> find_part(string name) const {
- for (auto &part: parts) {
- if (part->name == name) {
- return part.get();
- }
- }
-
- return nullopt;
+//class library {
+//public:
+// library(const string &name) : name(name) {}
+//
+// library(library &&l) : name(std::move(l.name)), parts(std::move(l.parts)) { }
+//
+// virtual ~library() { }
+//
+// const string name;
+// vector<unique_ptr<part>> parts;
+//
+// opt<part *> find_part(string name) const {
+// for (auto &part: parts) {
+// if (part->name == name) {
+// return part.get();
+// }
+// }
+//
+// return nullopt;
+// }
+//};
+
+//class kicad_gen {
+//public:
+// vector<library> libraries;
+//
+// kicad_gen() {
+// library kicad_utils("kicad_utils");
+// kicad_utils.parts.push_back(make_unique<arduino_uno>());
+// kicad_utils.parts.push_back(make_unique<intel_quark_d2000>());
+//
+// libraries.push_back(std::move(kicad_utils));
+// }
+//
+// opt<library *> find_library(string name) {
+// for (auto &l : libraries) {
+// if (l.name == name) {
+// return &l;
+// }
+// }
+//
+// return nullopt;
+// }
+//};
+
+opt<fs::path> find_template(const string &py_template, const vector<fs::path> &paths) {
+
+ fs::path p(py_template);
+
+ if (fs::exists(p)) {
+ return p;
}
-};
-
-class kicad_gen {
-public:
- vector<library> libraries;
-
- kicad_gen() {
- library kicad_utils("kicad_utils");
- kicad_utils.parts.push_back(make_unique<arduino_uno>());
- kicad_utils.parts.push_back(make_unique<intel_quark_d2000>());
- libraries.push_back(std::move(kicad_utils));
- }
+ for (auto &&prefix : paths) {
+ p = prefix / py_template;
- opt<library *> find_library(string name) {
- for (auto &l : libraries) {
- if (l.name == name) {
- return &l;
- }
+ if (fs::exists(p)) {
+ return p;
}
-
- return nullopt;
}
-};
-bool generate(const char *ref, const trygvis::kicad::netlist::netlist &netlist, stringstream &out) {
+ return nullopt;
+}
+
+/*
+bool generate(const char *ref, nl *const netlist, stringstream &out) {
kicad_gen gen;
- opt<const component *> componentO = netlist.find_component(ref);
+ opt<const component *> componentO = netlist->find_component(ref);
if (!componentO) {
cerr << "Could not find component '" << ref << "'" << endl;
@@ -256,15 +299,17 @@ bool generate(const char *ref, const trygvis::kicad::netlist::netlist &netlist,
out << "#ifndef SCHEMATIC_H" << endl;
out << "#define SCHEMATIC_H" << endl;
out << endl;
- out << "/*" << endl;
+ out << "*/
+/*" << endl;
out << "THIS FILE IS GENERATED. DO NOT EDIT." << endl;
out << endl;
out << "Generated from schematic for reference " << ref << ", part " << partName << " in library " <<
- library->name << "." << endl;
- out << "*/" << endl;
+ library->name << "." << endl;
+ out << "*//*
+" << endl;
out << endl;
- auto usages = netlist.find_usage_of(ref);
+ auto usages = netlist->find_usage_of(ref);
part->generate(out, ref, usages);
@@ -272,23 +317,133 @@ bool generate(const char *ref, const trygvis::kicad::netlist::netlist &netlist,
return true;
}
+*/
-int main(int argc, char **argv) {
- program = argv[0];
+bool generate_py(const char *ref, nl *const netlist, stringstream &out, const fs::path &py_template) {
+ py::dict vars;
+ pybind11::module kicad_utils_py_module = py::module::import("kicad_utils_py");
+ vars = kicad_utils_py_module.attr("__dict__");
+
+ pybind11::object netlist_py = py::cast(netlist);
+
+ vars["netlist"] = netlist_py;
+ vars["ref"] = py::cast(ref);
+ string init;
+ init += "generateHeader = GenerateHeader(ref, netlist)\n";
+ init += "del ref\n";
+ init += "del netlist\n";
+ py::eval<py::eval_mode::eval_statements>(init, vars);
+
+ py::eval_file(py_template.string(), vars);
+
+ string str = py::eval<py::eval_mode::eval_expr>("generateHeader.str", vars).cast<py::object>().cast<string>();
+ out << str;
+
+ return true;
+}
+
+int main(int argc, char **argv) {
bool debug;
char *net_filename;
char *ref;
+ char *py_template;
+ vector<fs::path> template_libs;
char *out_filename;
- parse_args(argc, argv, &debug, &net_filename, &ref, &out_filename);
+
+ fs::path bin(argv[0]);
+ fs::path basedir = bin.parent_path().parent_path();
+
+ template_libs.push_back(fs::current_path());
+ template_libs.push_back(basedir / "share" / "kicad-utils" / "template");
+
+ parse_args(argc, argv, &debug, &net_filename, &ref, &py_template, template_libs, &out_filename);
kicad_net_loader loader;
+ /*
+ string python_version = Py_GetVersion();
+ cout << "Python version: " << python_version << endl;
+ */
+
+ /*
+ map<string, string> env;
+ for (char **e = environ; *e != NULL; e++) {
+ string s = *e;
+ auto i = s.find('=');
+ env[s.substr(0, i)] = s.substr(i + 1);
+ }
+
+ for (auto &&e: env) {
+ cout << e.first << " = " << e.second << endl;
+ }
+ */
+
try {
- auto netlist = loader.load(net_filename);
+ nl netlist = loader.load(net_filename, cerr);
stringstream out;
- auto ok = generate(ref, netlist, out);
+ bool ok = false;
+
+ if (py_template) {
+ cerr << "Template path: " << endl;
+ for (auto &&p : template_libs) {
+ cerr << " " << p.string() << endl;
+ }
+
+ opt<fs::path> tmpl = find_template(py_template, template_libs);
+
+ if (!tmpl) {
+ cerr << "No such file: " << py_template << endl;
+ cerr << "Search path: " << endl;
+ for (auto &&p : template_libs) {
+ cerr << " " << p.string() << endl;
+ }
+ cerr << "Current path is " << fs::current_path().string() << endl;
+ } else {
+ wchar_t *program = Py_DecodeLocale(argv[0], NULL);
+ if (program == NULL) {
+ fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
+ exit(1);
+ }
+ Py_SetProgramName(program);
+
+ vector<fs::path> module_paths{
+ basedir / "python",
+ basedir / "lib",
+ };
+
+ std::wstring_convert<codecvt_utf8<wchar_t> > converter;
+ converter.from_bytes(string("foo"));
+
+ wstring pythonpath(Py_GetPath());
+ for (auto &path : module_paths) {
+ if (!fs::exists(path)) {
+ continue;
+ }
+// pythonpath += converter.from_bytes(PATH_SEPARATOR + path.string());
+ pythonpath = converter.from_bytes(path.string() + PATH_SEPARATOR) + pythonpath;
+ }
+ wcerr << "pythonpath=" << pythonpath << endl;
+ Py_SetPath(pythonpath.c_str());
+
+ cerr << "Compile-time Python version: " << PY_VERSION << endl;
+ cerr << "Current python version: " << Py_GetVersion() << endl;
+
+ Py_Initialize();
+ try {
+ ok = generate_py(ref, &netlist, out, tmpl.value());
+ } catch (py::error_already_set &e) {
+ cerr << "Python failure:" << endl << e.what() << endl;
+ } catch (std::runtime_error &e) {
+ cerr << "Generation failed: " << e.what() << endl;
+ }
+ Py_Finalize();
+ PyMem_RawFree(program);
+ }
+// } else {
+// ok = generate(ref, &netlist, out);
+ }
if (ok) {
auto contents = out.str();
diff --git a/cmake/KicadUtilsConfig.cmake b/cmake/KicadUtilsConfig.cmake
new file mode 100644
index 0000000..2302fe2
--- /dev/null
+++ b/cmake/KicadUtilsConfig.cmake
@@ -0,0 +1,2 @@
+include("${CMAKE_CURRENT_LIST_DIR}/kicad_generate_header.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/KicadUtilsTargets.cmake")
diff --git a/kicad.cmake b/cmake/kicad_generate_header.cmake
index f18e6fe..930c5ed 100644
--- a/kicad.cmake
+++ b/cmake/kicad_generate_header.cmake
@@ -1,6 +1,6 @@
function(kicad_generate_header)
set(options IN_SOURCE)
- set(oneValueArgs OUTPUT NET REF OUTPUT_DIR)
+ set(oneValueArgs OUTPUT NET REF OUTPUT_DIR TEMPLATE TEMPLATE_LIB_LIST)
cmake_parse_arguments(kicad_gen "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@@ -25,19 +25,33 @@ function(kicad_generate_header)
endif ()
set(output_dir "${kicad_gen_OUTPUT_DIR}")
+ set(output_rel_dir "${output_dir}")
else ()
if (kicad_gen_IN_SOURCE)
set(output_dir "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(output_rel_dir "${CMAKE_SOURCE_DIR}")
else ()
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ set(output_rel_dir "${CMAKE_BINARY_DIR}")
endif ()
endif ()
- set(output_file "${output_dir}/${output}")
+ if (kicad_gen_TEMPLATE)
+ set(t "-t")
+ set(template "${kicad_gen_TEMPLATE}")
+ endif ()
+
+ set(lib "-l;${CMAKE_CURRENT_SOURCE_DIR}")
+ foreach(l IN LISTS kicad_gen_TEMPLATE_LIB_LIST)
+ list(APPEND lib -l)
+ list(APPEND lib "${l}")
+ endforeach ()
+
+ set(output_file "${output_dir}/${output}")
+ file(RELATIVE_PATH output_file_rel "${output_rel_dir}" ${output_file})
add_custom_command(OUTPUT "${output_file}"
- COMMAND generate-header -n ${NET} -r ${REF} -o ${output_file}
+ COMMAND KicadUtils::generate-header -n ${NET} -r ${REF} -o ${output_file} ${t} ${template} ${lib}
MAIN_DEPENDENCY ${NET}
- DEPENDS kicad_utils
- COMMENT "Generating ${output}")
+ COMMENT "Generating ${output_file_rel}")
endfunction()
diff --git a/configure b/configure
new file mode 100755
index 0000000..4aaae1c
--- /dev/null
+++ b/configure
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+PROJECT=kicad-utils
+
+set -e
+
+CMAKE=`which cmake 2>/dev/null`
+PREFIX=$HOME/opt/$PROJECT
+# TODO: find basedir from the current binary
+BASEDIR=`pwd`
+
+if [ ! -x "$CMAKE" ]
+then
+ echo "cmake is not installed"
+ exit 1
+fi
+
+cd $BASEDIR
+
+NEW=`test -d build && echo 1 || true`
+
+mkdir -p build
+
+CMAKE_OPTS=()
+CMAKE_OPTS+=(-DCMAKE_INSTALL_PREFIX=$PREFIX)
+#CMAKE_OPTS+=(-DCMAKE_SKIP_RPATH=NO)
+#CMAKE_OPTS+=(-DCMAKE_SKIP_INSTALL_RPATH=NO)
+# These are required until Antlr C++ is installed by the system
+CMAKE_OPTS+=(-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE)
+CMAKE_OPTS+=(-DAntlr4_DIR=$HOME/opt/antlr4-cpp/lib/cmake/Antlr4)
+
+cd build
+echo ""
+echo "Generating build.."
+echo ""
+cmake "${CMAKE_OPTS[@]}" ..
+
+
+echo ""
+echo ""
+echo ""
+
+if [[ $NEW == 1 ]]
+then
+ echo "Reusing existing build/ directory. You should probably run cd build && make clean"
+else
+ echo "The build files are generated in build/. To build run: cd build && make install"
+ echo "The binaries will be installed under $PREFIX"
+fi
+
+echo ""
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
new file mode 100644
index 0000000..cbf8e78
--- /dev/null
+++ b/core/CMakeLists.txt
@@ -0,0 +1,22 @@
+find_package(Antlr4)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+antlr4_add_target(
+ TARGET KicadNet
+ LEXER KicadNetLexer.g4
+ PARSER KicadNetParser.g4
+ STATIC)
+
+add_library(kicad-utils-core
+ kicad.cpp)
+target_sources(kicad-utils-core PRIVATE $<TARGET_OBJECTS:KicadNet>)
+
+get_target_property(KicadNet_includes KicadNet INCLUDE_DIRECTORIES)
+
+target_include_directories(kicad-utils-core
+ PUBLIC include
+ PRIVATE include-priv ${KicadNet_includes})
+
+target_link_libraries(kicad-utils-core
+ Antlr4::antlr4_shared)
diff --git a/KicadNetLexer.g4 b/core/KicadNetLexer.g4
index e10f7e7..e10f7e7 100644
--- a/KicadNetLexer.g4
+++ b/core/KicadNetLexer.g4
diff --git a/KicadNetParser.g4 b/core/KicadNetParser.g4
index 3971111..3971111 100644
--- a/KicadNetParser.g4
+++ b/core/KicadNetParser.g4
diff --git a/include-priv/trygvis/antlr.h b/core/include-priv/trygvis/antlr.h
index f5656ea..f5656ea 100644
--- a/include-priv/trygvis/antlr.h
+++ b/core/include-priv/trygvis/antlr.h
diff --git a/include-priv/trygvis/string_utils.h b/core/include-priv/trygvis/string_utils.h
index 9902a3f..9902a3f 100644
--- a/include-priv/trygvis/string_utils.h
+++ b/core/include-priv/trygvis/string_utils.h
diff --git a/include/trygvis/kicad.h b/core/include/trygvis/kicad.h
index e555e9c..0c5005d 100644
--- a/include/trygvis/kicad.h
+++ b/core/include/trygvis/kicad.h
@@ -1,9 +1,10 @@
#pragma once
+#include <experimental/optional>
+#include <ostream>
+#include <stdexcept>
#include <string>
#include <vector>
-#include <stdexcept>
-#include <experimental/optional>
namespace trygvis {
namespace kicad {
@@ -21,7 +22,7 @@ struct lib_source {
const std::string lib;
const std::string part;
- lib_source(const std::string &lib, const std::string &part) : lib(lib), part(part) { }
+ lib_source(const std::string &lib, const std::string &part) : lib(lib), part(part) {}
};
struct component {
@@ -30,7 +31,7 @@ struct component {
const lib_source _lib_source;
component(const std::string &ref, const std::string &value, const lib_source &_lib_source) :
- ref(ref), value(value), _lib_source(_lib_source) { }
+ ref(ref), value(value), _lib_source(_lib_source) {}
};
struct pin {
@@ -48,7 +49,7 @@ public:
const std::string ref;
const int pin;
- node(const std::string &ref, int pin) : ref(ref), pin(pin) { }
+ node(const std::string &ref, int pin) : ref(ref), pin(pin) {}
};
class net {
@@ -57,9 +58,9 @@ public:
const std::string name;
const std::vector<node> nodes;
- net(int code, const std::string &name, const std::vector<node> &nodes) : code(code), name(name), nodes(nodes) { }
+ net(int code, const std::string &name, const std::vector<node> &nodes) : code(code), name(name), nodes(nodes) {}
- const node * node_for_ref(const std::string &ref) const;
+ const node *node_for_ref(const std::string &ref) const;
};
struct netlist {
@@ -75,7 +76,9 @@ struct netlist {
class kicad_parse_exception : public std::runtime_error {
public:
explicit kicad_parse_exception(const std::vector<std::string> &messages) :
- runtime_error("Parse error"), messages(messages) { }
+ runtime_error("Parse error"), messages(messages) {}
+
+ ~kicad_parse_exception() {}
const std::vector<std::string> messages;
};
@@ -86,7 +89,7 @@ public:
virtual ~kicad_net_loader();
- netlist load(std::string path);
+ netlist load(std::string path, std::ostream &err);
void setDebug(bool debug);
diff --git a/kicad.cpp b/core/kicad.cpp
index 0a6931d..1a6ca2f 100644
--- a/kicad.cpp
+++ b/core/kicad.cpp
@@ -136,7 +136,7 @@ public:
}
};
-netlist kicad_net_loader::load(string path) {
+netlist kicad_net_loader::load(string path, ostream &err) {
ANTLRFileStream input(path);
KicadNetLexer lexer(&input);
@@ -146,7 +146,7 @@ netlist kicad_net_loader::load(string path) {
if (debug_) {
for (auto token : tokens.getTokens()) {
- cerr << token->toString() << endl;
+ err << token->toString() << endl;
}
}
@@ -169,7 +169,7 @@ netlist kicad_net_loader::load(string path) {
auto file = parser.file();
if (debug_ && parser.getNumberOfSyntaxErrors() == 0) {
- cerr << file->toStringTree(&parser) << endl;
+ err << file->toStringTree(&parser) << endl;
}
return netlist {
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 04baca4..58048ff 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,2 +1,11 @@
+cmake_minimum_required(VERSION 3.5)
+project(kicad_utils_examples)
+
+find_package(KicadUtils QUIET)
+
+if (NOT KicadUtils_FOUND)
+ message(FATAL_ERROR "The KicadUtils CMake package was not found. Did you pass the correct value for KicadUtils_DIR?\nIt should probably be something like KicadUtils_DIR=$HOME/opt/kicad-utils/lib/cmake/KicadUtils")
+endif ()
+
add_subdirectory(arduino-led)
add_subdirectory(intel-quark-d2000)
diff --git a/examples/arduino-led/CMakeLists.txt b/examples/arduino-led/CMakeLists.txt
index 06ef920..a615fb7 100644
--- a/examples/arduino-led/CMakeLists.txt
+++ b/examples/arduino-led/CMakeLists.txt
@@ -1,3 +1,5 @@
+find_package(KicadUtils)
+
kicad_generate_header(
OUTPUT schematic.h
NET schematic/arduino-led.net
diff --git a/examples/intel-quark-d2000/CMakeLists.txt b/examples/intel-quark-d2000/CMakeLists.txt
index 1822996..3920d4b 100644
--- a/examples/intel-quark-d2000/CMakeLists.txt
+++ b/examples/intel-quark-d2000/CMakeLists.txt
@@ -1,8 +1,11 @@
+find_package(KicadUtils)
+
kicad_generate_header(
OUTPUT schematic.h
NET schematic/intel-quark-d2000.net
REF U1
- IN_SOURCE)
+ TEMPLATE intel-quark-d2000.py
+ TEMPLATE_LIB_LIST .)
if (FALSE)
# If you have Intel Quark support for CMake something like this would work:
@@ -10,5 +13,5 @@ if (FALSE)
#add_executable(arduino-led arduino-led.ino schematic.h)
#target_include_directories(arduino-led PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/kicad-include)
else ()
- add_custom_target(intel-quark-d2000 ALL DEPENDS schematic.h)
+ add_custom_target(intel-quark-d2000 ALL DEPENDS schematic.h schematic-py.h)
endif ()
diff --git a/examples/intel-quark-d2000/intel-quark-d2000.py b/examples/intel-quark-d2000/intel-quark-d2000.py
new file mode 100644
index 0000000..b69a919
--- /dev/null
+++ b/examples/intel-quark-d2000/intel-quark-d2000.py
@@ -0,0 +1,2 @@
+# noinspection PyUnresolvedReferences
+generateHeader.write("foo")
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644
index 0000000..2b612b9
--- /dev/null
+++ b/python/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_subdirectory(pybind11)
+
+pybind11_add_module(kicad_utils_py kicad_utils_py.cpp
+ include/trygvis/kicad/python.h
+ GenerateHeaderPy.cpp include/trygvis/kicad/GenerateHeaderPy.h)
+pybind11_enable_warnings(kicad_utils_py)
+
+target_include_directories(kicad_utils_py PRIVATE include)
+target_link_libraries(kicad_utils_py PRIVATE kicad-utils-core)
+
+install(TARGETS kicad_utils_py
+ EXPORT kicad_utils_export
+ LIBRARY DESTINATION lib)
diff --git a/python/GenerateHeaderPy.cpp b/python/GenerateHeaderPy.cpp
new file mode 100644
index 0000000..1a039a3
--- /dev/null
+++ b/python/GenerateHeaderPy.cpp
@@ -0,0 +1,40 @@
+#include "trygvis/kicad/GenerateHeaderPy.h"
+
+namespace trygvis {
+namespace kicad {
+namespace python {
+
+using namespace std;
+
+GenerateHeaderPy::GenerateHeaderPy(const string &ref, nl *netlist) : ref_(ref), netlist_(netlist) {
+}
+
+GenerateHeaderPy::~GenerateHeaderPy() {}
+
+string GenerateHeaderPy::ref() {
+ return ref_;
+}
+
+nl *GenerateHeaderPy::netlist() {
+ if (!netlist_) {
+ throw domain_error("No current netlist");
+ }
+
+ return netlist_;
+}
+
+string GenerateHeaderPy::str() {
+ return buf_.str();
+}
+
+void GenerateHeaderPy::print(const string &str) {
+ buf_ << str;
+}
+
+void GenerateHeaderPy::println(const string &str) {
+ buf_ << str << endl;
+}
+
+} // namespace python
+} // namespace kicad
+} // namespace trygvis
diff --git a/python/include/trygvis/kicad/GenerateHeaderPy.h b/python/include/trygvis/kicad/GenerateHeaderPy.h
new file mode 100644
index 0000000..893b7ed
--- /dev/null
+++ b/python/include/trygvis/kicad/GenerateHeaderPy.h
@@ -0,0 +1,45 @@
+#ifndef KICAD_UTILS_GENERATEHEADEPY_H
+#define KICAD_UTILS_GENERATEHEADEPY_H
+
+#include "trygvis/kicad.h"
+#include "pybind11/pybind11.h"
+#include <memory>
+#include <sstream>
+
+namespace trygvis {
+namespace kicad {
+namespace python {
+
+namespace py = pybind11;
+
+using nl = trygvis::kicad::netlist::netlist;
+
+class GenerateHeaderPy {
+public:
+ GenerateHeaderPy(const std::string &ref, nl *netlist);
+
+ virtual ~GenerateHeaderPy();
+
+ std::string ref();
+
+ nl *netlist();
+
+ std::string str();
+
+ void print(const std::string &str);
+
+ void println(const std::string &str);
+
+private:
+ std::string ref_;
+
+ nl *netlist_;
+
+ std::stringstream buf_;
+};
+
+} // namespace python
+} // namespace kicad
+} // namespace trygvis
+
+#endif
diff --git a/python/include/trygvis/kicad/python.h b/python/include/trygvis/kicad/python.h
new file mode 100644
index 0000000..f2ae816
--- /dev/null
+++ b/python/include/trygvis/kicad/python.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "trygvis/kicad/GenerateHeaderPy.h"
diff --git a/python/kicad_utils_py.cpp b/python/kicad_utils_py.cpp
new file mode 100644
index 0000000..6cd3948
--- /dev/null
+++ b/python/kicad_utils_py.cpp
@@ -0,0 +1,38 @@
+#include "trygvis/kicad/GenerateHeaderPy.h"
+
+#include "pybind11/stl.h"
+
+using namespace std;
+using namespace trygvis::kicad::netlist;
+using namespace trygvis::kicad::python;
+
+void init_module(py::module &m) {
+ py::class_<node>(m, "node").
+ def_readonly("ref", &node::ref).
+ def_readonly("pin", &node::pin);
+
+ py::class_<net>(m, "net").
+ def_readonly("code", &net::code).
+ def_readonly("name", &net::name).
+ def_readonly("nodes", &net::nodes).
+ def("node_for_ref", &net::node_for_ref, py::return_value_policy::reference);
+
+ py::class_<nl>(m, "netlist").
+ def("find_usages_of", &nl::find_usage_of, py::return_value_policy::reference);
+
+ py::class_<GenerateHeaderPy>(m, "GenerateHeader").
+ def(py::init<const string &, nl *>()).
+ def_property_readonly("netlist", &GenerateHeaderPy::netlist).
+ def_property_readonly("ref", &GenerateHeaderPy::ref).
+ def_property_readonly("str", &GenerateHeaderPy::str).
+ def("print", &GenerateHeaderPy::print).
+ def("println", &GenerateHeaderPy::println);
+}
+
+PYBIND11_PLUGIN(kicad_utils_py) {
+ py::module kicad_utils("kicad_utils_py");
+
+ init_module(kicad_utils);
+
+ return kicad_utils.ptr();
+}
diff --git a/python/pybind11 b/python/pybind11
new file mode 160000
+Subproject f38f359f96815421f1780c1a676715efd041f1a
diff --git a/template/intel-quark-d2000.py b/template/intel-quark-d2000.py
new file mode 100644
index 0000000..85572c5
--- /dev/null
+++ b/template/intel-quark-d2000.py
@@ -0,0 +1,69 @@
+global generateHeader
+gpio_map = {
+ 2: '10',
+ 3: '11',
+ 4: '12',
+ 5: '13',
+ 6: '14',
+ 7: '15',
+ 8: '16',
+ 9: '17',
+ 10: '18',
+
+ 11: '9',
+ 13: '20',
+ 14: '21',
+ 15: '22',
+ 16: '23',
+ 18: '19',
+
+ 21: '24',
+
+ 31: '0',
+ 32: '1',
+ 33: '2',
+ 34: '3',
+ 35: '4',
+ 36: '5',
+ 37: '6',
+ 38: '7',
+ 39: '8'
+}
+
+generateHeader.println("""
+#include <stddef.h>
+#include <qm_gpio.h>
+
+enum schematic_direction {
+ schematic_direction_out = 1,
+ schematic_direction_in = 2
+};
+""")
+
+usages = generateHeader.netlist.find_usages_of(generateHeader.ref)
+
+for usage in usages:
+ node = usage.node_for_ref(generateHeader.ref)
+
+ gpio = gpio_map.get(node.pin)
+
+ if gpio is None:
+ continue
+
+ generateHeader.println(
+ 'static const uint8_t SCHEMATIC_' + usage.name + ' = ' + gpio + ';\n'
+ '\n'
+ 'static inline\n'
+ 'qm_rc_t schematic_' + usage.name + '_direction(enum schematic_direction dir) {\n'
+ ' qm_gpio_port_config_t cfg;\n'
+ '\n'
+ ' qm_gpio_get_config(QM_GPIO_0, &cfg);\n'
+ '\n'
+ ' if (dir == schematic_direction_out) {\n'
+ ' cfg.direction |= BIT(SCHEMATIC_' + usage.name + ');\n'
+ ' } else {\n'
+ ' cfg.direction &= ~BIT(SCHEMATIC_' + usage.name + ');\n'
+ ' }\n'
+ '\n'
+ ' return qm_gpio_set_config(QM_GPIO_0, &cfg);\n'
+ '}')