aboutsummaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/CMakeLists.txt29
-rw-r--r--cli/generate-header.cpp466
2 files changed, 495 insertions, 0 deletions
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/cli/generate-header.cpp b/cli/generate-header.cpp
new file mode 100644
index 0000000..1033fc3
--- /dev/null
+++ b/cli/generate-header.cpp
@@ -0,0 +1,466 @@
+#include "trygvis/kicad.h"
+
+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;
+
+__attribute__((noreturn))
+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>] [-t <python template>]\n", program);
+ exit(EX_USAGE);
+}
+
+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:t:l:")) != -1) {
+ switch (c) {
+ case 'D':
+ *debug = true;
+ break;
+ case 'n':
+ *net_filename = optarg;
+ break;
+ 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;
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (!*net_filename || !*ref) {
+ usage();
+ }
+}
+
+class part {
+public:
+ part(const string &name) : name(name) {
+ }
+
+ virtual ~part() {
+ }
+
+ const string name;
+
+ virtual bool generate(stringstream &out, const string &ref, const vector<const net *> usages) = 0;
+};
+
+class arduino_uno : public part {
+public:
+ arduino_uno() : part("ARDUINO_UNO") {}
+
+ ~arduino_uno() {
+ }
+
+ virtual bool generate(stringstream &out, const string &ref, const vector<const net *> usages) override {
+ out << "namespace schematic {" << endl;
+ for (auto &usage: usages) {
+ auto node = usage->node_for_ref(ref);
+
+ if (node->pin >= 7 && node->pin <= 12) {
+ out << "static const int ANALOG_" << usage->name << " = " << (node->pin - 7) << ";" << endl;
+ } else if (node->pin >= 13 && node->pin <= 26) {
+ out << "static const int " << usage->name << " = " << (node->pin - 13) << ";" << endl;
+ }
+ }
+ out << "} // namespace schematic" << endl;
+
+ return true;
+ }
+};
+
+class intel_quark_d2000 : public part {
+public:
+ intel_quark_d2000() : part("INTEL_QUARK_D2000") {}
+
+ ~intel_quark_d2000() {
+ }
+
+ virtual bool generate(stringstream &out, const string &ref, const vector<const net *> usages) override {
+ static map<int, string> 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"},
+ };
+
+ out << "#include <stddef.h>" << endl;
+ out << "#include <qm_gpio.h>" << endl;
+ out << endl;
+ out << "enum schematic_direction {" << endl;
+ out << " schematic_direction_out = 1," << endl;
+ out << " schematic_direction_in = 2" << endl;
+ out << "};" << endl;;
+
+ for (auto &usage: usages) {
+ auto node = usage->node_for_ref(ref);
+
+ auto gpio = gpio_map.find(node->pin);
+
+ if (gpio == gpio_map.end()) {
+ continue;
+ }
+
+ out << "static const uint8_t SCHEMATIC_" << usage->name << " = " << gpio->second << ";" << endl;
+ out << endl;
+ out << "static inline" << endl;
+ out << "qm_rc_t schematic_PUSH_BUTTON_direction(enum schematic_direction dir) {" << endl;
+ out << " qm_gpio_port_config_t cfg;" << endl;
+ out << "" << endl;
+ out << " qm_gpio_get_config(QM_GPIO_0, &cfg);" << endl;
+ out << "" << endl;
+ out << " if (dir == schematic_direction_out) {" << endl;
+ out << " cfg.direction |= BIT(SCHEMATIC_PUSH_BUTTON);" << endl;
+ out << " } else {" << endl;
+ out << " cfg.direction &= ~BIT(SCHEMATIC_PUSH_BUTTON);" << endl;
+ out << " }" << endl;
+ out << "" << endl;
+ out << " return qm_gpio_set_config(QM_GPIO_0, &cfg);" << endl;
+ out << "}" << endl;
+ out << endl;
+ }
+
+ return true;
+ }
+};
+
+//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;
+ }
+
+ for (auto &&prefix : paths) {
+ p = prefix / py_template;
+
+ if (fs::exists(p)) {
+ return p;
+ }
+ }
+
+ return nullopt;
+}
+
+/*
+bool generate(const char *ref, nl *const netlist, stringstream &out) {
+ kicad_gen gen;
+ opt<const component *> componentO = netlist->find_component(ref);
+
+ if (!componentO) {
+ cerr << "Could not find component '" << ref << "'" << endl;
+ return false;
+ }
+
+ const component *c = *componentO;
+
+ cerr << "Generating connections for " << c->ref << " (" << c->value << ")" << endl;
+
+ auto libraryO = gen.find_library(c->_lib_source.lib);
+
+ if (!libraryO) {
+ cerr << "Unsupported library '" << c->_lib_source.lib << "'" << endl;
+ return false;
+ }
+
+ const library *library = *libraryO;
+
+ auto partName = c->_lib_source.part;
+
+ auto partO = library->find_part(partName);
+
+ if (!partO) {
+ cerr << "The library library " << library->name << " does not have a component named " << partName << endl;
+ return false;
+ }
+
+ part *part = *partO;
+
+ out << "#ifndef SCHEMATIC_H" << endl;
+ out << "#define SCHEMATIC_H" << 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;
+ out << endl;
+
+ auto usages = netlist->find_usage_of(ref);
+
+ part->generate(out, ref, usages);
+
+ out << "#endif // SCHEMATIC_H" << endl;
+
+ return true;
+}
+*/
+
+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;
+
+ 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 {
+ nl netlist = loader.load(net_filename, cerr);
+
+ stringstream 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();
+ if (out_filename != nullptr) {
+ ofstream outstream(out_filename);
+ outstream << contents;
+ outstream.close();
+ } else {
+ cout << contents << flush;
+ }
+ return EXIT_SUCCESS;
+ }
+ return EXIT_FAILURE;
+ } catch (kicad_parse_exception &e) {
+ for (auto &m: e.messages) {
+ fprintf(stderr, "%s\n", m.c_str());
+ }
+ errx(EX_DATAERR, "Could not parse netlist");
+ }
+}