/* * Lookup "Ultra Librarian" in your favorite search engine. * * AFAIK, TI has footprints in format compatible with this software for all its chips. */ #include #include #include #include #include enum KicadLayer { // visit: http://en.wikibooks.org/wiki/Kicad/file_formats#Layer_numbering TOP = 24, TOP_SILKSCREEN = 23, BOTTOM_SILKSCREEN = 22, TOP_PLACE_BOUND = 24, TOP_ASSEMBLY = 15 }; int print_pads(const pugi::xml_document& doc, const std::string& footprint_name, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set pads = doc.select_nodes((string("//footprint[@name='") + footprint_name + "']/pcbpin").c_str()); for (auto &pin : pads) { map ul_kicad_shape = { {"round", "C"}, {"rectangle", "R"} // ...others I don't know about }; const string pin_name = pin.node().attribute("name").value(); const string pin_style = pin.node().attribute("style").value(); xpath_node_set shape_node = doc.select_nodes( (string("//padstyle[@name='") + pin_style + "']" + "/padshape").c_str()); if (shape_node.empty()) throw runtime_error("We're screwed!"); const string pin_shape = shape_node.first().node().attribute("shape").value(); double pin_width = shape_node.first().node().attribute("width").as_double()*10; double pin_height = shape_node.first().node().attribute("height").as_double()*10; double pin_posx = pin.node().attribute("originx").as_double()*10; double pin_posy = pin.node().attribute("originy").as_double()*10; double pin_rotation = pin.node().attribute("rotation").as_double()*10; out << "$PAD" << endl; out << ".LocalClearance 0.001" << endl; out << "Po " << pin_posx << " " << pin_posy << endl; out << "Sh \"" << pin_name << "\" " << ul_kicad_shape[pin_shape] << " " << pin_width << " " << pin_height << " " << 0 << " " << 0 << " " << pin_rotation << endl; out << "At SMD N 00888000" << endl; out << "$EndPAD" << endl; } return pads.size(); } int print_lines(const pugi::xml_document& doc, const std::string& footprint_name, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set lines = doc.select_nodes((string("//footprint[@name='") + footprint_name + "']/line").c_str()); for (auto &line : lines) { double originx = line.node().attribute("originx").as_double()*10; double originy = line.node().attribute("originy").as_double()*10; double endx = line.node().attribute("endx").as_double()*10; double endy = line.node().attribute("endy").as_double()*10; double width = line.node().attribute("width").as_double()*10; out << "DS " << originx << " " << originy << " " << endx << " " << endy << " " << width << " " << TOP_SILKSCREEN << endl; } return lines.size(); } int print_polygons(const pugi::xml_document& doc, const std::string& footprint_name, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set polygons = doc.select_nodes((string("//footprint[@name='") + footprint_name + "']/polygon").c_str()); for (auto &polygon : polygons) { // no better way to do this :( int count = 0; for (auto &vertex : polygon.node()) ++count; double width = polygon.node().attribute("width").as_double()*10; out << "DP 0 0 0 0 " << count << " " << width << " " << TOP_PLACE_BOUND << endl; for (auto &vertex : polygon.node()) { double x = vertex.attribute("x").as_double()*10; double y = vertex.attribute("y").as_double()*10; out << "Dl " << x << " " << y << endl; } } } int print_footprints(const pugi::xml_document& doc, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set footprints = doc.select_nodes("//footprint"); for (auto &pin : footprints) { string footprint_name = pin.node().attribute("name").value(); out << "$MODULE " << footprint_name << endl << "Po 0 0 0 15 00000000 00000000 ~~" << endl << "Li " << footprint_name << endl; //print_lines(doc, footprint_name, out); //print_polygons(doc, footprint_name, out); print_pads(doc, footprint_name, out); out << ".LocalClearance 0" << endl; out << "$EndMODULE " << footprint_name << endl; } return footprints.size(); } void print_index(const pugi::xml_document& doc, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set footprints = doc.select_nodes("//footprint"); for (auto &footprint : footprints) out << footprint.node().attribute("name").value() << endl; } void print_library(const pugi::xml_document& doc, std::ostream& out) { using namespace pugi; using namespace std; out << "PCBNEW-LibModule-V1 Wed 17 Apr 2013 03:54:45 PM CEST" << endl; out << "$INDEX" << endl; print_index(doc,out); out << "$EndINDEX" << endl; print_footprints(doc, out); out << "$EndLIBRARY" << endl; } void print_pins(const pugi::xml_document& doc, const std::string& pin_name, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set pins = doc.select_nodes((string("//symbol[@name='") + pin_name + "']/sympin").c_str()); for (auto &pin : pins) { const int number = pin.node().attribute("number").as_int(); const double posx = pin.node().attribute("originx").as_double(); const double posy = pin.node().attribute("originy").as_double(); const int rotation = pin.node().attribute("rotation").as_int(); const double length = pin.node().attribute("length").as_double(); const string flipped = pin.node().attribute("flipped").value(); xpath_node pindes_node = doc.select_single_node((string("//symbol[@name='") + pin_name + "']/sympin[@number='" + to_string(number) + "']/text[@name='pindes']").c_str()); xpath_node pinname_node = doc.select_single_node((string("//symbol[@name='") + pin_name + "']/sympin[@number='" + to_string(number) + "']/text[@name='pinname']").c_str()); const string pinname = pinname_node.node().attribute("data").value(); const string pindes = pindes_node.node().attribute("data").value(); map kicad_rotation = { {270, 'U'}, {180, 'R'}, {90, 'D'}, {0, 'L'} }; /* * X TO 1 - 200 0.150 R 40 40 1 1 P */ out << "X " << pinname << " " << number << " " << posx << " " << posy << " " << length << " " << kicad_rotation[rotation] << " 40 40 0 0 U" << endl; } } int print_symbols(const pugi::xml_document& doc, std::ostream& out) { using namespace pugi; using namespace std; xpath_node_set symbols = doc.select_nodes("//symbol"); unsigned int part_number = 0; for (auto &pin : symbols) { string symbol_name = pin.node().attribute("name").value(); /* * DEF DIODE D 0 40 Y NR 1 0 NR */ out << "DEF " << symbol_name << " U 0 50 Y Y " << ++part_number << "L N" << endl; /* * F0 “D” 0.100 50 H V L CNN * F1 “DIODE” 0 -100 50 H V L CIB */ out << "F0 \"U\" 0 -100 50 H V L CNN" << endl << "F1 \"" + string(symbol_name) + "\" 0 -200 50 H V L CIB" << endl; out << "DRAW" << endl; print_pins(doc,symbol_name,out); out << "ENDDRAW" << endl << "ENDDEF" << endl; } return symbols.size(); } void print_module(const pugi::xml_document& doc, std::ostream& out) { using namespace std; using namespace pugi; out << "EESchema-LIBRARY Version 2.0 24/1/1997-18:9:6" << endl; print_symbols(doc,out); } int main(int argc, char* argv[]) { using namespace std; using namespace pugi; if (argc != 4) return 1; xml_document doc; doc.load_file(argv[1]); ofstream libfile(argv[2]); print_library(doc,libfile); libfile.close(); ofstream symfile(argv[3]); print_module(doc,symfile); symfile.close(); return 0; }