/** ****************************************************************************** * * @file uavobjectgenerator.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief UAVObjectGenerator, generates UAVObjects from XML files. * * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * The following is done by the object generator: * - Read all XML files in the XML source directory * - Process each XML and extract the information for all defined objects * - Generate the unique objects IDs and check for collisions * - Generate the GCS and Flight UAVObject code based on the supplied template source files * - Update the object initialization source files for both the GCS and Flight code */ #include "uavobjectgenerator.h" /** * Constructor * @param basepath The base directory where the 'flight' and 'gcs' folders are located (the SVN structure is expected) * @param out The stdout file */ UAVObjectGenerator::UAVObjectGenerator(QString& basepath, FILE* out) : basepath(basepath), sout(out) { xmlPath = QDir( basepath + QString("ground/src/shared/uavobjectdefinition")); flightCodePath = QDir( basepath + QString("flight/OpenPilot/UAVObjects")); gcsCodePath = QDir( basepath + QString("ground/src/plugins/uavobjects")); objectTemplateFilename = QString("uavobjecttemplate"); objectsInitTemplateFilename = QString("uavobjectsinittemplate"); objectsInitFilename = QString("uavobjectsinit"); sout << "- OpenPilot UAVObject Generator -" << endl; } /** * Process all XML files and generate object code. */ bool UAVObjectGenerator::processAll() { // Read the template files QString flightCodeTemplate = readFile( flightCodePath.absoluteFilePath(objectTemplateFilename + ".c") ); QString flightIncludeTemplate = readFile( flightCodePath.absoluteFilePath("inc/" + objectTemplateFilename + ".h") ); QString flightInitTemplate = readFile( flightCodePath.absoluteFilePath(objectsInitTemplateFilename + ".c") ); QString gcsCodeTemplate = readFile( gcsCodePath.absoluteFilePath(objectTemplateFilename + ".cpp") ); QString gcsIncludeTemplate = readFile( gcsCodePath.absoluteFilePath(objectTemplateFilename + ".h") ); QString gcsInitTemplate = readFile( gcsCodePath.absoluteFilePath(objectsInitTemplateFilename + ".cpp") ); if ( flightCodeTemplate.isNull() || flightIncludeTemplate.isNull() || gcsCodeTemplate.isNull() || gcsIncludeTemplate.isNull() || flightInitTemplate.isNull() || gcsInitTemplate.isNull() ) { sout << "Error: Could not open template files." << endl; return false; } // Get all XML files QStringList filters; filters.append("*.xml"); xmlPath.setNameFilters(filters); QFileInfoList xmlList = xmlPath.entryInfoList(); // Read in each XML file and parse it QList parsers; for (int n = 0; n < xmlList.length(); ++n) { QFileInfo fileinfo = xmlList[n]; QString filename = fileinfo.fileName(); QString xmlstr = readFile(fileinfo.absoluteFilePath()); UAVObjectParser* parser = new UAVObjectParser(); sout << "Parsing XML file: " << fileinfo.fileName() << endl; QString res = parser->parseXML(xmlstr, filename); if (!res.isNull()) { sout << "Error: " << res << endl; return false; } parsers.append(parser); } // Generate the code for each object and write it to the destination directory QList objIDList; QString objInc; QString flightObjInit; QString gcsObjInit; bool res; for (int parseridx = 0; parseridx < parsers.length(); ++ parseridx) { UAVObjectParser* parser = parsers[parseridx]; for (int objidx = 0; objidx < parser->getNumObjects(); ++objidx) { QString name = parser->getObjectName(objidx); QString namelc = name.toLower(); sout << "Generating code for object: " << name << endl; // Check for object ID conflicts quint32 id = parser->getObjectID(objidx); if ( objIDList.contains(id) ) { sout << "Error: Object ID collision found in object " << name << ", modify object name" << endl; return false; } else { objIDList.append(id); } // Generate the flight code QString flightCode; QString flightInclude; res = parser->generateFlightObject(objidx, flightIncludeTemplate, flightCodeTemplate, flightInclude, flightCode); if (!res) { sout << "Error: Improperly formatted flight object template file" << endl; return false; } // Generate the GCS code QString gcsCode; QString gcsInclude; res = parser->generateGCSObject(objidx, gcsIncludeTemplate, gcsCodeTemplate, gcsInclude, gcsCode); if (!res) { sout << "Error: Improperly formatted GCS object template file" << endl; return false; } // Write the flight code // TODO: Only write file if modified res = writeFile( flightCodePath.absolutePath() + "/" + namelc + ".c", flightCode ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } res = writeFile( flightCodePath.absolutePath() + "/inc/" + namelc + ".h", flightInclude ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } // Write the GCS code // TODO: Only write file if modified res = writeFile( gcsCodePath.absolutePath() + "/" + namelc + ".cpp", gcsCode ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } res = writeFile( gcsCodePath.absolutePath() + "/" + namelc + ".h", gcsInclude ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } // Update strings for the object initialization objInc.append("#include \"" + namelc + ".h\"\n"); flightObjInit.append(" " + name + "Initialize();\n"); gcsObjInit.append(" objMngr->registerObject( new " + name + "() );\n"); } } // Write the flight object inialization files sout << "Updating object initialization files" << endl; flightInitTemplate.replace( QString("$(OBJINC)"), objInc); flightInitTemplate.replace( QString("$(OBJINIT)"), flightObjInit); res = writeFile( flightCodePath.absolutePath() + "/" + objectsInitFilename + ".c", flightInitTemplate ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } // Write the gcs object inialization files gcsInitTemplate.replace( QString("$(OBJINC)"), objInc); gcsInitTemplate.replace( QString("$(OBJINIT)"), gcsObjInit); res = writeFile( gcsCodePath.absolutePath() + "/" + objectsInitFilename + ".cpp", gcsInitTemplate ); if (!res) { sout << "Error: Could not write output files" << endl; return false; } // Done sout << "Done: processed " << xmlList.length() << " XML files and generated " << objIDList.length() << " objects with no ID collisions." << endl; return true; } /** * Read a file and return its contents as a string */ QString UAVObjectGenerator::readFile(QString name) { QFile file(name); if (!file.open(QFile::ReadOnly)) return QString(); QTextStream fileStr(&file); QString str = fileStr.readAll(); file.close(); return str; } /** * Write contents of string to file */ bool UAVObjectGenerator::writeFile(QString name, QString& str) { QFile file(name); if (!file.open(QFile::WriteOnly)) return false; QTextStream fileStr(&file); fileStr << str; file.close(); return true; }