MAVLinkXMLParser.cc 31.5 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

    QGROUNDCONTROL 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.

    QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of class MAVLinkXMLParser
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
 */

pixhawk's avatar
pixhawk committed
30 31 32 33
#include <QFile>
#include <QDir>
#include <QPair>
#include <QList>
34
#include <QMap>
pixhawk's avatar
pixhawk committed
35
#include <QDateTime>
36
#include <QLocale>
pixhawk's avatar
pixhawk committed
37 38 39 40 41 42
#include "MAVLinkXMLParser.h"

#include <QDebug>

MAVLinkXMLParser::MAVLinkXMLParser(QDomDocument* document, QString outputDirectory, QObject* parent) : QObject(parent),
doc(document),
43 44
outputDirName(outputDirectory),
fileName("")
pixhawk's avatar
pixhawk committed
45 46 47 48 49 50 51 52 53 54 55 56
{
}

MAVLinkXMLParser::MAVLinkXMLParser(QString document, QString outputDirectory, QObject* parent) : QObject(parent)
{
    doc = new QDomDocument();
    QFile file(document);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        const QString instanceText(QString::fromUtf8(file.readAll()));
        doc->setContent(instanceText);
    }
57
    fileName = document;
pixhawk's avatar
pixhawk committed
58 59 60 61 62 63 64
    outputDirName = outputDirectory;
}

MAVLinkXMLParser::~MAVLinkXMLParser()
{
}

pixhawk's avatar
pixhawk committed
65 66 67
/**
 * Generate C-code (C-89 compliant) out of the XML protocol specs.
 */
