main.cc 7.43 KB
Newer Older
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
pixhawk's avatar
pixhawk committed
9 10 11 12 13 14 15 16 17


/**
 * @file
 *   @brief Main executable
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

18
#include <QtGlobal>
19
#include <QApplication>
Don Gagne's avatar
Don Gagne committed
20
#include <QSslSocket>
21
#include <QProcessEnvironment>
22 23
#include <QHostAddress>
#include <QUdpSocket>
Don Gagne's avatar
Don Gagne committed
24
#include <QtPlugin>
25
#include <QStringListModel>
Don Gagne's avatar
Don Gagne committed
26
#include "QGCApplication.h"
27
#include "AppMessages.h"
28

29 30
#define  SINGLE_INSTANCE_PORT   14499

31 32 33 34
#ifndef __mobile__
    #include "QGCSerialPortInfo.h"
#endif

35
#ifdef QT_DEBUG
36 37 38 39 40 41 42
    #ifndef __mobile__
        #include "UnitTest.h"
    #endif
    #include "CmdLineOptParser.h"
    #ifdef Q_OS_WIN
        #include <crtdbg.h>
    #endif
43
#endif
44

dogmaphobic's avatar
dogmaphobic committed
45
#ifdef QGC_ENABLE_BLUETOOTH
dogmaphobic's avatar
dogmaphobic committed
46 47 48
#include <QtBluetooth/QBluetoothSocket>
#endif

Don Gagne's avatar
Don Gagne committed
49
#include <iostream>
dogmaphobic's avatar
dogmaphobic committed
50
#include "QGCMapEngine.h"
unknown's avatar
unknown committed
51

52
/* SDL does ugly things to main() */
53
#ifdef main
54
#undef main
55
#endif
56

57
#ifndef __mobile__
58
    Q_DECLARE_METATYPE(QGCSerialPortInfo)
59
#endif
60 61

#ifdef Q_OS_WIN
62 63 64 65 66
/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
{
    Q_UNUSED(reportType);
67

68 69 70 71 72
    std::cerr << message << std::endl;  // Output message to stderr
    *returnValue = 0;                   // Don't break into debugger
    return true;                        // We handled this fully ourselves
}

73 74
#endif

Don Gagne's avatar
Don Gagne committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
#ifdef __android__
#include <jni.h>
#include "qserialport.h"

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    Q_UNUSED(reserved);

    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    QSerialPort::setNativeMethods();

    return JNI_VERSION_1_6;
}
#endif

pixhawk's avatar
pixhawk committed
94 95 96 97 98 99 100
/**
 * @brief Starts the application
 *
 * @param argc Number of commandline arguments
 * @param argv Commandline arguments
 * @return exit code, 0 for normal exit and !=0 for error cases
 */
101

