[Pkg-running-devel] [openambit] 30/131: Added initial support for movescount.com syncronisation.

Christian Perrier bubulle at moszumanska.debian.org
Thu Jul 17 20:19:08 UTC 2014


This is an automated email from the git hooks/post-receive script.

bubulle pushed a commit to branch master
in repository openambit.

commit e23f1f705ed8f8f8accefd366c4c0ac39c1d8203
Author: Emil Ljungdahl <emil at kratern.se>
Date:   Thu Jan 9 23:12:40 2014 +0100

    Added initial support for movescount.com syncronisation.
---
 src/openambit/devicemanager.cpp                    |  77 +-
 src/openambit/devicemanager.h                      |  15 +-
 src/openambit/logentry.cpp                         |  14 +
 src/openambit/logentry.h                           |   1 +
 src/openambit/logstore.cpp                         |  72 +-
 src/openambit/logstore.h                           |   8 +-
 src/openambit/mainwindow.cpp                       | 111 ++-
 src/openambit/mainwindow.h                         |  15 +-
 src/openambit/mainwindow.ui                        |  79 +-
 src/openambit/movescount.cpp                       | 924 +++++----------------
 src/openambit/movescount.h                         |  71 +-
 src/openambit/movescountjson.cpp                   | 502 +++++++++++
 src/openambit/{movescount.h => movescountjson.h}   |  44 +-
 .../{movescount.cpp => movescountxml.cpp}          |  22 +-
 src/openambit/{movescount.h => movescountxml.h}    |  12 +-
 src/openambit/openambit.pro                        |   8 +-
 src/openambit/settingsdialog.cpp                   |   2 +
 src/openambit/settingsdialog.h                     |   3 +
 18 files changed, 1151 insertions(+), 829 deletions(-)

diff --git a/src/openambit/devicemanager.cpp b/src/openambit/devicemanager.cpp
index 60c8e73..a9428a7 100644
--- a/src/openambit/devicemanager.cpp
+++ b/src/openambit/devicemanager.cpp
@@ -24,11 +24,10 @@
 #include <QTimer>
 #include <libambit.h>
 
-void DeviceManager::start()
+DeviceManager::DeviceManager(QObject *parent) :
+    QObject(parent)
 {
-    connect(&chargeTimer, SIGNAL(timeout()), this, SLOT(chargeTimerHit()));
-    chargeTimer.setInterval(10000);
-    chargeTimer.start();
+    movesCount = MovesCount::instance();
 }
 
 DeviceManager::~DeviceManager()
@@ -36,6 +35,13 @@ DeviceManager::~DeviceManager()
     chargeTimer.stop();
 }
 
+void DeviceManager::start()
+{
+    connect(&chargeTimer, SIGNAL(timeout()), this, SLOT(chargeTimerHit()));
+    chargeTimer.setInterval(10000);
+    chargeTimer.start();
+}
+
 void DeviceManager::detect()
 {
     int res = -1;
@@ -59,19 +65,60 @@ void DeviceManager::detect()
     }
 }
 
-void DeviceManager::startSync(bool readAllLogs = false)
+void DeviceManager::startSync(bool readAllLogs = false, bool syncTime = true, bool syncOrbit = true, bool syncMovescount = false)
 {
     int res = -1;
+    time_t current_time;
+    struct tm *local_time;
+    uint8_t *orbitData;
+    int orbitDataLen;
 
     mutex.lock();
+    this->syncMovescount = syncMovescount;
+    currentSyncPart = 0;
+    syncParts = 2;
+    if (syncTime) syncParts++;
+    if (syncOrbit) syncParts+=2;
+
     if (this->deviceObject != NULL) {
-        emit this->syncProgressInform(QString(tr("Reading personal settings")), true, 0);
+        emit this->syncProgressInform(QString(tr("Reading personal settings")), false, true, 0);
         res = libambit_personal_settings_get(this->deviceObject, &currentPersonalSettings);
+        currentSyncPart++;
+
+        libambit_sync_display_show(this->deviceObject);
+
+        if (syncTime && res != -1) {
+            emit this->syncProgressInform(QString(tr("Setting date/time")), false, true, 100*currentSyncPart/syncParts);
+            current_time = time(NULL);
+            local_time = localtime(&current_time);
+            res = libambit_date_time_set(this->deviceObject, local_time);
+            currentSyncPart++;
+        }
 
         if (res != -1) {
-            emit this->syncProgressInform(QString(tr("Reading log files")), true, 0);
+            emit this->syncProgressInform(QString(tr("Reading log files")), false, true, 100*currentSyncPart/syncParts);
             res = libambit_log_read(this->deviceObject, readAllLogs ? NULL : &log_skip_cb, &log_push_cb, &log_progress_cb, this);
+            currentSyncPart++;
+        }
+
+        if (syncOrbit && res != -1) {
+            emit this->syncProgressInform(QString(tr("Fetching orbital data")), false, true, 100*currentSyncPart/syncParts);
+            if ((orbitDataLen = movesCount->getOrbitalData(&orbitData)) != -1) {
+                currentSyncPart++;
+                emit this->syncProgressInform(QString(tr("Writing orbital data")), false, false, 100*currentSyncPart/syncParts);
+                res = libambit_gps_orbit_write(this->deviceObject, orbitData, orbitDataLen);
+                free(orbitData);
+            }
+            else {
+                currentSyncPart++;
+                emit this->syncProgressInform(QString(tr("Failed to get orbital data")), true, false, 100*currentSyncPart/syncParts);
+                res = -1;
+            }
+
+            currentSyncPart++;
         }
+
+        libambit_sync_display_clear(this->deviceObject);
     }
     mutex.unlock();
 
@@ -118,16 +165,22 @@ int DeviceManager::log_skip_cb(void *ref, ambit_log_header_t *log_header)
 void DeviceManager::log_push_cb(void *ref, ambit_log_entry_t *log_entry)
 {
     DeviceManager *manager = static_cast<DeviceManager*> (ref);
-    LogEntry *entry = manager->logStore.store(QString(manager->currentDeviceInfo.serial), &manager->currentPersonalSettings, log_entry);
+    LogEntry *entry = manager->logStore.store(&manager->currentDeviceInfo, &manager->currentPersonalSettings, log_entry);
     if (entry != NULL) {
-        manager->movesCount.sendLog(entry);
-    }
+        //! TODO: make this optional, only used for debugging
+        manager->movesCountXML.writeLog(entry);
 
-    delete entry;
+        if (manager->syncMovescount) {
+            manager->movesCount->writeLog(entry);
+        }
+
+        delete entry;
+    }
 }
 
 void DeviceManager::log_progress_cb(void *ref, uint16_t log_count, uint16_t log_current, uint8_t progress_percent)
 {
     DeviceManager *manager = static_cast<DeviceManager*> (ref);
-    emit manager->syncProgressInform(QString(tr("Downloading message %1 of %2")).arg(log_current).arg(log_count), false, progress_percent);
+    progress_percent = 100*manager->currentSyncPart/manager->syncParts + progress_percent*1/manager->syncParts;
+    emit manager->syncProgressInform(QString(tr("Downloading message %1 of %2")).arg(log_current).arg(log_count), false, false, progress_percent);
 }
diff --git a/src/openambit/devicemanager.h b/src/openambit/devicemanager.h
index aa7e1f6..7f8a683 100644
--- a/src/openambit/devicemanager.h
+++ b/src/openambit/devicemanager.h
@@ -31,23 +31,25 @@
 #include "settings.h"
 #include "logstore.h"
 #include "movescount.h"
+#include "movescountxml.h"
 #include <libambit.h>
 
 class DeviceManager : public QObject
 {
     Q_OBJECT
 public:
-    void start();
+    explicit DeviceManager(QObject *parent = 0);
     ~DeviceManager();
+    void start();
 signals:
     void deviceDetected(ambit_device_info_t deviceInfo, bool supported);
     void deviceRemoved(void);
     void deviceCharge(quint8 percent);
     void syncFinished(bool success);
-    void syncProgressInform(QString message, bool newRow, quint8 percentDone);
+    void syncProgressInform(QString message, bool error, bool newRow, quint8 percentDone);
 public slots:
     void detect(void);
-    void startSync(bool readAllLogs);
+    void startSync(bool readAllLogs, bool syncTime, bool syncOrbit, bool syncMovescount);
 
 private slots:
     void chargeTimerHit();
@@ -61,9 +63,14 @@ private:
     ambit_device_info_t currentDeviceInfo;
     ambit_personal_settings_t currentPersonalSettings;
 
+    int syncParts;
+    int currentSyncPart;
+    bool syncMovescount;
+
     QMutex mutex;
     QTimer chargeTimer;
-    MovesCount movesCount;
+    MovesCount *movesCount;
+    MovesCountXML movesCountXML;
     Settings settings;
     LogStore logStore;
 };