pixhawk's avatar
pixhawk committed
68 69 70 71 72 73
bool MAVLinkXMLParser::generate()
{
    // Process result
    bool success = true;

    // Only generate if output dir is correctly set
74 75 76 77 78 79 80
    if (outputDirName == "")
    {
        emit parseState(tr("<font color=\"red\">ERROR: No output directory given.\nAbort.</font>"));
        return false;
    }

    QString topLevelOutputDirName = outputDirName;
pixhawk's avatar
pixhawk committed
81 82 83 84

    // print out the element names of all elements that are direct children
    // of the outermost element.
    QDomElement docElem = doc->documentElement();
85 86 87 88 89 90
    QDomNode n = docElem;//.firstChild();
    QDomNode p = docElem;

    // Sanity check variables
    QList<int>* usedMessageIDs = new QList<int>();
    QMap<QString, QString>* usedMessageNames = new QMap<QString, QString>();
pixhawk's avatar
pixhawk committed
91 92 93 94

    QList< QPair<QString, QString> > cFiles;
    QString lcmStructDefs = "";

lm's avatar
lm committed
95
    QString pureFileName;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    QString pureIncludeFileName;

    QFileInfo fInfo(this->fileName);
    pureFileName = fInfo.baseName().split(".", QString::SkipEmptyParts).first();

    // XML parsed and converted to C code. Now generating the files
    outputDirName += QDir::separator() + pureFileName;
    QDateTime now = QDateTime::currentDateTime().toUTC();
    QLocale loc(QLocale::English);
    QString dateFormat = "dddd, MMMM d yyyy, hh:mm UTC";
    QString date = loc.toString(now, dateFormat);
    QString includeLine = "#include \"%1\"\n";
    QString mainHeaderName = pureFileName + ".h";
    QString messagesDirName = ".";//"generated";
    QDir dir(outputDirName + "/" + messagesDirName);



    // Start main header
    QString mainHeader = QString("/** @file\n *\t@brief MAVLink comm protocol.\n *\t@see http://pixhawk.ethz.ch/software/mavlink\n *\t Generated on %1\n */\n#ifndef " + pureFileName.toUpper() + "_H\n#define " + pureFileName.toUpper() + "_H\n\n").arg(date); // The main header includes all messages
    // Mark all code as C code
    mainHeader += "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
    mainHeader += "\n#include \"../protocol.h\"\n";
    mainHeader += "\n#define MAVLINK_ENABLED_" + pureFileName.toUpper() + "\n\n";

lm's avatar
lm committed
121

122 123 124
    // Run through root children
    while(!n.isNull())
    {
pixhawk's avatar
pixhawk committed
125 126
        // Each child is a message
        QDomElement e = n.toElement(); // try to convert the node to an element.
127 128 129
        if(!e.isNull())
        {
            if (e.tagName() == "mavlink")
pixhawk's avatar
pixhawk committed
130
            {
131 132 133
                p = n;
                n = n.firstChild();
                while (!n.isNull())
pixhawk's avatar
pixhawk committed
134
                {
135 136
                    e = n.toElement();
                    if (!e.isNull())
pixhawk's avatar
pixhawk committed
137
                    {
138 139
                        // Handle all include tags
                        if (e.tagName() == "include")
pixhawk's avatar
pixhawk committed
140
                        {
141
                            QString incFileName = e.text();
142
                            // Load file
143
                            //QDomDocument includeDoc = QDomDocument();
pixhawk's avatar
pixhawk committed
144

145 146
                            // Prepend file path if it is a relative path and
                            // make it relative to opened file
147 148 149
                            QFileInfo fInfo(incFileName);

                            QString incFilePath;
150
                            if (fInfo.isRelative())
151
                            {
152
                                QFileInfo rInfo(this->fileName);
153 154
                                incFilePath = rInfo.absoluteDir().canonicalPath() + "/" + incFileName;
                                pureIncludeFileName = fInfo.baseName().split(".", QString::SkipEmptyParts).first();
155
                            }
pixhawk's avatar
pixhawk committed
156

157
                            QFile file(incFilePath);
158
                            if (file.open(QIODevice::ReadOnly | QIODevice::Text))
pixhawk's avatar
pixhawk committed
159
                            {
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
                                emit parseState(QString("<font color=\"green\">Included messages from file: %1</font>").arg(incFileName));
                                // NEW MODE: CREATE INDIVIDUAL FOLDERS
                                // Create new output directory, parse included XML and generate C-code
                                MAVLinkXMLParser includeParser(incFilePath, topLevelOutputDirName, this);
                                connect(&includeParser, SIGNAL(parseState(QString)), this, SIGNAL(parseState(QString)));
                                // Generate and write
                                includeParser.generate();
                                mainHeader += "\n#include \"../" + pureIncludeFileName + "/" + pureIncludeFileName + ".h\"\n";


                                // OLD MODE: MERGE BOTH FILES
//                                        const QString instanceText(QString::fromUtf8(file.readAll()));
//                                        includeDoc.setContent(instanceText);
//                                // Get all messages
//                                QDomNode in = includeDoc.documentElement().firstChild();
//                                QDomElement ie = in.toElement();
//                                if (!ie.isNull())
//                                {
//                                    if (ie.tagName() == "messages" || ie.tagName() == "include")
//                                    {
//                                        QDomNode ref = n.parentNode().insertAfter(in, n);
//                                        if (ref.isNull())
//                                        {
//                                            emit parseState(QString("<font color=\"red\">ERROR: Inclusion failed: XML syntax error in file %1. Wrong/misspelled XML?\nAbort.</font>").arg(fileName));
//                                            return false;
//                                        }
//                                    }
//                                }

                                emit parseState(QString("<font color=\"green\">End of inclusion from file: %1</font>").arg(incFileName));
lm's avatar
lm committed
190
                            }
191 192
                            else
                            {
193 194 195
                                // Include file could not be opened
                                emit parseState(QString("<font color=\"red\">ERROR: Failed including file: %1, file is not readable. Wrong/misspelled filename?\nAbort.</font>").arg(fileName));
                                return false;
196
                            }
197

pixhawk's avatar
pixhawk committed
198
                        }
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
                        // Handle all message tags
                        else if (e.tagName() == "messages")
                        {
                            p = n;
                            n = n.firstChild();
                            while (!n.isNull())
                            {
                                e = n.toElement();
                                if(!e.isNull())
                                {
                                    //if (e.isNull()) continue;
                                    // Get message name
                                    QString messageName = e.attribute("name", "").toLower();
                                    if (messageName.size() == 0)
                                    {
                                        emit parseState(tr("<font color=\"red\">ERROR: Missing required name=\"\" attribute for tag %2 near line %1\nAbort.</font>").arg(QString::number(e.lineNumber()), e.tagName()));
                                        return false;
                                    }
                                    else
                                    {
                                        // Get message id
                                        bool ok;
                                        int messageId = e.attribute("id", "-1").toInt(&ok, 10);
                                        emit parseState(tr("Compiling message <strong>%1 \t(#%3)</strong> \tnear line %2").arg(messageName, QString::number(n.lineNumber()), QString::number(messageId)));

                                        // Sanity check: Accept only message IDs not used previously
                                        if (usedMessageIDs->contains(messageId))
                                        {
                                            emit parseState(tr("<font color=\"red\">ERROR: Message ID %1 used twice, second occurence near line %2 of file %3\nAbort.</font>").arg(QString::number(messageId), QString::number(e.lineNumber()), fileName));
                                            return false;
                                        }
                                        else
                                        {
                                            usedMessageIDs->append(messageId);
                                        }

                                        // Sanity check: Accept only message names not used previously
                                        if (usedMessageNames->contains(messageName))
                                        {
                                            emit parseState(tr("<font color=\"red\">ERROR: Message name %1 used twice, second occurence near line %2 of file %3\nAbort.</font>").arg(messageName, QString::number(e.lineNumber()), fileName));
                                            return false;
                                        }
                                        else
                                        {
                                            usedMessageNames->insert(messageName, QString::number(e.lineNumber()));
                                        }

246 247
                                        QString channelType("mavlink_channel_t");
                                        QString messageType("mavlink_message_t");
248 249

                                        // Build up function call
250 251
                                        QString commentContainer("/**\n * @brief Send a %1 message\n *\n%2 * @return length of the message in bytes (excluding serial stream start sign)\n */\n");
                                        QString commentEntry(" * @param %1 %2\n");
252
                                        QString idDefine = QString("#define MAVLINK_MSG_ID_%1 %2").arg(messageName.toUpper(), QString::number(messageId));
253
                                        QString arrayDefines;
254
                                        QString cStructName = QString("mavlink_%1_t").arg(messageName);
255 256 257
                                        QString cStruct("typedef struct __%1 \n{\n%2\n} %1;");
                                        QString cStructLines;
                                        QString encode("static inline uint16_t mavlink_msg_%1_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg, const %2* %1)\n{\n\treturn mavlink_msg_%1_pack(%3);\n}\n");
258

259 260 261
                                        QString decode("static inline void mavlink_msg_%1_decode(const mavlink_message_t* msg, %2* %1)\n{\n%3}\n");
                                        QString pack("static inline uint16_t mavlink_msg_%1_pack(uint8_t system_id, uint8_t component_id, mavlink_message_t* msg%2)\n{\n\tuint16_t i = 0;\n\tmsg->msgid = MAVLINK_MSG_ID_%3;\n\n%4\n\treturn mavlink_finalize_message(msg, system_id, component_id, i);\n}\n\n");
                                        QString compactSend("#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS\n\nstatic inline void mavlink_msg_%3_send(%1 chan%5)\n{\n\t%2 msg;\n\tmavlink_msg_%3_pack(mavlink_system.sysid, mavlink_system.compid, &msg%4);\n\tmavlink_send_uart(chan, &msg);\n}\n\n#endif");
262
                                        //QString compactStructSend = "#ifdef MAVLINK_USE_CONVENIENCE_FUNCTIONS\n\nstatic inline void mavlink_msg_%3_struct_send(%1 chan%5)\n{\n\t%2 msg;\n\tmavlink_msg_%3_encode(mavlink_system.sysid, mavlink_system.compid, &msg%4);\n\tmavlink_send_uart(chan, &msg);\n}\n\n#endif";
263 264 265 266 267 268 269 270 271 272
                                        QString unpacking;
                                        QString prepends;
                                        QString packParameters;
                                        QString packArguments("system_id, component_id, msg");
                                        QString packLines;
                                        QString decodeLines;
                                        QString sendArguments;
                                        QString commentLines;


273 274 275 276 277 278

                                        // Get the message fields
                                        QDomNode f = e.firstChild();
                                        while (!f.isNull())
                                        {
                                            QDomElement e2 = f.toElement();
279
                                            if (!e2.isNull() && e2.tagName() == "field")
280 281 282 283 284
                                            {
                                                QString fieldType = e2.attribute("type", "");
                                                QString fieldName = e2.attribute("name", "");
                                                QString fieldText = e2.text();

285 286 287
                                                QString unpackingCode;
                                                QString unpackingComment = QString("/**\n * @brief Get field %1 from %2 message\n *\n * @return %3\n */\n").arg(fieldName, messageName, fieldText);

288 289 290 291 292 293 294 295 296 297 298 299 300 301
                                                // Send arguments are the same for integral types and arrays
                                                sendArguments += ", " + fieldName;

                                                // Array handling is different from simple types
                                                if (fieldType.startsWith("array"))
                                                {
                                                    int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt();
                                                    QString arrayType = fieldType.split("[").first();
                                                    packParameters += QString(", const ") + QString("int8_t*") + " " + fieldName;
                                                    packArguments += ", " + messageName + "->" + fieldName;

                                                    // Add field to C structure
                                                    cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg("int8_t", fieldName, QString::number(arrayLength), fieldText);
                                                    // Add pack line to message_xx_pack function
302
                                                    packLines += QString("\ti += put_%1_by_index(%2, %3, i, msg->payload); //%4\n").arg(arrayType, fieldName, QString::number(arrayLength), fieldText);
303 304
                                                    // Add decode function for this type
                                                    decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName);
305
                                                    arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength));
306 307 308 309 310 311 312 313 314 315 316 317 318 319
                                                }
                                                else if (fieldType.startsWith("string"))
                                                {
                                                    int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt();
                                                    QString arrayType = fieldType.split("[").first();
                                                    packParameters += QString(", const ") + QString("char*") + " " + fieldName;
                                                    packArguments += ", " + messageName + "->" + fieldName;

                                                    // Add field to C structure
                                                    cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg("char", fieldName, QString::number(arrayLength), fieldText);
                                                    // Add pack line to message_xx_pack function
                                                    packLines += QString("\ti += put_%1_by_index(%2, %3, i, msg->payload); //%4\n").arg(arrayType, fieldName, QString::number(arrayLength), e2.text());
                                                    // Add decode function for this type
                                                    decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName);
320
                                                    arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength));
321
                                                }
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
                                                // Expand array handling to all valid mavlink data types
                                                else if(fieldType.contains('[') && fieldType.contains(']'))
                                                {
                                                    int arrayLength = QString(fieldType.split("[").at(1).split("]").first()).toInt();
                                                    QString arrayType = fieldType.split("[").first();
                                                    packParameters += QString(", const ") + arrayType + "* " + fieldName;
                                                    packArguments += ", " + messageName + "->" + fieldName;

                                                    // Add field to C structure
                                                    cStructLines += QString("\t%1 %2[%3]; ///< %4\n").arg(arrayType, fieldName, QString::number(arrayLength), fieldText);
                                                    // Add pack line to message_xx_pack function
                                                    packLines += QString("\ti += put_array_by_index((int8_t*)%1, sizeof(%2)*%3, i, msg->payload); //%4\n").arg(fieldName, arrayType, QString::number(arrayLength), fieldText);
                                                    // Add decode function for this type
                                                    decodeLines += QString("\tmavlink_msg_%1_get_%2(msg, %1->%2);\n").arg(messageName, fieldName);
                                                    arrayDefines += QString("#define MAVLINK_MSG_%1_FIELD_%2_LEN %3\n").arg(messageName.toUpper(), fieldName.toUpper(), QString::number(arrayLength));

                                                    unpackingCode = QString("\n\tmemcpy(r_data, msg->payload%1, sizeof(%2)*%3);\n\treturn sizeof(%2)*%3;").arg(prepends, arrayType, QString::number(arrayLength));

                                                    unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, %3* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, arrayType, unpackingCode);
//                                                    decodeLines += "";
                                                    prepends += QString("+sizeof(%1)*%2").arg(arrayType, QString::number(arrayLength));

                                                }
345 346 347 348 349 350 351 352 353 354 355 356 357 358
                                                else
                                                    // Handle simple types like integers and floats
                                                {
                                                    packParameters += ", " + fieldType + " " + fieldName;
                                                    packArguments += ", " + messageName + "->" + fieldName;

                                                    // Add field to C structure
                                                    cStructLines += QString("\t%1 %2; ///< %3\n").arg(fieldType, fieldName, fieldText);
                                                    // Add pack line to message_xx_pack function
                                                    packLines += QString("\ti += put_%1_by_index(%2, i, msg->payload); //%3\n").arg(fieldType, fieldName, e2.text());
                                                    // Add decode function for this type
                                                    decodeLines += QString("\t%1->%2 = mavlink_msg_%1_get_%2(msg);\n").arg(messageName, fieldName);
                                                }
                                                commentLines += commentEntry.arg(fieldName, fieldText);
359

360
                                                //
361
//                                                QString unpackingCode;
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

                                                if (fieldType == "uint8_t" || fieldType == "int8_t")
                                                {
                                                    unpackingCode = QString("\treturn (%1)(msg->payload%2)[0];").arg(fieldType, prepends);
                                                }
                                                else if (fieldType == "uint16_t" || fieldType == "int16_t")
                                                {
                                                    unpackingCode = QString("\tgeneric_16bit r;\n\tr.b[1] = (msg->payload%1)[0];\n\tr.b[0] = (msg->payload%1)[1];\n\treturn (%2)r.s;").arg(prepends).arg(fieldType);
                                                }
                                                else if (fieldType == "uint32_t" || fieldType == "int32_t")
                                                {
                                                    unpackingCode = QString("\tgeneric_32bit r;\n\tr.b[3] = (msg->payload%1)[0];\n\tr.b[2] = (msg->payload%1)[1];\n\tr.b[1] = (msg->payload%1)[2];\n\tr.b[0] = (msg->payload%1)[3];\n\treturn (%2)r.i;").arg(prepends).arg(fieldType);
                                                }
                                                else if (fieldType == "float")
                                                {
                                                    unpackingCode = QString("\tgeneric_32bit r;\n\tr.b[3] = (msg->payload%1)[0];\n\tr.b[2] = (msg->payload%1)[1];\n\tr.b[1] = (msg->payload%1)[2];\n\tr.b[0] = (msg->payload%1)[3];\n\treturn (%2)r.f;").arg(prepends).arg(fieldType);
                                                }
                                                else if (fieldType == "uint64_t" || fieldType == "int64_t")
                                                {
                                                    unpackingCode = QString("\tgeneric_64bit r;\n\tr.b[7] = (msg->payload%1)[0];\n\tr.b[6] = (msg->payload%1)[1];\n\tr.b[5] = (msg->payload%1)[2];\n\tr.b[4] = (msg->payload%1)[3];\n\tr.b[3] = (msg->payload%1)[4];\n\tr.b[2] = (msg->payload%1)[5];\n\tr.b[1] = (msg->payload%1)[6];\n\tr.b[0] = (msg->payload%1)[7];\n\treturn (%2)r.ll;").arg(prepends).arg(fieldType);
                                                }
                                                else if (fieldType.startsWith("array"))
                                                {  // fieldtype formatis string[n] where n is the number of bytes, extract n from field type string
                                                    unpackingCode = QString("\n\tmemcpy(r_data, msg->payload%1, %2);\n\treturn %2;").arg(prepends, fieldType.split("[").at(1).split("]").first());
                                                }
                                                else if (fieldType.startsWith("string"))
                                                {  // fieldtype formatis string[n] where n is the number of bytes, extract n from field type string
                                                    unpackingCode = QString("\n\tstrcpy(r_data, msg->payload%1, %2);\n\treturn %2;").arg(prepends, fieldType.split("[").at(1).split("]").first());
                                                }

392

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
                                                // Generate the message decoding function
                                                // Array handling is different from simple types
                                                if (fieldType.startsWith("array"))
                                                {
                                                    unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, int8_t* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, unpackingCode);
                                                    decodeLines += "";
                                                    QString arrayLength = QString(fieldType.split("[").at(1).split("]").first());
                                                    prepends += "+" + arrayLength;
                                                }
                                                else if (fieldType.startsWith("string"))
                                                {
                                                    unpacking += unpackingComment + QString("static inline uint16_t mavlink_msg_%1_get_%2(const mavlink_message_t* msg, char* r_data)\n{\n%4\n}\n\n").arg(messageName, fieldName, unpackingCode);
                                                    decodeLines += "";
                                                    QString arrayLength = QString(fieldType.split("[").at(1).split("]").first());
                                                    prepends += "+" + arrayLength;
                                                }
409 410 411 412
                                                else if(fieldType.contains('[') && fieldType.contains(']'))
                                                {
                                                    // prevent this case from being caught in the following else
                                                }
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
                                                else
                                                {
                                                    unpacking += unpackingComment + QString("static inline %1 mavlink_msg_%2_get_%3(const mavlink_message_t* msg)\n{\n%4\n}\n\n").arg(fieldType, messageName, fieldName, unpackingCode);
                                                    decodeLines += "";
                                                    prepends += "+sizeof(" + e2.attribute("type", "void") + ")";
                                                }
                                            }
                                            f = f.nextSibling();
                                        }

                                        cStruct = cStruct.arg(cStructName, cStructLines);
                                        lcmStructDefs.append("\n").append(cStruct).append("\n");
                                        pack = pack.arg(messageName, packParameters, messageName.toUpper(), packLines);
                                        encode = encode.arg(messageName).arg(cStructName).arg(packArguments);
                                        decode = decode.arg(messageName).arg(cStructName).arg(decodeLines);
                                        compactSend = compactSend.arg(channelType, messageType, messageName, sendArguments, packParameters);
                                        QString cFile = "// MESSAGE " + messageName.toUpper() + " PACKING\n\n" + idDefine + "\n\n" + cStruct + "\n\n" + arrayDefines + "\n\n" + commentContainer.arg(messageName.toLower(), commentLines) + pack + encode + "\n" + compactSend + "\n" + "// MESSAGE " + messageName.toUpper() + " UNPACKING\n\n" + unpacking + decode;
                                        cFiles.append(qMakePair(QString("mavlink_msg_%1.h").arg(messageName), cFile));
                                    } // Check if tag = message
                                } // Check if e = NULL
                                n = n.nextSibling();
                            } // While through <message>
                            n = p;

                        } // Check if tag = messages
                    } // Check if e = NULL
                    n = n.nextSibling();
                } // While through include and messages
                n = p;

            } // Check if tag = mavlink
        } // Check if e = NULL
