#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 #include #include #include #include #include #include #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 -r [-o ] [-t ]\n", program); exit(EX_USAGE); } void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **ref, char **py_template, vector &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 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 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 usages) override { static map 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 " << endl; out << "#include " << 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> parts; // // opt find_part(string name) const { // for (auto &part: parts) { // if (part->name == name) { // return part.get(); // } // } // // return nullopt; // } //}; //class kicad_gen { //public: // vector libraries; // // kicad_gen() { // library kicad_utils("kicad_utils"); // kicad_utils.parts.push_back(make_unique()); // kicad_utils.parts.push_back(make_unique()); // // libraries.push_back(std::move(kicad_utils)); // } // // opt find_library(string name) { // for (auto &l : libraries) { // if (l.name == name) { // return &l; // } // } // // return nullopt; // } //}; opt find_template(const string &py_template, const vector &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 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(init, vars); py::eval_file(py_template.string(), vars); string str = py::eval("generateHeader.str", vars).cast().cast(); out << str; return true; } int main(int argc, char **argv) { bool debug; char *net_filename; char *ref; char *py_template; vector 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 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 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 module_paths{ basedir / "python", basedir / "lib", }; std::wstring_convert > 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"); } }