diff --git a/src/openambit/logentry.cpp b/src/openambit/logentry.cpp
index b09dfcd..b4c8654 100644
--- a/src/openambit/logentry.cpp
+++ b/src/openambit/logentry.cpp
@@ -29,6 +29,14 @@ LogEntry::LogEntry(const LogEntry &other)
 {
     u_int32_t i;
 
+    if (other.deviceInfo != NULL) {
+        deviceInfo = (ambit_device_info_t*)malloc(sizeof(ambit_device_info_t));
+        memcpy(deviceInfo, other.deviceInfo, sizeof(ambit_device_info_t));
+    }
+    else {
+        deviceInfo = NULL;
+    }
+
     if (other.personalSettings != NULL) {
         personalSettings = (ambit_personal_settings_t*)malloc(sizeof(ambit_personal_settings_t));
         memcpy(personalSettings, other.personalSettings, sizeof(ambit_personal_settings_t));
@@ -73,6 +81,7 @@ LogEntry& LogEntry::operator=(const LogEntry &rhs)
 
     std::swap(device, tmp.device);
     std::swap(time, tmp.time);
+    std::swap(deviceInfo, tmp.deviceInfo);
     std::swap(personalSettings, tmp.personalSettings);
     std::swap(logEntry, tmp.logEntry);
 
@@ -83,6 +92,11 @@ LogEntry::~LogEntry()
 {
     u_int32_t i;
 
+    if (deviceInfo != NULL) {
+        free(deviceInfo);
+        deviceInfo = NULL;
+    }
+
     if (personalSettings != NULL) {
         free(personalSettings);
         personalSettings = NULL;
diff --git a/src/openambit/logentry.h b/src/openambit/logentry.h
index 62465bc..23dc3e9 100644
--- a/src/openambit/logentry.h
+++ b/src/openambit/logentry.h
@@ -36,6 +36,7 @@ public:
 
     QString device;
     QDateTime time;
+    ambit_device_info_t *deviceInfo = NULL;
     ambit_personal_settings_t *personalSettings = NULL;
     ambit_log_entry_t *logEntry = NULL;
 signals:
diff --git a/src/openambit/logstore.cpp b/src/openambit/logstore.cpp
index e8f60bf..248b777 100644
--- a/src/openambit/logstore.cpp
+++ b/src/openambit/logstore.cpp
@@ -94,14 +94,14 @@ LogStore::LogStore(QObject *parent) :
     storagePath = QString(getenv("HOME")) + "/.openambit";
 }
 
-LogEntry *LogStore::store(QString device, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry)
+LogEntry *LogStore::store(ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry)
 {
     LogEntry *retEntry = new LogEntry();
     QDateTime dateTime(QDate(logEntry->header.date_time.year, logEntry->header.date_time.month, logEntry->header.date_time.day),
                        QTime(logEntry->header.date_time.hour, logEntry->header.date_time.minute, logEntry->header.date_time.msec/1000));
 
-    XMLWriter writer(device, dateTime, personalSettings, logEntry);
-    QFile logfile(logEntryPath(device, dateTime));
+    XMLWriter writer(deviceInfo, dateTime, personalSettings, logEntry);
+    QFile logfile(logEntryPath(QString(deviceInfo->serial), dateTime));
     logfile.open(QIODevice::WriteOnly);
     writer.write(&logfile);
     logfile.close();
@@ -227,6 +227,9 @@ void LogStore::XMLReader::readRoot()
         else if (xml.name() == "Time") {
             readTime();
         }
+        else if (xml.name() == "DeviceInfo") {
+            readDeviceInfo();
+        }
         else if (xml.name() == "PersonalSettings") {
             readPersonalSettings();
         }
@@ -254,6 +257,49 @@ void LogStore::XMLReader::readTime()
     logEntry->time = QDateTime::fromString(datestring, Qt::ISODate);
 }
 
+void LogStore::XMLReader::readDeviceInfo()
+{
+    QRegExp versionRX("([0-9]+)\\.([0-9]+)\\.([0-9]+)");
+
+    Q_ASSERT(xml.isStartElement() && xml.name() == "DeviceInfo");
+
+    if (logEntry->deviceInfo == NULL) {
+        logEntry->deviceInfo = (ambit_device_info_t*)malloc(sizeof(ambit_device_info_t));
+        memset(logEntry->deviceInfo, 0, sizeof(ambit_device_info_t));
+    }
+
+    while (xml.readNextStartElement()) {
+        if (xml.name() == "Serial") {
+            strcpy(logEntry->deviceInfo->serial, xml.readElementText().toAscii().data());
+        }
+        else if (xml.name() == "Model") {
+            strcpy(logEntry->deviceInfo->model, xml.readElementText().toAscii().data());
+        }
+        else if (xml.name() == "Name") {
+            strcpy(logEntry->deviceInfo->name, xml.readElementText().toAscii().data());
+        }
+        else if (xml.name() == "FWVersion") {
+            if (versionRX.indexIn(xml.readElementText()) >= 0) {
+                logEntry->deviceInfo->fw_version[0] = versionRX.cap(1).toInt();
+                logEntry->deviceInfo->fw_version[1] = versionRX.cap(2).toInt();
+                logEntry->deviceInfo->fw_version[2] = versionRX.cap(3).toInt() & 0xff;
+                logEntry->deviceInfo->fw_version[3] = (versionRX.cap(3).toInt() >> 8) & 0xff;
+            }
+        }
+        else if (xml.name() == "HWVersion") {
+            if (versionRX.indexIn(xml.readElementText()) >= 0) {
+                logEntry->deviceInfo->hw_version[0] = versionRX.cap(1).toInt();
+                logEntry->deviceInfo->hw_version[1] = versionRX.cap(2).toInt();
+                logEntry->deviceInfo->hw_version[2] = versionRX.cap(3).toInt() & 0xff;
+                logEntry->deviceInfo->hw_version[3] = (versionRX.cap(3).toInt() >> 8) & 0xff;
+            }
+        }
+        else {
+            xml.skipCurrentElement();
+        }
+    }
+}
+
 void LogStore::XMLReader::readPersonalSettings()
 {
     Q_ASSERT(xml.isStartElement() && xml.name() == "PersonalSettings");
@@ -1112,8 +1158,8 @@ void LogStore::XMLReader::readPeriodicSample(QList<ambit_log_sample_periodic_val
 }
 
 
-LogStore::XMLWriter::XMLWriter(QString serial, QDateTime time, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry) :
-    serial(serial), time(time), personalSettings(personalSettings), logEntry(logEntry)
+LogStore::XMLWriter::XMLWriter(ambit_device_info_t *deviceInfo, QDateTime time, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry) :
+    deviceInfo(deviceInfo), time(time), personalSettings(personalSettings), logEntry(logEntry)
 {
     xml.setAutoFormatting(true);
 }
@@ -1129,8 +1175,9 @@ bool LogStore::XMLWriter::write(QIODevice *device)
     xml.writeStartElement("openambitlog");
     xml.writeAttribute("version", "1.0");
 
-    xml.writeTextElement("SerialNumber", serial);
+    xml.writeTextElement("SerialNumber", QString("%1").arg(deviceInfo->serial));
     xml.writeTextElement("Time", time.toString(Qt::ISODate));
+    ret = writeDeviceInfo();
     ret = writePersonalSettings();
     if (ret) {
         ret = writeLogEntry();
@@ -1141,6 +1188,19 @@ bool LogStore::XMLWriter::write(QIODevice *device)
     return ret;
 }
 
+bool LogStore::XMLWriter::writeDeviceInfo()
+{
+    xml.writeStartElement("DeviceInfo");
+    xml.writeTextElement("Serial", QString("%1").arg(deviceInfo->serial));
+    xml.writeTextElement("Model", QString("%1").arg(deviceInfo->model));
+    xml.writeTextElement("Name", QString("%1").arg(deviceInfo->name));
+    xml.writeTextElement("FWVersion", QString("%1.%2.%3").arg((int)deviceInfo->fw_version[0]).arg((int)deviceInfo->fw_version[1]).arg((int)deviceInfo->fw_version[2] | ((int)deviceInfo->fw_version[3] << 8)));
+    xml.writeTextElement("HWVersion", QString("%1.%2.%3").arg((int)deviceInfo->hw_version[0]).arg((int)deviceInfo->hw_version[1]).arg((int)deviceInfo->hw_version[2] | ((int)deviceInfo->hw_version[3] << 8)));
+    xml.writeEndElement();
+
+    return true;
+}
+
 bool LogStore::XMLWriter::writePersonalSettings()
 {
     xml.writeStartElement("PersonalSettings");
diff --git a/src/openambit/logstore.h b/src/openambit/logstore.h
index adaf484..32e5443 100644
--- a/src/openambit/logstore.h
+++ b/src/openambit/logstore.h
@@ -45,7 +45,7 @@ public:
     };
 
     explicit LogStore(QObject *parent = 0);
-    LogEntry *store(QString device, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
+    LogEntry *store(ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
     bool logExists(QString device, ambit_log_header_t *logHeader);
     LogEntry *read(QString device, QDateTime time);
     LogEntry *read(LogDirEntry dirEntry);
@@ -71,6 +71,7 @@ private:
         void readRoot();
         void readSerial();
         void readTime();
+        void readDeviceInfo();
         void readPersonalSettings();
         void readLog();
         void readLogHeader();
@@ -83,16 +84,17 @@ private:
     class XMLWriter
     {
     public:
-        XMLWriter(QString serial, QDateTime time, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
+        XMLWriter(ambit_device_info_t *deviceInfo, QDateTime time, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
         bool write(QIODevice *device);
 
     private:
+        bool writeDeviceInfo();
         bool writePersonalSettings();
         bool writeLogEntry();
         bool writeLogSample(ambit_log_sample_t *sample);
         bool writePeriodicSample(ambit_log_sample_t *sample);
 
-        QString serial;
+        ambit_device_info_t *deviceInfo;
         QDateTime time;
         QXmlStreamWriter xml;
         ambit_personal_settings_t *personalSettings;
diff --git a/src/openambit/mainwindow.cpp b/src/openambit/mainwindow.cpp
index 07f3337..eec67a1 100644
--- a/src/openambit/mainwindow.cpp
+++ b/src/openambit/mainwindow.cpp
@@ -24,6 +24,9 @@
 
 #include <QListWidgetItem>
 
+#define APPKEY                 "HpF9f1qV5qrDJ1hY1QK1diThyPsX10Mh4JvCw9xVQSglJNLdcwr3540zFyLzIC3e"
+#define MOVESCOUNT_DEFAULT_URL "https://uiservices.movescount.com/"
+
 MainWindow::MainWindow(QWidget *parent) :
     QMainWindow(parent),
     ui(new Ui::MainWindow)
@@ -32,9 +35,16 @@ MainWindow::MainWindow(QWidget *parent) :
 
     // Setup UI parts
     QIcon warningIcon = QIcon::fromTheme("dialog-warning");
+    QIcon infoIcon = QIcon::fromTheme("dialog-information");
     ui->labelNotSupportedIcon->setPixmap(warningIcon.pixmap(8,8));
     ui->labelNotSupportedIcon->setHidden(true);
     ui->labelNotSupported->setHidden(true);
+    ui->labelMovescountAuthIcon->setPixmap(warningIcon.pixmap(8,8));
+    ui->labelMovescountAuthIcon->setHidden(true);
+    ui->labelMovescountAuth->setHidden(true);
+    ui->labelNewFirmwareIcon->setPixmap(infoIcon.pixmap(8,8));
+    ui->labelNewFirmwareIcon->setHidden(true);
+    ui->labelNewFirmware->setHidden(true);
     ui->labelCharge->setHidden(true);
     ui->chargeIndicator->setHidden(true);
     ui->checkBoxResyncAll->setHidden(true);
@@ -51,10 +61,10 @@ MainWindow::MainWindow(QWidget *parent) :
     connect(deviceManager, SIGNAL(deviceRemoved()), this, SLOT(deviceRemoved()), Qt::QueuedConnection);
     connect(deviceManager, SIGNAL(deviceCharge(quint8)), this, SLOT(deviceCharge(quint8)), Qt::QueuedConnection);
     connect(deviceManager, SIGNAL(syncFinished(bool)), this, SLOT(syncFinished(bool)), Qt::QueuedConnection);
-    connect(deviceManager, SIGNAL(syncProgressInform(QString,bool,quint8)), this, SLOT(syncProgressInform(QString,bool,quint8)), Qt::QueuedConnection);
+    connect(deviceManager, SIGNAL(syncProgressInform(QString,bool,bool,quint8)), this, SLOT(syncProgressInform(QString,bool,bool,quint8)), Qt::QueuedConnection);
     connect(ui->buttonDeviceReload, SIGNAL(clicked()), deviceManager, SLOT(detect()));
     connect(ui->buttonSyncNow, SIGNAL(clicked()), this, SLOT(syncNowClicked()));
-    connect(this, SIGNAL(syncNow(bool)), deviceManager, SLOT(startSync(bool)));
+    connect(this, SIGNAL(syncNow(bool,bool,bool,bool)), deviceManager, SLOT(startSync(bool,bool,bool,bool)));
     deviceWorkerThread.start();
     deviceManager->start();
     deviceManager->detect();
@@ -65,6 +75,9 @@ MainWindow::MainWindow(QWidget *parent) :
     connect(ui->logsList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenuForLogItem(QPoint)));
 
     updateLogList();
+
+    // Setup Movescount
+    movesCountSetup();
 }
 
 MainWindow::~MainWindow()
@@ -78,11 +91,20 @@ void MainWindow::showSettings()
 {
     settingsDialog = new SettingsDialog(this);
     settingsDialog->setModal(true);
+    connect(settingsDialog, SIGNAL(settingsSaved()), this, SLOT(settingsSaved()));
     settingsDialog->show();
 }
 
+void MainWindow::settingsSaved()
+{
+    // Update Movescount
+    movesCountSetup();
+}
+
 void MainWindow::syncNowClicked()
 {
+    bool syncTime, syncOrbit, syncMovescount;
+
     ui->checkBoxResyncAll->setEnabled(false);
     ui->buttonSyncNow->setEnabled(false);
     currentLogMessageRow = NULL;
@@ -93,7 +115,15 @@ void MainWindow::syncNowClicked()
     }
     ui->syncProgressBar->setHidden(false);
     ui->syncProgressBar->setValue(0);
-    emit MainWindow::syncNow(ui->checkBoxResyncAll->isChecked());
+
+    settings.beginGroup("syncSettings");
+    syncTime = settings.value("syncTime", true).toBool();
+    syncOrbit = settings.value("syncOrbit", true).toBool();
+    settings.endGroup();
+    settings.beginGroup("movescountSettings");
+    syncMovescount = settings.value("movescountEnable", true).toBool();
+    settings.endGroup();
+    emit MainWindow::syncNow(ui->checkBoxResyncAll->isChecked(), syncTime, syncOrbit, syncMovescount);
 }
 
 void MainWindow::deviceDetected(ambit_device_info_t deviceInfo, bool supported)
@@ -103,6 +133,10 @@ void MainWindow::deviceDetected(ambit_device_info_t deviceInfo, bool supported)
     if (!supported) {
         ui->labelNotSupportedIcon->setHidden(false);
         ui->labelNotSupported->setHidden(false);
+        ui->labelMovescountAuthIcon->setHidden(true);
+        ui->labelMovescountAuth->setHidden(true);
+        ui->labelNewFirmwareIcon->setHidden(true);
+        ui->labelNewFirmware->setHidden(true);
         ui->labelCharge->setHidden(true);
         ui->chargeIndicator->setHidden(true);
         ui->checkBoxResyncAll->setHidden(true);
@@ -112,10 +146,27 @@ void MainWindow::deviceDetected(ambit_device_info_t deviceInfo, bool supported)
     else {
         ui->labelNotSupportedIcon->setHidden(true);
         ui->labelNotSupported->setHidden(true);
+        ui->labelMovescountAuthIcon->setHidden(true);
+        ui->labelMovescountAuth->setHidden(true);
+        ui->labelNewFirmwareIcon->setHidden(true);
+        ui->labelNewFirmware->setHidden(true);
         ui->labelCharge->setHidden(false);
         ui->chargeIndicator->setHidden(false);
         ui->checkBoxResyncAll->setHidden(false);
         ui->buttonSyncNow->setHidden(false);
+
+        movesCountSetup();
+        if (movesCount != NULL) {
+            movesCount->setDevice(&deviceInfo);
+            settings.beginGroup("movescountSettings");
+            if (settings.value("checkNewVersions", true).toBool()) {
+                movesCount->checkLatestFirmwareVersion();
+            }
+            if (settings.value("movescountEnable", true).toBool()) {
+                movesCount->getDeviceSettings();
+            }
+            settings.endGroup();
+        }
     }
 }
 
@@ -125,6 +176,10 @@ void MainWindow::deviceRemoved(void)
     ui->labelSerial->setText("");
     ui->labelNotSupportedIcon->setHidden(true);
     ui->labelNotSupported->setHidden(true);
+    ui->labelMovescountAuthIcon->setHidden(true);
+    ui->labelMovescountAuth->setHidden(true);
+    ui->labelNewFirmwareIcon->setHidden(true);
+    ui->labelNewFirmware->setHidden(true);
     ui->labelCharge->setHidden(true);
     ui->chargeIndicator->setHidden(true);
     ui->checkBoxResyncAll->setHidden(true);
@@ -162,7 +217,7 @@ void MainWindow::syncFinished(bool success)
     updateLogList();
 }
 
-void MainWindow::syncProgressInform(QString message, bool newRow, quint8 percentDone)
+void MainWindow::syncProgressInform(QString message, bool error, bool newRow, quint8 percentDone)
 {
     if (newRow) {
         if (currentLogMessageRow != NULL) {
@@ -176,11 +231,27 @@ void MainWindow::syncProgressInform(QString message, bool newRow, quint8 percent
     else {
         if (currentLogMessageRow != NULL) {
             currentLogMessageRow->setMessage(message);
+            if (error) {
+                currentLogMessageRow->setStatus(LogMessageRow::StatusFailed);
+            }
         }
     }
     ui->syncProgressBar->setValue(percentDone);
 }
 
+void MainWindow::newerFirmwareExists(QByteArray fw_version)
+{
+    ui->labelNewFirmware->setText(QString(tr("Newer firmware exists (%1.%2.%3)")).arg((int)fw_version[0]).arg((int)fw_version[1]).arg((int)(fw_version[2] | ((int)fw_version[3] << 8))));
+    ui->labelNewFirmware->setHidden(false);
+    ui->labelNewFirmwareIcon->setHidden(false);
+}
+
+void MainWindow::movesCountAuth(bool authorized)
+{
+    ui->labelMovescountAuth->setHidden(authorized);
+    ui->labelMovescountAuthIcon->setHidden(authorized);
+}
+
 void MainWindow::logItemSelected(QListWidgetItem *current,QListWidgetItem *previous)
 {
     LogEntry *logEntry = NULL;
@@ -209,7 +280,8 @@ void MainWindow::logItemWriteMovescount()
 
     logEntry = logStore.read(ui->logsList->selectedItems().at(0)->data(Qt::UserRole).toString());
     if (logEntry != NULL) {
-        movesCount.sendLog(logEntry);
+        movesCount->writeLog(logEntry);
+        movesCountXML.writeLog(logEntry);
         delete logEntry;
     }
 }
@@ -264,3 +336,32 @@ void MainWindow::LogMessageRow::setStatus(Status status)
     }
     iconLabel->setPixmap(icon.pixmap(8,8));
 }
+
+void MainWindow::movesCountSetup()
+{
+    bool syncOrbit = false;
+    bool movescountEnable = false;
+
+    settings.beginGroup("syncSettings");
+    syncOrbit = settings.value("syncOrbit").toBool();
+    settings.endGroup();
+
+    settings.beginGroup("movescountSettings");
+    movescountEnable = settings.value("movescountEnable").toBool();
+    if (syncOrbit || movescountEnable) {
+        if (movesCount == NULL) {
+            movesCount = MovesCount::instance();
+            movesCount->setAppkey(APPKEY);
+            movesCount->setBaseAddress(settings.value("movescountBaseAddress", MOVESCOUNT_DEFAULT_URL).toString());
+            if (settings.value("movescountUserkey", "").toString().length() == 0) {
+                settings.setValue("movescountUserkey", movesCount->generateUserkey());
+            }
+            movesCount->setUserkey(settings.value("movescountUserkey").toString());
+
+            connect(movesCount, SIGNAL(newerFirmwareExists(QByteArray)), this, SLOT(newerFirmwareExists(QByteArray)), Qt::QueuedConnection);
+            connect(movesCount, SIGNAL(movesCountAuth(bool)), this, SLOT(movesCountAuth(bool)), Qt::QueuedConnection);
+        }
+        movesCount->setUsername(settings.value("email").toString());
+    }
+    settings.endGroup();
+}
diff --git a/src/openambit/mainwindow.h b/src/openambit/mainwindow.h
index f4632bd..301fdbf 100644
--- a/src/openambit/mainwindow.h
+++ b/src/openambit/mainwindow.h
@@ -24,6 +24,7 @@
 
 #include "devicemanager.h"
 #include "settingsdialog.h"
+#include "movescount.h"
 #include <QMainWindow>
 #include <QThread>
 #include <QVBoxLayout>
@@ -43,10 +44,11 @@ public:
     ~MainWindow();
 
 signals:
-    void syncNow(bool readAll);
+    void syncNow(bool readAll, bool syncTime, bool syncOrbit, bool syncMovescount);
 
 private slots:
     void showSettings();
+    void settingsSaved();
 
     void syncNowClicked();
 
@@ -54,7 +56,10 @@ private slots:
     void deviceRemoved();
     void deviceCharge(quint8 percent);
     void syncFinished(bool success);
-    void syncProgressInform(QString message, bool newRow, quint8 percentDone);
+    void syncProgressInform(QString message, bool error, bool newRow, quint8 percentDone);
+
+    void newerFirmwareExists(QByteArray fw_version);
+    void movesCountAuth(bool authorized);
 
     void logItemSelected(QListWidgetItem *current,QListWidgetItem *previous);
     void showContextMenuForLogItem(const QPoint &pos);
@@ -66,11 +71,15 @@ private:
     void updateLogMessageRow(QString message);
     void finalizeLogMessageRow();
 
+    void movesCountSetup();
+
     Ui::MainWindow *ui;
+    Settings settings;
     SettingsDialog *settingsDialog;
     DeviceManager *deviceManager;
     LogStore logStore;
-    MovesCount movesCount;
+    MovesCountXML movesCountXML;
+    MovesCount *movesCount = NULL;
     QThread deviceWorkerThread;
 
     class LogMessageRow : public QHBoxLayout
diff --git a/src/openambit/mainwindow.ui b/src/openambit/mainwindow.ui
index c3988c8..8b76f79 100644
--- a/src/openambit/mainwindow.ui
+++ b/src/openambit/mainwindow.ui
@@ -132,12 +132,18 @@
            </widget>
           </item>
           <item>
-           <layout class="QHBoxLayout" name="horizontalLayout_2">
+           <layout class="QHBoxLayout" name="horizontalLayoutNotSupported">
             <item>
              <widget class="QLabel" name="labelNotSupported">
               <property name="enabled">
                <bool>true</bool>
               </property>
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
               <property name="text">
                <string>Device not supported yet!</string>
               </property>
@@ -145,9 +151,78 @@
             </item>
             <item>
              <widget class="QLabel" name="labelNotSupportedIcon">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
               <property name="text">
                <string/>
               </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayoutMovescountAuth">
+            <item>
+             <widget class="QLabel" name="labelMovescountAuth">
+              <property name="enabled">
+               <bool>true</bool>
+              </property>
+              <property name="text">
+               <string>Auth on movescount.com!</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="labelMovescountAuthIcon">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayoutNewFirmware">
+            <item>
+             <widget class="QLabel" name="labelNewFirmware">
+              <property name="enabled">
+               <bool>true</bool>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QLabel" name="labelNewFirmwareIcon">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string/>
+              </property>
+              <property name="alignment">
+               <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+              </property>
              </widget>
             </item>
            </layout>
@@ -255,7 +330,7 @@
      <x>0</x>
      <y>0</y>
      <width>872</width>
-     <height>20</height>
+     <height>21</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuOpenambit">
diff --git a/src/openambit/movescount.cpp b/src/openambit/movescount.cpp
index 37cc842..5a1b311 100644
--- a/src/openambit/movescount.cpp
+++ b/src/openambit/movescount.cpp
@@ -20,787 +20,261 @@
  *
  */
 #include "movescount.h"
-#include <QFile>
-
-#define _USE_MATH_DEFINES
-#include <math.h>
-
-typedef struct typename_lookup_entry_s {
-    u_int8_t id;
-    QString XMLName;
-} typename_lookup_entry_t;
-
-static typename_lookup_entry_t sampleDistanceSourceNames[] = {
-    { 0x02, "Gps" },
-    { 0x03, "Wrist" },
-    { 0, "" }
-};
-
-static typename_lookup_entry_t sampleAltitudeSourceNames[] = {
-    { 0x04, "Pressure" },
-    { 0, "" }
-};
-
-static typename_lookup_entry_t sampleLapEventTypeNames[] = {
-    { 0x01, "Manual" },
-    { 0x14, "High Interval" },
-    { 0x15, "Low Interval" },
-    { 0x16, "Interval" },
-    { 0x1e, "Pause" },
-    { 0x1f, "Start" },
-    { 0, "" }
-};
-
-static typename_lookup_entry_t sampleActivityNames[] = {
-    { 0x01, "Not Specified Sport" },
-    { 0x02, "Multisport" },
-    { 0x03, "Run" },
-    { 0x04, "Cycling" },
-    { 0x05, "Mountain Biking" },
-    { 0x06, "UNDEFINED7" },
-    { 0x07, "Skating" },
-    { 0x08, "Aerobics" },
-    { 0x09, "Yoga Pilates" },
-    { 0x0a, "Trekking" },
-    { 0x0b, "Walking" },
-    { 0x0c, "Sailing" },
-    { 0x0d, "Kayaking" },
-    { 0x0e, "Rowing" },
-    { 0x0f, "Climbing" },
-    { 0x10, "Indoor Cycling" },
-    { 0x11, "Circuit Training" },
-    { 0x12, "Triathlon" },
-    { 0x13, "Alpine Skiing" },
-    { 0x14, "Snowboarding" },
-    { 0x15, "Crosscountry Skiing" },
-    { 0x16, "Weight Training" },
-    { 0x17, "Basketball" },
-    { 0x18, "Soccer" },
-    { 0x19, "Ice Hockey" },
-    { 0x1a, "Volleyball" },
-    { 0x1b, "Football" },
-    { 0x1c, "Softball" },
-    { 0x1d, "Cheerleading" },
-    { 0x1e, "Baseball" },
-    { 0x1f, "UNDEFINED32" },
-    { 0x20, "Tennis" },
-    { 0x21, "Badminton" },
-    { 0x22, "Table Tenni" },
-    { 0x23, "Racquet Ball" },
-    { 0x24, "Squash" },
-    { 0x25, "Combat Sport" },
-    { 0x26, "Boxing" },
-    { 0x27, "Floorball" },
-    { 0x28, "UNDEFINED41" },
-    { 0x29, "UNDEFINED42" },
-    { 0x2a, "UNDEFINED43" },
-    { 0x2b, "UNDEFINED44" },
-    { 0x2c, "UNDEFINED45" },
-    { 0x2d, "UNDEFINED46" },
-    { 0x2e, "UNDEFINED47" },
-    { 0x2f, "UNDEFINED48" },
-    { 0x30, "UNDEFINED49" },
-    { 0x31, "UNDEFINED50" },
-    { 0x32, "Scuba Diving" },
-    { 0x33, "Free Diving" },
-    { 0x34, "UNDEFINED53" },
-    { 0x35, "UNDEFINED54" },
-    { 0x36, "UNDEFINED55" },
-    { 0x37, "UNDEFINED56" },
-    { 0x38, "UNDEFINED57" },
-    { 0x39, "UNDEFINED58" },
-    { 0x3a, "UNDEFINED59" },
-    { 0x3b, "UNDEFINED60" },
-    { 0x3c, "Adventure Racing" },
-    { 0x3d, "Bowling" },
-    { 0x3e, "Cricket" },
-    { 0x3f, "Crosstrainer" },
-    { 0x40, "Dancing" },
-    { 0x41, "Golf" },
-    { 0x42, "Gymnastics" },
-    { 0x43, "Handball" },
-    { 0x44, "Horseback Riding" },
-    { 0x45, "Ice Skating" },
-    { 0x46, "Indoor Rowing" },
-    { 0x47, "Canoeing" },
-    { 0x48, "Motorsports" },
-    { 0x49, "Mountaineering" },
-    { 0x4a, "Orienteering" },
-    { 0x4b, "Rugby" },
-    { 0x4c, "UNDEFINED77" },
-    { 0x4d, "Ski Touring" },
-    { 0x4e, "Stretching" },
-    { 0x4f, "Telemark Skiing" },
-    { 0x50, "Track And Field" },
-    { 0x51, "Trail Running" },
-    { 0x52, "Openwater Swimming" },
-    { 0x53, "UNDEFINED84" },
-    { 0x54, "UNDEFINED85" },
-    { 0x55, "UNDEFINED86" },
-    { 0x56, "UNDEFINED87" },
-    { 0x57, "UNDEFINED88" },
-    { 0x58, "UNDEFINED89" },
-    { 0x59, "UNDEFINED90" },
-    { 0x5a, "UNDEFINED91" },
-    { 0x5b, "UNDEFINED92" },
-    { 0x5c, "UNDEFINED93" },
-    { 0x5d, "UNDEFINED94" },
-    { 0x5e, "UNDEFINED95" },
-    { 0x5f, "UNDEFINED96" },
-    { 0x60, "UNDEFINED97" },
-    { 0x61, "UNDEFINED98" },
-    { 0x62, "UNDEFINED99" },
-    { 0x63, "Other" },
-    { 0x64, "Butterfly" },
-    { 0x65, "Backstroke" },
-    { 0x66, "Breaststroke" },
-    { 0x67, "Freestyle" },
-    { 0x68, "Drill" },
-    { 0, "" }
-};
-
-MovesCount::MovesCount(QObject *parent) :
-    QObject(parent)
+#include <QtNetwork/QNetworkRequest>
+#include <QEventLoop>
+#include <QMutex>
+
+#include <qdebug.h>
+
+#define AUTH_CHECK_TIMEOUT 5000 /* ms */
+#define GPS_ORBIT_DATA_MIN_SIZE 30000 /* byte */
+
+static MovesCount *m_Instance;
+
+MovesCount* MovesCount::instance()
 {
-    storagePath = QString(getenv("HOME")) + "/.openambit/movescount";
+    static QMutex mutex;
+    if (!m_Instance) {
+        mutex.lock();
+
+        if (!m_Instance)
+            m_Instance = new MovesCount;
+
+        mutex.unlock();
+    }
+
+    return m_Instance;
 }
 
-void MovesCount::sendLog(LogEntry *logEntry)
+void MovesCount::setBaseAddress(QString baseAddress)
 {
-    XMLWriter writer(logEntry);
-    QFile logfile(logEntryPath(logEntry));
-    logfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
-
-    writer.write(&logfile);
+    this->baseAddress = baseAddress;
+    if (this->baseAddress[this->baseAddress.length()-1] == '/') {
+        this->baseAddress = this->baseAddress.remove(this->baseAddress.length()-1, 1);
+    }
+}
 
-    logfile.close();
+void MovesCount::setAppkey(QString appkey)
+{
+    this->appkey = appkey;
 }
 
-QString MovesCount::logEntryPath(LogEntry *logEntry)
+void MovesCount::setUsername(QString username)
 {
-    return storagePath + "/log-" + logEntry->device + "-" + logEntry->time.toString("yyyy-MM-ddThh_mm_ss") + "-0.log";
+    this->username = username;
 }
 
-MovesCount::XMLWriter::XMLWriter(LogEntry *logEntry) :
-    logEntry(logEntry)
+void MovesCount::setUserkey(QString userkey)
 {
-    xml.setAutoFormatting(true);
-    xml.setAutoFormattingIndent(-1);
+    this->userkey = userkey;
 }
 
-bool MovesCount::XMLWriter::write(QIODevice *device)
+QString MovesCount::generateUserkey()
 {
-    bool ret = true;
+    char randString[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    QString retString = "";
 
-    xml.setDevice(device);
+    for (int i=0; i<14; i++) {
+        retString += QString(randString[qrand() % sizeof(randString)]);
+    }
 
-    xml.writeStartDocument();
-    ret = writeLogEntry();
-    xml.writeEndDocument();
+    return retString;
+}
 
-    return ret;
+void MovesCount::setDevice(ambit_device_info_t *device_info)
+{
+    memcpy(&this->device_info, device_info, sizeof(ambit_device_info_t));
 }
 
-bool MovesCount::XMLWriter::writeLogEntry()
+bool MovesCount::isAuthorized()
 {
-    u_int32_t i;
-
-    xml.writeStartElement("header");
-    xml.writeTextElement("Duration", QString::number((double)logEntry->logEntry->header.duration/1000.0, 'g', 16));
-    xml.writeTextElement("Ascent", QString("%1").arg(logEntry->logEntry->header.ascent));
-    xml.writeTextElement("Descent", QString("%1").arg(logEntry->logEntry->header.descent));
-    xml.writeTextElement("AscentTime", QString::number((double)logEntry->logEntry->header.ascent_time/1000.0, 'g', 16));
-    xml.writeTextElement("DescentTime", QString::number((double)logEntry->logEntry->header.descent_time/1000.0, 'g', 16));
-    xml.writeTextElement("RecoveryTime", QString::number((double)logEntry->logEntry->header.recovery_time/1000.0, 'g', 16));
-    xml.writeStartElement("Speed");
-    xml.writeTextElement("Avg", QString::number((double)logEntry->logEntry->header.speed_avg/3600.0, 'g', 16));
-    xml.writeTextElement("Max", QString::number((double)logEntry->logEntry->header.speed_max/3600.0, 'g', 16));
-    xml.writeTextElement("MaxTime", QString::number((double)logEntry->logEntry->header.speed_max_time/1000.0, 'g', 16));
-    xml.writeEndElement();
-    // We have no idea about cadence yet, but we better include an empty tag!
-    xml.writeStartElement("Cadence");
-    xml.writeTextElement("MaxTime", QString::number(0));
-    xml.writeEndElement();
-    xml.writeStartElement("Altitude");
-    xml.writeTextElement("Max", QString("%1").arg(logEntry->logEntry->header.altitude_max));
-    xml.writeTextElement("Min", QString("%1").arg(logEntry->logEntry->header.altitude_min));
-    xml.writeTextElement("MaxTime", QString::number((double)logEntry->logEntry->header.altitude_max_time/1000.0, 'g', 16));
-    xml.writeTextElement("MinTime", QString::number((double)logEntry->logEntry->header.altitude_min_time/1000.0, 'g', 16));
-    xml.writeEndElement();
-    // Only include HR if heartrate seems to be present
-    if (logEntry->logEntry->header.heartrate_avg != 0) {
-        xml.writeStartElement("HR");
-        xml.writeTextElement("Avg", QString::number((double)logEntry->logEntry->header.heartrate_avg/logEntry->personalSettings->rest_hr, 'g', 16));
-        xml.writeTextElement("Max", QString::number((double)logEntry->logEntry->header.heartrate_max/logEntry->personalSettings->rest_hr, 'g', 16));
-        xml.writeTextElement("Min", QString::number((double)logEntry->logEntry->header.heartrate_min/logEntry->personalSettings->rest_hr, 'g', 16));
-        xml.writeTextElement("MaxTime", QString::number((double)logEntry->logEntry->header.heartrate_max_time/1000.0, 'g', 16));
-        xml.writeTextElement("MinTime", QString::number((double)logEntry->logEntry->header.heartrate_min_time/1000.0, 'g', 16));
-        xml.writeEndElement();
-        xml.writeTextElement("PeakTrainingEffect", QString::number((double)logEntry->logEntry->header.peak_training_effect/10.0, 'g', 16));
-    }
-    xml.writeTextElement("ActivityType", QString("%1").arg(logEntry->logEntry->header.activity_type));
-    xml.writeTextElement("Activity", QString(logEntry->logEntry->header.activity_name));
-    xml.writeStartElement("Temperature");
-    xml.writeTextElement("Max", QString::number((double)logEntry->logEntry->header.temperature_max/10.0 + 273.15, 'g', 16));
-    xml.writeTextElement("Min", QString::number((double)logEntry->logEntry->header.temperature_min/10.0 + 273.15, 'g', 16));
-    xml.writeTextElement("MaxTime", QString::number((double)logEntry->logEntry->header.temperature_max_time/1000.0, 'g', 16));
-    xml.writeTextElement("MinTime", QString::number((double)logEntry->logEntry->header.temperature_min_time/1000.0, 'g', 16));
-    xml.writeEndElement();
-    xml.writeTextElement("Distance", QString("%1").arg(logEntry->logEntry->header.distance));
-    xml.writeTextElement("LogItemCount", QString("%1").arg(logEntry->logEntry->header.samples_count));
-    // Only include energy if heartrate seems to be present
-    if (logEntry->logEntry->header.heartrate_avg != 0) {
-        xml.writeTextElement("Energy", QString::number((double)logEntry->logEntry->header.energy_consumption*4186.8, 'g', 16)); // kcal to Joule
-    }
-    xml.writeTextElement("TimeToFirstFix", QString::number((double)logEntry->logEntry->header.first_fix_time/1000.0, 'g', 16));
-    xml.writeTextElement("BatteryChargeAtStart", QString::number((double)logEntry->logEntry->header.battery_start/100.0, 'g', 16));
-    xml.writeTextElement("BatteryCharge", QString::number((double)logEntry->logEntry->header.battery_end/100.0, 'g', 16));
-    xml.writeTextElement("DistanceBeforeCalibrationChange", QString("%1").arg(logEntry->logEntry->header.distance_before_calib));
-    QDateTime dateTime(QDate(logEntry->logEntry->header.date_time.year,
-                             logEntry->logEntry->header.date_time.month,
-                             logEntry->logEntry->header.date_time.day),
-                       QTime(logEntry->logEntry->header.date_time.hour,
-                             logEntry->logEntry->header.date_time.minute, 0).addMSecs(logEntry->logEntry->header.date_time.msec));
-    xml.writeTextElement("DateTime", dateTime.toString(Qt::ISODate));
-    xml.writeEndElement();
-    QList<quint16> ibis;
-    xml.writeStartElement("Samples");
-    QList<int> order = rearrangeSamples();
-    foreach(int index, order) {
-        writeLogSample(&logEntry->logEntry->samples[index], &ibis);
-    }
+    return authorized;
+}
 
-    xml.writeEndElement();
-    if (ibis.count() > 0) {
-        xml.writeStartElement("IBI");
-        for (i=0; i<(u_int32_t)ibis.count(); i++) {
-            if (i > 0) {
-                xml.writeCharacters(" ");
-            }
-            xml.writeCharacters(QString("%1").arg(ibis.at(i)));
+int MovesCount::getOrbitalData(u_int8_t **data)
+{
+    int ret = -1;
+    QNetworkReply *reply;
+
+    reply = syncGET("/devices/gpsorbit/binary", "", false);
+
+    if(reply->error() == QNetworkReply::NoError) {
+        QByteArray _data = reply->readAll();
+
+        if (_data.length() >= GPS_ORBIT_DATA_MIN_SIZE) {
+            *data = (u_int8_t*)malloc(_data.length());
+
+            memcpy(*data, _data.data(), _data.length());
+
+            ret = _data.length();
         }
-        xml.writeEndElement();
     }
 
-    return true;
+    delete reply;
+
+    return ret;
+}
+
+int MovesCount::getPersonalSettings(ambit_personal_settings_t *settings)
+{
+    Q_UNUSED(settings);
+    return 0;
 }
 
-bool MovesCount::XMLWriter::writeLogSample(ambit_log_sample_t *sample, QList<quint16> *ibis)
+int MovesCount::getDeviceSettings()
 {
-    typename_lookup_entry_t *name_lookup;
-    int i;
-
-    switch(sample->type) {
-    case ambit_log_sample_type_periodic:
-        xml.writeStartElement("Sample");
-        writePeriodicSample(sample);
-        xml.writeEndElement();
-        break;
-    case ambit_log_sample_type_logpause:
-    {
-        //! TODO: Unknown representation!
-        break;
+    QNetworkReply *reply;
+
+    reply = syncGET("/userdevices/" + QString("%1").arg(device_info.serial), "", true);
+
+    if (checkReplyAuthorization(reply)) {
+        QByteArray _data = reply->readAll();
+
+        return 0;
     }
-    case ambit_log_sample_type_logrestart:
-    {
-        //! TODO: Unknown representation!
-        break;
+
+    return -1;
+}
+
+void MovesCount::checkLatestFirmwareVersion()
+{
+    if (firmwareCheckReply == NULL) {
+        firmwareCheckReply = asyncGET("/devices/" + QString("%1/%2.%3.%4")
+                                      .arg(device_info.model)
+                                      .arg(device_info.hw_version[0])
+                                      .arg(device_info.hw_version[1])
+                                      .arg(device_info.hw_version[3] << 8 | device_info.hw_version[2]), "", false);
+        connect(firmwareCheckReply, SIGNAL(finished()), this, SLOT(firmwareReplyFinished()));
     }
-    case ambit_log_sample_type_ibi:
-        for (i=0; i<sample->u.ibi.ibi_count; i++) {
-            ibis->append(sample->u.ibi.ibi[i]);
-        }
-        break;
-    case ambit_log_sample_type_ttff:
-        /* Unknown! */
-        break;
-    case ambit_log_sample_type_distance_source:
-    {
-        xml.writeStartElement("Sample");
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        xml.writeStartElement("Events");
-        xml.writeStartElement("Distance");
-        xml.writeStartElement("Source");
-        for (name_lookup = &sampleDistanceSourceNames[0]; name_lookup->XMLName != ""; name_lookup++) {
-            if (name_lookup->id == sample->u.distance_source) {
-                xml.writeCharacters(QString(name_lookup->XMLName));
-                break;
-            }
-        }
-        xml.writeEndElement();
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addMSecs(sample->utc_time.msec));
-        dateTime.setTimeSpec(Qt::UTC);
-        if (sample->u.distance_source == 0x02) {
-            // Only include UTC time for GPS source
-            xml.writeTextElement("UTC", dateTimeString(dateTime));
+}
+
+void MovesCount::writePersonalSettings(ambit_personal_settings_t *settings)
+{
+    Q_UNUSED(settings);
+}
+
+void MovesCount::writeLog(LogEntry *logEntry)
+{
+    QByteArray output;
+    QNetworkReply *reply;
+    QString moveId;
+
+    jsonParser.generateLogData(logEntry, output);
+
+    reply = syncPOST("/moves/", "", output, true);
+
+    if (reply->error() == QNetworkReply::NoError) {
+        QByteArray data = reply->readAll();
+        if (jsonParser.parseLogReply(data, moveId) == 0) {
+            emit logMoveID(logEntry->device, logEntry->time, moveId);
         }
-        xml.writeEndElement();
-        xml.writeEndElement();
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeEndElement();
-        break;
     }
-    case ambit_log_sample_type_lapinfo:
-    {
-        xml.writeStartElement("Sample");
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addMSecs(sample->utc_time.msec));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        xml.writeStartElement("Events");
-        if (sample->u.lapinfo.event_type == 0x1e || sample->u.lapinfo.event_type == 0x1f) {
-            xml.writeStartElement("Pause");
-            xml.writeTextElement("Type", QString("%1").arg(sample->u.lapinfo.event_type));
-            xml.writeTextElement("Duration", QString::number((double)sample->u.lapinfo.duration/1000.0, 'g', 16));
-            xml.writeTextElement("Distance", QString("%1").arg(sample->u.lapinfo.distance));
-            xml.writeTextElement("State", sample->u.lapinfo.event_type == 0x1e ? "True" : "False");
-            xml.writeEndElement();
-        }
-        else {
-            xml.writeStartElement("Lap");
-            xml.writeStartElement("Type");
-            for (name_lookup = &sampleLapEventTypeNames[0]; name_lookup->XMLName != ""; name_lookup++) {
-                if (name_lookup->id == sample->u.lapinfo.event_type) {
-                    xml.writeCharacters(QString(name_lookup->XMLName));
+}
+
+void MovesCount::firmwareReplyFinished()
+{
+    u_int8_t fw_version[4];
+
+    if (firmwareCheckReply != NULL) {
+        if (firmwareCheckReply->error() == QNetworkReply::NoError) {
+            QByteArray data = firmwareCheckReply->readAll();
+            if (jsonParser.parseFirmwareVersionReply(data, fw_version) == 0) {
+                if (fw_version[0] > device_info.fw_version[0] ||
+                    (fw_version[0] == device_info.fw_version[0] && (fw_version[1] > device_info.fw_version[1] ||
+                     (fw_version[1] == device_info.fw_version[1] && ((fw_version[2] | (fw_version[3] << 8)) > (device_info.fw_version[2] | (device_info.fw_version[3] << 8))))))) {
+                    emit newerFirmwareExists(QByteArray((const char*)fw_version, 4));
                 }
             }
-            xml.writeEndElement();
-            xml.writeTextElement("Duration", QString::number((double)sample->u.lapinfo.duration/1000.0, 'g', 16));
-            xml.writeTextElement("Distance", QString("%1").arg(sample->u.lapinfo.distance));
-            xml.writeEndElement();
-        }
-        xml.writeEndElement();
-        xml.writeEndElement();
-        break;
-    }
-    case ambit_log_sample_type_altitude_source:
-    {
-        xml.writeStartElement("Sample");
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        xml.writeStartElement("Events");
-        xml.writeStartElement("Altitude");
-        xml.writeStartElement("Source");
-        for (name_lookup = &sampleAltitudeSourceNames[0]; name_lookup->XMLName != ""; name_lookup++) {
-            if (name_lookup->id == sample->u.altitude_source.source_type) {
-                xml.writeCharacters(QString(name_lookup->XMLName));
-                break;
-            }
         }
-        xml.writeEndElement();
-        xml.writeTextElement("AltitudeOffset", QString("%1").arg(sample->u.altitude_source.altitude_offset));
-        xml.writeTextElement("PressureOffset", QString("%1").arg(sample->u.altitude_source.pressure_offset*10));
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addMSecs(sample->utc_time.msec));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeEndElement();
-        xml.writeEndElement();
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeEndElement();
-        break;
-    }
-    case ambit_log_sample_type_gps_base:
-    {
-        xml.writeStartElement("Sample");
-        QString sprintfer;
-        QString navtype = sprintfer.sprintf("0x%04x", sample->u.gps_base.navtype);
-        xml.writeTextElement("NavType", navtype);
-        if (sample->u.gps_base.navvalid == 0x0000) {
-            xml.writeTextElement("NavValid", "validated");
-        }
-        else {
-            xml.writeTextElement("NavValid", "not validated");
-        }
-        QString navTypeExplanation;
 
-        if ((sample->u.gps_base.navtype & 0x0007) == 0) {
-            navTypeExplanation = "no fix";
-        }
-        else {
-            switch ((sample->u.gps_base.navtype & 0x0007)) {
-            case 0x01:
-                navTypeExplanation = "1-SV KF solution";
-                break;
-            case 0x02:
-                navTypeExplanation = "2-SV KF solution";
-                break;
-            case 0x03:
-                navTypeExplanation = "3-SV KF solution";
-                break;
-            case 0x04:
-                navTypeExplanation = "4 or more SV KF solution";
-                break;
-            case 0x05:
-                navTypeExplanation = "2-D least-squares solution";
-                break;
-            case 0x06:
-                navTypeExplanation = "3-D least-squares solution";
-                break;
-            case 0x07:
-                navTypeExplanation = "DR solution (see bits 8, 14-15)";
-                break;
-            }
-            if ((sample->u.gps_base.navtype & 0x0008)) {
-                navTypeExplanation += ", trickle";
-            }
-            switch ((sample->u.gps_base.navtype & 0x0030) >> 4) {
-            case 0x01:
-                navTypeExplanation += ", KF alti hold";
-                break;
-            case 0x02:
-                navTypeExplanation += ", user alti hold";
-                break;
-            case 0x03:
-                navTypeExplanation += ", always alti hold";
-                break;
-            }
-            if ((sample->u.gps_base.navtype & 0x0040)) {
-                navTypeExplanation += ", DOP exceeded";
-            }
-            if ((sample->u.gps_base.navtype & 0x0080)) {
-                navTypeExplanation += ", DGPS corr";
-            }
-            if ((sample->u.gps_base.navtype & 0x0200)) {
-                navTypeExplanation += ", overdetermined";
-            }
-            if ((sample->u.gps_base.navtype & 0x0400)) {
-                navTypeExplanation += ", velo DR timeout";
-            }
-            if ((sample->u.gps_base.navtype & 0x1000)) {
-                navTypeExplanation += ", invalid velocity";
-            }
-            if ((sample->u.gps_base.navtype & 0x2000)) {
-                navTypeExplanation += ", alti hold disabled";
-            }
-        }
-        xml.writeTextElement("NavTypeExplanation", navTypeExplanation);
-        xml.writeStartElement("Satellites");
-        ambit_log_gps_satellite_t *satellite;
-        for (i=0; i<sample->u.gps_base.satellites_count; i++) {
-            xml.writeStartElement("Satellite");
-            satellite = &sample->u.gps_base.satellites[i];
-            xml.writeTextElement("SV", QString("%1").arg(satellite->sv));
-            xml.writeTextElement("SNR", QString("%1").arg(satellite->snr));
-            //! TODO: What parts of state should be used to determine this!?
-            if (satellite->state & 0x20) {
-                xml.writeTextElement("CodeLocked", "true");
-            }
-            else {
-                xml.writeTextElement("CodeLocked", "false");
-            }
-            if (satellite->state & 0x80) {
-                xml.writeTextElement("Ephemeris", "true");
-            }
-            else {
-                xml.writeTextElement("Ephemeris", "false");
-            }
-            QString stateText;
-            if (satellite->state == 0) {
-                stateText = "State 0";
-            }
-            else {
-                stateText = sprintfer.sprintf("State 0x%02x", satellite->state);
-            }
-            xml.writeTextElement("Custom", stateText);
-            xml.writeEndElement();
-        }
-        xml.writeEndElement();
-        xml.writeTextElement("GPSAltitude", QString::number((double)sample->u.gps_base.altitude/100.0, 'g', 16));
-        xml.writeTextElement("GPSHeading", QString::number((double)sample->u.gps_base.heading*M_PI/180/100, 'g', 16));
-        xml.writeTextElement("GPSSpeed", QString::number((double)sample->u.gps_base.speed/100.0, 'g', 16));
-        xml.writeTextElement("GpsHDOP", QString::number((double)sample->u.gps_base.hdop/5.0, 'g', 16));
-        xml.writeTextElement("NumberOfSatellites", QString("%1").arg(sample->u.gps_base.noofsatellites));
-        xml.writeTextElement("Latitude", QString::number((double)sample->u.gps_base.latitude*M_PI/180/10000000, 'g', 16)); // degrees -> radians
-        xml.writeTextElement("Longitude", QString::number((double)sample->u.gps_base.longitude*M_PI/180/10000000, 'g', 16)); // degrees -> radians
-        xml.writeTextElement("EHPE", QString::number((double)sample->u.gps_base.ehpe/100.0, 'g', 16));
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        QDateTime dateTime(QDate(sample->u.gps_base.utc_base_time.year, sample->u.gps_base.utc_base_time.month, sample->u.gps_base.utc_base_time.day), QTime(sample->u.gps_base.utc_base_time.hour, sample->u.gps_base.utc_base_time.minute, 0).addMSecs(sample->u.gps_base.utc_base_time.msec));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeTextElement("SampleType", "gps-base");
-        xml.writeEndElement();
-        break;
-    }
-    case ambit_log_sample_type_gps_small:
-    {
-        xml.writeStartElement("Sample");
-        xml.writeTextElement("NumberOfSatellites", QString("%1").arg(sample->u.gps_small.noofsatellites));
-        xml.writeTextElement("Latitude", QString::number((double)sample->u.gps_small.latitude*M_PI/180/10000000, 'g', 16));
-        xml.writeTextElement("Longitude", QString::number((double)sample->u.gps_small.longitude*M_PI/180/10000000, 'g', 16));
-        xml.writeTextElement("EHPE", QString::number((double)sample->u.gps_small.ehpe/100.0, 'g', 16));
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        // "Mimic" moveslinks strange second handling
-        int seconds = sample->utc_time.msec/1000;
-        if ((sample->utc_time.msec % 1000) >= 100) {
-            seconds++;
-        }
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addSecs(seconds));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeTextElement("SampleType", "gps-small");
-        xml.writeEndElement();
-        break;
-    }
-    case ambit_log_sample_type_gps_tiny:
-    {
-        xml.writeStartElement("Sample");
-        xml.writeTextElement("Latitude", QString::number((double)sample->u.gps_tiny.latitude*M_PI/180/10000000, 'g', 16));
-        xml.writeTextElement("Longitude", QString::number((double)sample->u.gps_tiny.longitude*M_PI/180/10000000, 'g', 16));
-        xml.writeTextElement("EHPE", QString::number((double)sample->u.gps_tiny.ehpe/100.0, 'g', 16));
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        // "Mimic" moveslinks strange second handling
-        int seconds = sample->utc_time.msec/1000;
-        if ((sample->utc_time.msec % 1000) >= 100) {
-            seconds++;
-        }
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addSecs(seconds));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeTextElement("SampleType", "gps-tiny");
-        xml.writeEndElement();
-        break;
-    }
-    case ambit_log_sample_type_time:
-    {
-        //! TODO: Unknown representation!
-        break;
+        firmwareCheckReply->deleteLater();
+        firmwareCheckReply = NULL;
     }
-    case ambit_log_sample_type_activity:
-    {
-        xml.writeStartElement("Sample");
-        xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-        xml.writeStartElement("Events");
-        xml.writeStartElement("Activity");
-        xml.writeTextElement("CustomModeId", QString("%1").arg(sample->u.activity.custommode));
-        xml.writeStartElement("Type");
-        typename_lookup_entry_t *name_lookup;
-        for (name_lookup = &sampleActivityNames[0]; name_lookup->XMLName != ""; name_lookup++) {
-            if (name_lookup->id == sample->u.activity.activitytype) {
-                xml.writeCharacters(QString(name_lookup->XMLName));
-                break;
-            }
-        }
-        xml.writeEndElement();
-        xml.writeEndElement();
-        xml.writeEndElement();
-        QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addMSecs(sample->utc_time.msec));
-        dateTime.setTimeSpec(Qt::UTC);
-        xml.writeTextElement("UTC", dateTimeString(dateTime));
-        xml.writeEndElement();
-        break;
+}
+
+void MovesCount::recheckAuthorization()
+{
+    getDeviceSettings();
+}
+
+MovesCount::MovesCount()
+{
+    this->manager = new QNetworkAccessManager(this);
+}
+
+QNetworkReply *MovesCount::asyncGET(QString path, QString additionalHeaders, bool auth)
+{
+    QNetworkRequest req;
+    QString url = this->baseAddress + path + "?appkey=" + this->appkey;
+
+    if (auth) {
+        url += "&userkey=" + this->userkey + "&email=" + this->username;
     }
-    case ambit_log_sample_type_position:
-        //! TODO: Unknown representation!
-        break;
-    default:
-        break;
+    if (additionalHeaders.length() > 0) {
+        url += "&" + additionalHeaders;
     }
 
-    return true;
+    req.setRawHeader("User-Agent", "ArREST v1.0");
+    req.setUrl(QUrl(url));
+
+    return this->manager->get(req);
 }
 
-bool MovesCount::XMLWriter::writePeriodicSample(ambit_log_sample_t *sample)
+QNetworkReply *MovesCount::syncGET(QString path, QString additionalHeaders, bool auth)
 {
-    int i;
-    ambit_log_sample_periodic_value_t *value;
-
-    for (i=0; i<sample->u.periodic.value_count; i++) {
-        value = &sample->u.periodic.values[i];
-
-        switch(value->type) {
-        case ambit_log_sample_periodic_type_latitude:
-            xml.writeTextElement("Latitude", QString::number((double)value->u.latitude*M_PI/180/10000000, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_longitude:
-            xml.writeTextElement("Longitude", QString::number((double)value->u.longitude*M_PI/180/10000000, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_distance:
-            xml.writeTextElement("Distance", QString("%1").arg(value->u.distance));
-            break;
-        case ambit_log_sample_periodic_type_speed:
-            xml.writeTextElement("Speed", QString::number((double)value->u.speed/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_hr:
-            xml.writeTextElement("HR", QString::number((double)value->u.hr/logEntry->personalSettings->rest_hr, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_time:
-            xml.writeTextElement("Time", QString::number((double)value->u.time/1000.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_gpsspeed:
-            xml.writeTextElement("GPSSpeed", QString::number((double)value->u.gpsspeed/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_wristaccspeed:
-            xml.writeTextElement("WristAccSpeed", QString::number((double)value->u.wristaccspeed/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_bikepodspeed:
-            xml.writeTextElement("BikePodSpeed", QString::number((double)value->u.bikepodspeed/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_ehpe:
-            xml.writeTextElement("EHPE", QString("%1").arg(value->u.ehpe));
-            break;
-        case ambit_log_sample_periodic_type_evpe:
-            xml.writeTextElement("EVPE", QString("%1").arg(value->u.evpe));
-            break;
-        case ambit_log_sample_periodic_type_altitude:
-            xml.writeTextElement("Altitude", QString("%1").arg(value->u.altitude));
-            break;
-        case ambit_log_sample_periodic_type_abspressure:
-            xml.writeTextElement("AbsPressure", QString("%1").arg(value->u.abspressure*10));
-            break;
-        case ambit_log_sample_periodic_type_energy:
-            xml.writeTextElement("EnergyConsumption", QString::number((double)value->u.energy*6.978, 'g', 16)); // WTF is this unit!?
-            break;
-        case ambit_log_sample_periodic_type_temperature:
-            xml.writeTextElement("Temperature", QString::number((double)value->u.temperature/10.0 + 273.15, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_charge:
-            xml.writeTextElement("BatteryCharge", QString::number((double)value->u.charge/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_gpsaltitude:
-            xml.writeTextElement("GPSAltitude", QString("%1").arg(value->u.gpsaltitude));
-            break;
-        case ambit_log_sample_periodic_type_gpsheading:
-            xml.writeTextElement("GPSHeading", QString::number((double)value->u.gpsheading*M_PI/180/10000000, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_gpshdop:
-            xml.writeTextElement("GpsHDOP", QString("%1").arg(value->u.gpshdop));
-            break;
-        case ambit_log_sample_periodic_type_gpsvdop:
-            xml.writeTextElement("GpsVDOP", QString("%1").arg(value->u.gpsvdop));
-            break;
-        case ambit_log_sample_periodic_type_wristcadence:
-            xml.writeTextElement("WristCadence", QString("%1").arg(value->u.wristcadence));
-            break;
-        case ambit_log_sample_periodic_type_snr:
-        {
-            QString snr = QString("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x")
-                                           .arg(value->u.snr[0])
-                                           .arg(value->u.snr[1])
-                                           .arg(value->u.snr[2])
-                                           .arg(value->u.snr[3])
-                                           .arg(value->u.snr[4])
-                                           .arg(value->u.snr[5])
-                                           .arg(value->u.snr[6])
-                                           .arg(value->u.snr[7])
-                                           .arg(value->u.snr[8])
-                                           .arg(value->u.snr[9])
-                                           .arg(value->u.snr[10])
-                                           .arg(value->u.snr[11])
-                                           .arg(value->u.snr[12])
-                                           .arg(value->u.snr[13])
-                                           .arg(value->u.snr[14])
-                                           .arg(value->u.snr[15]);
-            xml.writeTextElement("SNR", snr);
-            break;
-        }
-        case ambit_log_sample_periodic_type_noofsatellites:
-            xml.writeTextElement("NumberOfSatellites", QString("%1").arg(value->u.noofsatellites));
-            break;
-        case ambit_log_sample_periodic_type_sealevelpressure:
-            xml.writeTextElement("SeaLevelPressure", QString("%1").arg(value->u.sealevelpressure*10));
-            break;
-        case ambit_log_sample_periodic_type_verticalspeed:
-            xml.writeTextElement("VerticalSpeed", QString::number((double)value->u.verticalspeed/100.0, 'g', 16));
-            break;
-        case ambit_log_sample_periodic_type_cadence:
-            xml.writeTextElement("Cadence", QString("%1").arg(value->u.cadence));
-            break;
-        case ambit_log_sample_periodic_type_bikepower:
-            xml.writeTextElement("BikePower", QString("%1").arg(value->u.bikepower));
-            break;
-        case ambit_log_sample_periodic_type_swimingstrokecnt:
-            xml.writeTextElement("SwimmingStrokeCount", QString("%1").arg(value->u.swimingstrokecnt));
-            break;
-        case ambit_log_sample_periodic_type_ruleoutput1:
-            xml.writeTextElement("RuleOutput1", QString("%1").arg(value->u.ruleoutput1));
-            break;
-        case ambit_log_sample_periodic_type_ruleoutput2:
-            xml.writeTextElement("RuleOutput2", QString("%1").arg(value->u.ruleoutput2));
-            break;
-        case ambit_log_sample_periodic_type_ruleoutput3:
-            xml.writeTextElement("RuleOutput3", QString("%1").arg(value->u.ruleoutput3));
-            break;
-        case ambit_log_sample_periodic_type_ruleoutput4:
-            xml.writeTextElement("RuleOutput4", QString("%1").arg(value->u.ruleoutput4));
-            break;
-        case ambit_log_sample_periodic_type_ruleoutput5:
-            xml.writeTextElement("RuleOutput5", QString("%1").arg(value->u.ruleoutput5));
-            break;
-        }
-    }
+    QNetworkReply *reply;
 
-    xml.writeTextElement("Time", QString::number((double)sample->time/1000.0, 'g', 16));
-    xml.writeTextElement("SampleType", "periodic");
-    QDateTime dateTime(QDate(sample->utc_time.year, sample->utc_time.month, sample->utc_time.day), QTime(sample->utc_time.hour, sample->utc_time.minute, 0).addMSecs(sample->utc_time.msec));
-    dateTime.setTimeSpec(Qt::UTC);
-    xml.writeTextElement("UTC", dateTimeString(dateTime));
+    reply = asyncGET(path, additionalHeaders, auth);
+    QEventLoop loop;
+    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
+    loop.exec();
 
-    return true;
+    return reply;
 }
 
-QString MovesCount::XMLWriter::dateTimeString(QDateTime &dateTime)
+QNetworkReply *MovesCount::asyncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth)
 {
-    if (dateTime.time().msec() != 0) {
-        return dateTime.toString("yyyy-MM-ddThh:mm:ss.zzzZ");
+    QNetworkRequest req;
+    QString url = this->baseAddress + path + "?appkey=" + this->appkey;
+
+    if (auth) {
+        url += "&userkey=" + this->userkey + "&email=" + this->username;
     }
-    else {
-        return dateTime.toString("yyyy-MM-ddThh:mm:ssZ");
+    if (additionalHeaders.length() > 0) {
+        url += "&" + additionalHeaders;
     }
+
+    req.setRawHeader("User-Agent", "ArREST v1.0");
+    req.setRawHeader("Content-Type", "application/json");
+    req.setUrl(QUrl(url));
+
+    return this->manager->post(req, postData);
 }
 
-QList<int> MovesCount::XMLWriter::rearrangeSamples()
+QNetworkReply *MovesCount::syncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth)
 {
-    QList<int> sampleList;
-    u_int32_t index = 0;
-    u_int32_t lastMatching = 0;
-
-    while (index < logEntry->logEntry->samples_count) {
-        // First find all entries with the same time
-        lastMatching = index;
-        while (lastMatching + 1 < logEntry->logEntry->samples_count &&
-               logEntry->logEntry->samples[index].time == logEntry->logEntry->samples[lastMatching+1].time) {
-            lastMatching++;
-        }
+    QNetworkReply *reply;
 
-        // Put start/stop at top
-        for (u_int32_t i=index; i<=lastMatching; i++) {
-            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_lapinfo &&
-                (logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1e ||
-                 logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1f)) {
-                sampleList.append(i);
-            }
-        }
-
-        // Then any gps-entries
-        for (u_int32_t i=index; i<=lastMatching; i++) {
-            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_base ||
-                logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_small ||
-                logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_tiny) {
-                sampleList.append(i);
-            }
-        }
+    reply = asyncPOST(path, additionalHeaders, postData, auth);
+    QEventLoop loop;
+    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
+    loop.exec();
 
-        // Then periodic samples
-        for (u_int32_t i=index; i<=lastMatching; i++) {
-            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_periodic) {
-                sampleList.append(i);
-            }
-        }
+    return reply;
+}
 
-        // Then any other!
-        for (u_int32_t i=index; i<=lastMatching; i++) {
-            if (logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_base &&
-                logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_small &&
-                logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_tiny &&
-                logEntry->logEntry->samples[i].type != ambit_log_sample_type_periodic &&
-                !(logEntry->logEntry->samples[i].type == ambit_log_sample_type_lapinfo &&
-                    (logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1e ||
-                     logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1f))) {
-                sampleList.append(i);
-            }
-        }
 
-        index = lastMatching + 1;
+bool MovesCount::checkReplyAuthorization(QNetworkReply *reply)
+{
+    if (reply->error() == QNetworkReply::AuthenticationRequiredError) {
+        authorized = false;
+        emit movesCountAuth(false);
+        QTimer::singleShot(AUTH_CHECK_TIMEOUT, this, SLOT(recheckAuthorization()));
+    }
+    else if(reply->error() == QNetworkReply::NoError) {
+        authorized = true;
+        emit movesCountAuth(true);
     }
 
-    return sampleList;
+    return authorized;
 }
diff --git a/src/openambit/movescount.h b/src/openambit/movescount.h
index 626c8a5..ebc410c 100644
--- a/src/openambit/movescount.h
+++ b/src/openambit/movescount.h
@@ -23,44 +23,71 @@
 #define MOVESCOUNT_H
 
 #include <QObject>
-#include <QList>
-#include <QIODevice>
-#include <QXmlStreamWriter>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+#include <QTimer>
+#include <libambit.h>
 #include "logentry.h"
+#include "movescountjson.h"
 
 class MovesCount : public QObject
 {
     Q_OBJECT
 public:
-    explicit MovesCount(QObject *parent = 0);
-    
+    static MovesCount* instance();
+
+    void setBaseAddress(QString baseAddress);
+    void setAppkey(QString appkey);
+    void setUsername(QString username);
+    void setUserkey(QString userkey);
+    QString generateUserkey();
+    void setDevice(ambit_device_info_t *device_info);
+
+    bool isAuthorized();
+    int getOrbitalData(u_int8_t **data);
+    int getPersonalSettings(ambit_personal_settings_t *settings);
+    int getDeviceSettings();
 signals:
+    void newerFirmwareExists(QByteArray fw_version);
+    void movesCountAuth(bool authorized);
+    void logMoveID(QString device, QDateTime time, QString moveID);
     
 public slots:
-    void sendLog(LogEntry *logEntry);
+    void checkLatestFirmwareVersion();
+    void writePersonalSettings(ambit_personal_settings_t *settings);
+    void writeLog(LogEntry *logEntry);
+
+private slots:
+    void firmwareReplyFinished();
+    void recheckAuthorization();
 
 private:
-    QString logEntryPath(LogEntry *logEntry);
+    MovesCount();
+    MovesCount(const MovesCount &);
+    MovesCount& operator=(const MovesCount &);
+
+    QNetworkReply *asyncGET(QString path, QString additionalHeaders, bool auth);
+    QNetworkReply *syncGET(QString path, QString additionalHeaders, bool auth);
+
+    QNetworkReply *asyncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth);
+    QNetworkReply *syncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth);
 
-    QString storagePath;
+    bool checkReplyAuthorization(QNetworkReply *reply);
 
-    class XMLWriter
-    {
-    public:
-        XMLWriter(LogEntry *logEntry);
-        bool write(QIODevice *device);
+    bool authorized = false;
 
-    private:
-        bool writeLogEntry();
-        bool writeLogSample(ambit_log_sample_t *sample, QList<quint16> *ibis);
-        bool writePeriodicSample(ambit_log_sample_t *sample);
+    QString baseAddress;
+    QString appkey;
+    QString username;
+    QString userkey;
+    QString model;
+    QString serial;
+    ambit_device_info_t device_info;
 
-        QString dateTimeString(QDateTime &dateTime);
-        QList<int> rearrangeSamples();
+    QNetworkAccessManager *manager;
+    QNetworkReply *firmwareCheckReply = NULL;
 
-        LogEntry *logEntry;
-        QXmlStreamWriter xml;
-    };
+    MovesCountJSON jsonParser;
 };
 
 #endif // MOVESCOUNT_H
diff --git a/src/openambit/movescountjson.cpp b/src/openambit/movescountjson.cpp
new file mode 100644
index 0000000..b67ae10
--- /dev/null
+++ b/src/openambit/movescountjson.cpp
@@ -0,0 +1,502 @@
+/*
+ * (C) Copyright 2013 Emil Ljungdahl
+ *
+ * This file is part of Openambit.
+ *
+ * Openambit 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributors:
+ *
+ */
+#include "movescountjson.h"
+
+#include <QRegExp>
+#include <QVariantMap>
+#include <QVariantList>
+#include <qjson/parser.h>
+#include <qjson/serializer.h>
+#include <zlib.h>
+#include <math.h>
+
+MovesCountJSON::MovesCountJSON(QObject *parent) :
+    QObject(parent)
+{
+}
+
+int MovesCountJSON::parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[4])
+{
+    QJson::Parser parser;
+    bool ok;
+    QRegExp rx("([0-9]+)\\.([0-9]+)\\.([0-9]+)");
+
+    if (input.length() <= 0) {
+        return -1;
+    }
+
+    QVariantMap result = parser.parse(input, &ok).toMap();
+
+    if (ok && result["LatestFirmwareVersion"].toString().length() > 0) {
+        if (rx.indexIn(result["LatestFirmwareVersion"].toString()) >= 0) {
+            fw_version[0] = rx.cap(1).toInt();
+            fw_version[1] = rx.cap(2).toInt();
+            fw_version[2] = rx.cap(3).toInt() & 0xff;
+            fw_version[3] = (rx.cap(3).toInt() >> 8) & 0xff;
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+int MovesCountJSON::parseLogReply(QByteArray &input, QString &moveId)
+{
+    QJson::Parser parser;
+    bool ok;
+
+    if (input.length() <= 0) {
+        return -1;
+    }
+
+    QVariantMap result = parser.parse(input, &ok).toMap();
+
+    if (ok && result["MoveID"].toString().length() > 0 && result["MoveID"].toString() != "0") {
+        moveId = result["MoveID"].toString();
+        return 0;
+    }
+
+    return -1;
+}
+
+int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
+{
+    QJson::Serializer serializer;
+    bool ok;
+    QVariantMap content;
+    QVariantList IBIContent;
+    QVariantList marksContent;
+    QVariantList periodicSamplesContent;
+    QVariantList GPSSamplesContent;
+    QByteArray uncompressedData, compressedData;
+    ambit_log_sample_t *sample;
+
+    QDateTime localBaseTime(QDate(logEntry->logEntry->header.date_time.year,
+                                  logEntry->logEntry->header.date_time.month,
+                                  logEntry->logEntry->header.date_time.day),
+                            QTime(logEntry->logEntry->header.date_time.hour,
+                                  logEntry->logEntry->header.date_time.minute, 0).addMSecs(logEntry->logEntry->header.date_time.msec));
+
+    // Loop through content
+    QList<int> order = rearrangeSamples(logEntry);
+    foreach(int index, order) {
+        sample = &logEntry->logEntry->samples[index];
+
+        switch(sample->type) {
+        case ambit_log_sample_type_periodic:
+        {
+            QVariantMap tmpMap;
+            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            writePeriodicSample(sample, tmpMap);
+            periodicSamplesContent.append(tmpMap);
+            break;
+        }
+        case ambit_log_sample_type_ibi:
+            for (int j=0; j<sample->u.ibi.ibi_count; j++) {
+                IBIContent.append(sample->u.ibi.ibi[j]);
+            }
+            break;
+        case ambit_log_sample_type_gps_base:
+        {
+            QVariantMap tmpMap;
+            tmpMap.insert("Altitude", (double)sample->u.gps_base.altitude/100.0);
+            tmpMap.insert("EHPE", (double)sample->u.gps_base.ehpe/100.0);
+            tmpMap.insert("Latitude", (double)sample->u.gps_base.latitude/10000000);
+            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            tmpMap.insert("Longitude", (double)sample->u.gps_base.longitude/10000000);
+            GPSSamplesContent.append(tmpMap);
+            break;
+        }
+        case ambit_log_sample_type_gps_small:
+        {
+            QVariantMap tmpMap;
+            tmpMap.insert("Altitude", (double)0);
+            tmpMap.insert("EHPE", (double)sample->u.gps_small.ehpe/100.0);
+            tmpMap.insert("Latitude", (double)sample->u.gps_small.latitude/10000000);
+            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            tmpMap.insert("Longitude", (double)sample->u.gps_small.longitude/10000000);
+            GPSSamplesContent.append(tmpMap);
+            break;
+        }
+        case ambit_log_sample_type_gps_tiny:
+        {
+            QVariantMap tmpMap;
+            tmpMap.insert("Altitude", (double)0);
+            tmpMap.insert("EHPE", (double)sample->u.gps_tiny.ehpe/100.0);
+            tmpMap.insert("Latitude", (double)sample->u.gps_tiny.latitude/10000000);
+            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            tmpMap.insert("Longitude", (double)sample->u.gps_tiny.longitude/10000000);
+            GPSSamplesContent.append(tmpMap);
+            break;
+        }
+        case ambit_log_sample_type_lapinfo:
+            switch (sample->u.lapinfo.event_type) {
+            case 0x01: /* manual = 0 */
+            case 0x16: /* interval = 0 */
+            {
+                QVariantMap tmpMap;
+                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                tmpMap.insert("Type", 0);
+                marksContent.append(tmpMap);
+                break;
+            }
+            case 0x1f: /* start = 1 */
+            {
+                QVariantMap tmpMap;
+                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                if (sample->time > 0) {
+                    tmpMap.insert("Type", 1);
+                }
+                marksContent.append(tmpMap);
+                break;
+            }
+            case 0x1e: /* pause = 2 */
+            {
+                QVariantMap tmpMap;
+                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                tmpMap.insert("Type", 2);
+                marksContent.append(tmpMap);
+                break;
+            }
+            case 0x14: /* high interval = 3 */
+            case 0x15: /* low interval = 3 */
+            {
+                QVariantMap tmpMap;
+                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                tmpMap.insert("Type", 3);
+                marksContent.append(tmpMap);
+                break;
+            }
+            };
+            break;
+        case ambit_log_sample_type_activity:
+        {
+            QVariantMap tmpMap;
+            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            tmpMap.insert("NextActivityID", sample->u.activity.activitytype);
+            tmpMap.insert("Type", 8);
+            marksContent.append(tmpMap);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    serializer.setDoublePrecision(16);
+    serializer.setIndentMode(QJson::IndentCompact);
+
+    content.insert("ActivityID", logEntry->logEntry->header.activity_type);
+    content.insert("AscentAltitude", (double)logEntry->logEntry->header.ascent);
+    content.insert("AscentTime", (double)logEntry->logEntry->header.ascent_time/1000.0);
+    content.insert("AvgCadence", QVariant::Invalid);
+    content.insert("AvgHR", logEntry->logEntry->header.heartrate_avg);
+    content.insert("AvgSpeed", (double)logEntry->logEntry->header.speed_avg/3600.0);
+    content.insert("DescentAltitude", (double)logEntry->logEntry->header.descent);
+    content.insert("DescentTime", (double)logEntry->logEntry->header.descent_time/1000.0);
+    content.insert("DeviceName", logEntry->deviceInfo->model);
+    content.insert("DeviceSerialNumber", logEntry->deviceInfo->serial);
+    content.insert("Distance", logEntry->logEntry->header.distance);
+    content.insert("Duration", (double)logEntry->logEntry->header.duration/1000.0);
+    content.insert("Energy", logEntry->logEntry->header.energy_consumption);
+    content.insert("FlatTime", QVariant::Invalid);
+    content.insert("HighAltitude", (double)logEntry->logEntry->header.altitude_max);
+    uncompressedData = serializer.serialize(IBIContent);
+    compressData(uncompressedData, compressedData);
+    QVariantMap IBIDataMap;
+    IBIDataMap.insert("CompressedValues", compressedData.toBase64());
+    content.insert("IBIData", IBIDataMap);                        /* compressed */
+    content.insert("LocalStartTime", dateTimeString(localBaseTime));
+    content.insert("LowAltitude", (double)logEntry->logEntry->header.altitude_min);
+    content.insert("Marks", marksContent);
+    content.insert("MaxCadence", QVariant::Invalid);
+    content.insert("MaxSpeed", (double)logEntry->logEntry->header.speed_max/3600.0);
+    content.insert("MaxTemp", (double)logEntry->logEntry->header.temperature_max/10.0);
+    content.insert("MinHR", logEntry->logEntry->header.heartrate_min);
+    content.insert("MinTemp", (double)logEntry->logEntry->header.temperature_min/10.0);
+    content.insert("PeakHR", logEntry->logEntry->header.heartrate_max);
+    content.insert("PeakTrainingEffect", (double)logEntry->logEntry->header.peak_training_effect/10.0);
+    content.insert("RecoveryTime", (double)logEntry->logEntry->header.recovery_time/1000.0);
+    uncompressedData = serializer.serialize(periodicSamplesContent);
+    compressData(uncompressedData, compressedData);
+    QVariantMap periodicSamplesDataMap;
+    periodicSamplesDataMap.insert("CompressedSampleSets", compressedData.toBase64());
+    content.insert("Samples", periodicSamplesDataMap);            /* compressed */
+    content.insert("SerialNumber", QVariant::Invalid);
+    content.insert("StartLatitude", QVariant::Invalid);
+    content.insert("StartLongitude", QVariant::Invalid);
+    uncompressedData = serializer.serialize(GPSSamplesContent);
+    compressData(uncompressedData, compressedData);
+    QVariantMap GPSSamplesDataMap;
+    GPSSamplesDataMap.insert("CompressedTrackPoints", compressedData.toBase64());
+    content.insert("Track", GPSSamplesDataMap);                   /* compressed */
+
+    output = serializer.serialize(content, &ok);
+
+    return (ok ? 0 : -1);
+}
+
+bool MovesCountJSON::writePeriodicSample(ambit_log_sample_t *sample, QVariantMap &output)
+{
+    int i;
+    ambit_log_sample_periodic_value_t *value;
+
+    for (i=0; i<sample->u.periodic.value_count; i++) {
+        value = &sample->u.periodic.values[i];
+
+        switch(value->type) {
+        case ambit_log_sample_periodic_type_latitude:
+            output.insert("Latitude", (double)value->u.latitude/10000000);
+            break;
+        case ambit_log_sample_periodic_type_longitude:
+            output.insert("Longitude", (double)value->u.longitude/10000000);
+            break;
+        case ambit_log_sample_periodic_type_distance:
+            output.insert("Distance", value->u.distance);
+            break;
+        case ambit_log_sample_periodic_type_speed:
+            output.insert("Speed", (double)value->u.speed/100.0);
+            break;
+        case ambit_log_sample_periodic_type_hr:
+            output.insert("HeartRate", value->u.hr);
+            break;
+        case ambit_log_sample_periodic_type_time:
+            output.insert("Time", (double)value->u.time/1000.0);
+            break;
+        case ambit_log_sample_periodic_type_gpsspeed:
+            output.insert("GPSSpeed", (double)value->u.gpsspeed/100.0);
+            break;
+        case ambit_log_sample_periodic_type_wristaccspeed:
+            output.insert("WristAccSpeed", (double)value->u.wristaccspeed/100.0);
+            break;
+        case ambit_log_sample_periodic_type_bikepodspeed:
+            output.insert("BikePodSpeed", (double)value->u.bikepodspeed/100.0);
+            break;
+        case ambit_log_sample_periodic_type_ehpe:
+            output.insert("EHPE", value->u.ehpe);
+            break;
+        case ambit_log_sample_periodic_type_evpe:
+            output.insert("EVPE", value->u.evpe);
+            break;
+        case ambit_log_sample_periodic_type_altitude:
+            output.insert("Altitude", (double)value->u.altitude);
+            break;
+        case ambit_log_sample_periodic_type_abspressure:
+            output.insert("AbsPressure", (int)round((double)value->u.abspressure/10.0));
+            break;
+        case ambit_log_sample_periodic_type_energy:
+            output.insert("EnergyConsumption", (double)value->u.energy/10.0);
+            break;
+        case ambit_log_sample_periodic_type_temperature:
+            output.insert("Temperature", (double)value->u.temperature/10.0);
+            break;
+        case ambit_log_sample_periodic_type_charge:
+            output.insert("BatteryCharge", (double)value->u.charge/100.0);
+            break;
+        case ambit_log_sample_periodic_type_gpsaltitude:
+            output.insert("GPSAltitude", value->u.gpsaltitude);
+            break;
+        case ambit_log_sample_periodic_type_gpsheading:
+            output.insert("GPSHeading", (double)value->u.gpsheading/10000000);
+            break;
+        case ambit_log_sample_periodic_type_gpshdop:
+            output.insert("GpsHDOP", value->u.gpshdop);
+            break;
+        case ambit_log_sample_periodic_type_gpsvdop:
+            output.insert("GpsVDOP", value->u.gpsvdop);
+            break;
+        case ambit_log_sample_periodic_type_wristcadence:
+            output.insert("WristCadence", value->u.wristcadence);
+            break;
+        case ambit_log_sample_periodic_type_snr:
+        {
+            QString snr = QString("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x")
+                                           .arg(value->u.snr[0])
+                                           .arg(value->u.snr[1])
+                                           .arg(value->u.snr[2])
+                                           .arg(value->u.snr[3])
+                                           .arg(value->u.snr[4])
+                                           .arg(value->u.snr[5])
+                                           .arg(value->u.snr[6])
+                                           .arg(value->u.snr[7])
+                                           .arg(value->u.snr[8])
+                                           .arg(value->u.snr[9])
+                                           .arg(value->u.snr[10])
+                                           .arg(value->u.snr[11])
+                                           .arg(value->u.snr[12])
+                                           .arg(value->u.snr[13])
+                                           .arg(value->u.snr[14])
+                                           .arg(value->u.snr[15]);
+            output.insert("SNR", snr);
+            break;
+        }
+        case ambit_log_sample_periodic_type_noofsatellites:
+            output.insert("NumberOfSatellites", value->u.noofsatellites);
+            break;
+        case ambit_log_sample_periodic_type_sealevelpressure:
+            output.insert("SeaLevelPressure", (int)round((double)value->u.sealevelpressure/10.0));
+            break;
+        case ambit_log_sample_periodic_type_verticalspeed:
+            output.insert("VerticalSpeed", (double)value->u.verticalspeed/100.0);
+            break;
+        case ambit_log_sample_periodic_type_cadence:
+            output.insert("Cadence", value->u.cadence);
+            break;
+        case ambit_log_sample_periodic_type_bikepower:
+            output.insert("BikePower", value->u.bikepower);
+            break;
+        case ambit_log_sample_periodic_type_swimingstrokecnt:
+            output.insert("SwimmingStrokeCount", value->u.swimingstrokecnt);
+            break;
+        case ambit_log_sample_periodic_type_ruleoutput1:
+            output.insert("RuleOutput1", value->u.ruleoutput1);
+            break;
+        case ambit_log_sample_periodic_type_ruleoutput2:
+            output.insert("RuleOutput2", value->u.ruleoutput2);
+            break;
+        case ambit_log_sample_periodic_type_ruleoutput3:
+            output.insert("RuleOutput3", value->u.ruleoutput3);
+            break;
+        case ambit_log_sample_periodic_type_ruleoutput4:
+            output.insert("RuleOutput4", value->u.ruleoutput4);
+            break;
+        case ambit_log_sample_periodic_type_ruleoutput5:
+            output.insert("RuleOutput5", value->u.ruleoutput5);
+            break;
+        }
+    }
+
+    return true;
+}
+
+int MovesCountJSON::compressData(QByteArray &content, QByteArray &output)
+{
+    int ret = -1, res, deflate_res;
+    z_stream strm;
+    gz_header header;
+    size_t destLen = compressBound(content.length());
+
+    memset(&strm, 0, sizeof(z_stream));
+    memset(&header, 0, sizeof(gz_header));
+
+    if (destLen > 0) {
+        u_int8_t *buf = (u_int8_t*)malloc(destLen);
+        strm.zalloc = Z_NULL;
+        strm.zfree = Z_NULL;
+        strm.opaque = Z_NULL;
+        header.os = 0x00; // FAT
+
+        res = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
+        res = deflateSetHeader(&strm, &header);
+
+        strm.next_in = reinterpret_cast<uint8_t *>(content.data());
+        strm.avail_in = content.length();
+        strm.next_out = buf;
+        strm.avail_out = destLen;
+
+        res = deflate(&strm, Z_NO_FLUSH);
+
+        if (res == Z_OK) {
+            deflate_res = Z_OK;
+            while (deflate_res == Z_OK) {
+                deflate_res = deflate(&strm, Z_FINISH);
+            }
+
+            if (deflate_res == Z_STREAM_END) {
+                output.setRawData((char*)buf, destLen - strm.avail_out);
+                ret = 0;
+            }
+        }
+
+        deflateEnd(&strm);
+    }
+
+    return ret;
+}
+
+QList<int> MovesCountJSON::rearrangeSamples(LogEntry *logEntry)
+{
+    QList<int> sampleList;
+    u_int32_t index = 0;
+    u_int32_t lastMatching = 0;
+
+    while (index < logEntry->logEntry->samples_count) {
+        // First find all entries with the same time
+        lastMatching = index;
+        while (lastMatching + 1 < logEntry->logEntry->samples_count &&
+               logEntry->logEntry->samples[index].time == logEntry->logEntry->samples[lastMatching+1].time) {
+            lastMatching++;
+        }
+
+        // Put start/stop at top
+        for (u_int32_t i=index; i<=lastMatching; i++) {
+            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_lapinfo &&
+                (logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1e ||
+                 logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1f)) {
+                sampleList.append(i);
+            }
+        }
+
+        // Then any gps-entries
+        for (u_int32_t i=index; i<=lastMatching; i++) {
+            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_base ||
+                logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_small ||
+                logEntry->logEntry->samples[i].type == ambit_log_sample_type_gps_tiny) {
+                sampleList.append(i);
+            }
+        }
+
+        // Then periodic samples
+        for (u_int32_t i=index; i<=lastMatching; i++) {
+            if (logEntry->logEntry->samples[i].type == ambit_log_sample_type_periodic) {
+                sampleList.append(i);
+            }
+        }
+
+        // Then any other!
+        for (u_int32_t i=index; i<=lastMatching; i++) {
+            if (logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_base &&
+                logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_small &&
+                logEntry->logEntry->samples[i].type != ambit_log_sample_type_gps_tiny &&
+                logEntry->logEntry->samples[i].type != ambit_log_sample_type_periodic &&
+                !(logEntry->logEntry->samples[i].type == ambit_log_sample_type_lapinfo &&
+                    (logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1e ||
+                     logEntry->logEntry->samples[i].u.lapinfo.event_type == 0x1f))) {
+                sampleList.append(i);
+            }
+        }
+
+        index = lastMatching + 1;
+    }
+
+    return sampleList;
+}
+
+QString MovesCountJSON::dateTimeString(QDateTime dateTime)
+{
+    if (dateTime.time().msec() != 0) {
+        return dateTime.toString("yyyy-MM-ddThh:mm:ss.zzz");
+    }
+    else {
+        return dateTime.toString("yyyy-MM-ddThh:mm:ss");
+    }
+}
diff --git a/src/openambit/movescount.h b/src/openambit/movescountjson.h
similarity index 53%
copy from src/openambit/movescount.h
copy to src/openambit/movescountjson.h
index 626c8a5..04b6c44 100644
--- a/src/openambit/movescount.h
+++ b/src/openambit/movescountjson.h
@@ -19,48 +19,36 @@
  * Contributors:
  *
  */
-#ifndef MOVESCOUNT_H
-#define MOVESCOUNT_H
+#ifndef MOVESCOUNTJSON_H
+#define MOVESCOUNTJSON_H
 
 #include <QObject>
 #include <QList>
-#include <QIODevice>
-#include <QXmlStreamWriter>
+#include <QVariantMap>
+#include <libambit.h>
 #include "logentry.h"
 
-class MovesCount : public QObject
+class MovesCountJSON : public QObject
 {
     Q_OBJECT
 public:
-    explicit MovesCount(QObject *parent = 0);
+    explicit MovesCountJSON(QObject *parent = 0);
+
+    int parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[4]);
+    int parseLogReply(QByteArray &input, QString &moveId);
+
+    int generateLogData(LogEntry *logEntry, QByteArray &output);
     
 signals:
     
 public slots:
-    void sendLog(LogEntry *logEntry);
 
 private:
-    QString logEntryPath(LogEntry *logEntry);
-
-    QString storagePath;
-
-    class XMLWriter
-    {
-    public:
-        XMLWriter(LogEntry *logEntry);
-        bool write(QIODevice *device);
-
-    private:
-        bool writeLogEntry();
-        bool writeLogSample(ambit_log_sample_t *sample, QList<quint16> *ibis);
-        bool writePeriodicSample(ambit_log_sample_t *sample);
-
-        QString dateTimeString(QDateTime &dateTime);
-        QList<int> rearrangeSamples();
+    bool writePeriodicSample(ambit_log_sample_t *sample, QVariantMap &output);
 
-        LogEntry *logEntry;
-        QXmlStreamWriter xml;
-    };
+    int compressData(QByteArray &content, QByteArray &output);
+    QList<int> rearrangeSamples(LogEntry *logEntry);
+    QString dateTimeString(QDateTime dateTime);
 };
 
-#endif // MOVESCOUNT_H
+#endif // MOVESCOUNTJSON_H
diff --git a/src/openambit/movescount.cpp b/src/openambit/movescountxml.cpp
similarity index 98%
copy from src/openambit/movescount.cpp
copy to src/openambit/movescountxml.cpp
index 37cc842..b23b6e2 100644
--- a/src/openambit/movescount.cpp
+++ b/src/openambit/movescountxml.cpp
@@ -19,7 +19,7 @@
  * Contributors:
  *
  */
-#include "movescount.h"
+#include "movescountxml.h"
 #include <QFile>
 
 #define _USE_MATH_DEFINES
@@ -159,13 +159,13 @@ static typename_lookup_entry_t sampleActivityNames[] = {
     { 0, "" }
 };
 
-MovesCount::MovesCount(QObject *parent) :
+MovesCountXML::MovesCountXML(QObject *parent) :
     QObject(parent)
 {
     storagePath = QString(getenv("HOME")) + "/.openambit/movescount";
 }
 
-void MovesCount::sendLog(LogEntry *logEntry)
+void MovesCountXML::writeLog(LogEntry *logEntry)
 {
     XMLWriter writer(logEntry);
     QFile logfile(logEntryPath(logEntry));
@@ -176,19 +176,19 @@ void MovesCount::sendLog(LogEntry *logEntry)
     logfile.close();
 }
 
-QString MovesCount::logEntryPath(LogEntry *logEntry)
+QString MovesCountXML::logEntryPath(LogEntry *logEntry)
 {
     return storagePath + "/log-" + logEntry->device + "-" + logEntry->time.toString("yyyy-MM-ddThh_mm_ss") + "-0.log";
 }
 
-MovesCount::XMLWriter::XMLWriter(LogEntry *logEntry) :
+MovesCountXML::XMLWriter::XMLWriter(LogEntry *logEntry) :
     logEntry(logEntry)
 {
     xml.setAutoFormatting(true);
     xml.setAutoFormattingIndent(-1);
 }
 
-bool MovesCount::XMLWriter::write(QIODevice *device)
+bool MovesCountXML::XMLWriter::write(QIODevice *device)
 {
     bool ret = true;
 
@@ -201,7 +201,7 @@ bool MovesCount::XMLWriter::write(QIODevice *device)
     return ret;
 }
 
-bool MovesCount::XMLWriter::writeLogEntry()
+bool MovesCountXML::XMLWriter::writeLogEntry()
 {
     u_int32_t i;
 
@@ -285,7 +285,7 @@ bool MovesCount::XMLWriter::writeLogEntry()
     return true;
 }
 
-bool MovesCount::XMLWriter::writeLogSample(ambit_log_sample_t *sample, QList<quint16> *ibis)
+bool MovesCountXML::XMLWriter::writeLogSample(ambit_log_sample_t *sample, QList<quint16> *ibis)
 {
     typename_lookup_entry_t *name_lookup;
     int i;
@@ -598,7 +598,7 @@ bool MovesCount::XMLWriter::writeLogSample(ambit_log_sample_t *sample, QList<qui
     return true;
 }
 
-bool MovesCount::XMLWriter::writePeriodicSample(ambit_log_sample_t *sample)
+bool MovesCountXML::XMLWriter::writePeriodicSample(ambit_log_sample_t *sample)
 {
     int i;
     ambit_log_sample_periodic_value_t *value;
@@ -737,7 +737,7 @@ bool MovesCount::XMLWriter::writePeriodicSample(ambit_log_sample_t *sample)
     return true;
 }
 
-QString MovesCount::XMLWriter::dateTimeString(QDateTime &dateTime)
+QString MovesCountXML::XMLWriter::dateTimeString(QDateTime &dateTime)
 {
     if (dateTime.time().msec() != 0) {
         return dateTime.toString("yyyy-MM-ddThh:mm:ss.zzzZ");
@@ -747,7 +747,7 @@ QString MovesCount::XMLWriter::dateTimeString(QDateTime &dateTime)
     }
 }
 
-QList<int> MovesCount::XMLWriter::rearrangeSamples()
+QList<int> MovesCountXML::XMLWriter::rearrangeSamples()
 {
     QList<int> sampleList;
     u_int32_t index = 0;
diff --git a/src/openambit/movescount.h b/src/openambit/movescountxml.h
similarity index 88%
copy from src/openambit/movescount.h
copy to src/openambit/movescountxml.h
index 626c8a5..717f19d 100644
--- a/src/openambit/movescount.h
+++ b/src/openambit/movescountxml.h
@@ -19,8 +19,8 @@
  * Contributors:
  *
  */
-#ifndef MOVESCOUNT_H
-#define MOVESCOUNT_H
+#ifndef MOVESCOUNTXML_H
+#define MOVESCOUNTXML_H
 
 #include <QObject>
 #include <QList>
@@ -28,16 +28,16 @@
 #include <QXmlStreamWriter>
 #include "logentry.h"
 
-class MovesCount : public QObject
+class MovesCountXML : public QObject
 {
     Q_OBJECT
 public:
-    explicit MovesCount(QObject *parent = 0);
+    explicit MovesCountXML(QObject *parent = 0);
     
 signals:
     
 public slots:
-    void sendLog(LogEntry *logEntry);
+    void writeLog(LogEntry *logEntry);
 
 private:
     QString logEntryPath(LogEntry *logEntry);
@@ -63,4 +63,4 @@ private:
     };
 };
 
-#endif // MOVESCOUNT_H
+#endif // MOVESCOUNTXML_H
diff --git a/src/openambit/openambit.pro b/src/openambit/openambit.pro
index 9f6c5c4..a039ae2 100644
--- a/src/openambit/openambit.pro
+++ b/src/openambit/openambit.pro
@@ -4,7 +4,7 @@
 #
 #-------------------------------------------------
 
-QT       += core gui
+QT       += core gui network
 
 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 
@@ -19,6 +19,8 @@ SOURCES += main.cpp\
     settings.cpp \
     logstore.cpp \
     logentry.cpp \
+    movescountxml.cpp \
+    movescountjson.cpp \
     movescount.cpp
 
 HEADERS  += mainwindow.h \
@@ -27,6 +29,8 @@ HEADERS  += mainwindow.h \
     settings.h \
     logstore.h \
     logentry.h \
+    movescountxml.h \
+    movescountjson.h \
     movescount.h
 
 FORMS    += mainwindow.ui \
@@ -35,4 +39,4 @@ FORMS    += mainwindow.ui \
 INCLUDEPATH += ../libambit
 QMAKE_LIBDIR += ../libambit-build
 
-LIBS += -lambit
+LIBS += -lambit -lqjson -lz
diff --git a/src/openambit/settingsdialog.cpp b/src/openambit/settingsdialog.cpp
index 5d65e4e..583f2b6 100644
--- a/src/openambit/settingsdialog.cpp
+++ b/src/openambit/settingsdialog.cpp
@@ -98,4 +98,6 @@ void SettingsDialog::writeSettings()
     }
     settings.setValue("storeDebugFiles", ui->checkBoxDebugFiles->isChecked());
     settings.endGroup();
+
+    emit settingsSaved();
 }
diff --git a/src/openambit/settingsdialog.h b/src/openambit/settingsdialog.h
index d05d4f0..2f8aae0 100644
--- a/src/openambit/settingsdialog.h
+++ b/src/openambit/settingsdialog.h
@@ -39,6 +39,9 @@ public:
     explicit SettingsDialog(QWidget *parent = 0);
     ~SettingsDialog();
 
+signals:
+    void settingsSaved();
+
 public slots:
     void changePage(QListWidgetItem *current, QListWidgetItem *previous);
     void accept();

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-running/openambit.git



More information about the Pkg-running-devel mailing list