pixhawk's avatar
pixhawk committed
445
        n = n.nextSibling();
446
    } // While through root children
pixhawk's avatar
pixhawk committed
447

448

pixhawk's avatar
pixhawk committed
449
    // Create directory if it doesn't exist, report result in success
450
    if (!dir.exists()) success = success && dir.mkpath(outputDirName + "/" + messagesDirName);
pixhawk's avatar
pixhawk committed
451 452 453 454 455 456
    for (int i = 0; i < cFiles.size(); i++)
    {
        QFile rawFile(dir.filePath(cFiles.at(i).first));
        bool ok = rawFile.open(QIODevice::WriteOnly | QIODevice::Text);
        success = success && ok;
        rawFile.write(cFiles.at(i).second.toLatin1());
457
        rawFile.close();
pixhawk's avatar
pixhawk committed
458 459 460 461 462
        mainHeader += includeLine.arg(messagesDirName + "/" + cFiles.at(i).first);
    }

    mainHeader += "#ifdef __cplusplus\n}\n#endif\n";
    mainHeader += "#endif";
lm's avatar
lm committed
463 464
    // Newline to make compiler happy
    mainHeader += "\n";
pixhawk's avatar
pixhawk committed
465 466 467 468 469 470

    // Write main header
    QFile rawHeader(outputDirName + "/" + mainHeaderName);
    bool ok = rawHeader.open(QIODevice::WriteOnly | QIODevice::Text);
    success = success && ok;
    rawHeader.write(mainHeader.toLatin1());
