aboutsummaryrefslogtreecommitdiff
path: root/generate-header.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'generate-header.cpp')
-rw-r--r--generate-header.cpp311
1 files changed, 311 insertions, 0 deletions
diff --git a/generate-header.cpp b/generate-header.cpp
new file mode 100644
index 0000000..d134d47
--- /dev/null
+++ b/generate-header.cpp
@@ -0,0 +1,311 @@
+#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;
+
+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>]\n", program);
+ exit(EX_USAGE);
+}
+
+void parse_args(int argc, char **argv, bool *debug, char **net_filename, char **ref, char **out_filename) {
+ *debug = false;
+ *ref = nullptr;
+ *out_filename = nullptr;
+ *ref = nullptr;
+
+ int c;
+ while ((c = getopt(argc, argv, "Dn:r:o:")) != -1) {
+ switch (c) {
+ case 'D':
+ *debug = true;
+ break;
+ case 'n':
+ *net_filename = optarg;
+ break;
+ case 'r':
+ *ref = 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)) { }
+
+ 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;
+ }
+};
+
+bool generate(const char *ref, const trygvis::kicad::netlist::netlist &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;
+}
+
+int main(int argc, char **argv) {
+ program = argv[0];
+
+ bool debug;
+ char *net_filename;
+ char *ref;
+ char *out_filename;
+ parse_args(argc, argv, &debug, &net_filename, &ref, &out_filename);
+
+ kicad_net_loader loader;
+
+ try {
+ auto netlist = loader.load(net_filename);
+
+ stringstream out;
+ auto 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");
+ }
+}