kicad_footprint_converter/footprint_conv.cc

282 lines
7.8 KiB
C++

/*
* Lookup "Ultra Librarian" in your favorite search engine.
*
* AFAIK, TI has footprints in format compatible with this software for all its chips.
*/
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <pugixml.hpp>
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<string, string> 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<int, char> 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;
}