Commit dc3c636b authored by lm's avatar lm

Merge branch 'master' of git@github.com:pixhawk/qgroundcontrol

parents 17bd4fa3 cd785b3d
......@@ -73,7 +73,8 @@ FORMS += src/ui/MainWindow.ui \
src/ui/watchdog/WatchdogProcessView.ui \
src/ui/watchdog/WatchdogView.ui \
src/ui/QGCFirmwareUpdate.ui \
src/ui/QGCPxImuFirmwareUpdate.ui
src/ui/QGCPxImuFirmwareUpdate.ui \
src/ui/QGCDataPlot2D.ui
INCLUDEPATH += src \
src/ui \
src/ui/linechart \
......@@ -149,7 +150,10 @@ HEADERS += src/MG.h \
src/ui/HSIDisplay.h \
src/QGC.h \
src/ui/QGCFirmwareUpdate.h \
src/ui/QGCPxImuFirmwareUpdate.h
src/ui/QGCPxImuFirmwareUpdate.h \
src/comm/MAVLinkLightProtocol.h \
src/ui/QGCDataPlot2D.h \
src/ui/linechart/IncrementalPlot.h
SOURCES += src/main.cc \
src/Core.cc \
src/uas/UASManager.cc \
......@@ -207,5 +211,8 @@ SOURCES += src/main.cc \
src/ui/HSIDisplay.cc \
src/QGC.cc \
src/ui/QGCFirmwareUpdate.cc \
src/ui/QGCPxImuFirmwareUpdate.cc
src/ui/QGCPxImuFirmwareUpdate.cc \
src/comm/MAVLinkLightProtocol.cc \
src/ui/QGCDataPlot2D.cc \
src/ui/linechart/IncrementalPlot.cc
RESOURCES = mavground.qrc
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QFileInfo>
#include "LogCompressor.h"
#include <QDebug>
LogCompressor::LogCompressor(QString logFileName, int uasid) :
LogCompressor::LogCompressor(QString logFileName, QString outFileName, int uasid) :
logFileName(logFileName),
outFileName(outFileName),
running(true),
currentDataLine(0),
dataLines(1),
uasid(uasid)
{
start();
......@@ -17,13 +22,23 @@ void LogCompressor::run()
QString separator = "\t";
QString fileName = logFileName;
QFile file(fileName);
QFile outfile(outFileName);
QStringList* keys = new QStringList();
QStringList* times = new QStringList();
if (!file.exists()) return;
if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
if (outFileName != "")
{
// Check if file is writeable
if (!QFileInfo(outfile).isWritable())
{
return;
}
}
// Find all keys
QTextStream in(&file);
while (!in.atEnd()) {
......@@ -43,9 +58,9 @@ void LogCompressor::run()
spacer += " " + separator;
}
qDebug() << header;
//qDebug() << header;
qDebug() << "NOW READING TIMES";
//qDebug() << "NOW READING TIMES";
// Find all times
//in.reset();
......@@ -62,6 +77,9 @@ void LogCompressor::run()
times->append(time);
}
}
dataLines = times->length();
times->sort();
// Create lines
......@@ -74,7 +92,10 @@ void LogCompressor::run()
// Fill in the values for all keys
file.reset();
QTextStream data(&file);
int linecounter = 0;
while (!data.atEnd()) {
linecounter++;
currentDataLine = linecounter;
QString line = data.readLine();
QStringList parts = line.split(separator);
// Get time
......@@ -100,20 +121,43 @@ void LogCompressor::run()
// Add header, write out file
file.close();
QFile::remove(file.fileName());
if (!file.open(QIODevice::ReadWrite | QIODevice::Text))
if (outFileName == "")
{
QFile::remove(file.fileName());
outfile.setFileName(file.fileName());
}
if (!outfile.open(QIODevice::WriteOnly | QIODevice::Text))
return;
file.write(QString(QString("unix_timestamp") + separator + header.replace(" ", "_") + QString("\n")).toLatin1());
outfile.write(QString(QString("unix_timestamp") + separator + header.replace(" ", "_") + QString("\n")).toLatin1());
//QString fileHeader = QString("unix_timestamp") + header.replace(" ", "_") + QString("\n");
// Debug output
// File output
for (int i = 0; i < outLines->length(); i++)
{
//qDebug() << outLines->at(i);
file.write(QString(outLines->at(i) + "\n").toLatin1());
outfile.write(QString(outLines->at(i) + "\n").toLatin1());
}
currentDataLine = 0;
dataLines = 1;
delete keys;
qDebug() << "Done with logfile processing";
running = false;
}
bool LogCompressor::isFinished()
{
return !running;
}
int LogCompressor::getCurrentLine()
{
return currentDataLine;
}
int LogCompressor::getDataLines()
{
return dataLines;
}
......@@ -6,10 +6,17 @@
class LogCompressor : public QThread
{
public:
LogCompressor(QString logFileName, int uasid = 0);
LogCompressor(QString logFileName, QString outFileName="", int uasid = 0);
bool isFinished();
int getDataLines();
int getCurrentLine();
protected:
void run();
QString logFileName;
QString outFileName;
bool running;
int currentDataLine;
int dataLines;
int uasid;
};
......
/*=====================================================================
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 Example implementation of a different protocol than the default MAVLink.
* @author Lorenz Meier <mail@qgroundcontrol.org>
*/
#include "MAVLinkLightProtocol.h"
#include "UASManager.h"
#include "ArduPilotMAV.h"
#include "LinkManager.h"
MAVLinkLightProtocol::MAVLinkLightProtocol() :
MAVLinkProtocol()
{
}
/**
* @param message message to send
*/
void MAVLinkLightProtocol::sendMessage(mavlink_light_message_t message)
{
// Get all links connected to this unit
QList<LinkInterface*> links = LinkManager::instance()->getLinksForProtocol(this);
// Emit message on all links that are currently connected
QList<LinkInterface*>::iterator i;
for (i = links.begin(); i != links.end(); ++i)
{
sendMessage(*i, message);
}
}
/**
* @param link the link to send the message over
* @param message message to send
*/
void MAVLinkLightProtocol::sendMessage(LinkInterface* link, mavlink_light_message_t message)
{
// Create buffer
uint8_t buffer[100]; // MAXIMUM PACKET LENGTH, INCLUDING STX BYTES
// Write message into buffer, prepending start sign
//int len = mavlink_msg_to_send_buffer(buffer, &message);
// FIXME TO SEND BUFFER FUNCTION MISSING
Q_UNUSED(message);
int len = 0;
// If link is connected
if (link->isConnected())
{
// Send the portion of the buffer now occupied by the message
link->writeBytes((const char*)buffer, len);
}
}
/**
* The bytes are copied by calling the LinkInterface::readBytes() method.
* This method parses all incoming bytes and constructs a MAVLink packet.
* It can handle multiple links in parallel, as each link has it's own buffer/
* parsing state machine.
* @param link The interface to read from
* @see LinkInterface
**/
void MAVLinkLightProtocol::receiveBytes(LinkInterface* link)
{
receiveMutex.lock();
// Prepare buffer
static const int maxlen = 4096 * 100;
static char buffer[maxlen];
qint64 bytesToRead = link->bytesAvailable();
// Get all data at once, let link read the bytes in the buffer array
link->readBytes(buffer, maxlen);
// Run through all bytes
for (int position = 0; position < bytesToRead; position++)
{
mavlink_light_message_t msg;
// FIXME PARSE
if (1 == 0/* parsing returned a message */)
{
int sysid = 0; // system id from message, or always null if only one MAV is supported
UASInterface* uas = UASManager::instance()->getUASForId(sysid);
// Check and (if necessary) create UAS object
if (uas == NULL)
{
ArduPilotMAV* mav = new ArduPilotMAV(this, sysid); // FIXME change to msg.sysid if this field exists
// Connect this robot to the UAS object
// it is IMPORTANT here to use the right object type,
// else the slot of the parent object is called (and thus the special
// packets never reach their goal)
connect(this, SIGNAL(messageReceived(LinkInterface*, mavlink_message_t)), mav, SLOT(receiveMessage(LinkInterface*, mavlink_message_t)));
uas = mav;
// Make UAS aware that this link can be used to communicate with the actual robot
uas->addLink(link);
// Now add UAS to "official" list, which makes the whole application aware of it
UASManager::instance()->addUAS(uas);
}
// The packet is emitted as a whole, as it is only 255 - 261 bytes short
// kind of inefficient, but no issue for a groundstation pc.
// It buys as reentrancy for the whole code over all threads
emit messageReceived(link, msg);
}
}
receiveMutex.unlock();
}
/**
* @return The name of this protocol
**/
QString MAVLinkLightProtocol::getName()
{
return QString(tr("MAVLinkLight protocol"));
}
/*=====================================================================
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 Example implementation of a different protocol than the default MAVLink.
* @author Lorenz Meier <mail@qgroundcontrol.org>
*/
#ifndef MAVLINKLIGHTPROTOCOL_H
#define MAVLINKLIGHTPROTOCOL_H
#include <inttypes.h>
#include <MAVLinkProtocol.h>
#define MAVLINK_LIGHT_MAX_PAYLOAD_LEN 50
// Not part of message struct, but sent on link
// uint8_t stx1;
// uint8_t stx2;
typedef struct {
uint8_t msgid; ///< ID of message in payload
uint8_t payload[MAVLINK_LIGHT_MAX_PAYLOAD_LEN]; ///< Payload data, ALIGNMENT IMPORTANT ON MCU
uint8_t ck_a; ///< Checksum high byte
uint8_t ck_b; ///< Checksum low byte
} mavlink_light_message_t;
class MAVLinkLightProtocol : public MAVLinkProtocol
{
Q_OBJECT
public:
explicit MAVLinkLightProtocol();
QString getName();
signals:
/** @brief Message received and directly copied via signal */
void messageReceived(LinkInterface* link, mavlink_light_message_t message);
public slots:
void sendMessage(mavlink_light_message_t message);
void sendMessage(LinkInterface* link, mavlink_light_message_t message);
void receiveBytes(LinkInterface* link);
};
#endif // MAVLINKLIGHTPROTOCOL_H
......@@ -323,7 +323,7 @@ void MAVLinkProtocol::sendMessage(mavlink_message_t message)
for (i = links.begin(); i != links.end(); ++i)
{
sendMessage(*i, message);
qDebug() << __FILE__ << __LINE__ << "SENT HEARTBEAT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size();
//qDebug() << __FILE__ << __LINE__ << "SENT MESSAGE OVER" << ((LinkInterface*)*i)->getName() << "LIST SIZE:" << links.size();
}
}
......
......@@ -186,10 +186,13 @@ void MAVLinkSimulationLink::mainloop()
static float drainRate = 0.025; // x.xx% of the capacity is linearly drained per second
mavlink_attitude_t attitude;
memset(&attitude, 0, sizeof(mavlink_attitude_t));
#ifdef MAVLINK_ENABLED_PIXHAWK_MESSAGES
mavlink_raw_aux_t rawAuxValues;
memset(&rawAuxValues, 0, sizeof(mavlink_raw_aux_t));
#endif
mavlink_raw_imu_t rawImuValues;
memset(&rawImuValues, 0, sizeof(mavlink_raw_imu_t));
uint8_t buffer[MAVLINK_MAX_PACKET_LEN];
int bufferlength;
......
/*=====================================================================
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 MainWindow
* @author Your Name here
*/
#include "ArduPilotMAV.h"
ArduPilotMAV::ArduPilotMAV(MAVLinkProtocol* mavlink, int id) :
......
......@@ -99,7 +99,7 @@ CommConfigurationWindow::CommConfigurationWindow(LinkInterface* link, ProtocolIn
}
else if (dynamic_cast<UDPLink*>(link) != 0)
{
ui.linkGroupBox->setTitle(tr("udp link"));
ui.linkGroupBox->setTitle(tr("UDP Link"));
}
else
{
......
......@@ -2,9 +2,7 @@
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL/PIXHAWK PROJECT
<http://www.qgroundcontrol.org>
<http://pixhawk.ethz.ch>
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
......@@ -140,15 +138,18 @@ void MainWindow::buildWidgets()
headDown1 = new HDDisplay(acceptList, this);
headDown2 = new HDDisplay(acceptList2, this);
joystick = new JoystickInput();
dataplot = new QGCDataPlot2D();
}
void MainWindow::connectWidgets(){
void MainWindow::connectWidgets()
{
connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), linechart, SLOT(addSystem(UASInterface*)));
connect(UASManager::instance(), SIGNAL(activeUASSet(int)), linechart, SLOT(selectSystem(int)));
connect(mavlink, SIGNAL(receiveLossChanged(int, float)), info, SLOT(updateSendLoss(int, float)));
}
void MainWindow::arrangeCenterStack(){
void MainWindow::arrangeCenterStack()
{
centerStack = new QStackedWidget(this);
......@@ -156,11 +157,13 @@ void MainWindow::arrangeCenterStack(){
centerStack->addWidget(protocol);
centerStack->addWidget(map);
centerStack->addWidget(hud);
centerStack->addWidget(dataplot);
setCentralWidget(centerStack);
}
void MainWindow::configureWindowName(){
void MainWindow::configureWindowName()
{
QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
bool prevAddr = false;
......@@ -245,11 +248,14 @@ void MainWindow::reloadStylesheet()
{
styleSheet = new QFile(":/images/style-mission.css");
}
if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text)) {
if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
{
QString style = QString(styleSheet->readAll());
style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
qApp->setStyleSheet(style);
} else {
}
else
{
qDebug() << "Style not set:" << styleSheet->fileName() << "opened: " << styleSheet->isOpen();
}
delete styleSheet;
......@@ -292,12 +298,59 @@ void MainWindow::connectActions()
connect(ui.actionSettingsView, SIGNAL(triggered()), this, SLOT(loadSettingsView()));
connect(ui.actionShow_full_view, SIGNAL(triggered()), this, SLOT(loadAllView()));
connect(ui.actionShow_MAVLink_view, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
connect(ui.actionShow_data_analysis_view, SIGNAL(triggered()), this, SLOT(loadDataView()));
connect(ui.actionStyleConfig, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
connect(ui.actionOnline_documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
connect(ui.actionCredits_Developers, SIGNAL(triggered()), this, SLOT(showCredits()));
connect(ui.actionProject_Roadmap, SIGNAL(triggered()), this, SLOT(showRoadMap()));
// Joystick configuration
connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
}
void MainWindow::showHelp()
{
if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/user_guide")))
{
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText("Could not open help in browser");
msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/user_guide in a browser.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
}
void MainWindow::showCredits()
{
if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits")))
{
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText("Could not open credits in browser");
msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/credits in a browser.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
}
void MainWindow::showRoadMap()
{
if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap")))
{
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText("Could not open roadmap in browser");
msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/roadmap in a browser.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
}
void MainWindow::configure()
{
joystickWidget = new JoystickWidget(joystick, this);
......@@ -485,6 +538,12 @@ void MainWindow::loadPixhawkView()
this->show();
}
void MainWindow::loadDataView()
{
clearView();
centerStack->setCurrentWidget(dataplot);
}
void MainWindow::loadPilotView()
{
clearView();
......
......@@ -62,6 +62,7 @@ This file is part of the PIXHAWK project
#include "HDDisplay.h"
#include "WatchdogControl.h"
#include "HSIDisplay.h"
#include "QGCDataPlot2D.h"
#include "LogCompressor.h"
......@@ -116,6 +117,15 @@ public slots:
void loadAllView();
/** @brief Load MAVLink XML generator view */
void loadMAVLinkView();
/** @brief Load data view, allowing to plot flight data */
void loadDataView();
/** @brief Show the online help for users */
void showHelp();
/** @brief Show the authors / credits */
void showCredits();
/** @brief Show the project roadmap */
void showRoadMap();
// Fixme find a nicer solution that scales to more AP types
void loadSlugsView();
......@@ -158,6 +168,7 @@ protected:
HDDisplay* headDown2;
WatchdogControl* watchdogControl;
HSIDisplay* hsi;
QGCDataPlot2D* dataplot;
// Popup widgets
JoystickWidget* joystickWidget;
......
......@@ -35,7 +35,7 @@
<x>0</x>
<y>0</y>
<width>1000</width>
<height>25</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuMGround">
......@@ -75,13 +75,23 @@
<addaction name="actionSettingsView"/>
<addaction name="separator"/>
<addaction name="actionShow_MAVLink_view"/>
<addaction name="actionShow_data_analysis_view"/>
<addaction name="actionShow_full_view"/>
<addaction name="actionStyleConfig"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionOnline_documentation"/>
<addaction name="actionProject_Roadmap"/>
<addaction name="actionCredits_Developers"/>
</widget>
<addaction name="menuMGround"/>
<addaction name="menuNetwork"/>
<addaction name="menuUnmanned_System"/>
<addaction name="menuWindow"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
......@@ -263,6 +273,42 @@
<string>Show MAVLink view</string>
</property>
</action>
<action name="actionOnline_documentation">
<property name="icon">
<iconset resource="../../mavground.qrc">
<normaloff>:/images/categories/applications-internet.svg</normaloff>:/images/categories/applications-internet.svg</iconset>
</property>
<property name="text">
<string>Online documentation</string>
</property>
</action>
<action name="actionShow_data_analysis_view">
<property name="icon">
<iconset resource="../../mavground.qrc">
<normaloff>:/images/apps/utilities-system-monitor.svg</normaloff>:/images/apps/utilities-system-monitor.svg</iconset>
</property>
<property name="text">
<string>Show data analysis view</string>
</property>
</action>
<action name="actionProject_Roadmap">
<property name="icon">
<iconset resource="../../mavground.qrc">
<normaloff>:/images/status/software-update-available.svg</normaloff>:/images/status/software-update-available.svg</iconset>
</property>
<property name="text">
<string>Project Roadmap</string>
</property>
</action>
<action name="actionCredits_Developers">
<property name="icon">
<iconset resource="../../mavground.qrc">
<normaloff>:/images/categories/preferences-system.svg</normaloff>:/images/categories/preferences-system.svg</iconset>
</property>
<property name="text">
<string>Credits / Developers</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
......
This diff is collapsed.
#ifndef QGCDATAPLOT2D_H
#define QGCDATAPLOT2D_H
#include <QWidget>
#include <QFile>
#include "IncrementalPlot.h"
#include "LogCompressor.h"
namespace Ui {
class QGCDataPlot2D;
}
class QGCDataPlot2D : public QWidget {
Q_OBJECT
public:
QGCDataPlot2D(QWidget *parent = 0);
~QGCDataPlot2D();
/** @brief Linear regression over data points */
int linearRegression(double *x,double *y,int n,double *a,double *b,double *r);
public slots:
void loadFile();
/** @brief Reload a file, with filtering enabled */
void reloadFile();
void selectFile();
void loadCsvLog(QString file, QString xAxisName="", QString yAxisFilter="");
void loadRawLog(QString file, QString xAxisName="", QString yAxisFilter="");
void saveCsvLog();
/** @brief Save plot to PDF or SVG */
void savePlot();
/** @brief Export SVG file */
void exportSVG(QString file);
/** @brief Print or save PDF file (MacOS/Linux) */
void print();
protected:
void changeEvent(QEvent *e);
IncrementalPlot* plot;
LogCompressor* compressor;
QFile* logFile;