From c307e9f234e544386fa3ae53083c7510668e1716 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 29 Jul 2016 00:39:45 +0200 Subject: o Renaming cmake function from kicad_gen to kicad_generate_header, more to the point. o Renaming binary from kicad_gen to generate-header too. Should probably be kicad-utils-generate-header or somesuch later. o Moving the cmake code used by the examples into its own file, should be part of the installation target later on. --- .gitmodules | 4 + CMakeLists.txt | 63 +----- examples/arduino-led/CMakeLists.txt | 4 +- examples/arduino-led/schematic.h | 1 - examples/intel-quark-d2000/CMakeLists.txt | 4 +- examples/intel-quark-d2000/schematic.h | 1 - generate-header.cpp | 311 ++++++++++++++++++++++++++++++ kicad.cmake | 43 +++++ main.cpp | 311 ------------------------------ 9 files changed, 370 insertions(+), 372 deletions(-) create mode 100644 .gitmodules create mode 100644 generate-header.cpp create mode 100644 kicad.cmake delete mode 100644 main.cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a84f300 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "pybind11"] + path = pybind11 + url = https://github.com/pybind/pybind11.git + branch = master diff --git a/CMakeLists.txt b/CMakeLists.txt index ff91ac6..926f7c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,62 +4,15 @@ project(kicad_utils) find_package(Antlr4) antlr4_add_target(TARGET KicadNet LEXER KicadNetLexer.g4 PARSER KicadNetParser.g4 STATIC) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") -set(SOURCE_FILES main.cpp kicad.cpp include/trygvis/kicad.h include-priv/trygvis/antlr.h include-priv/trygvis/string_utils.h) -add_executable(kicad_utils ${SOURCE_FILES}) -target_include_directories(kicad_utils PUBLIC include PRIVATE include-priv) -target_link_libraries(kicad_utils KicadNet Antlr4::antlr4_shared) -target_compile_options(kicad_utils PUBLIC --std=c++14) -target_compile_options(kicad_utils PUBLIC -Wall -Wextra) +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) - -function(kicad_gen) - set(options IN_SOURCE) - set(oneValueArgs TARGET NET REF OUTPUT_DIR) - - cmake_parse_arguments(kicad_gen "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if (NOT kicad_gen_TARGET) - message(FATAL_ERROR "TARGET is required") - endif () - set(TARGET "${kicad_gen_TARGET}") - - if (NOT kicad_gen_NET) - message(FATAL_ERROR "NET is required") - endif () - set(NET "${CMAKE_CURRENT_SOURCE_DIR}/${kicad_gen_NET}") - - if (NOT kicad_gen_REF) - message(FATAL_ERROR "REF is required") - endif () - set(REF "${kicad_gen_REF}") - - if (kicad_gen_OUTPUT_DIR) - if (kicad_gen_IN_SOURCE) - message(FATAL_ERROR "IN_SOURCE can't be used if OUTPUT_DIR is used") - endif () - - set(OUTPUT_DIR "${kicad_gen_OUTPUT_DIR}") - else () - message("IN_SOURCE=${kicad_gen_IN_SOURCE}") - if (kicad_gen_IN_SOURCE) - set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - else () - set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") - endif () - endif () - - set(OUTPUT_FILE "${OUTPUT_DIR}/${TARGET}") - message("OUTPUT_FILE=${OUTPUT_FILE}") - message("NET=${NET}") - - add_custom_command(OUTPUT ${OUTPUT_FILE} - COMMAND kicad_utils -n ${NET} -r ${REF} -o ${OUTPUT_FILE} - MAIN_DEPENDENCY ${NET} - DEPENDS kicad_utils - COMMENT "Generating ${TARGET}") -endfunction() - add_subdirectory(examples) diff --git a/examples/arduino-led/CMakeLists.txt b/examples/arduino-led/CMakeLists.txt index 7bd82af..06ef920 100644 --- a/examples/arduino-led/CMakeLists.txt +++ b/examples/arduino-led/CMakeLists.txt @@ -1,5 +1,5 @@ -kicad_gen( - TARGET schematic.h +kicad_generate_header( + OUTPUT schematic.h NET schematic/arduino-led.net REF U1 IN_SOURCE) diff --git a/examples/arduino-led/schematic.h b/examples/arduino-led/schematic.h index f41a300..c935528 100644 --- a/examples/arduino-led/schematic.h +++ b/examples/arduino-led/schematic.h @@ -11,5 +11,4 @@ namespace schematic { static const int STATUS_LED = 3; static const int ANALOG_LIGHT_1 = 2; } // namespace schematic - #endif // SCHEMATIC_H diff --git a/examples/intel-quark-d2000/CMakeLists.txt b/examples/intel-quark-d2000/CMakeLists.txt index e139440..1822996 100644 --- a/examples/intel-quark-d2000/CMakeLists.txt +++ b/examples/intel-quark-d2000/CMakeLists.txt @@ -1,5 +1,5 @@ -kicad_gen( - TARGET schematic.h +kicad_generate_header( + OUTPUT schematic.h NET schematic/intel-quark-d2000.net REF U1 IN_SOURCE) diff --git a/examples/intel-quark-d2000/schematic.h b/examples/intel-quark-d2000/schematic.h index 62545f0..8bc46ae 100644 --- a/examples/intel-quark-d2000/schematic.h +++ b/examples/intel-quark-d2000/schematic.h @@ -48,5 +48,4 @@ qm_rc_t schematic_PUSH_BUTTON_direction(enum schematic_direction dir) { return qm_gpio_set_config(QM_GPIO_0, &cfg); } - #endif // SCHEMATIC_H 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 -r [-o ]\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 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)) { } + + 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; + } +}; + +bool generate(const char *ref, const trygvis::kicad::netlist::netlist &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; +} + +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"); + } +} diff --git a/kicad.cmake b/kicad.cmake new file mode 100644 index 0000000..f18e6fe --- /dev/null +++ b/kicad.cmake @@ -0,0 +1,43 @@ +function(kicad_generate_header) + set(options IN_SOURCE) + set(oneValueArgs OUTPUT NET REF OUTPUT_DIR) + + cmake_parse_arguments(kicad_gen "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT kicad_gen_OUTPUT) + message(FATAL_ERROR "OUTPUT is required") + endif () + set(output "${kicad_gen_OUTPUT}") + + if (NOT kicad_gen_NET) + message(FATAL_ERROR "NET is required") + endif () + set(NET "${CMAKE_CURRENT_SOURCE_DIR}/${kicad_gen_NET}") + + if (NOT kicad_gen_REF) + message(FATAL_ERROR "REF is required") + endif () + set(REF "${kicad_gen_REF}") + + if (kicad_gen_OUTPUT_DIR) + if (kicad_gen_IN_SOURCE) + message(FATAL_ERROR "IN_SOURCE can't be used if OUTPUT_DIR is used") + endif () + + set(output_dir "${kicad_gen_OUTPUT_DIR}") + else () + if (kicad_gen_IN_SOURCE) + set(output_dir "${CMAKE_CURRENT_SOURCE_DIR}") + else () + set(output_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif () + endif () + + set(output_file "${output_dir}/${output}") + + add_custom_command(OUTPUT "${output_file}" + COMMAND generate-header -n ${NET} -r ${REF} -o ${output_file} + MAIN_DEPENDENCY ${NET} + DEPENDS kicad_utils + COMMENT "Generating ${output}") +endfunction() diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 4449f46..0000000 --- a/main.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -r [-o ]\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 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)) { } - - 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; - } -}; - -bool generate(const char *ref, const trygvis::kicad::netlist::netlist &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 << "kicad_gen does not support 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 << "kicad_gen's 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"); - } -} -- cgit v1.2.3