471 472 473 474 475 476 477 478 479 480 481 482
    rawHeader.close();

    // Write alias mavlink header
    QFile mavlinkHeader(outputDirName + "/mavlink.h");
    ok = mavlinkHeader.open(QIODevice::WriteOnly | QIODevice::Text);
    success = success && ok;
    QString mHeader = QString("/** @file\n *\t@brief MAVLink comm protocol.\n *\t@see http://pixhawk.ethz.ch/software/mavlink\n *\t Generated on %1\n */\n#ifndef MAVLINK_H\n#define MAVLINK_H\n\n").arg(date); // The main header includes all messages
    // Mark all code as C code
    mHeader += "#include \"" + mainHeaderName + "\"\n\n";
    mHeader += "#endif\n";
    mavlinkHeader.write(mHeader.toLatin1());
    mavlinkHeader.close();
pixhawk's avatar
pixhawk committed
483 484

    // Write C structs / lcm definitions
pixhawk's avatar
pixhawk committed
485 486 487 488
//    QFile lcmStructs(outputDirName + "/mavlink.lcm");
//    ok = lcmStructs.open(QIODevice::WriteOnly | QIODevice::Text);
//    success = success && ok;
//    lcmStructs.write(lcmStructDefs.toLatin1());
pixhawk's avatar
pixhawk committed
489 490 491

    return success;
}