pixhawk's avatar
pixhawk committed
102 103
int main(int argc, char *argv[])
{
104
#ifdef Q_OS_UNIX
Daniel Agar's avatar
Daniel Agar committed
105
    //Force writing to the console on UNIX/BSD devices
106 107 108 109
    if (!qEnvironmentVariableIsSet("QT_LOGGING_TO_CONSOLE"))
        qputenv("QT_LOGGING_TO_CONSOLE", "1");
#endif

110
    // install the message handler
111
    AppMessages::installHandler();
112

113
#ifndef __mobile__
114 115 116 117 118 119 120 121 122
    //-- Test for another instance already running. If that's the case, we simply exit.
    QHostAddress host("127.0.0.1");
    QUdpSocket socket;
    if(!socket.bind(host, SINGLE_INSTANCE_PORT, QAbstractSocket::DontShareAddress)) {
        qWarning() << "Another instance already running. Exiting.";
        exit(-1);
    }
#endif

Lorenz Meier's avatar
Lorenz Meier committed
123
#ifdef Q_OS_MAC
124
#ifndef __ios__
125 126 127
    // Prevent Apple's app nap from screwing us over
    // tip: the domain can be cross-checked on the command line with <defaults domains>
    QProcess::execute("defaults write org.qgroundcontrol.qgroundcontrol NSAppSleepDisabled -bool YES");
128
#endif
Lorenz Meier's avatar
Lorenz Meier committed
129
#endif
130

131
#ifdef Q_OS_WIN
132 133
    // Set our own OpenGL buglist
    qputenv("QT_OPENGL_BUGLIST", ":/opengl/resources/opengl/buglist.json");
134 135 136 137 138 139 140 141 142 143 144

    // Allow for command line override of renderer
    for (int i = 0; i < argc; i++) {
        const QString arg(argv[i]);
        if (arg == QStringLiteral("-angle")) {
            QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
            break;
        } else if (arg == QStringLiteral("-swrast")) {
            QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
            break;
        }
145
    }
146
#endif
147 148 149 150 151

    // The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
dogmaphobic's avatar
dogmaphobic committed
152
#ifndef __ios__
153
    qRegisterMetaType<QSerialPort::SerialPortError>();
dogmaphobic's avatar
dogmaphobic committed
154
#endif
dogmaphobic's avatar
dogmaphobic committed
155
#ifdef QGC_ENABLE_BLUETOOTH
dogmaphobic's avatar
dogmaphobic committed
156 157
    qRegisterMetaType<QBluetoothSocket::SocketError>();
    qRegisterMetaType<QBluetoothServiceInfo>();
dogmaphobic's avatar
dogmaphobic committed
158
#endif
159
    qRegisterMetaType<QAbstractSocket::SocketError>();
160
#ifndef __mobile__
161
    qRegisterMetaType<QGCSerialPortInfo>();
162
#endif
dogmaphobic's avatar
dogmaphobic committed
163 164

    // We statically link our own QtLocation plugin
165 166 167 168 169 170

#ifdef Q_OS_WIN
    // In Windows, the compiler doesn't see the use of the class created by Q_IMPORT_PLUGIN
#pragma warning( disable : 4930 4101 )
#endif

171
    Q_IMPORT_PLUGIN(QGeoServiceProviderFactoryQGC)
172

Don Gagne's avatar
Don Gagne committed
173
    bool runUnitTests = false;          // Run unit tests
174

175
#ifdef QT_DEBUG
176
    // We parse a small set of command line options here prior to QGCApplication in order to handle the ones
177
    // which need to be handled before a QApplication object is started.
178

Don Gagne's avatar
Don Gagne committed
179
    bool stressUnitTests = false;       // Stress test unit tests
180
    bool quietWindowsAsserts = false;   // Don't let asserts pop dialog boxes
181

182
    QString unitTestOptions;
183
    CmdLineOpt_t rgCmdLineOptions[] = {
184
        { "--unittest",             &runUnitTests,          &unitTestOptions },
185
        { "--unittest-stress",      &stressUnitTests,       &unitTestOptions },
186
        { "--no-windows-assert-ui", &quietWindowsAsserts,   NULL },
187 188
        // Add additional command line option flags here
    };
189

190
    ParseCmdLineOptions(argc, argv, rgCmdLineOptions, sizeof(rgCmdLineOptions)/sizeof(rgCmdLineOptions[0]), false);
191 192 193
    if (stressUnitTests) {
        runUnitTests = true;
    }
194

195 196 197 198 199
    if (quietWindowsAsserts) {
#ifdef Q_OS_WIN
        _CrtSetReportHook(WindowsCrtReportHook);
#endif
    }
200 201 202 203 204 205 206 207

#ifdef Q_OS_WIN
    if (runUnitTests) {
        // Don't pop up Windows Error Reporting dialog when app crashes. This prevents TeamCity from
        // hanging.
        DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
        SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX);
    }
208
#endif
209
#endif // QT_DEBUG
210

Don Gagne's avatar
Don Gagne committed
211
    QGCApplication* app = new QGCApplication(argc, argv, runUnitTests);
212
    Q_CHECK_PTR(app);
213

214 215 216 217 218 219
    // There appears to be a threading issue in qRegisterMetaType which can cause it to throw a qWarning
    // about duplicate type converters. This is caused by a race condition in the Qt code. Still working
    // with them on tracking down the bug. For now we register the type which is giving us problems here
    // while we only have the main thread. That should prevent it from hitting the race condition later
    // on in the code.
    qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
220

221
    app->_initCommon();
dogmaphobic's avatar
dogmaphobic committed
222 223
    //-- Initialize Cache System
    getQGCMapEngine()->init();
224

225
    int exitCode = 0;
226

dogmaphobic's avatar
dogmaphobic committed
227
#ifndef __mobile__
228
#ifdef QT_DEBUG
229
    if (runUnitTests) {
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
        for (int i=0; i < (stressUnitTests ? 20 : 1); i++) {
            if (!app->_initForUnitTests()) {
                return -1;
            }

            // Run the test
            int failures = UnitTest::run(unitTestOptions);
            if (failures == 0) {
                qDebug() << "ALL TESTS PASSED";
                exitCode = 0;
            } else {
                qDebug() << failures << " TESTS FAILED!";
                exitCode = -failures;
                break;
            }
245
        }
246
    } else
dogmaphobic's avatar
dogmaphobic committed
247
#endif
248
#endif
249 250 251 252
    {
        if (!app->_initForNormalAppBoot()) {
            return -1;
        }
Don Gagne's avatar
Don Gagne committed
253
        exitCode = app->exec();
254
    }
255

Don Gagne's avatar
Don Gagne committed
256
    delete app;
dogmaphobic's avatar
dogmaphobic committed
257 258
    //-- Shutdown Cache System
    destroyMapEngine();
259

Don Gagne's avatar
Don Gagne committed
260
    qDebug() << "After app delete";
261

Don Gagne's avatar
Don Gagne committed
262
    return exitCode;
pixhawk's avatar
pixhawk committed
263
}