diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/generate-header.cpp | 470 |
1 files changed, 141 insertions, 329 deletions
diff --git a/cli/generate-header.cpp b/cli/generate-header.cpp index 1033fc3..6fd64c6 100644 --- a/cli/generate-header.cpp +++ b/cli/generate-header.cpp @@ -37,39 +37,51 @@ 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); + fprintf(stderr, "usage: %s -n <net file> -r <ref> -t <template> [-l <template lib dir>] [-o <out file>]\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; +struct opts { + bool debug; + string net_filename; + string ref; + string py_template; + opt<string> out_filename; + vector<fs::path> template_libs; +}; + +struct opts parse_args(int argc, char **argv) { + struct opts opts = { + .debug = false, + .net_filename = "", + .ref = "", + .py_template = "", + .out_filename = nullopt, + .template_libs = {}, + }; int c; while ((c = getopt(argc, argv, "Dn:r:o:t:l:")) != -1) { switch (c) { case 'D': - *debug = true; + opts.debug = true; break; case 'n': - *net_filename = optarg; + opts.net_filename = optarg; break; case 'r': - *ref = optarg; + opts.ref = optarg; break; case 't': - *py_template = optarg; + opts.py_template = optarg; break; case 'l': - template_libs.push_back(fs::path(optarg)); + opts.template_libs.push_back(fs::path(optarg)); break; case 'o': if (strcmp("-", optarg) != 0) { - *out_filename = optarg; + opts.out_filename = string(optarg); } break; default: @@ -77,182 +89,24 @@ void parse_args(int argc, char **argv, bool *debug, char **net_filename, char ** } } - if (!*net_filename || !*ref) { + if (opts.net_filename.empty() || opts.ref.empty() || opts.py_template.empty()) { 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 opts; +} - return true; - } -}; +static +opt<fs::path> find_py_template(const string &py_template, const vector<fs::path> &paths) { -//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); + fs::path p(py_template + ".py"); if (fs::exists(p)) { return p; } for (auto &&prefix : paths) { - p = prefix / py_template; + p = prefix / (py_template + ".py"); if (fs::exists(p)) { return p; @@ -262,67 +116,11 @@ opt<fs::path> find_template(const string &py_template, const vector<fs::path> &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) { +bool generate(const string &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::module main_module = py::module::import("__main__"); + vars = main_module.attr("__dict__"); pybind11::object netlist_py = py::cast(netlist); @@ -343,30 +141,8 @@ bool generate_py(const char *ref, nl *const netlist, stringstream &out, const fs 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; - */ - - /* +__attribute__((unused)) static +void show_env() { map<string, string> env; for (char **e = environ; *e != NULL; e++) { string s = *e; @@ -377,86 +153,122 @@ int main(int argc, char **argv) { for (auto &&e: env) { cout << e.first << " = " << e.second << endl; } - */ +} + +__attribute__((unused)) static +void show_py_info() { + cerr << "Compile-time Python version: " << PY_VERSION << endl; + cerr << "Current python version: " << Py_GetVersion() << endl; +} + +class python_init { +private: + wchar_t *program = nullptr; + +public: + class python_init_error : public std::runtime_error { + public: + python_init_error(const string &what) : runtime_error(what) {} + }; + + python_init(const char *argv0, const vector<fs::path> &python_paths) { + std::wstring_convert<codecvt_utf8<wchar_t>> converter; + + wstring pythonpath(Py_GetPath()); + for (auto &path : python_paths) { + if (!fs::exists(path)) { + continue; + } + pythonpath = converter.from_bytes(path.string() + PATH_SEPARATOR) + pythonpath; + } + wcerr << "PYTHONPATH: " << pythonpath << endl; + Py_SetPath(pythonpath.c_str()); + + program = Py_DecodeLocale(argv0, NULL); + if (program == NULL) { + throw python_init_error("Fatal error: cannot decode argv[0]\n"); + } + Py_SetProgramName(program); + + show_py_info(); + + Py_Initialize(); + } + + ~python_init() { + Py_Finalize(); + PyMem_RawFree(program); + } +}; + +int main(int argc, char **argv) { + program = argv[0]; + + fs::path bin(argv[0]); + fs::path basedir = bin.parent_path().parent_path(); + + struct opts opts = parse_args(argc, argv); + + opts.template_libs.push_back(fs::current_path()); + opts.template_libs.push_back(basedir / "share" / "kicad-utils" / "template"); + + kicad_net_loader loader; + + if (opts.debug) { + show_env(); + } try { - nl netlist = loader.load(net_filename, cerr); + nl netlist = loader.load(opts.net_filename, cerr); stringstream out; - bool ok = false; - if (py_template) { - cerr << "Template path: " << endl; - for (auto &&p : template_libs) { + cerr << "Template search path: " << endl; + for (auto &&p : opts.template_libs) { + cerr << " " << p.string() << endl; + } + + opt<fs::path> py_template = find_py_template(opts.py_template, opts.template_libs); + + if (!py_template) { + cerr << "No such file: " << opts.py_template << endl; + cerr << "Search path: " << endl; + for (auto &&p : opts.template_libs) { cerr << " " << p.string() << endl; } + cerr << "Current path is " << fs::current_path().string() << endl; + return EXIT_FAILURE; + } - opt<fs::path> tmpl = find_template(py_template, template_libs); + vector<fs::path> module_paths{ + basedir / "python", + basedir / "lib", + }; - 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; + python_init python(argv[0], module_paths); + try { + auto ok = generate(opts.ref, &netlist, out, py_template.value()); + + if (ok) { + auto contents = out.str(); + if (opts.out_filename) { + ofstream outstream(opts.out_filename.value()); + outstream << contents; + outstream.close(); + } else { + cout << contents << flush; } - 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); + return EXIT_SUCCESS; } -// } else { -// ok = generate(ref, &netlist, out); + } catch (py::error_already_set &e) { + cerr << "Python failure:" << endl << e.what() << endl; + } catch (std::runtime_error &e) { + cerr << "Generation failed: " << e.what() << endl; } - 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; + return EXIT_SUCCESS; + } catch (python_init::python_init_error &e) { + errx(EX_IOERR, e.what()); } catch (kicad_parse_exception &e) { for (auto &m: e.messages) { fprintf(stderr, "%s\n", m.c_str()); |