[Pkg-running-devel] [openambit] 16/23: Imported Upstream version 0.3+20151210

Christian Perrier bubulle at moszumanska.debian.org
Sat Jul 1 19:36:28 UTC 2017


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

bubulle pushed a commit to branch master
in repository openambit.

commit f75bc690be18ba298cf234913e532ba38248eaa4
Author: Christian Perrier <bubulle at debian.org>
Date:   Fri Feb 19 19:04:44 2016 +0100

    Imported Upstream version 0.3+20151210
---
 .gitignore                                         |   6 -
 CMakeLists.txt                                     |  45 ++
 Dockerfile                                         | 102 ++++
 README                                             |  91 ---
 README.rst                                         | 166 +++++
 build.sh                                           |  47 +-
 run.sh                                             |  19 +-
 src/example/CMakeLists.txt                         |  16 +-
 src/example/ambitconsole.c                         |  39 +-
 src/example/cmake/Findlibambit.cmake               |   1 +
 src/libambit/CMakeLists.txt                        |  27 +-
 src/libambit/cmake/FindPCAP.cmake                  |  74 +++
 src/libambit/cmake/HidapiDriver.cmake              |  30 +
 src/libambit/crc16.c                               |   2 +-
 src/libambit/crc16.h                               |  31 +
 src/libambit/debian/changelog                      |  11 -
 src/libambit/debian/compat                         |   1 -
 src/libambit/debian/control                        |  26 -
 src/libambit/debian/copyright                      |  39 --
 src/libambit/debian/docs                           |   0
 src/libambit/debian/libambit-dev.dirs              |   1 -
 src/libambit/debian/libambit-dev.install           |   2 -
 src/libambit/debian/libambit0.dirs                 |   1 -
 src/libambit/debian/libambit0.install              |   1 -
 src/libambit/debian/rules                          |  13 -
 src/libambit/debian/source/format                  |   1 -
 src/libambit/debug.c                               |   3 +-
 src/libambit/debug.h                               |  52 ++
 src/libambit/device_driver.h                       |  45 ++
 src/libambit/device_driver_ambit.c                 | 299 +++++++++
 src/libambit/device_driver_ambit3.c                | 459 ++++++++++++++
 src/libambit/device_driver_common.c                | 127 ++++
 src/libambit/device_driver_common.h                |  36 ++
 src/libambit/device_support.c                      | 105 ++++
 src/libambit/device_support.h                      |  39 ++
 src/libambit/{ => hidapi}/hid-libusb.c             |   0
 src/libambit/{hid.c => hidapi/hid-linux.c}         |   0
 src/libambit/hidapi/hid-pcapsimulate.c             | 442 ++++++++++++++
 src/libambit/libambit.c                            | 672 +++++++++------------
 src/libambit/libambit.h                            |  99 ++-
 src/libambit/libambit.rules                        |  30 +
 src/libambit/libambit_int.h                        | 122 +---
 src/libambit/personal.c                            |  12 +-
 src/libambit/personal.h                            |  31 +
 src/libambit/pmem20.c                              | 569 +++++++++++------
 src/libambit/pmem20.h                              |  60 ++
 src/libambit/protocol.c                            |   8 +-
 src/libambit/protocol.h                            |  63 ++
 src/libambit/sbem0102.c                            | 249 ++++++++
 src/libambit/sbem0102.h                            | 173 ++++++
 src/libambit/sha256.c                              | 176 ++++++
 src/libambit/sha256.h                              |  42 ++
 src/libambit/utils.c                               | 205 +++++++
 src/libambit/utils.h                               |  94 +++
 src/movescount/CMakeLists.txt                      |  87 +++
 src/movescount/deviceinfo.cpp                      |  42 ++
 .../logentry.h => movescount/deviceinfo.h}         |  38 +-
 src/{openambit => movescount}/logentry.cpp         |  52 +-
 src/{openambit => movescount}/logentry.h           |   5 +-
 src/{openambit => movescount}/logstore.cpp         | 254 ++++++--
 src/{openambit => movescount}/logstore.h           |   9 +-
 src/{openambit => }/movescount/movescount.cpp      |  33 +-
 src/{openambit => }/movescount/movescount.h        |   9 +-
 src/{openambit => }/movescount/movescountjson.cpp  | 197 +++++-
 src/{openambit => }/movescount/movescountjson.h    |   4 +-
 .../movescount/movescountlogchecker.cpp            |   0
 .../movescount/movescountlogchecker.h              |   0
 .../movescount/movescountlogdirentry.cpp           |   0
 .../movescount/movescountlogdirentry.h             |   0
 src/{openambit => }/movescount/movescountxml.cpp   |   2 +-
 src/{openambit => }/movescount/movescountxml.h     |   0
 src/openambit/CMakeLists.txt                       |  79 ++-
 src/openambit/cmake/FindMovescount.cmake           |  29 +
 src/openambit/cmake/Findlibambit.cmake             |  18 +-
 src/openambit/debian/changelog                     |  11 -
 src/openambit/debian/compat                        |   1 -
 src/openambit/debian/control                       |  17 -
 src/openambit/debian/copyright                     |  39 --
 src/openambit/debian/docs                          |   0
 src/openambit/debian/rules                         |  13 -
 src/openambit/debian/source/format                 |   1 -
 src/openambit/deployment/99-suunto-ambit.rules     |  22 -
 src/openambit/deployment/openambit.desktop         |   4 +-
 src/openambit/devicemanager.cpp                    |  18 +-
 src/openambit/devicemanager.h                      |  10 +-
 src/openambit/logview.cpp                          |  54 ++
 src/openambit/logview.h                            |  26 +
 src/openambit/main.cpp                             |  68 +++
 src/openambit/mainwindow.cpp                       |  45 +-
 src/openambit/mainwindow.h                         |   7 +-
 src/openambit/mainwindow.ui                        |   2 +-
 src/openambit/movescount/CMakeLists.txt            |  19 -
 src/openambit/movescount/include.pri               |   9 -
 src/openambit/settingsdialog.cpp                   |   2 +
 src/openambit/settingsdialog.ui                    |   7 +
 src/openambit/signalhandler.cpp                    | 172 ++++++
 src/openambit/signalhandler.h                      |  63 ++
 src/openambit/translations/openambit_de.ts         | 336 +++++++++++
 src/openambit/translations/openambit_fr.ts         | 327 ++++++++++
 src/openambit/translations/openambit_it.ts         | 336 +++++++++++
 src/openambit/translations/openambit_ja.ts         | 305 ++++++++++
 src/openambit/translations/openambit_nl.ts         | 305 ++++++++++
 src/openambit/translations/openambit_pl.ts         | 336 +++++++++++
 src/openambit/translations/openambit_sv.ts         | 325 ++++++++++
 tools/movescountXmlDiff.pl                         | 171 +++---
 tools/openambit2gpx.py                             |  16 +-
 wireshark_dissector/CMakeLists.txt                 |  13 +-
 wireshark_dissector/ambit-dissector.c              | 228 ++++++-
 wireshark_dissector/cmake/FindWireshark.cmake      |   2 +-
 .../cmake/UseMakeDissectorReg.cmake                |   6 +-
 110 files changed, 7752 insertions(+), 1426 deletions(-)

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 44bdc73..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ignore build directories
-*build*/
-
-# Ignore temporary and user files
-*~
-*.user
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..466186f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,45 @@
+#  CMakeLists.txt -- Openambit top-level build specification
+#  Copyright (C) 2015 Olaf Meeuwissen
+#
+#  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/>.
+
+
+cmake_minimum_required(VERSION 3.0)
+
+project(Openambit
+  LANGUAGES NONE)
+
+add_subdirectory(src/libambit)
+add_subdirectory(src/movescount)
+add_subdirectory(src/openambit)
+
+if (NOT ${LIBAMBIT_FOUND})
+  add_dependencies(movescount ambit)
+  add_dependencies(openambit ambit)
+endif ()
+if (NOT ${MOVESCOUNT_FOUND})
+  add_dependencies(openambit movescount)
+endif ()
+
+if (BUILD_EXTRAS)
+  add_subdirectory(src/example)
+  add_subdirectory(wireshark_dissector)
+
+  if (NOT ${LIBAMBIT_FOUND})
+    add_dependencies(ambitconsole ambit)
+  endif ()
+
+endif ()
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..3c7aa2e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,102 @@
+#  Dockerfile -- to build the sources on a well-known platform
+#  Copyright (C) 2014, 2015  Olaf Meeuwissen
+#
+#  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.
+#
+#    Openambit 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 Openambit.  If not, see https://www.gnu.org/licenses/.
+
+#  Recommended way to build the container this creates (for lack of
+#  an easy way to exclude everything but the Dockerfile):
+#
+#    docker build -t openambit:jessie - < Dockerfile
+#
+#  After that is just a matter of compiling the sources with:
+#
+#    docker run --rm -v $PWD:/code -u $(id -u) openambit:jessie
+#
+#  Doing so gives you a basic sanity check of code compilability on a
+#  minimalistic, reproducible development platform.
+#
+#  If you don't like the defaults of building in $PWD/_build with no
+#  options to either cmake or make, feel free to adjust the relevant
+#  environment variables.  For example, you could build with:
+#
+#    docker run --rm -v $PWD:/code -u $(id -u) \
+#      --env BUILD_DIR=tmp \
+#      --env CMAKE_OPTS="-DBUILD_EXTRAS=1" \
+#      --env MAKE_OPTS=-k \
+#      openambit:jessie
+#
+#  Check out the --env-file option to docker if you find that overly
+#  long-winded.  If you use a BUILD_DIR that is not below /code make
+#  sure to drop the --rm option.
+#
+#  For interactive sessions, you may want to use:
+#
+#    docker run -i -t --rm -v $PWD:/code -u $(id -u) \
+#      openambit:jessie /bin/bash
+#
+#  Again, drop the --rm option if you build in a location that is not
+#  below /code.
+
+FROM        debian:jessie
+MAINTAINER  Olaf Meeuwissen <paddy-hack at member.fsf.org>
+
+ENV  APT_OPTS --assume-yes --no-install-recommends
+
+# build system dependencies
+# Note that gcc does *not* depend on any specific C library.  Debian
+# and derivatives ship several ...
+RUN  apt-get update \
+     && apt-get install ${APT_OPTS} \
+                cmake \
+                make \
+                gcc \
+                libc-dev
+
+# libambit and example application build dependencies
+# The HID API support needs at least one of these to be available.  The
+# HIDAPI_DRIVER `cmake` variable controls what is used.
+RUN  apt-get update \
+     && apt-get install ${APT_OPTS} \
+             libudev-dev \
+             libusb-1.0-0-dev \
+             libpcap-dev
+
+# openambit build dependencies
+# Note that libqjson-dev needs to be >= 0.8
+RUN  apt-get update \
+     && apt-get install ${APT_OPTS} \
+             g++ \
+	     libqjson-dev \
+             libqt4-dev \
+             zlib1g-dev
+
+# wireshark dissector build dependencies
+RUN  apt-get update \
+     && apt-get install ${APT_OPTS} \
+             libglib2.0-dev \
+             libwireshark-dev \
+             python
+
+WORKDIR  /code
+ENV      BUILD_DIR _build
+CMD      test -d ${BUILD_DIR} || mkdir ${BUILD_DIR}; \
+	      cd ${BUILD_DIR} \
+	      && cmake ${CMAKE_OPTS} .. \
+	      && make ${MAKE_OPTS}
+
+# Finally, things that really should be fixed in the Openambit code.
+# FIXME add multiarch support to src/libambit/cmake/FindUdev.cmake
+RUN  cd /usr/lib/ && ln -s x86_64-linux-gnu/libudev.so
diff --git a/README b/README
deleted file mode 100644
index 9d4a924..0000000
--- a/README
+++ /dev/null
@@ -1,91 +0,0 @@
-OPENAMBIT
-=========
-
-The openambit source repository consists of several parts.
-Each part is briefly described below.
-Most people would like to use both the device communication
-library (libambit) and the GUI (openambit). The build / install
-scripts described below make your life easier if you are
-like most people.
-You can choose to run the GUI from the build folder or install
-it to your system.
-
-BUILD SCRIPT
-============
-Builds libambit and openambit in one command
-> cd YOUR/git/REPO/location
-> ./build.sh
-
-
-BUILD AND INSTALL SCRIPT
-========================
-Builds and install libambit and openambit in one command.
-Note that the script will try to run sudo to install things.
-> cd YOUR/git/REPO/location
-> ./install.sh
-
-
-DEPENDENCIES
-============
-To be able to build libambit and openambit the following libraries
-(and their header files) need to be available:
- - libudev
- - libusb
- - libqjson
-
-For debian-based systems:
-> sudo apt-get install libudev-dev libusb-1.0-0-dev libqjson-dev
-
-
-src/libambit
-============
-The "driver" library as a shared object. Written in C.
-
-Build instructions:
-> mkdir libambit-build
-> cd libambit-build
-> cmake ../src/libambit
-> make
-Optionally:
-> sudo make install
-
-
-src/openambit
-=============
-The GUI application. Uses the libambit library.
-
-Build instructions:
-First build libambit as instructed above
-> mkdir openambit-build
-> cd openambit-build
-> cmake ../src/openambit
-> make
-Optionally:
-> sudo make install
-
-Run the application without installing:
-> cd openambit-build
-> LD_LIBRARY_PATH=../libambit-build ./openambit
-
-
-tools/movescountXmlDiff.pl
-==========================
-Small Perl-script to compare XML-files generated by
-openambit and Suuntos Moveslink. Basically a diff with
-added floating point round errors ignored.
-
-
-wireshark_dissector
-===================
-To ease the parsing of the protocol a wireshark dissector
-is maintained. This dissector parses pcap-files made with
-usbpcap. The parts of the protocol that is known atm
-should be present in the latest dissector.
-
-Build instructions:
-> mkdir build
-> cd build
-> cmake ..
-> make
-> cp ambit.so ~/.wireshark/plugins
-
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..6ceabdb
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,166 @@
+Openambit
+=========
+
+Openambit makes your computer the Free (as in Freedom) conduit between
+your Ambit watch and Suunto's `Movescount`_ site (if you want it to go
+that far).  It enables you to get your hard-earned "move" log data off
+*your* watch and onto *your* computer.  And if you really want it to,
+Openambit will pump that data into the cloud where Big Data can crunch
+it to pieces and analyze your moves to shreds.
+
+
+Modules
+-------
+
+Openambit includes the following modules:
+
+src/libambit
+  a library that let's you computer communicate with your Ambit watch
+
+src/openambit
+  a Qt based GUI application to get data off your watch and push it to
+  Suunto's `Movescount`_ site
+
+src/example
+  a very simple command-line application that reports on your watch's
+  support status, and, if your watch is supported, battery charge and
+  a summary of the moves on your watch.
+
+tools
+  contains a few utilities that people thought useful.  One compares
+  Openambit's XML log files with those from `Moveslink2`_ and another
+  converts the XML to `GPX`_
+
+wireshark_dissector
+  a `Wireshark`_ packet dissector to help reverse engineer the Ambit
+  device protocol by picking your packet captures apart.
+
+
+Source Or Binary?
+-----------------
+
+Let's be clear, building from the latest revision in the repository is
+not quite for the faint of heart.  You need a development environment,
+make sure build requirements are met, actually build (doh!) and pray
+things work as intended.  And if worse comes to worst, you might even
+brick your Ambit watch and turn it into a `paperweight`_.
+
+Of course, we try our damnedest (and often put our own Ambits to the
+test) to prevent that absolutely worst-case scenario but there are
+*no* guarantees.
+
+Distribution provided binary packages, such as provided by `Debian`_
+and `Ubuntu`_ are normally built from reasonably well tested sources.
+As in, it probably will not turn your Ambit into a paperweight.  That
+might just meet your needs.  For other distributions, have a look at
+`OSWatershed.org`_, or hit your favourite search engine.
+
+If you cannot find binaries that meet your needs (not that unlikely at
+present), you can compile from one of the source code archives on our
+`release`_ page (or the corresponding ``git tag``).  That would also
+be on the safe side.
+
+As a last resort, or if you're a developer type, go ahead and build
+from the latest, greatest "bleeding edge" version on the repository's
+``master`` branch.
+
+
+Requirements
+------------
+
+In order to build Openambit from source you need a couple of tools and
+libraries.  To begin with, you will need ``cmake``, ``make`` and C and
+C++ compilers.  You will need C and C++ libraries, Qt4, ``libqjson``
+and ``zlib`` as well as one of ``libudev`` and ``libusb-1.0``.  For
+all these libraries you will also need their header files (typically
+provided in ``*-dev`` or ``*-devel`` packages).
+
+
+Build Procedure
+---------------
+
+The simplest way to build from source is by means of the ``build.sh``
+script.  It will build all components needed to use Openambit.  Any
+command-line arguments you specify are passed on to ``cmake``.  That
+means you can set up a "Debug" build with
+
+.. code-block:: sh
+
+   cd /path/to/your/clone/of/openambit
+   ./build.sh -DCMAKE_BUILD_TYPE=Debug
+
+Developer and otherwise inquisitive types may want to build some of
+the extras that are included.  To do so
+
+.. code-block:: sh
+
+   cd /path/to/your/clone/of/openambit
+   BUILD_EXTRAS=1 ./build.sh
+
+You can run the applications you built *without* installing as follows
+
+.. code-block:: sh
+
+   ./run.sh			# runs the GUI application
+   ./run.sh openambit		# runs the GUI application
+   ./run.sh ambitconsole	# runs the example application
+
+If you are only interested in building a selected module, you can just
+use ``cmake`` directly.  For example, if all you really want to build
+is ``libambit`` and nothing else, you could (for example)
+
+.. code-block:: sh
+
+   cd /path/to/your/clone/of/openambit
+   mkdir _build
+   cd _build
+   cmake ../src/libambit
+   make
+
+Actually, you can also build everything directly with ``cmake``.  The
+following ought to work
+
+.. code-block:: sh
+
+   cd /path/to/your/clone/of/openambit
+   mkdir _build
+   cd _build
+   cmake ..
+   make
+
+Install Procedure
+-----------------
+
+If you have built from source with ``build.sh``, you can install with
+``install.sh``.  This only installs the ``openambit`` application and
+the ``libambit`` library it needs.  When you have built only selected
+parts, simply install them with
+
+.. code-block:: sh
+
+   cd /path/to/your/build/directory
+   sudo make install
+
+If you built directly with ``cmake``, installation is simply
+
+.. code-block:: sh
+
+   cd /path/to/you/clone/of/openambit
+   cd _build
+   sudo make install
+
+To enable the Wireshark dissector, just copy the ``ambit.so`` file to
+your ``~/.wireshark/plugins/`` directory.  You can also put a symbolic
+link there pointing to the build result so your next ``wireshark`` run
+will use the latest, greatest(?) version.
+
+
+.. _Movescount: http://www.movescount.com/
+.. _Moveslink2: http://www.movescount.com/connect/moveslink/Suunto_Ambit
+.. _GPX: https://en.wikipedia.org/wiki/GPS_Exchange_Format
+.. _Wireshark: https://www.wireshark.org/
+.. _paperweight: https://en.wikipedia.org/wiki/Paperweight
+.. _Debian: https://packages.debian.org/search?keywords=openambit
+.. _Ubuntu: http://packages.ubuntu.com/search?keywords=openambit
+.. _OSWatershed.org: http://oswatershed.org/pkg/openambit
+.. _release: https://github.com/openambitproject/openambit/releases
diff --git a/build.sh b/build.sh
index 50245c7..6c5b047 100755
--- a/build.sh
+++ b/build.sh
@@ -1,27 +1,36 @@
+#!/bin/bash
+
 SOURCE_LOCATION="`dirname \"$0\"`"
 SOURCE_LOCATION="`( cd \"$SOURCE_LOCATION\" && pwd )`"
 
 CORES=$(cat /proc/cpuinfo | grep processor | wc -l)
 
-cd $SOURCE_LOCATION
+for target in libambit movescount openambit
+do
+    cd $SOURCE_LOCATION
+    echo "------building $target------"
+    mkdir -p $target-build
+    cd $target-build
+    cmake "$@" ../src/$target
+    make -j$CORES
+    if [ "$DO_INSTALL" == "1" ]; then
+	echo "------installing $target------"
+	sudo make install
+    fi
+done
 
-echo "------building libambit------"
-mkdir -p libambit-build
-cd libambit-build
-cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../src/libambit
-make -j$CORES
-if [ "$DO_INSTALL" == "1" ]; then
-    echo "------installing libambit------"
-    sudo make install
-fi
+if [ "$BUILD_EXTRAS" == "1" ]; then
+    cd $SOURCE_LOCATION
+    echo "------building example------"
+    mkdir -p example-build
+    cd example-build
+    cmake "$@" ../src/example
+    make -j$CORES
 
-cd $SOURCE_LOCATION
-echo "------building openambit------"
-mkdir -p openambit-build
-cd openambit-build
-cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../src/openambit
-make -j$CORES
-if [ "$DO_INSTALL" == "1" ]; then
-    echo "------installing openambit------"
-    sudo make install
+    cd $SOURCE_LOCATION
+    echo "------building wireshark dissector------"
+    mkdir -p dissector-build
+    cd dissector-build
+    cmake "$@" ../wireshark_dissector
+    make -j$CORES
 fi
diff --git a/run.sh b/run.sh
index 7d3ec6c..b65b833 100755
--- a/run.sh
+++ b/run.sh
@@ -1,8 +1,23 @@
+#!/bin/sh
+
 SOURCE_LOCATION="`dirname \"$0\"`"
 SOURCE_LOCATION="`( cd \"$SOURCE_LOCATION\" && pwd )`"
 
 cd $SOURCE_LOCATION
-echo "------running openambit------"
-LD_LIBRARY_PATH=./libambit-build ./openambit-build/openambit
 
+application=openambit
+if test -n "$1"; then
+     application=$1
+     shift
+fi
+case "$application" in
+    openambit)          builddir=$application-build;;
+    ambitconsole)       builddir=example-build;;
+    *)
+	echo "$application: not supported" >&2
+	exit 1
+	;;
+esac
 
+echo "------running $application------"
+LD_LIBRARY_PATH=./libambit-build ./$builddir/$application
diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt
index f639da0..7a1b459 100644
--- a/src/example/CMakeLists.txt
+++ b/src/example/CMakeLists.txt
@@ -1,9 +1,19 @@
+cmake_minimum_required(VERSION 2.8.5)
+project (EXAMPLE C)
+
+# Where to lookup modules
+set(CMAKE_MODULE_PATH "${EXAMPLE_SOURCE_DIR}/cmake")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+
+find_package(libambit REQUIRED)
+
 include_directories(
-  ${OPENAMBIT_SOURCE_DIR}/libambit
+  ${LIBAMBIT_INCLUDE_DIR}
 )
 
 link_directories(
-  ${OPENAMBIT_BINARY_DIR}/libambit
+  ${LIBAMBIT_LIBS_DIR}
 )
 
 add_executable(
@@ -11,5 +21,5 @@ add_executable(
 )
 
 target_link_libraries(
-  ambitconsole ambit
+  ambitconsole ${LIBAMBIT_LIBS}
 )
diff --git a/src/example/ambitconsole.c b/src/example/ambitconsole.c
index 18a5ed1..1de556b 100644
--- a/src/example/ambitconsole.c
+++ b/src/example/ambitconsole.c
@@ -1,5 +1,6 @@
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 #include <libambit.h>
 
 static int log_skip_cb(void *ambit_object, ambit_log_header_t *log_header);
@@ -7,18 +8,25 @@ static void log_data_cb(void *object, ambit_log_entry_t *log_entry);
 
 int main(int argc, char *argv[])
 {
+    ambit_device_info_t *info = libambit_enumerate();
     ambit_object_t *ambit_object;
-    ambit_device_info_t info;
     ambit_device_status_t status;
     ambit_personal_settings_t settings;
-    time_t current_time;
-    struct tm *local_time;
 
-    if ((ambit_object = libambit_detect()) != NULL) {
-        libambit_device_info_get(ambit_object, &info);
+    if (info) {
+        printf("Device: %s, serial: %s\n", info->name, info->serial);
+        if (0 == info->access_status) {
+          printf("F/W version: %d.%d.%d\n", info->fw_version[0], info->fw_version[1], (info->fw_version[2] << 0) | (info->fw_version[3] << 8));
+            if (!info->is_supported) {
+                printf("Device is not supported yet!\n");
+            }
+        }
+        else {
+            printf("%s: %s\n", info->path, strerror(info->access_status));
+        }
 
-        if (libambit_device_supported(ambit_object)) {
-            printf("Device: %s, serial: %s, FW version: %d.%d.%d\n", info.name, info.serial, info.fw_version[0], info.fw_version[1], info.fw_version[2] | (info.fw_version[3] << 8));
+        ambit_object = libambit_new(info);
+        if (ambit_object) {
 
             if (libambit_device_status_get(ambit_object, &status) == 0) {
                 printf("Current charge: %d%%\n", status.charge);
@@ -30,28 +38,17 @@ int main(int argc, char *argv[])
             if (libambit_personal_settings_get(ambit_object, &settings) == 0) {
             }
             else {
-                printf("Failed to read status\n");
+                printf("Failed to read personal settings\n");
             }
 
-            current_time = time(NULL);
-            local_time = localtime(&current_time);
-            //if (libambit_date_time_set(ambit_object, local_time) == 0) {
-            //}
-            //else {
-            //    printf("Failed to set date and time\n");
-            //}
-
             libambit_log_read(ambit_object, log_skip_cb, log_data_cb, NULL, ambit_object);
+            libambit_close(ambit_object);
         }
-        else {
-            printf("Device: %s (fw_version: %d.%d.%d) is not supported yet!\n", info.name, info.fw_version[0], info.fw_version[1], info.fw_version[2] | (info.fw_version[3] << 8));
-        }
-
-        libambit_close(ambit_object);
     }
     else {
         printf("No clock found, exiting\n");
     }
+    libambit_free_enumeration(info);
 
     return 0;
 }
diff --git a/src/example/cmake/Findlibambit.cmake b/src/example/cmake/Findlibambit.cmake
new file mode 120000
index 0000000..dfd420f
--- /dev/null
+++ b/src/example/cmake/Findlibambit.cmake
@@ -0,0 +1 @@
+../../openambit/cmake/Findlibambit.cmake
\ No newline at end of file
diff --git a/src/libambit/CMakeLists.txt b/src/libambit/CMakeLists.txt
index e744510..93b5042 100644
--- a/src/libambit/CMakeLists.txt
+++ b/src/libambit/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required (VERSION 2.8.5)
-project (LIBAMBIT)
+project (LIBAMBIT C)
 
 # Where to lookup modules
 set(CMAKE_MODULE_PATH "${LIBAMBIT_SOURCE_DIR}/cmake")
@@ -15,8 +15,7 @@ IF (DEFINED DEBUG_PRINT_FILE_LINE)
   set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG_PRINT_FILE_LINE=${DEBUG_PRINT_FILE_LINE}")
 ENDIF()
 
-find_package(libusb REQUIRED)
-find_package(UDev REQUIRED)
+include(HidapiDriver)
 include(GNUInstallDirs)
 
 add_library (
@@ -24,25 +23,39 @@ add_library (
   SHARED
   crc16.c
   debug.c
-  hid.c
+  device_driver_ambit.c
+  device_driver_ambit3.c
+  device_driver_common.c
+  device_support.c
   libambit.c
   personal.c
   pmem20.c
   protocol.c
+  sbem0102.c
+  sha256.c
+  utils.c
+  ${HIDAPI_SOURCE_FILES}
 )
 
 target_link_libraries(
   ambit
-  ${UDEV_LIBS}
-  ${LIBUSB_LIBRARIES}
+  ${HIDAPI_LIBS}
   m
 )
 
 set_target_properties(ambit PROPERTIES VERSION 0.3.0 SOVERSION 0)
 
 include_directories(
-  hidapi
+  ${HIDAPI_INCLUDE_DIR}
 )
 
 install(TARGETS ambit DESTINATION ${CMAKE_INSTALL_LIBDIR})
 install(FILES libambit.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+set(CMAKE_INSTALL_UDEVRULESDIR /etc/udev/rules.d
+    CACHE PATH "Where to install udev rules")
+mark_as_advanced(CMAKE_INSTALL_UDEVRULESDIR)
+
+install(FILES libambit.rules
+        DESTINATION $ENV{DESTDIR}${CMAKE_INSTALL_UDEVRULESDIR}
+        COMPONENT system)
diff --git a/src/libambit/cmake/FindPCAP.cmake b/src/libambit/cmake/FindPCAP.cmake
new file mode 100644
index 0000000..e5049bf
--- /dev/null
+++ b/src/libambit/cmake/FindPCAP.cmake
@@ -0,0 +1,74 @@
+# - Try to find libpcap include dirs and libraries
+#
+# Usage of this module as follows:
+#
+#     find_package(PCAP)
+#
+# Variables used by this module, they can change the default behaviour and need
+# to be set before calling find_package:
+#
+#  PCAP_ROOT_DIR             Set this variable to the root installation of
+#                            libpcap if the module has problems finding the
+#                            proper installation path.
+#
+# Variables defined by this module:
+#
+#  PCAP_FOUND                System has libpcap, include and library dirs found
+#  PCAP_INCLUDE_DIR          The libpcap include directories.
+#  PCAP_LIBRARY              The libpcap library (possibly includes a thread
+#                            library e.g. required by pf_ring's libpcap)
+#  HAVE_PF_RING              If a found version of libpcap supports PF_RING
+
+find_path(PCAP_ROOT_DIR
+    NAMES include/pcap.h
+)
+
+find_path(PCAP_INCLUDE_DIR
+    NAMES pcap.h
+    HINTS ${PCAP_ROOT_DIR}/include
+)
+
+find_library(PCAP_LIBRARY
+    NAMES pcap
+    HINTS ${PCAP_ROOT_DIR}/lib
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PCAP DEFAULT_MSG
+    PCAP_LIBRARY
+    PCAP_INCLUDE_DIR
+)
+
+include(CheckCSourceCompiles)
+set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY})
+check_c_source_compiles("int main() { return 0; }" PCAP_LINKS_SOLO)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+# check if linking against libpcap also needs to link against a thread library
+if (NOT PCAP_LINKS_SOLO)
+    find_package(Threads)
+    if (THREADS_FOUND)
+        set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
+        check_c_source_compiles("int main() { return 0; }" PCAP_NEEDS_THREADS)
+        set(CMAKE_REQUIRED_LIBRARIES)
+    endif ()
+    if (THREADS_FOUND AND PCAP_NEEDS_THREADS)
+        set(_tmp ${PCAP_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
+        list(REMOVE_DUPLICATES _tmp)
+        set(PCAP_LIBRARY ${_tmp}
+            CACHE STRING "Libraries needed to link against libpcap" FORCE)
+    else ()
+        message(FATAL_ERROR "Couldn't determine how to link against libpcap")
+    endif ()
+endif ()
+
+include(CheckFunctionExists)
+set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY})
+check_function_exists(pcap_get_pfring_id HAVE_PF_RING)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+mark_as_advanced(
+    PCAP_ROOT_DIR
+    PCAP_INCLUDE_DIR
+    PCAP_LIBRARY
+)
diff --git a/src/libambit/cmake/HidapiDriver.cmake b/src/libambit/cmake/HidapiDriver.cmake
new file mode 100644
index 0000000..1c3f275
--- /dev/null
+++ b/src/libambit/cmake/HidapiDriver.cmake
@@ -0,0 +1,30 @@
+# - Resolve what hidapi driver to use
+# This module is affected by the following defines
+#  HIDAPI_DRIVER (possible values: usbraw, libusb, pcapsimulate)
+#
+# This module defines
+#  HIDAPI_INCLUDE_DIR
+#  HIDAPI_SOURCE_FILES
+#  HIDAPI_LIBS
+
+if (NOT HIDAPI_RESOLVED)
+    if (HIDAPI_DRIVER STREQUAL "libusb")
+        find_package(libusb REQUIRED)
+        set (HIDAPI_INCLUDE_DIR "hidapi" ${LIBUSB_INCLUDE_DIR})
+        set (HIDAPI_SOURCE_FILES "hidapi/hid-libusb.c")
+        set (HIDAPI_LIBS ${LIBUSB_LIBRARIES})
+    elseif (HIDAPI_DRIVER STREQUAL "pcapsimulate")
+        find_package(PCAP REQUIRED)
+        set (HIDAPI_INCLUDE_DIR "hidapi" ${PCAP_INCLUDE_DIR})
+        set (HIDAPI_SOURCE_FILES "hidapi/hid-pcapsimulate.c")
+        set (HIDAPI_LIBS ${PCAP_LIBRARY})
+    else (HIDAPI_DRIVER STREQUAL "libusb")
+        find_package(UDev REQUIRED)
+        set (HIDAPI_INCLUDE_DIR "hidapi" ${UDEV_INCLUDE_DIR})
+        set (HIDAPI_SOURCE_FILES "hidapi/hid-linux.c")
+        set (HIDAPI_LIBS ${UDEV_LIBS})
+    endif (HIDAPI_DRIVER STREQUAL "libusb")
+
+    mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_SOURCE_FILES HIDAPI_LIBS)
+    set (HIDAPI_RESOLVED TRUE)
+endif (NOT HIDAPI_RESOLVED)
diff --git a/src/libambit/crc16.c b/src/libambit/crc16.c
index ce1db5f..3f5e511 100644
--- a/src/libambit/crc16.c
+++ b/src/libambit/crc16.c
@@ -18,7 +18,7 @@
 /*                                                               */
 /*****************************************************************/
 
-#include "libambit_int.h"
+#include "crc16.h"
 
 static uint16_t crctable[256] =
 {
diff --git a/src/libambit/crc16.h b/src/libambit/crc16.h
new file mode 100644
index 0000000..57185e6
--- /dev/null
+++ b/src/libambit/crc16.h
@@ -0,0 +1,31 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __CRC16_H__
+#define __CRC16_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+uint16_t crc16_ccitt_false(unsigned char *buf, size_t buflen);
+uint16_t crc16_ccitt_false_init(unsigned char *buf, size_t buflen, uint16_t crc);
+
+#endif /* __CRC16_H__ */
diff --git a/src/libambit/debian/changelog b/src/libambit/debian/changelog
deleted file mode 100644
index 38c535a..0000000
--- a/src/libambit/debian/changelog
+++ /dev/null
@@ -1,11 +0,0 @@
-libambit (0.3-1) trusty; urgency=medium
-
-  * New upstream release including support for Ambit 2R
-
- -- Emil Ljungdahl <emil at openambit.org>  Mon, 15 Sep 2014 22:30:01 +0200
-
-libambit (0.2-1) saucy; urgency=low
-
-  * Initial release
-
- -- Emil Ljungdahl <emil at openambit.org>  Thu, 30 Jan 2014 13:35:49 +0100
diff --git a/src/libambit/debian/compat b/src/libambit/debian/compat
deleted file mode 100644
index 45a4fb7..0000000
--- a/src/libambit/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-8
diff --git a/src/libambit/debian/control b/src/libambit/debian/control
deleted file mode 100644
index 88de188..0000000
--- a/src/libambit/debian/control
+++ /dev/null
@@ -1,26 +0,0 @@
-Source: libambit
-Priority: extra
-Maintainer: Emil Ljungdahl <ppa at openambit.org>
-Build-Depends: dpkg (>= 1.16.1~), debhelper (>= 9), cmake (>= 2.8.5), libudev-dev, libusb-1.0-0-dev
-Standards-Version: 3.9.4
-Section: libs
-Homepage: http://openambit.org/
-#Vcs-Git: git://git.debian.org/collab-maint/libambit.git
-#Vcs-Browser: http://git.debian.org/?p=collab-maint/libambit.git;a=summary
-
-Package: libambit-dev
-Section: libdevel
-Architecture: any
-Depends: libambit0 (= ${binary:Version}), ${misc:Depends}
-Description: Communication library for Suunto Ambit series 
- Libambit is the driver library to communicate with the Suunto Ambit series
- of sport watches. This is the -dev version of the package container
- header files required for compiling against the library.
-
-Package: libambit0
-Section: libs
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Pre-Depends}, ${misc:Depends}
-Description: Communication library for Suunto Ambit series
- Libambit is the driver library to communicate with the Suunto Ambit series
- of sport watches.
diff --git a/src/libambit/debian/copyright b/src/libambit/debian/copyright
deleted file mode 100644
index abc5415..0000000
--- a/src/libambit/debian/copyright
+++ /dev/null
@@ -1,39 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: libambit
-Source: http://openambit.org/
-
-Files: *
-Copyright: 2014 Emil Ljungdahl <emil at openambit.org>
-License: GPL-3
- libambit 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/>.
-
-Files: debian/*
-Copyright: 2014 Emil Ljungdahl <emil at openambit.org>
-License: GPL-2+
- This package 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 2 of the License, or
- (at your option) any later version.
- .
- This package 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/>
- .
- On Debian systems, the complete text of the GNU General
- Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
-
diff --git a/src/libambit/debian/docs b/src/libambit/debian/docs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/libambit/debian/libambit-dev.dirs b/src/libambit/debian/libambit-dev.dirs
deleted file mode 100644
index e43b95c..0000000
--- a/src/libambit/debian/libambit-dev.dirs
+++ /dev/null
@@ -1 +0,0 @@
-usr/include
diff --git a/src/libambit/debian/libambit-dev.install b/src/libambit/debian/libambit-dev.install
deleted file mode 100644
index 92be58d..0000000
--- a/src/libambit/debian/libambit-dev.install
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/include/*
-usr/lib/*/libambit.so
diff --git a/src/libambit/debian/libambit0.dirs b/src/libambit/debian/libambit0.dirs
deleted file mode 100644
index 0bf940b..0000000
--- a/src/libambit/debian/libambit0.dirs
+++ /dev/null
@@ -1 +0,0 @@
-/usr/lib
diff --git a/src/libambit/debian/libambit0.install b/src/libambit/debian/libambit0.install
deleted file mode 100644
index 8e5ee50..0000000
--- a/src/libambit/debian/libambit0.install
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/*/libambit.so.*
diff --git a/src/libambit/debian/rules b/src/libambit/debian/rules
deleted file mode 100755
index b760bee..0000000
--- a/src/libambit/debian/rules
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-%:
-	dh $@ 
diff --git a/src/libambit/debian/source/format b/src/libambit/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/src/libambit/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/src/libambit/debug.c b/src/libambit/debug.c
index bd30f68..b36aa88 100644
--- a/src/libambit/debug.c
+++ b/src/libambit/debug.c
@@ -19,8 +19,7 @@
  * Contributors:
  *
  */
-#include "libambit.h"
-#include "libambit_int.h"
+#include "debug.h"
 
 #include <stdarg.h>
 #include <stdio.h>
diff --git a/src/libambit/debug.h b/src/libambit/debug.h
new file mode 100644
index 0000000..cf8cf61
--- /dev/null
+++ b/src/libambit/debug.h
@@ -0,0 +1,52 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef enum debug_level_e {
+    debug_level_err,
+    debug_level_warn,
+    debug_level_info
+} debug_level_t;
+
+void debug_printf(debug_level_t level, const char *file, int line, const char *func, const char *fmt, ...);
+
+#ifdef DEBUG_PRINT_ERROR
+#define LOG_ERROR(fmt, ...) debug_printf(debug_level_err, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
+#else
+#define LOG_ERROR(fmt, ...)
+#endif
+#ifdef DEBUG_PRINT_WARNING
+#define LOG_WARNING(fmt, ...) debug_printf(debug_level_warn, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
+#else
+#define LOG_WARNING(fmt, ...)
+#endif
+#ifdef DEBUG_PRINT_INFO
+#define LOG_INFO(fmt, ...) debug_printf(debug_level_info, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
+#else
+#define LOG_INFO(fmt, ...)
+#endif
+
+#endif /* __DEBUG_H__ */
diff --git a/src/libambit/device_driver.h b/src/libambit/device_driver.h
new file mode 100644
index 0000000..28e800b
--- /dev/null
+++ b/src/libambit/device_driver.h
@@ -0,0 +1,45 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __DEVICE_DRIVER_H__
+#define __DEVICE_DRIVER_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libambit.h"
+
+typedef struct ambit_device_driver_s {
+    void (*init)(ambit_object_t *object, uint32_t driver_param);
+    void (*deinit)(ambit_object_t *object);
+    int (*lock_log)(ambit_object_t *object, bool lock);
+    int (*date_time_set)(ambit_object_t *object, struct tm *tm);
+    int (*status_get)(ambit_object_t *object, ambit_device_status_t *status);
+    int (*personal_settings_get)(ambit_object_t *object, ambit_personal_settings_t *settings);
+    int (*log_read)(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref);
+    int (*gps_orbit_header_read)(ambit_object_t *object, uint8_t data[8]);
+    int (*gps_orbit_write)(ambit_object_t *object, uint8_t *data, size_t datalen);
+} ambit_device_driver_t;
+
+extern ambit_device_driver_t ambit_device_driver_ambit;  // Ambit & Ambit2
+extern ambit_device_driver_t ambit_device_driver_ambit3; // Ambit3
+
+#endif /* __DEVICE_DRIVER_H__ */
diff --git a/src/libambit/device_driver_ambit.c b/src/libambit/device_driver_ambit.c
new file mode 100644
index 0000000..c17a963
--- /dev/null
+++ b/src/libambit/device_driver_ambit.c
@@ -0,0 +1,299 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "device_driver.h"
+#include "device_driver_common.h"
+#include "libambit_int.h"
+#include "protocol.h"
+#include "pmem20.h"
+#include "personal.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Local definitions
+ */
+#define PMEM20_LOG_START                  0x000f4240
+#define PMEM20_LOG_SIZE                   0x0029f630 /* 2 750 000 */
+
+struct ambit_device_driver_data_s {
+    libambit_pmem20_t pmem20;
+};
+
+/*
+ * Static functions
+ */
+static void init(ambit_object_t *object, uint32_t driver_param);
+static void deinit(ambit_object_t *object);
+static int personal_settings_get(ambit_object_t *object, ambit_personal_settings_t *settings);
+static int log_read(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref);
+static int gps_orbit_header_read(ambit_object_t *object, uint8_t data[8]);
+static int gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen);
+
+/*
+ * Global variables
+ */
+ambit_device_driver_t ambit_device_driver_ambit = {
+    init,
+    deinit,
+    libambit_device_driver_lock_log,
+    libambit_device_driver_date_time_set,
+    libambit_device_driver_status_get,
+    personal_settings_get,
+    log_read,
+    gps_orbit_header_read,
+    gps_orbit_write
+};
+
+/*
+ * Static functions implementation
+ */
+/**
+ * Init function
+ * \param object to initialize
+ * \param driver_param PMEM20 chunk size
+ */
+static void init(ambit_object_t *object, uint32_t driver_param)
+{
+    struct ambit_device_driver_data_s *data;
+
+    if ((data = calloc(1, sizeof(struct ambit_device_driver_data_s))) != NULL) {
+        object->driver_data = data;
+        libambit_pmem20_init(&object->driver_data->pmem20, object, driver_param);
+    }
+}
+
+static void deinit(ambit_object_t *object)
+{
+    if (object->driver_data != NULL) {
+        libambit_pmem20_deinit(&object->driver_data->pmem20);
+    }
+}
+
+static int personal_settings_get(ambit_object_t *object, ambit_personal_settings_t *settings)
+{
+    uint8_t *reply_data = NULL;
+    size_t replylen = 0;
+    int ret = -1;
+
+    LOG_INFO("Reading personal settings");
+
+    if (libambit_protocol_command(object, ambit_command_personal_settings, NULL, 0, &reply_data, &replylen, 0) == 0) {
+        ret = libambit_personal_settings_parse(reply_data, replylen, settings);
+        libambit_protocol_free(reply_data);
+    }
+    else {
+        LOG_WARNING("Failed to read personal settings");
+    }
+
+    return ret;
+}
+
+static int log_read(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref)
+{
+    int entries_read = 0;
+
+    uint8_t *reply_data = NULL;
+    size_t replylen = 0;
+    uint16_t log_entries_total = 0;
+    uint16_t log_entries_walked = 0;
+
+    uint32_t more = 0x00000400;
+
+    bool read_pmem = false;
+
+    ambit_log_header_t log_header;
+    ambit_log_entry_t *log_entry;
+
+    LOG_INFO("Reading number of logs");
+    log_header.activity_name = NULL;
+
+    /*
+     * Read number of log entries
+     */
+    if (libambit_protocol_command(object, ambit_command_log_count, NULL, 0, &reply_data, &replylen, 0) != 0) {
+        LOG_WARNING("Failed to read number of log entries");
+        return -1;
+    }
+    log_entries_total = le16toh(*(uint16_t*)(reply_data + 2));
+    libambit_protocol_free(reply_data);
+
+    LOG_INFO("Number of logs=%d", log_entries_total);
+
+    /*
+     * First part walks through headers to check if there is any point in start
+     * reading the PMEM content. If no skip callback is defined, there is no
+     * point in checking the headers, because no one can tell us to not include
+     * the logs...
+     */
+
+    if (skip_cb != NULL) {
+        LOG_INFO("Look in headers for new logs");
+        // Rewind
+        if (libambit_protocol_command(object, ambit_command_log_head_first, NULL, 0, &reply_data, &replylen, 0) != 0) {
+            LOG_WARNING("Failed to rewind header pointer");
+            return -1;
+        }
+        more = le32toh(*(uint32_t*)reply_data);
+        libambit_protocol_free(reply_data);
+
+        // Loop through logs while more entries exists
+        while (more == 0x00000400) {
+            LOG_INFO("Reading next header");
+            // Go to next entry
+            if (libambit_protocol_command(object, ambit_command_log_head_step, NULL, 0, &reply_data, &replylen, 0) != 0) {
+                LOG_WARNING("Failed to walk to next header");
+                return -1;
+            }
+            libambit_protocol_free(reply_data);
+
+            // Assume every header is composited by 2 parts, where only the
+            // second is of interrest right now
+            if (libambit_protocol_command(object, ambit_command_log_head, NULL, 0, &reply_data, &replylen, 0) != 0) {
+                LOG_WARNING("Failed to read first part of header");
+                return -1;
+            }
+            libambit_protocol_free(reply_data);
+
+            if (libambit_protocol_command(object, ambit_command_log_head, NULL, 0, &reply_data, &replylen, 0) == 0) {
+                if (replylen > 8 && libambit_pmem20_log_parse_header(reply_data + 8, replylen - 8, &log_header) == 0) {
+                    if (skip_cb(userref, &log_header) != 0) {
+                        // Header was NOT skipped, break out!
+                        read_pmem = true;
+                        LOG_INFO("Found new entry, start reading log data");
+                        break;
+                    }
+                }
+                else {
+                    LOG_ERROR("Failed to parse log header");
+                    return -1;
+                }
+                libambit_protocol_free(reply_data);
+            }
+            else {
+                LOG_WARNING("Failed to read second part of header");
+                return -1;
+            }
+
+            // Is there more entries to read?
+            if (libambit_protocol_command(object, ambit_command_log_head_peek, NULL, 0, &reply_data, &replylen, 0) != 0) {
+                LOG_WARNING("Failed to check for more headers");
+                return -1;
+            }
+            more = le32toh(*(uint32_t*)reply_data);
+            libambit_protocol_free(reply_data);
+        }
+    }
+    else {
+        LOG_INFO("No skip callback defined, reading log data");
+        read_pmem = true;
+    }
+
+    if (read_pmem) {
+        if (libambit_pmem20_log_init(&object->driver_data->pmem20, PMEM20_LOG_START, PMEM20_LOG_SIZE) != 0) {
+            return -1;
+        }
+
+        // Loop through all log entries, first check headers
+        while (log_entries_walked < log_entries_total && libambit_pmem20_log_next_header(&object->driver_data->pmem20, &log_header) == 1) {
+            LOG_INFO("Reading header of log %d of %d", log_entries_walked + 1, log_entries_total);
+            if (progress_cb != NULL) {
+                progress_cb(userref, log_entries_total, log_entries_walked+1, 100*log_entries_walked/log_entries_total);
+            }
+            // Check if this entry needs to be read
+            if (skip_cb == NULL || skip_cb(userref, &log_header) != 0) {
+                LOG_INFO("Reading data of log %d of %d", log_entries_walked + 1, log_entries_total);
+                log_entry = libambit_pmem20_log_read_entry(&object->driver_data->pmem20);
+                if (log_entry != NULL) {
+                    if (push_cb != NULL) {
+                        push_cb(userref, log_entry);
+                    }
+                    entries_read++;
+                }
+            }
+            else {
+                LOG_INFO("Log %d of %d already exists, skip reading data", log_entries_walked + 1, log_entries_total);
+            }
+            log_entries_walked++;
+            if (progress_cb != NULL) {
+                progress_cb(userref, log_entries_total, log_entries_walked, 100*log_entries_walked/log_entries_total);
+            }
+        }
+    }
+
+    LOG_INFO("%d entries read", entries_read);
+
+    return entries_read;
+}
+
+static int gps_orbit_header_read(ambit_object_t *object, uint8_t data[8])
+{
+    uint8_t *reply_data = NULL;
+    size_t replylen = 0;
+    int ret = -1;
+
+    if (libambit_protocol_command(object, ambit_command_gps_orbit_head, NULL, 0, &reply_data, &replylen, 0) == 0 && replylen >= 9) {
+        memcpy(data, &reply_data[1], 8);
+        libambit_protocol_free(reply_data);
+
+        ret = 0;
+    }
+    else {
+        LOG_WARNING("Failed to read GPS orbit header");
+    }
+
+    return ret;
+}
+
+static int gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen)
+{
+    uint8_t header[8], cmpheader[8];
+    int ret = -1;
+
+    LOG_INFO("Writing GPS orbit data");
+
+    libambit_protocol_command(object, ambit_command_write_start, NULL, 0, NULL, NULL, 0);
+
+    if (object->driver->gps_orbit_header_read(object, header) == 0) {
+        cmpheader[0] = data[7]; // Year, swap bytes
+        cmpheader[1] = data[6];
+        cmpheader[2] = data[8];
+        cmpheader[3] = data[9];
+        cmpheader[4] = data[13]; // 4 byte swap
+        cmpheader[5] = data[12];
+        cmpheader[6] = data[11];
+        cmpheader[7] = data[10];
+
+        // Check if new data differs 
+        if (memcmp(header, cmpheader, 8) != 0) {
+            ret = libambit_pmem20_gps_orbit_write(&object->driver_data->pmem20, data, datalen, false);
+        }
+        else {
+            LOG_INFO("Current GPS orbit data is already up to date, skipping");
+            ret = 0;
+        }
+    }
+
+    return ret;
+}
+
diff --git a/src/libambit/device_driver_ambit3.c b/src/libambit/device_driver_ambit3.c
new file mode 100644
index 0000000..05011d9
--- /dev/null
+++ b/src/libambit/device_driver_ambit3.c
@@ -0,0 +1,459 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "device_driver.h"
+#include "device_driver_common.h"
+#include "libambit_int.h"
+#include "protocol.h"
+#include "pmem20.h"
+#include "personal.h"
+#include "sbem0102.h"
+#include "utils.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Local definitions
+ */
+typedef struct memory_map_entry_s {
+    uint32_t start;
+    uint32_t size;
+    uint8_t hash[32];
+} memory_map_entry_t;
+
+struct ambit_device_driver_data_s {
+    libambit_pmem20_t pmem20;
+    libambit_sbem0102_t sbem0102;
+    struct {
+        uint8_t initialized;
+        memory_map_entry_t waypoints;
+        memory_map_entry_t routes;
+        memory_map_entry_t rules;
+        memory_map_entry_t gps;
+        memory_map_entry_t custom_modes;
+        memory_map_entry_t training_program;
+        memory_map_entry_t excercise_log;
+        memory_map_entry_t event_log;
+        memory_map_entry_t ble_pairing;
+    } memory_maps;
+};
+
+typedef struct ambit3_log_header_s {
+    ambit_log_header_t header;
+    uint32_t address;
+    uint32_t end_address;
+    uint8_t synced;
+} ambit3_log_header_t;
+
+/*
+ * Static functions
+ */
+static void init(ambit_object_t *object, uint32_t driver_param);
+static void deinit(ambit_object_t *object);
+static int personal_settings_get(ambit_object_t *object, ambit_personal_settings_t *settings);
+static int log_read(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref);
+static int gps_orbit_header_read(ambit_object_t *object, uint8_t data[8]);
+static int gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen);
+
+static int parse_log_header(const uint8_t *data, ambit3_log_header_t *log_header);
+static int get_memory_maps(ambit_object_t *object);
+
+/*
+ * Global variables
+ */
+ambit_device_driver_t ambit_device_driver_ambit3 = {
+    init,
+    deinit,
+    libambit_device_driver_lock_log,
+    libambit_device_driver_date_time_set,
+    libambit_device_driver_status_get,
+    personal_settings_get,
+    log_read,
+    gps_orbit_header_read,
+    gps_orbit_write
+};
+
+/*
+ * Static functions implementation
+ */
+/**
+ * Init function
+ * \param object to initialize
+ * \param driver_param PMEM20 chunk size
+ */
+static void init(ambit_object_t *object, uint32_t driver_param)
+{
+    struct ambit_device_driver_data_s *data;
+
+    if ((data = calloc(1, sizeof(struct ambit_device_driver_data_s))) != NULL) {
+        object->driver_data = data;
+        libambit_pmem20_init(&object->driver_data->pmem20, object, driver_param);
+        libambit_sbem0102_init(&object->driver_data->sbem0102, object, driver_param);
+    }
+}
+
+static void deinit(ambit_object_t *object)
+{
+    if (object->driver_data != NULL) {
+        libambit_pmem20_deinit(&object->driver_data->pmem20);
+        libambit_sbem0102_deinit(&object->driver_data->sbem0102);
+    }
+}
+
+static int personal_settings_get(ambit_object_t *object, ambit_personal_settings_t *settings)
+{
+    uint8_t send_data[4] = { 0x00, 0x00, 0x00, 0x00 };
+    libambit_sbem0102_data_t reply_data_object;
+
+    LOG_INFO("Reading personal settings");
+
+    libambit_sbem0102_data_init(&reply_data_object);
+    if (libambit_sbem0102_command_request_raw(&object->driver_data->sbem0102, ambit_command_ambit3_settings, send_data, sizeof(send_data), &reply_data_object) != 0) {
+        LOG_WARNING("Failed to read personal settings");
+        return -1;
+    }
+
+    memset(settings, 0, sizeof(ambit_personal_settings_t));
+
+    while (libambit_sbem0102_data_next(&reply_data_object) == 0) {
+        switch (libambit_sbem0102_data_id(&reply_data_object)) {
+          case 0x1a:
+            settings->weight = read16(libambit_sbem0102_data_ptr(&reply_data_object), 0);
+            break;
+          case 0x1f:
+            if (libambit_sbem0102_data_len(&reply_data_object) == 11) {
+                sscanf((const char*)libambit_sbem0102_data_ptr(&reply_data_object), "%04hu-", &settings->birthyear);
+            }
+            break;
+          case 0x1b:
+          case 0x1e:
+            // settings->length = libambit_sbem0102_data_ptr(&reply_data_object)[0];
+            //break;
+          case 0x1c:
+            //settings->backlight_brightness = libambit_sbem0102_data_ptr(&reply_data_object)[0];
+            //break;
+          case 0x1d:
+            //settings->display_brightness = libambit_sbem0102_data_ptr(&reply_data_object)[0];
+            //break;
+          default:
+            /*
+            printf("Got id=%02x: ", libambit_sbem0102_data_id(&reply_data_object));
+            switch(libambit_sbem0102_data_len(&reply_data_object)) {
+              case 1:
+                printf("%d", libambit_sbem0102_data_ptr(&reply_data_object)[0]);
+                break;
+              case 2:
+                printf("%d", read16(libambit_sbem0102_data_ptr(&reply_data_object), 0));
+                break;
+              case 4:
+                printf("%d", read32(libambit_sbem0102_data_ptr(&reply_data_object), 0));
+                break;
+              default:
+                {
+                    int q;
+                for(q=0; q<libambit_sbem0102_data_len(&reply_data_object); q++)
+                    printf("%02x", libambit_sbem0102_data_ptr(&reply_data_object)[q]);
+                }
+                break;
+            }
+            printf("\n");
+            */
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int log_read(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref)
+{
+    int entries_read = 0;
+
+    uint16_t log_entries_total = 0;
+    uint16_t log_entries_walked = 0;
+    uint16_t log_entries_notsynced = 0;
+
+    ambit3_log_header_t log_header;
+    ambit_log_entry_t *log_entry;
+
+    libambit_sbem0102_data_t send_data_object, reply_data_object;
+
+    LOG_INFO("Reading log headers");
+    log_header.header.activity_name = NULL;
+    
+    libambit_sbem0102_data_init(&send_data_object);
+    libambit_sbem0102_data_init(&reply_data_object);
+    libambit_sbem0102_data_add(&send_data_object, 0x81, NULL, 0);
+    if (libambit_sbem0102_command_request(&object->driver_data->sbem0102, ambit_command_ambit3_log_headers, &send_data_object, &reply_data_object) != 0) {
+        LOG_WARNING("Failed to read log headers");
+        return -1;
+    }
+
+    if (object->driver_data->memory_maps.initialized == 0) {
+        if (get_memory_maps(object) != 0) {
+            return -1;
+        }
+    }
+
+    // Initialize PMEM20 log before starting to read logs
+    libambit_pmem20_log_init(&object->driver_data->pmem20, object->driver_data->memory_maps.excercise_log.start, object->driver_data->memory_maps.excercise_log.size);
+
+    while (libambit_sbem0102_data_next(&reply_data_object) == 0) {
+        switch (libambit_sbem0102_data_id(&reply_data_object)) {
+          case 0x4e:
+            log_entries_total = read16(libambit_sbem0102_data_ptr(&reply_data_object), 0);
+            LOG_INFO("Number of logs=%d", log_entries_total);
+            break;
+          case 0x4f:
+            log_entries_notsynced = read16(libambit_sbem0102_data_ptr(&reply_data_object), 0);
+            LOG_INFO("Number of logs marked as not syncronized=%d", log_entries_notsynced);
+            break;
+          case 0x7e:
+            if (parse_log_header(libambit_sbem0102_data_ptr(&reply_data_object), &log_header) == 0) {
+                LOG_INFO("Log header parsed successfully");
+                if (skip_cb(userref, &log_header.header) != 0) {
+                    LOG_INFO("Reading data of log %d of %d", log_entries_walked + 1, log_entries_total);
+                    log_entry = libambit_pmem20_log_read_entry_address(&object->driver_data->pmem20, log_header.address, log_header.end_address - log_header.address);
+                    if (log_entry != NULL) {
+                        if (push_cb != NULL) {
+                            push_cb(userref, log_entry);
+                        }
+                        entries_read++;
+                    }
+                }
+                else {
+                    LOG_INFO("Log entry already exists, skipping");
+                }
+            }
+            else {
+                LOG_INFO("Failed to parse log header");
+            }
+            log_entries_walked++;
+            if (progress_cb != NULL) {
+                progress_cb(userref, log_entries_total, log_entries_walked, 100*log_entries_walked/log_entries_total);
+            }
+            break;
+          default:
+            break;
+        }
+    }
+
+    libambit_sbem0102_data_free(&send_data_object);
+    libambit_sbem0102_data_free(&reply_data_object);
+
+    return entries_read;
+}
+
+static int gps_orbit_header_read(ambit_object_t *object, uint8_t data[8])
+{
+    uint8_t *reply_data = NULL;
+    size_t replylen = 0;
+    int ret = -1;
+
+    if (libambit_protocol_command(object, ambit_command_gps_orbit_head, NULL, 0, &reply_data, &replylen, 0) == 0 && replylen >= 9) {
+        memcpy(data, &reply_data[1], 8);
+        libambit_protocol_free(reply_data);
+
+        ret = 0;
+    }
+    else {
+        LOG_WARNING("Failed to read GPS orbit header");
+    }
+
+    return ret;
+}
+
+static int gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen)
+{
+    uint8_t header[8], cmpheader[8];
+    int ret = -1;
+
+    LOG_INFO("Writing GPS orbit data");
+
+    libambit_protocol_command(object, ambit_command_write_start, NULL, 0, NULL, NULL, 0);
+
+    if (object->driver->gps_orbit_header_read(object, header) == 0) {
+        cmpheader[0] = data[7]; // Year, swap bytes
+        cmpheader[1] = data[6];
+        cmpheader[2] = data[8];
+        cmpheader[3] = data[9];
+        cmpheader[4] = data[13]; // 4 byte swap
+        cmpheader[5] = data[12];
+        cmpheader[6] = data[11];
+        cmpheader[7] = data[10];
+
+        // Check if new data differs 
+        if (memcmp(header, cmpheader, 8) != 0) {
+            ret = libambit_pmem20_gps_orbit_write(&object->driver_data->pmem20, data, datalen, true);
+        }
+        else {
+            LOG_INFO("Current GPS orbit data is already up to date, skipping");
+            ret = 0;
+        }
+    }
+
+    return ret;
+}
+
+static int parse_log_header(const uint8_t *data, ambit3_log_header_t *log_header)
+{
+    struct tm tm;
+    char *ptr;
+    size_t offset = 0;
+
+    // Start with parsing the time
+    if ((ptr = libambit_strptime((const char *)data, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL) {
+        return -1;
+    }
+    log_header->header.date_time.year = 1900 + tm.tm_year;
+    log_header->header.date_time.month = tm.tm_mon + 1;
+    log_header->header.date_time.day = tm.tm_mday;
+    log_header->header.date_time.hour = tm.tm_hour;
+    log_header->header.date_time.minute = tm.tm_min;
+    log_header->header.date_time.msec = tm.tm_sec*1000;
+    offset += (size_t)ptr - (size_t)data + 1;
+
+    log_header->synced = read8inc(data, &offset);
+    log_header->address = read32inc(data, &offset);
+    log_header->end_address = read32inc(data, &offset);
+    offset += 8; // Unknown bytes
+    log_header->header.heartrate_min = read8inc(data, &offset);
+    log_header->header.heartrate_avg = read8inc(data, &offset);
+    log_header->header.heartrate_max = read8inc(data, &offset);
+    log_header->header.heartrate_max_time = read32inc(data, &offset);
+    log_header->header.heartrate_min_time = read32inc(data, &offset);
+    // temperature format is messed up, 1 byte is missing, just skip for now
+    log_header->header.temperature_min = 0;
+    log_header->header.temperature_max = 0;
+    offset += 2;
+    log_header->header.temperature_min_time = read32inc(data, &offset);
+    log_header->header.temperature_max_time = read32inc(data, &offset);
+    log_header->header.altitude_min = read16inc(data, &offset);
+    log_header->header.altitude_max = read16inc(data, &offset);
+    log_header->header.altitude_min_time = read32inc(data, &offset);
+    log_header->header.altitude_max_time = read32inc(data, &offset);
+    log_header->header.cadence_avg = read8inc(data, &offset);
+    log_header->header.cadence_max = read8inc(data, &offset);
+    log_header->header.cadence_max_time = read32inc(data, &offset);
+    log_header->header.speed_avg = read16inc(data, &offset); // 10 m/h
+    log_header->header.speed_max = read16inc(data, &offset); // 10 m/h
+    log_header->header.speed_max_time = read32inc(data, &offset);
+    offset += 4; // Unknown bytes
+    log_header->header.duration = read32inc(data, &offset)*100; // seconds 0.1
+    log_header->header.ascent = read16inc(data, &offset);
+    log_header->header.descent = read16inc(data, &offset);
+    log_header->header.ascent_time = read32inc(data, &offset)*1000;
+    log_header->header.descent_time = read32inc(data, &offset)*1000;
+    log_header->header.recovery_time = read16inc(data, &offset)*60*1000;
+    log_header->header.peak_training_effect = read8inc(data, &offset);
+    if (log_header->header.activity_name) {
+        free(log_header->header.activity_name);
+    }
+    log_header->header.activity_name = utf8memconv((const char*)(data + offset), 16, "ISO-8859-15");
+    log_header->header.distance = read32inc(data, &offset);
+    log_header->header.energy_consumption = read16inc(data, &offset);
+
+    return 0;
+}
+
+static int get_memory_maps(ambit_object_t *object)
+{
+    uint8_t *reply_data = NULL;
+    size_t replylen = 0;
+    uint8_t send_data[4] = { 0x00, 0x00, 0x00, 0x00 };
+    libambit_sbem0102_data_t reply_data_object;
+    memory_map_entry_t *mm_entry;
+    const uint8_t *ptr;
+
+    if (libambit_protocol_command(object, ambit_command_unknown2, NULL, 0, &reply_data, &replylen, 2) != 0 || replylen < 4) {
+        libambit_protocol_free(reply_data);
+        LOG_WARNING("Failed to read memory map key");
+        return -1;
+    }
+    libambit_protocol_free(reply_data);
+
+    libambit_sbem0102_data_init(&reply_data_object);
+    if (libambit_sbem0102_command_request_raw(&object->driver_data->sbem0102, ambit_command_ambit3_memory_map, send_data, sizeof(send_data), &reply_data_object) != 0) {
+        LOG_WARNING("Failed to read memory map");
+        return -1;
+    }
+
+    while (libambit_sbem0102_data_next(&reply_data_object) == 0) {
+        if (libambit_sbem0102_data_id(&reply_data_object) == 0x3f) {
+            ptr = libambit_sbem0102_data_ptr(&reply_data_object);
+            mm_entry = NULL;
+            if (strcmp((char*)ptr, "Waypoints") == 0) {
+                mm_entry = &object->driver_data->memory_maps.waypoints;
+            }
+            else if (strcmp((char*)ptr, "Routes") == 0) {
+                mm_entry = &object->driver_data->memory_maps.waypoints;
+            }
+            else if (strcmp((char*)ptr, "Rules") == 0) {
+                mm_entry = &object->driver_data->memory_maps.rules;
+            }
+            else if (strcmp((char*)ptr, "GpsSGEE") == 0) {
+                mm_entry = &object->driver_data->memory_maps.gps;
+            }
+            else if (strcmp((char*)ptr, "CustomModes") == 0) {
+                mm_entry = &object->driver_data->memory_maps.custom_modes;
+            }
+            else if (strcmp((char*)ptr, "TrainingProgram") == 0) {
+                mm_entry = &object->driver_data->memory_maps.training_program;
+            }
+            else if (strcmp((char*)ptr, "ExerciseLog") == 0) {
+                mm_entry = &object->driver_data->memory_maps.excercise_log;
+            }
+            else if (strcmp((char*)ptr, "EventLog") == 0) {
+                mm_entry = &object->driver_data->memory_maps.event_log;
+            }
+            else if (strcmp((char*)ptr, "BlePairingInfo") == 0) {
+                mm_entry = &object->driver_data->memory_maps.ble_pairing;
+            }
+            else {
+                LOG_WARNING("Unknown memory map type \"%s\"", (char*)ptr);
+            }
+
+            if (mm_entry != NULL) {
+                // We have dealed with the name, advance to hash
+                ptr += strlen((char*)ptr) + 1;
+
+                if (libambit_htob((const char*)ptr, mm_entry->hash, sizeof(mm_entry->hash)) < 0) {
+                    LOG_ERROR("Failed to read memory map hash");
+                }
+                ptr += strlen((char*)ptr) + 1;
+
+                mm_entry->start = read32(ptr, 0);
+                ptr += 4;
+                mm_entry->size = read32(ptr, 0);
+            }
+        }
+    }
+
+    object->driver_data->memory_maps.initialized = 1;
+    libambit_sbem0102_data_free(&reply_data_object);
+
+    LOG_INFO("Memory map successfully parsed");
+
+    return 0;
+}
diff --git a/src/libambit/device_driver_common.c b/src/libambit/device_driver_common.c
new file mode 100644
index 0000000..859efb3
--- /dev/null
+++ b/src/libambit/device_driver_common.c
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "device_driver_common.h"
+#include "protocol.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Local definitions
+ */
+
+/*
+ * Static functions
+ */
+
+/*
+ * Public functions
+ */
+int libambit_device_driver_lock_log(ambit_object_t *object, bool lock)
+{
+    int ret = -1;
+    uint8_t send_data[] = { 0x00, 0x00, 0x00, 0x00 };
+    uint8_t *reply_data = NULL;
+    size_t replylen;
+
+    uint32_t current_lock = 0xffffffff;
+
+    if ((ret = libambit_protocol_command(object, ambit_command_lock_check, NULL, 0, &reply_data, &replylen, 0)) == 0) {
+        current_lock = le32toh(*(uint32_t*)reply_data);
+        libambit_protocol_free(reply_data);
+    }
+
+    if (lock && current_lock == 0) {
+        LOG_INFO("Setting Sync message to device display");
+        send_data[0] = 1;
+        ret = libambit_protocol_command(object, ambit_command_lock_set, send_data, sizeof(send_data), &reply_data, &replylen, 0);
+        libambit_protocol_free(reply_data);
+    }
+    else if (!lock && current_lock == 1) {
+        LOG_INFO("Clearing Sync message to device display");
+        send_data[0] = 0;
+        ret = libambit_protocol_command(object, ambit_command_lock_set, send_data, sizeof(send_data), &reply_data, &replylen, 0);
+        libambit_protocol_free(reply_data);
+    }
+
+    return ret;
+}
+
+int libambit_device_driver_date_time_set(ambit_object_t *object, struct tm *tm)
+{
+    uint8_t date_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 };
+    uint8_t time_data[8];
+    uint16_t year = htole16(1900 + tm->tm_year);
+    uint16_t sec = htole16(1000*tm->tm_sec);
+    int ret = -1;
+
+    LOG_INFO("Writing date and time to clock");
+
+    // Set date
+    memcpy(&date_data[0], &year, sizeof(uint16_t));
+    date_data[2] = 1 + tm->tm_mon;
+    date_data[3] = tm->tm_mday;
+    // byte[4-7] unknown (but set to 0x28000000 in moveslink)
+
+    // Set time (+date)
+    memcpy(&time_data[0], &year, sizeof(uint16_t));
+    time_data[2] = 1 + tm->tm_mon;
+    time_data[3] = tm->tm_mday;
+    time_data[4] = tm->tm_hour;
+    time_data[5] = tm->tm_min;
+    memcpy(&time_data[6], &sec, sizeof(uint16_t));
+
+    if (libambit_protocol_command(object, ambit_command_date, date_data, sizeof(date_data), NULL, NULL, 0) == 0 &&
+        libambit_protocol_command(object, ambit_command_time, time_data, sizeof(time_data), NULL, NULL, 0) == 0) {
+
+        ret = 0;
+    }
+    else {
+        LOG_WARNING("Failed to write date and time");
+    }
+
+    return ret;
+}
+
+int libambit_device_driver_status_get(ambit_object_t *object, ambit_device_status_t *status)
+{
+    uint8_t *reply_data = NULL;
+    size_t replylen;
+    int ret = -1;
+
+    LOG_INFO("Reading device status");
+
+    if (libambit_protocol_command(object, ambit_command_status, NULL, 0, &reply_data, &replylen, 0) == 0) {
+        if (status != NULL) {
+            status->charge = reply_data[1];
+        }
+        ret = 0;
+    }
+    else {
+        LOG_WARNING("Failed to read device status");
+    }
+
+    libambit_protocol_free(reply_data);
+
+    return ret;
+}
diff --git a/src/libambit/device_driver_common.h b/src/libambit/device_driver_common.h
new file mode 100644
index 0000000..c1312df
--- /dev/null
+++ b/src/libambit/device_driver_common.h
@@ -0,0 +1,36 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __DEVICE_DRIVER_COMMON_H__
+#define __DEVICE_DRIVER_COMMON_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "libambit.h"
+
+int libambit_device_driver_lock_log(ambit_object_t *object, bool lock);
+int libambit_device_driver_date_time_set(ambit_object_t *object, struct tm *tm);
+int libambit_device_driver_status_get(ambit_object_t *object, ambit_device_status_t *status);
+
+#endif /* DEVICE_DRIVER_COMMON */
diff --git a/src/libambit/device_support.c b/src/libambit/device_support.c
new file mode 100644
index 0000000..2d589e9
--- /dev/null
+++ b/src/libambit/device_support.c
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "device_support.h"
+#include "device_driver.h"
+
+#include <string.h>
+
+/*
+ * Local definitions
+ */
+#define SUUNTO_USB_VENDOR_ID 0x1493
+
+typedef struct int_known_device_s {
+    uint16_t vid;
+    uint16_t pid;
+    char *model;
+    uint8_t min_sw_version[4];
+    ambit_known_device_t public_info;
+} int_known_device_t;
+
+/*
+ * Static functions
+ */
+static uint32_t version_number(const uint8_t version[4]);
+
+/*
+ * Static variables
+ */
+static int_known_device_t known_devices[] = {
+    { SUUNTO_USB_VENDOR_ID, 0x001c, "Finch", {0x00,0x00,0x00,0x00}, { "Suunto Ambit3 Sport", true, &ambit_device_driver_ambit3, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x001b, "Emu", {0x00,0x00,0x00,0x00}, { "Suunto Ambit3 Peak", true, &ambit_device_driver_ambit3, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x001d, "Greentit", {0x00,0x00,0x00,0x00}, { "Suunto Ambit2 R", true, &ambit_device_driver_ambit, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x01,0x01,0x02,0x00}, { "Suunto Ambit2 S", true, &ambit_device_driver_ambit, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x01,0x01,0x02,0x00}, { "Suunto Ambit2", true, &ambit_device_driver_ambit, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x00,0x02,0x03,0x00}, { "Suunto Ambit2 S", false, NULL, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x00,0x02,0x03,0x00}, { "Suunto Ambit2", false, NULL, 0x0400 } },
+    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x00,0x02,0x02,0x00}, { "Suunto Ambit2 S (up to 0.2.2)", false, NULL, 0x0200 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x00,0x02,0x02,0x00}, { "Suunto Ambit2 (up to 0.2.2)", false, NULL, 0x0200 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x02,0x01,0x00,0x00}, { "Suunto Ambit", true, &ambit_device_driver_ambit, 0x0200 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x09,0x00,0x00}, { "Suunto Ambit", false, NULL, 0x0200 } }, /* First with PMEM 2.0!? */
+    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x06,0x00,0x00}, { "Suunto Ambit", false, NULL, 0 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x01,0x00,0x00}, { "Suunto Ambit", false, NULL, 0 } },
+    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x00,0x00,0x00,0x00}, { "Suunto Ambit", false, NULL, 0 } },
+    { 0x0000, 0x0000, NULL, {0x00,0x00,0x00,0x00}, { NULL, false, NULL, 0 } }
+};
+
+bool libambit_device_support_known(uint16_t vendor_id, uint16_t product_id)
+{
+    int i;
+
+    for (i=0; i<sizeof(known_devices)/sizeof(known_devices[0]); i++) {
+        if (vendor_id == known_devices[i].vid && product_id == known_devices[i].pid) {
+            // Found at least one row with the correct device
+            return true;
+        }
+    }
+
+    return false;
+}
+
+const ambit_known_device_t *libambit_device_support_find(uint16_t vendor_id, uint16_t product_id, const char *model, const uint8_t *fw_version)
+{
+    ambit_known_device_t *device = NULL;
+    int i;
+
+    for (i=0; i<sizeof(known_devices)/sizeof(known_devices[0]); i++) {
+        if (vendor_id == known_devices[i].vid &&
+            product_id == known_devices[i].pid &&
+            strcmp(model, known_devices[i].model) == 0 &&
+            (version_number (fw_version) >= version_number (known_devices[i].min_sw_version))) {
+            // Found matching entry, reset to this one!
+            device = &known_devices[i].public_info;
+            break;
+        }
+    }
+
+    return device;
+}
+
+static uint32_t version_number(const uint8_t version[4])
+{
+    return (  (version[0] << 24)
+            | (version[1] << 16)
+            | (version[2] <<  0)
+            | (version[3] <<  8));
+}
diff --git a/src/libambit/device_support.h b/src/libambit/device_support.h
new file mode 100644
index 0000000..90470c4
--- /dev/null
+++ b/src/libambit/device_support.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __DEVICE_SUPPORT_H__
+#define __DEVICE_SUPPORT_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct ambit_known_device_s {
+    char *name;
+    bool supported;
+    struct ambit_device_driver_s *driver;
+    uint32_t driver_param;
+} ambit_known_device_t;
+
+bool libambit_device_support_known(uint16_t vendor_id, uint16_t product_id);
+const ambit_known_device_t *libambit_device_support_find(uint16_t vendor_id, uint16_t product_id, const char *model, const uint8_t *fw_version);
+
+#endif /* __DEVICE_SUPPORT_H__ */
diff --git a/src/libambit/hid-libusb.c b/src/libambit/hidapi/hid-libusb.c
similarity index 100%
rename from src/libambit/hid-libusb.c
rename to src/libambit/hidapi/hid-libusb.c
diff --git a/src/libambit/hid.c b/src/libambit/hidapi/hid-linux.c
similarity index 100%
rename from src/libambit/hid.c
rename to src/libambit/hidapi/hid-linux.c
diff --git a/src/libambit/hidapi/hid-pcapsimulate.c b/src/libambit/hidapi/hid-pcapsimulate.c
new file mode 100644
index 0000000..c21ac79
--- /dev/null
+++ b/src/libambit/hidapi/hid-pcapsimulate.c
@@ -0,0 +1,442 @@
+/*******************************************************
+ HIDAPI simulation interface for PCAP files
+
+ Set PCAP-file to parse by setting environment variable
+ HIDAPI_PCAPSIMULATE_FILENAME to the file path
+********************************************************/
+
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pcap/pcap.h>
+
+#include "hidapi.h"
+
+/* Local definitions */
+struct hid_device_ {
+    pcap_t *pcap;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    uint16_t last_write_command;
+    uint16_t last_sequence_number;
+    uint8_t reading_parts;
+};
+
+typedef struct device_id_mappings_s {
+    uint16_t vendor_id;
+    uint16_t product_id;
+    char *model;
+    char *manufacturer;
+    char *product;
+} device_id_mappings_t;
+
+// crc16.c
+uint16_t crc16_ccitt_false(unsigned char *buf, size_t buflen);
+uint16_t crc16_ccitt_false_init(unsigned char *buf, size_t buflen, uint16_t crc);
+
+/* Static functions */
+static pcap_t *pcap_file_reopen(pcap_t *old_pcap, char *errbuf);
+static const u_char *pcap_file_get_next(pcap_t *pcap);
+static const u_char *pcap_file_find_next_pkt(pcap_t *pcap, uint16_t command, uint8_t recv_not_send, const u_char *data);
+static uint16_t pcap_file_find_next_pkt_reass(pcap_t *pcap, uint16_t command, uint8_t recv_not_send, const u_char *data, u_char **buf);
+
+static hid_device *new_hid_device(void);
+static wchar_t *utf8_to_wchar_t(const char *utf8);
+
+
+/* Static data */
+static device_id_mappings_t device_id_mapping[] = {
+    { 0x1493, 0x001d, "Greentit", "Suunto", "Ambit" },
+    { 0x1493, 0x001c, "Finch", "Suunto", "Ambit" },
+    { 0x1493, 0x001b, "Emu", "Suunto", "Ambit" },
+    { 0x1493, 0x001a, "Colibri", "Suunto", "Ambit" },
+    { 0x1493, 0x0019, "Duck", "Suunto", "Ambit" },
+    { 0x1493, 0x0010, "Bluebird", "Suunto", "Ambit" }
+};
+static const device_id_mappings_t *detected_device = NULL;
+static char *detected_device_serial = NULL;
+
+int HID_API_EXPORT hid_init(void)
+{
+    pcap_t *pcap;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    u_char *pktbuf;
+    uint16_t pktbuf_len;
+    char *model_string;
+    char *serial_string;
+    int i;
+
+    if (detected_device == NULL) {
+        pcap = pcap_file_reopen(NULL, errbuf);
+        if (pcap == NULL) {
+            return -1;
+        }
+
+        // Try to find device info in PCAP file
+        pktbuf_len = pcap_file_find_next_pkt_reass(pcap, 0x0002, 1, NULL, &pktbuf);
+
+        if (pktbuf_len > 0) {
+            model_string = (char*)pktbuf;
+            serial_string = (char*)(pktbuf + 16);
+
+            // Try to find matching model
+            for (i=0; i<sizeof(device_id_mapping)/sizeof(device_id_mapping[0]); i++) {
+                if (strncmp(device_id_mapping[i].model, model_string, 16) == 0) {
+                    detected_device = &device_id_mapping[i];
+                    detected_device_serial = malloc(17);
+                    strncpy(detected_device_serial, serial_string, 16);
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+    return 0;
+}
+
+
+struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+    struct hid_device_info *root = NULL; /* return object */
+
+    hid_init();
+
+    if (detected_device != NULL) {
+        struct hid_device_info *tmp;
+
+        tmp = malloc(sizeof(struct hid_device_info));
+        tmp->next = NULL;
+
+        tmp->path = calloc(1, 1);
+        tmp->vendor_id = detected_device->vendor_id;
+        tmp->product_id = detected_device->product_id;
+        tmp->serial_number = utf8_to_wchar_t(detected_device_serial);
+        tmp->release_number = 0x0;
+        tmp->interface_number = -1;
+        tmp->manufacturer_string = utf8_to_wchar_t(detected_device->manufacturer);
+        tmp->product_string = utf8_to_wchar_t(detected_device->product);
+
+        root = tmp;
+    }
+
+    return root;
+}
+
+void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+    struct hid_device_info *d = devs;
+    while (d) {
+        struct hid_device_info *next = d->next;
+        free(d->path);
+        free(d->serial_number);
+        free(d->manufacturer_string);
+        free(d->product_string);
+        free(d);
+        d = next;
+    }
+}
+
+hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+    hid_device *handle = NULL;
+
+    handle = hid_open_path(NULL);
+
+    return handle;
+}
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+    hid_device *dev = NULL;
+
+    hid_init();
+
+    if (detected_device != NULL) {
+        dev = new_hid_device();
+        dev->pcap = pcap_file_reopen(NULL, dev->errbuf);
+        if (dev->pcap == NULL) {
+            return NULL;
+        }
+    }
+
+    return dev;
+}
+
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+    const u_char *pkt;
+    uint16_t command;
+    uint8_t pkt_part;
+    uint8_t len;
+
+    // Parse a few parts of the data
+    len = data[1];
+    pkt_part = data[2];
+    command = be16toh(*(uint16_t*)(data + 8));
+
+    // If this is a contineous write, we have to assume this is just fine, do
+    // nothing
+    if (pkt_part == 0x5d) {
+        // First try, search to end
+        pkt = pcap_file_find_next_pkt(dev->pcap, command, 0, len != 20 ? data + 20 : NULL);
+        if (pkt != NULL) {
+        }
+        // Second try, read from top
+        if (pkt == NULL) {
+            dev->pcap = pcap_file_reopen(dev->pcap, dev->errbuf);
+            pkt = pcap_file_find_next_pkt(dev->pcap, command, 0, len != 20 ? data + 20 : NULL);
+        }
+        if (pkt != NULL) {
+        }
+        // Third try, do not care about data
+        if (pkt == NULL) {
+            dev->pcap = pcap_file_reopen(dev->pcap, dev->errbuf);
+            pkt = pcap_file_find_next_pkt(dev->pcap, command, 0, NULL);
+        }
+        if (pkt != NULL) {
+        }
+
+        dev->last_write_command = command;
+        dev->last_sequence_number = le16toh(*(uint16_t*)(data + 14));
+        dev->reading_parts = 0;
+    }
+    
+    return pkt != NULL ? 0 : -1;
+}
+
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+    const u_char *pkt = NULL;
+    u_char tmpbuf[64];
+    uint16_t *payload_crc, tmpcrc;
+
+    // If we have already started to read parts, we should just continue with
+    // next valid packet, else we need to resolve first packet
+    if (dev->reading_parts) {
+        pkt = pcap_file_get_next(dev->pcap);
+    }
+    else {
+        // Search for next receive packet
+        pkt = pcap_file_find_next_pkt(dev->pcap, 0xffff, 1, NULL);
+    }
+
+    if (pkt != NULL) {
+        if (dev->reading_parts == 0) {
+            // If we found firstpacket, we need to rewrite sequence number and crc
+            memcpy(tmpbuf, pkt, 64);
+            *(uint16_t*)(tmpbuf + 14) = htole16(dev->last_sequence_number);
+            tmpcrc = crc16_ccitt_false(&tmpbuf[2], 4);
+            *(uint16_t*)(tmpbuf + 6) = htole16(tmpcrc);
+            payload_crc = (uint16_t *)&tmpbuf[tmpbuf[1]];
+            *payload_crc = htole16(crc16_ccitt_false_init(&tmpbuf[8], tmpbuf[3], tmpcrc));
+            pkt = tmpbuf;
+        }
+        dev->reading_parts = 1;
+        // Fix length
+        if (length > 64)
+            length = 64;
+        if (data != NULL) {
+            memcpy(data, pkt, length);
+        }
+        return length;
+    }
+    return -1;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+    return hid_read_timeout(dev, data, length, 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+    return 0; /* Success */
+}
+
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+    return 0;
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+    return 0;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+    if (!dev)
+        return;
+
+    pcap_close(dev->pcap);
+}
+
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+    return -1;
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+    return -1;
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+    return -1;
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+    return -1;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+    return NULL;
+}
+
+static pcap_t *pcap_file_reopen(pcap_t *old_pcap, char *errbuf)
+{
+    char *pcap_file;
+    pcap_t *pcap = NULL;
+
+    if (old_pcap != NULL) {
+        pcap_close(old_pcap);
+    }
+
+    pcap_file = getenv("HIDAPI_PCAPSIMULATE_FILENAME");
+    if (pcap_file != NULL) {
+        pcap = pcap_open_offline(pcap_file, errbuf);
+        if (pcap == NULL) {
+            printf("Error: Failed to open pcap file %s\n", pcap_file);
+        }
+    }
+    else {
+        printf("Error: No HIDAPI_PCAPSIMULATE_FILENAME variable defined\n");
+    }
+
+    return pcap;
+}
+
+static const u_char *pcap_file_get_next(pcap_t *pcap)
+{
+    struct pcap_pkthdr h;
+    const u_char *pktdata;
+    size_t data_offset;
+
+    do {
+        pktdata = pcap_next(pcap, &h);
+        if (h.len == 128 || h.len == 91) { // Linux USB vs USBPcap
+            data_offset = h.len - 64;
+            if (pktdata[data_offset] == 0x3f) { // Sanity check, first byte
+                return pktdata + data_offset;
+            }
+        }
+    } while(pktdata != NULL);
+
+    return NULL;
+}
+
+static const u_char *pcap_file_find_next_pkt(pcap_t *pcap, uint16_t command, uint8_t recv_not_send, const u_char *data)
+{
+    const u_char *pktdata;
+
+    do {
+        pktdata = pcap_file_get_next(pcap);
+        if (pktdata != NULL) {
+            uint8_t len = pktdata[1];
+            uint8_t pkttype = pktdata[2];
+            uint16_t pktcommand = be16toh(*(uint16_t*)(pktdata + 8));
+            uint8_t send_recv = (pktdata[10] & 0x03) >> 1;
+            if (pkttype == 0x5d &&
+                (command == 0xffff || pktcommand == command) &&
+                send_recv == recv_not_send) {
+                if (data != NULL) {
+                    // Compare data as well
+                    if (memcmp(data, pktdata + 20, len - 20) == 0) {
+                        break;
+                    }
+                }
+                else {
+                    break;
+                }
+            }
+        }
+    } while(pktdata != NULL);
+
+    return pktdata;
+}
+
+static uint16_t pcap_file_find_next_pkt_reass(pcap_t *pcap, uint16_t command, uint8_t recv_not_send, const u_char *data, u_char **buf)
+{
+    const u_char *pkt;
+    u_char *retbuf = NULL;
+    uint16_t retlen = 0;
+    uint16_t msg_parts, msg_part;
+    uint16_t pkts_captured = 1;
+
+    pkt = pcap_file_find_next_pkt(pcap, command, recv_not_send, data);
+
+    if (pkt != NULL) {
+        // Check how many packets this entry should consist of
+        msg_parts = le16toh(*(uint16_t*)(pkt + 4));
+        retlen = le32toh(*(uint32_t*)(pkt + 16));
+        retbuf = malloc(44 + 56*(msg_parts-1));
+
+        if (retbuf != NULL) {
+            memcpy(retbuf, pkt + 20, 44);
+            while (msg_parts > pkts_captured) {
+                pkt = pcap_file_get_next(pcap);
+                if (pkt == NULL) {
+                    free(retbuf);
+                    retbuf = NULL;
+                    retlen = 0;
+                    break;
+                }
+                msg_part = le16toh(*(uint16_t*)(pkt + 4));
+                memcpy(retbuf + 44 + 56*(msg_part-1), pkt + 8, 56);
+                pkts_captured++;
+            }
+        }
+    }
+
+    *buf = retbuf;
+    return retlen;
+}
+
+static hid_device *new_hid_device(void)
+{
+    hid_device *dev = calloc(1, sizeof(hid_device));
+
+    return dev;
+}
+
+/* The caller must free the returned string with free(). */
+static wchar_t *utf8_to_wchar_t(const char *utf8)
+{
+    wchar_t *ret = NULL;
+
+    if (utf8) {
+        size_t wlen = mbstowcs(NULL, utf8, 0);
+        if ((size_t) -1 == wlen) {
+            return wcsdup(L"");
+        }
+        ret = calloc(wlen+1, sizeof(wchar_t));
+        mbstowcs(ret, utf8, wlen+1);
+        ret[wlen] = 0x0000;
+    }
+
+    return ret;
+}
diff --git a/src/libambit/libambit.c b/src/libambit/libambit.c
index deccfb2..78ffc8c 100644
--- a/src/libambit/libambit.c
+++ b/src/libambit/libambit.c
@@ -21,8 +21,14 @@
  */
 #include "libambit.h"
 #include "libambit_int.h"
+#include "device_support.h"
+#include "device_driver.h"
+#include "protocol.h"
+#include "utils.h"
+#include "debug.h"
 
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -34,221 +40,177 @@
 /*
  * Local definitions
  */
-#define SUUNTO_USB_VENDOR_ID 0x1493
-
-typedef struct ambit_known_device_s ambit_known_device_t;
-
-struct ambit_known_device_s {
-    uint16_t vid;
-    uint16_t pid;
-    char *model;
-    uint8_t min_sw_version[4];
-    char *name;
-    bool supported;
-    uint16_t pmem20_chunksize;
-};
+#define LIBAMBIT_MODEL_LENGTH    16
+#define LIBAMBIT_SERIAL_LENGTH   16
 
 /*
  * Static functions
  */
 static int device_info_get(ambit_object_t *object, ambit_device_info_t *info);
-static int lock_log(ambit_object_t *object, bool lock);
-static uint32_t version_number(const uint8_t version[4]);
+static ambit_device_info_t * ambit_device_info_new(const struct hid_device_info *dev);
 
 /*
  * Static variables
  */
-static ambit_known_device_t known_devices[] = {
-    { SUUNTO_USB_VENDOR_ID, 0x001c, "Finch", {0x00,0x00,0x00,0x00}, "Suunto Ambit3 Sport", false, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x001b, "Emu", {0x00,0x00,0x00,0x00}, "Suunto Ambit3 Peak", false, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x001d, "Greentit", {0x00,0x00,0x00,0x00}, "Suunto Ambit2 R", true, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x01,0x01,0x02,0x00}, "Suunto Ambit2 S", true, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x01,0x01,0x02,0x00}, "Suunto Ambit2", true, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x00,0x02,0x03,0x00}, "Suunto Ambit2 S", false, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x00,0x02,0x03,0x00}, "Suunto Ambit2", false, 0x0400 },
-    { SUUNTO_USB_VENDOR_ID, 0x001a, "Colibri", {0x00,0x02,0x02,0x00}, "Suunto Ambit2 S (up to 0.2.2)", false, 0x0200 },
-    { SUUNTO_USB_VENDOR_ID, 0x0019, "Duck", {0x00,0x02,0x02,0x00}, "Suunto Ambit2 (up to 0.2.2)", false, 0x0200 },
-    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x02,0x01,0x00,0x00}, "Suunto Ambit", true, 0x0200 },
-    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x09,0x00,0x00}, "Suunto Ambit", false, 0x0200 }, /* First with PMEM 2.0!? */
-    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x06,0x00,0x00}, "Suunto Ambit", false, 0 },
-    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x01,0x01,0x00,0x00}, "Suunto Ambit", false, 0 },
-    { SUUNTO_USB_VENDOR_ID, 0x0010, "Bluebird", {0x00,0x00,0x00,0x00}, "Suunto Ambit", false, 0 },
-    { 0x0000, 0x0000, NULL, {0x00,0x00,0x00,0x00}, NULL, false }
-};
-
-static uint8_t komposti_version[] = { 0x01, 0x08, 0x01, 0x00 };
+static uint8_t komposti_version[] = { 0x02, 0x00, 0x2d, 0x00 };
 
 /*
  * Public functions
  */
-ambit_object_t *libambit_detect(void)
+ambit_device_info_t * libambit_enumerate(void)
 {
-    hid_device *handle;
-    struct hid_device_info *devs, *cur_dev;
-    ambit_object_t *ret_object = NULL;
-    int i;
-    ambit_known_device_t *device = NULL;
-    char *path = NULL;
-
-    LOG_INFO("Searching devices");
-
-    devs = hid_enumerate(0x0, 0x0);
-    cur_dev = devs;
-    while (cur_dev) {
-        LOG_INFO("vendor_id=%04x, product_id=%04x", cur_dev->vendor_id, cur_dev->product_id);
-        for (i=0; i<sizeof(known_devices)/sizeof(known_devices[0]); i++) {
-            if (cur_dev->vendor_id == known_devices[i].vid && cur_dev->product_id == known_devices[i].pid) {
-                LOG_INFO("match!");
-                // Found at least one supported row, lets remember that!
-                device = &known_devices[i];
-                path = strdup (cur_dev->path);
-                break;
-            }
-        }
-        if (device != NULL) {
-            // Devcice was found, we can stop looping through devices now...
-            break;
-        }
-        cur_dev = cur_dev->next;
-    }
-    hid_free_enumeration(devs);
+    ambit_device_info_t *devices = NULL;
 
-    if (device != NULL) {
-        LOG_INFO("Trying to open device");
-        handle = hid_open(device->vid, device->pid, NULL);
-        if (handle != NULL) {
-            // Setup hid device correctly
-            hid_set_nonblocking(handle, 1);
-
-            ret_object = malloc(sizeof(ambit_object_t));
-            memset(ret_object, 0, sizeof(ambit_object_t));
-            ret_object->handle = handle;
-            ret_object->vendor_id = device->vid;
-            ret_object->product_id = device->pid;
-
-            // Get device info to resolve supported functionality
-            if (device_info_get(ret_object, &ret_object->device_info) == 0) {
-                // Let's resolve the correct device
-                for (i=0; i<sizeof(known_devices)/sizeof(known_devices[0]); i++) {
-                    if (ret_object->vendor_id == known_devices[i].vid &&
-                        ret_object->product_id == known_devices[i].pid &&
-                        strncmp(ret_object->device_info.model, known_devices[i].model, LIBAMBIT_MODEL_NAME_LENGTH) == 0 &&
-                        (version_number (ret_object->device_info.fw_version) >= version_number (known_devices[i].min_sw_version))) {
-                        // Found matching entry, reset to this one!
-                        device = &known_devices[i];
-                        break;
-                    }
-                }
-                strncpy(ret_object->device_info.name, device->name, LIBAMBIT_PRODUCT_NAME_LENGTH);
-                ret_object->device_info.is_supported = device->supported;
+    struct hid_device_info *devs = hid_enumerate(0, 0);
+    struct hid_device_info *current;
+
+    if (!devs) {
+      LOG_WARNING("HID: no USB HID devices found");
+      return NULL;
+    }
 
-                // Initialize pmem
-                libambit_pmem20_init(ret_object, device->pmem20_chunksize);
+    current = devs;
+    while (current) {
+        ambit_device_info_t *tmp = ambit_device_info_new(current);
 
-                LOG_INFO("Successfully opened device \"%s (%s)\" SW: %d.%d.%d, Supported: %s", device->name, device->model, ret_object->device_info.fw_version[0], ret_object->device_info.fw_version[1], ret_object->device_info.fw_version[3] << 8 | ret_object->device_info.fw_version[2], device->supported ? "YES" : "NO");
+        if (tmp) {
+            if (devices) {
+                tmp->next = devices;
             }
             else {
-                free(ret_object);
-                ret_object = NULL;
-                LOG_ERROR("Failed to get device info from \"%s (%s)\"", device->name, device->model);
+                devices = tmp;
             }
         }
-        else {
-#ifdef DEBUG_PRINT_ERROR
-            int error = 0;
-            int fd = 0;
-            if (path) fd = open (path, O_RDWR);
-            if (-1 == fd) error = errno;
-            else close (fd);
-#endif
-            LOG_ERROR("Failed to open device \"%s (%s)\"", device->name, device->model);
-            LOG_ERROR("Reason: %s", (error ? strerror(error) : "Unknown"));
-        }
+        current = current->next;
     }
+    hid_free_enumeration(devs);
 
-    if (path) free (path);
-    return ret_object;
+    return devices;
 }
 
-void libambit_close(ambit_object_t *object)
+void libambit_free_enumeration(ambit_device_info_t *devices)
 {
-    LOG_INFO("Closing");
-    if (object != NULL) {
-        if (object->handle != NULL) {
-            // Make sure to clear log lock (if possible)
-            lock_log(object, false);
-            hid_close(object->handle);
-        }
-
-        libambit_pmem20_deinit(object);
-        free(object);
+    while (devices) {
+        ambit_device_info_t *next = devices->next;
+        if (devices->name)   free(devices->name);
+        if (devices->model)  free(devices->model);
+        if (devices->serial) free(devices->serial);
+        free((char *) devices->path);
+        free(devices);
+        devices = next;
     }
 }
 
-bool libambit_device_supported(ambit_object_t *object)
+ambit_object_t * libambit_new(const ambit_device_info_t *device)
 {
-    bool ret = false;
+    ambit_object_t *object = NULL;
+    const ambit_known_device_t *known_device = NULL;
+    const char *path = NULL;
 
-    if (object != NULL) {
-        ret = object->device_info.is_supported;
+    if (!device || !device->path) {
+        LOG_ERROR("%s", strerror(EINVAL));
+        return NULL;
     }
 
-    return ret;
+    path = strdup (device->path);
+    if (!path) return NULL;
+
+    if (0 == device->access_status && device->is_supported) {
+        // Note, this should never fail if device was properly received with libambit_enumerate
+        known_device = libambit_device_support_find(device->vendor_id, device->product_id, device->model, device->fw_version);
+        if (known_device != NULL) {
+            object = calloc(1, sizeof(*object));
+            if (object) {
+                object->handle = hid_open_path(path);
+                memcpy(&object->device_info, device, sizeof(*device));
+                object->device_info.path = path;
+                object->driver = known_device->driver;
+
+                if (object->handle) {
+                    hid_set_nonblocking(object->handle, true);
+                }
+
+                // Initialize driver
+                object->driver->init(object, known_device->driver_param);
+            }
+        }
+    }
+    if (!object) {
+        free((char *) path);
+    }
+
+    return object;
 }
 
-int libambit_device_info_get(ambit_object_t *object, ambit_device_info_t *info)
+ambit_object_t * libambit_new_from_pathname(const char* pathname)
 {
-    int ret = -1;
+    ambit_object_t *object = NULL;
+    ambit_device_info_t *info;
+    ambit_device_info_t *current;
 
-    if (object != NULL) {
-        if (info != NULL) {
-            memcpy(info, &object->device_info, sizeof(ambit_device_info_t));
+    if (!pathname) {
+        LOG_ERROR("%s", strerror(EINVAL));
+        return NULL;
+    }
+
+    info = libambit_enumerate();
+    current = info;
+    while (!object && current) {
+        if (0 == strcmp(pathname, current->path)) {
+            object = libambit_new(current);
         }
-        ret = 0;
+        current = current->next;
     }
+    libambit_free_enumeration(info);
 
-    return ret;
+    return object;
+}
+
+void libambit_close(ambit_object_t *object)
+{
+    LOG_INFO("Closing");
+    if (object != NULL) {
+        if (object->driver != NULL) {
+            // Make sure to clear log lock (if possible)
+            if (object->driver->lock_log != NULL) {
+                object->driver->lock_log(object, false);
+            }
+            if (object->driver->deinit != NULL) {
+                object->driver->deinit(object);
+            }
+        }
+        if (object->handle != NULL) {
+            hid_close(object->handle);
+        }
+
+        free((char *) object->device_info.path);
+        free(object);
+    }
 }
 
 void libambit_sync_display_show(ambit_object_t *object)
 {
-    lock_log(object, true);
+    if (object->driver != NULL && object->driver->lock_log != NULL) {
+        object->driver->lock_log(object, true);
+    }
 }
 
 void libambit_sync_display_clear(ambit_object_t *object)
 {
-    lock_log(object, false);
+    if (object->driver != NULL && object->driver->lock_log != NULL) {
+        object->driver->lock_log(object, false);
+    }
 }
 
 int libambit_date_time_set(ambit_object_t *object, struct tm *tm)
 {
-    uint8_t date_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 };
-    uint8_t time_data[8];
     int ret = -1;
 
-    LOG_INFO("Writing date and time to clock");
-
-    // Set date
-    *(uint16_t*)(&date_data[0]) = htole16(1900 + tm->tm_year);
-    date_data[2] = 1 + tm->tm_mon;
-    date_data[3] = tm->tm_mday;
-    // byte[4-7] unknown (but set to 0x28000000 in moveslink)
-
-    // Set time (+date)
-    *(uint16_t*)(&time_data[0]) = htole16(1900 + tm->tm_year);
-    time_data[2] = 1 + tm->tm_mon;
-    time_data[3] = tm->tm_mday;
-    time_data[4] = tm->tm_hour;
-    time_data[5] = tm->tm_min;
-    *(uint16_t*)(&time_data[6]) = htole16(1000*tm->tm_sec);
-
-    if (libambit_protocol_command(object, ambit_command_date, date_data, sizeof(date_data), NULL, NULL, 0) == 0 &&
-        libambit_protocol_command(object, ambit_command_time, time_data, sizeof(time_data), NULL, NULL, 0) == 0) {
-
-        ret = 0;
+    if (object->driver != NULL && object->driver->date_time_set != NULL) {
+        ret = object->driver->date_time_set(object, tm);
     }
     else {
-        LOG_WARNING("Failed to write date and time");
+        LOG_WARNING("Driver does not support date_time_set");
     }
 
     return ret;
@@ -256,41 +218,27 @@ int libambit_date_time_set(ambit_object_t *object, struct tm *tm)
 
 int libambit_device_status_get(ambit_object_t *object, ambit_device_status_t *status)
 {
-    uint8_t *reply_data = NULL;
-    size_t replylen;
     int ret = -1;
 
-    LOG_INFO("Reading device status");
-
-    if (libambit_protocol_command(object, ambit_command_status, NULL, 0, &reply_data, &replylen, 0) == 0) {
-        if (status != NULL) {
-            status->charge = reply_data[1];
-        }
-        ret = 0;
+    if (object->driver != NULL && object->driver->status_get != NULL) {
+        ret = object->driver->status_get(object, status);
     }
     else {
-        LOG_WARNING("Failed to read device status");
+        LOG_WARNING("Driver does not support status_get");
     }
 
-    libambit_protocol_free(reply_data);
-
     return ret;
 }
 
 int libambit_personal_settings_get(ambit_object_t *object, ambit_personal_settings_t *settings)
 {
-    uint8_t *reply_data = NULL;
-    size_t replylen = 0;
     int ret = -1;
 
-    LOG_INFO("Reading personal settings");
-
-    if (libambit_protocol_command(object, ambit_command_personal_settings, NULL, 0, &reply_data, &replylen, 0) == 0) {
-        ret = libambit_personal_settings_parse(reply_data, replylen, settings);
-        libambit_protocol_free(reply_data);
+    if (object->driver != NULL && object->driver->personal_settings_get != NULL) {
+        ret = object->driver->personal_settings_get(object, settings);
     }
     else {
-        LOG_WARNING("Failed to read personal settings");
+        LOG_WARNING("Driver does not support personal_settings_get");
     }
 
     return ret;
@@ -298,18 +246,13 @@ int libambit_personal_settings_get(ambit_object_t *object, ambit_personal_settin
 
 int libambit_gps_orbit_header_read(ambit_object_t *object, uint8_t data[8])
 {
-    uint8_t *reply_data = NULL;
-    size_t replylen = 0;
     int ret = -1;
 
-    if (libambit_protocol_command(object, ambit_command_gps_orbit_head, NULL, 0, &reply_data, &replylen, 0) == 0 && replylen >= 9) {
-        memcpy(data, &reply_data[1], 8);
-        libambit_protocol_free(reply_data);
-
-        ret = 0;
+    if (object->driver != NULL && object->driver->gps_orbit_header_read != NULL) {
+        ret = object->driver->gps_orbit_header_read(object, data);
     }
     else {
-        LOG_WARNING("Failed to read GPS orbit header");
+        LOG_WARNING("Driver does not support gps_orbit_header_read");
     }
 
     return ret;
@@ -317,31 +260,13 @@ int libambit_gps_orbit_header_read(ambit_object_t *object, uint8_t data[8])
 
 int libambit_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen)
 {
-    uint8_t header[8], cmpheader[8];
     int ret = -1;
 
-    LOG_INFO("Writing GPS orbit data");
-
-    libambit_protocol_command(object, ambit_command_write_start, NULL, 0, NULL, NULL, 0);
-
-    if (libambit_gps_orbit_header_read(object, header) == 0) {
-        cmpheader[0] = data[7]; // Year, swap bytes
-        cmpheader[1] = data[6];
-        cmpheader[2] = data[8];
-        cmpheader[3] = data[9];
-        cmpheader[4] = data[13]; // 4 byte swap
-        cmpheader[5] = data[12];
-        cmpheader[6] = data[11];
-        cmpheader[7] = data[10];
-
-        // Check if new data differs 
-        if (memcmp(header, cmpheader, 8) != 0) {
-            ret = libambit_pmem20_gps_orbit_write(object, data, datalen);
-        }
-        else {
-            LOG_INFO("Current GPS orbit data is already up to date, skipping");
-            ret = 0;
-        }
+    if (object->driver != NULL && object->driver->gps_orbit_write != NULL) {
+        ret = object->driver->gps_orbit_write(object, data, datalen);
+    }
+    else {
+        LOG_WARNING("Driver does not support gps_orbit_write");
     }
 
     return ret;
@@ -349,138 +274,16 @@ int libambit_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datal
 
 int libambit_log_read(ambit_object_t *object, ambit_log_skip_cb skip_cb, ambit_log_push_cb push_cb, ambit_log_progress_cb progress_cb, void *userref)
 {
-    int entries_read = 0;
-
-    uint8_t *reply_data = NULL;
-    size_t replylen = 0;
-    uint16_t log_entries_total = 0;
-    uint16_t log_entries_walked = 0;
-
-    uint32_t more = 0x00000400;
-
-    bool read_pmem = false;
-
-    ambit_log_header_t log_header;
-    ambit_log_entry_t *log_entry;
-
-    LOG_INFO("Reading number of logs");
-
-    /*
-     * Read number of log entries
-     */
-    if (libambit_protocol_command(object, ambit_command_log_count, NULL, 0, &reply_data, &replylen, 0) != 0) {
-        LOG_WARNING("Failed to read number of log entries");
-        return -1;
-    }
-    log_entries_total = le16toh(*(uint16_t*)(reply_data + 2));
-    libambit_protocol_free(reply_data);
-
-    LOG_INFO("Number of logs=%d", log_entries_total);
-
-    /*
-     * First part walks through headers to check if there is any point in start
-     * reading the PMEM content. If no skip callback is defined, there is no
-     * point in checking the headers, because no one can tell us to not include
-     * the logs...
-     */
-
-    if (skip_cb != NULL) {
-        LOG_INFO("Look in headers for new logs");
-        // Rewind
-        if (libambit_protocol_command(object, ambit_command_log_head_first, NULL, 0, &reply_data, &replylen, 0) != 0) {
-            LOG_WARNING("Failed to rewind header pointer");
-            return -1;
-        }
-        more = le32toh(*(uint32_t*)reply_data);
-        libambit_protocol_free(reply_data);
-
-        // Loop through logs while more entries exists
-        while (more == 0x00000400) {
-            LOG_INFO("Reading next header");
-            // Go to next entry
-            if (libambit_protocol_command(object, ambit_command_log_head_step, NULL, 0, &reply_data, &replylen, 0) != 0) {
-                LOG_WARNING("Failed to walk to next header");
-                return -1;
-            }
-            libambit_protocol_free(reply_data);
-
-            // Assume every header is composited by 2 parts, where only the
-            // second is of interrest right now
-            if (libambit_protocol_command(object, ambit_command_log_head, NULL, 0, &reply_data, &replylen, 0) != 0) {
-                LOG_WARNING("Failed to read first part of header");
-                return -1;
-            }
-            libambit_protocol_free(reply_data);
-
-            if (libambit_protocol_command(object, ambit_command_log_head, NULL, 0, &reply_data, &replylen, 0) == 0) {
-                if (replylen > 8 && libambit_pmem20_log_parse_header(reply_data + 8, replylen - 8, &log_header) == 0) {
-                    if (skip_cb(userref, &log_header) != 0) {
-                        // Header was NOT skipped, break out!
-                        read_pmem = true;
-                        LOG_INFO("Found new entry, start reading log data");
-                        break;
-                    }
-                }
-                else {
-                    LOG_ERROR("Failed to parse log header");
-                    return -1;
-                }
-                libambit_protocol_free(reply_data);
-            }
-            else {
-                LOG_WARNING("Failed to read second part of header");
-                return -1;
-            }
+    int ret = -1;
 
-            // Is there more entries to read?
-            if (libambit_protocol_command(object, ambit_command_log_head_peek, NULL, 0, &reply_data, &replylen, 0) != 0) {
-                LOG_WARNING("Failed to check for more headers");
-                return -1;
-            }
-            more = le32toh(*(uint32_t*)reply_data);
-            libambit_protocol_free(reply_data);
-        }
+    if (object->driver != NULL && object->driver->log_read != NULL) {
+        ret = object->driver->log_read(object, skip_cb, push_cb, progress_cb, userref);
     }
     else {
-        LOG_INFO("No skip callback defined, reading log data");
-        read_pmem = true;
+        LOG_WARNING("Driver does not support log_read");
     }
 
-    if (read_pmem) {
-        if (libambit_pmem20_log_init(object) != 0) {
-            return -1;
-        }
-
-        // Loop through all log entries, first check headers
-        while (log_entries_walked < log_entries_total && libambit_pmem20_log_next_header(object, &log_header) == 1) {
-            LOG_INFO("Reading header of log %d of %d", log_entries_walked + 1, log_entries_total);
-            if (progress_cb != NULL) {
-                progress_cb(userref, log_entries_total, log_entries_walked+1, 100*log_entries_walked/log_entries_total);
-            }
-            // Check if this entry needs to be read
-            if (skip_cb == NULL || skip_cb(userref, &log_header) != 0) {
-                LOG_INFO("Reading data of log %d of %d", log_entries_walked + 1, log_entries_total);
-                log_entry = libambit_pmem20_log_read_entry(object);
-                if (log_entry != NULL) {
-                    if (push_cb != NULL) {
-                        push_cb(userref, log_entry);
-                    }
-                    entries_read++;
-                }
-            }
-            else {
-                LOG_INFO("Log %d of %d already exists, skip reading data", log_entries_walked + 1, log_entries_total);
-            }
-            log_entries_walked++;
-            if (progress_cb != NULL) {
-                progress_cb(userref, log_entries_total, log_entries_walked, 100*log_entries_walked/log_entries_total);
-            }
-        }
-    }
-
-    LOG_INFO("%d entries read", entries_read);
-
-    return entries_read;
+    return ret;
 }
 
 void libambit_log_entry_free(ambit_log_entry_t *log_entry)
@@ -508,6 +311,9 @@ void libambit_log_entry_free(ambit_log_entry_t *log_entry)
             }
             free(log_entry->samples);
         }
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
+        }
         free(log_entry);
     }
 }
@@ -522,12 +328,14 @@ static int device_info_get(ambit_object_t *object, ambit_device_info_t *info)
 
     if (libambit_protocol_command(object, ambit_command_device_info, komposti_version, sizeof(komposti_version), &reply_data, &replylen, 1) == 0) {
         if (info != NULL) {
-            memcpy(info->model, reply_data, 16);
-            info->model[16] = 0;
-            memcpy(info->serial, &reply_data[16], 16);
-            info->serial[16] = 0;
-            memcpy(info->fw_version, &reply_data[32], 4);
-            memcpy(info->hw_version, &reply_data[36], 4);
+            const char *p = (char *)reply_data;
+
+            info->model  = utf8memconv(p, LIBAMBIT_MODEL_LENGTH, NULL);
+            p += LIBAMBIT_MODEL_LENGTH;
+            info->serial = utf8memconv(p, LIBAMBIT_SERIAL_LENGTH, NULL);
+            p += LIBAMBIT_SERIAL_LENGTH;
+            memcpy(info->fw_version, p, 4);
+            memcpy(info->hw_version, p + 4, 4);
         }
         ret = 0;
     }
@@ -540,40 +348,164 @@ static int device_info_get(ambit_object_t *object, ambit_device_info_t *info)
     return ret;
 }
 
-static int lock_log(ambit_object_t *object, bool lock)
+const size_t LIBAMBIT_VERSION_LENGTH = 13;      /* max: 255.255.65535 */
+static inline void version_string(char string[LIBAMBIT_VERSION_LENGTH+1],
+                                  const uint8_t version[4])
 {
-    int ret = -1;
-    uint8_t send_data[] = { 0x00, 0x00, 0x00, 0x00 };
-    uint8_t *reply_data = NULL;
-    size_t replylen;
+  if (!string || !version) return;
 
-    uint32_t current_lock = 0xffffffff;
+  snprintf(string, LIBAMBIT_VERSION_LENGTH+1, "%d.%d.%d",
+           version[0], version[1], (version[2] << 0) | (version[3] << 8));
+}
+
+static ambit_device_info_t * ambit_device_info_new(const struct hid_device_info *dev)
+{
+    ambit_device_info_t *device = NULL;
+    const ambit_known_device_t *known_device = NULL;
 
-    if ((ret = libambit_protocol_command(object, ambit_command_lock_check, NULL, 0, &reply_data, &replylen, 0)) == 0) {
-        current_lock = le32toh(*(uint32_t*)reply_data);
-        libambit_protocol_free(reply_data);
+    const char *dev_path;
+
+    uint16_t vid;
+    uint16_t pid;
+
+    hid_device *hid;
+
+    if (!dev || !dev->path) {
+        LOG_ERROR("internal error: expecting hidraw device");
+        return NULL;
     }
 
-    if (lock && current_lock == 0) {
-        LOG_INFO("Setting Sync message to device display");
-        send_data[0] = 1;
-        ret = libambit_protocol_command(object, ambit_command_lock_set, send_data, sizeof(send_data), &reply_data, &replylen, 0);
-        libambit_protocol_free(reply_data);
+    dev_path = dev->path;
+    vid = dev->vendor_id;
+    pid = dev->product_id;
+
+    if (!libambit_device_support_known(vid, pid)) {
+        LOG_INFO("ignoring unknown device (VID/PID: %04x/%04x)", vid, pid);
+        return NULL;
     }
-    else if (!lock && current_lock == 1) {
-        LOG_INFO("Clearing Sync message to device display");
-        send_data[0] = 0;
-        ret = libambit_protocol_command(object, ambit_command_lock_set, send_data, sizeof(send_data), &reply_data, &replylen, 0);
-        libambit_protocol_free(reply_data);
+
+    dev_path = strdup(dev_path);
+    if (!dev_path) return NULL;
+
+    device = calloc(1, sizeof(*device));
+    if (!device) {
+        free ((char *) dev_path);
+        return NULL;
     }
 
-    return ret;
-}
+    device->path = dev_path;
+    device->vendor_id  = vid;
+    device->product_id = pid;
+
+    {                           /* create name for display purposes */
+        char *vendor  = utf8wcsconv(dev->manufacturer_string);
+        char *product = utf8wcsconv(dev->product_string);
+        if (vendor && product) {
+            char *name = (char *)malloc((strlen(vendor) + 1
+                                         + strlen(product) + 1)
+                                        * sizeof(char));
+            if (name) {
+                strcpy(name, vendor);
+                strcat(name, " ");
+                strcat(name, product);
+                free(vendor);
+                free(product);
+                device->name = name;
+            }
+            else {
+                device->name = product;
+                if (vendor) free(vendor);
+            }
+        }
+        else {
+            device->name = product;
+            if (vendor) free(vendor);
+        }
+        device->serial = utf8wcsconv(dev->serial_number);
+    }
 
-static uint32_t version_number(const uint8_t version[4])
-{
-    return (  (version[0] << 24)
-            | (version[1] << 16)
-            | (version[2] <<  0)
-            | (version[3] <<  8));
+    LOG_INFO("HID  : %s: '%s' (serial: %s, VID/PID: %04x/%04x)",
+             device->path, device->name, device->serial,
+             device->vendor_id, device->product_id);
+
+    hid = hid_open_path(device->path);
+    if (hid) {
+        /* HACK ALERT: minimally initialize an ambit object so we can
+         * call device_info_get().  Note that this function sets the
+         * device's model and serial string fields.  Above the latter
+         * has been set already using the HID information.
+         */
+        char *serial = device->serial;
+        ambit_object_t obj;
+        obj.handle = hid;
+        obj.sequence_no = 0;
+        if (0 == device_info_get(&obj, device)) {
+
+            if (!device->serial) { /* fall back to HID information */
+                device->serial = serial;
+            }
+            else {
+                if (serial && 0 != strcmp(device->serial, serial)) {
+                  LOG_INFO("preferring F/W serial number over HID '%s'",
+                           serial);
+                }
+                if (serial) free(serial);
+            }
+
+            known_device = libambit_device_support_find(device->vendor_id, device->product_id, device->model, device->fw_version);
+            if (known_device != NULL) {
+                device->is_supported = known_device->supported;
+                if (device->name && known_device->name
+                    && 0 != strcmp(device->name, known_device->name)) {
+                    char *name = strdup(known_device->name);
+                    if (name) {
+                        LOG_INFO("preferring known name over HID '%s'",
+                                 device->name);
+                        free(device->name);
+                        device->name = name;
+                    }
+                }
+            }
+
+#ifdef DEBUG_PRINT_INFO
+            {
+                char fw_version[LIBAMBIT_VERSION_LENGTH+1];
+                char hw_version[LIBAMBIT_VERSION_LENGTH+1];
+                version_string(fw_version, device->fw_version);
+                version_string(hw_version, device->hw_version);
+
+                LOG_INFO("Ambit: %s: '%s' (serial: %s, VID/PID: %04x/%04x, "
+                         "nick: %s, F/W: %s, H/W: %s, supported: %s)",
+                         device->path, device->name, device->serial,
+                         device->vendor_id, device->product_id,
+                         device->model, fw_version, hw_version,
+                         (device->is_supported ? "YES" : "NO"));
+            }
+#endif
+        }
+        else {
+            LOG_ERROR("cannot get device info from %s", device->path);
+        }
+        hid_close(hid);
+    }
+    else {
+        /* Store an educated guess as to why we cannot open the HID
+         * device.  Without read/write access we cannot communicate
+         * to begin with but there may be other reasons.
+         */
+        int fd = open(device->path, O_RDWR);
+
+        if (-1 == fd) {
+            device->access_status = errno;
+            LOG_ERROR("cannot open HID device (%s): %s", device->path,
+                      strerror (device->access_status));
+        }
+        else {
+            LOG_WARNING("have read/write access to %s but cannot open HID "
+                        "device", device->path);
+            close(fd);
+        }
+    }
+
+    return device;
 }
diff --git a/src/libambit/libambit.h b/src/libambit/libambit.h
index 02f1ed3..264a2d2 100644
--- a/src/libambit/libambit.h
+++ b/src/libambit/libambit.h
@@ -30,19 +30,22 @@ extern "C" {
 #include <stdbool.h>
 #include <time.h>
 
-#define LIBAMBIT_MODEL_NAME_LENGTH    16
-#define LIBAMBIT_SERIAL_LENGTH        16
-#define LIBAMBIT_PRODUCT_NAME_LENGTH  32
-
 typedef struct ambit_object_s ambit_object_t;
 
 typedef struct ambit_device_info_s {
-    char name[LIBAMBIT_PRODUCT_NAME_LENGTH+1];
-    char model[LIBAMBIT_MODEL_NAME_LENGTH+1];
-    char serial[LIBAMBIT_SERIAL_LENGTH+1];
+    char *name;                                        /* UTF-8 */
+    char *model;                                       /* UTF-8 */
+    char *serial;                                      /* UTF-8 */
     uint8_t fw_version[4];
     uint8_t hw_version[4];
-    bool is_supported;
+
+    const char *path;                   /* file system encoding */
+    uint16_t    vendor_id;
+    uint16_t    product_id;
+    bool        is_supported;
+    int         access_status;
+
+    struct ambit_device_info_s *next;
 } ambit_device_info_t;
 
 typedef struct ambit_device_status_s {
@@ -94,12 +97,15 @@ typedef struct ambit_personal_settings_s {
     uint8_t  is_male;
     uint8_t  length;
     uint8_t  alti_baro_mode;
+    uint8_t  storm_alarm;
     uint8_t  fused_alti_disabled;
     uint16_t bikepod_calibration;     /* scale 0.0001 */
     uint16_t bikepod_calibration2;    /* scale 0.0001 */
     uint16_t bikepod_calibration3;    /* scale 0.0001 */
     uint16_t footpod_calibration;     /* scale 0.0001 */
     uint8_t  automatic_bikepower_calib;
+    uint8_t  automatic_footpod_calib;
+    uint8_t  training_program;
 } ambit_personal_settings_t;
 
 typedef struct ambit_log_date_time_s {
@@ -124,8 +130,12 @@ typedef enum ambit_log_sample_type_e {
     ambit_log_sample_type_gps_small = 0x0310,
     ambit_log_sample_type_gps_tiny = 0x0311,
     ambit_log_sample_type_time = 0x0312,
+    ambit_log_sample_type_swimming_turn = 0x0314,
+    ambit_log_sample_type_swimming_stroke = 0x0315,
     ambit_log_sample_type_activity = 0x0318,
+    ambit_log_sample_type_cadence_source = 0x031a,
     ambit_log_sample_type_position = 0x031b,
+    ambit_log_sample_type_fwinfo = 0x031c,
     ambit_log_sample_type_unknown = 0xf000
 } ambit_log_sample_type_t;
 
@@ -224,7 +234,12 @@ typedef struct ambit_log_sample_s {
             uint16_t ibi[32];
         } ibi;
         uint16_t ttff;
-        uint8_t  distance_source;               /* 2 = GPS, 3 = Wrist */
+        uint8_t  distance_source;               /* 0x00 = Bikepod,
+                                                   0x01 = Footpod,
+                                                   0x02 = GPS,
+                                                   0x03 = Wrist,
+                                                   0x04 = Indoorswimming,
+                                                   0x05 = Outdoorswimming */
         struct {
             uint8_t event_type;                 /* 0x01 = manual lap,
                                                    0x14 = high interval end,
@@ -274,14 +289,31 @@ typedef struct ambit_log_sample_s {
             uint8_t  second;
         } time;
         struct {
+            uint32_t distance;                  /* Total distance, meters scale: 0.01 */
+            uint16_t lengths;                   /* Total pool lengths */
+            uint16_t classification[4];
+            uint8_t  style;                     /* (style of previous length)
+                                                   0x00 = Other,
+                                                   0x01 = Butterfly,
+                                                   0x02 = Backstroke,
+                                                   0x03 = Breaststroke,
+                                                   0x04 = Freestyle,
+                                                   0x05 = Drill */
+        } swimming_turn;
+        struct {
             uint16_t activitytype;
             uint32_t custommode;
         } activity;
+        uint8_t cadence_source;                 /* 0x40 = Wrist */
         struct {
             int32_t  latitude;                  /* degree, scale: 0.0000001, -90 <= latitude <= 90 */
             int32_t  longitude;                 /* degree, scale: 0.0000001, -180 <= latitude <= 180 */
         } position;
         struct {
+            uint8_t version[4];
+            ambit_date_time_t build_date;
+        } fwinfo;
+        struct {
             size_t datalen;
             uint8_t *data;
         } unknown;
@@ -310,7 +342,7 @@ typedef struct ambit_log_header_s {
     uint32_t heartrate_min_time;    /* ms */
     uint8_t  peak_training_effect;  /* effect scale 0.1 */
     uint8_t  activity_type;
-    char     activity_name[16+1];   /* name of activity in ISO 8859-1 */
+    char    *activity_name;         /* name of activity in UTF-8 */
     int16_t  temperature_max;       /* degree celsius scale 0.1 */
     int16_t  temperature_min;       /* degree celsius scale 0.1 */
     uint32_t temperature_max_time;  /* ms */
@@ -327,9 +359,10 @@ typedef struct ambit_log_header_s {
     uint8_t  unknown2;
     uint8_t  cadence_max;           /* rpm */
     uint8_t  cadence_avg;           /* rpm */
-    uint8_t  unknown3[4];
+    uint8_t  unknown3[2];
+    uint16_t swimming_pool_lengths;
     uint32_t cadence_max_time;      /* ms */
-    uint8_t  unknown4[4];
+    uint32_t swimming_pool_length;  /* m */
     uint8_t  unknown5[4];
     uint8_t  unknown6[24];
 } ambit_log_header_t;
@@ -340,33 +373,37 @@ typedef struct ambit_log_entry_s {
     ambit_log_sample_t *samples;
 } ambit_log_entry_t;
 
-/**
- * Try to detect clock
- * If clock detected, object handle is returned
- * \return object handle if clock found, else NULL
+/** \brief Create a list of all known Ambit clocks on the system
+ *
+ *  The list may include clocks that are not supported or cannot be
+ *  accessed.
  */
-ambit_object_t *libambit_detect(void);
+ambit_device_info_t * libambit_enumerate(void);
 
-/**
- * Close open Ambit object
- * \param object Object to close
+/** \brief Release resources acquired by libambit_enumerate()
  */
-void libambit_close(ambit_object_t *object);
+void libambit_free_enumeration(ambit_device_info_t *devices);
 
-/**
- * Check if detected device is currently supported
- * \param object Object to check
- * \return true if device supported, else false
+/** \brief Create an Ambit object for a clock
+ *
+ *  The pointer returned corresponds to a known, accessible and
+ *  supported clock.  In case no such clock is found \c NULL is
+ *  returned.
+ */
+ambit_object_t * libambit_new(const ambit_device_info_t *device);
+
+/** \brief Create an Ambit object from a \a pathname
+ *
+ *  Convenience function for when the path name for a clock is known.
+ *  These path names are platform dependent.
  */
-bool libambit_device_supported(ambit_object_t *object);
+ambit_object_t * libambit_new_from_pathname(const char *pathname);
 
 /**
- * Get device info on connected dev
- * \param object Object to get info from
- * \param status Status object to be filled
- * \return 0 on success, else -1
+ * Close open Ambit object
+ * \param object Object to close
  */
-int libambit_device_info_get(ambit_object_t *object, ambit_device_info_t *status);
+void libambit_close(ambit_object_t *object);
 
 /**
  * Set sync message to device display
diff --git a/src/libambit/libambit.rules b/src/libambit/libambit.rules
new file mode 100644
index 0000000..b4093fb
--- /dev/null
+++ b/src/libambit/libambit.rules
@@ -0,0 +1,30 @@
+# Rules for Suunto Ambit devices
+# Change permissions so that libambit can communicate with these
+# devices for any user.
+
+ACTION!="add", GOTO="openambit_rules_end"
+ATTR{idVendor}!="1493", GOTO="openambit_rules_end"
+
+LABEL="openambit_rules_begin"
+
+# Bluebird (a.k.a Suunto Ambit)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="0010", ENV{openambit}="yes"
+
+# Duck (a.k.a Suunto Ambit2)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="0019", ENV{openambit}="yes"
+
+# Colibri (a.k.a Suunto Ambit2 S)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="001a", ENV{openambit}="yes"
+
+# Emu (a.k.a Suunto Ambit3 Peak)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="001b", ENV{openambit}="yes"
+
+# Finch (a.k.a Suunto Ambit3 Sport)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="001c", ENV{openambit}="yes"
+
+# Greentit (a.k.a Suunto Ambit2 R)
+SUBSYSTEMS=="usb", ATTRS{idProduct}=="001d", ENV{openambit}="yes"
+
+ENV{openambit}=="yes", MODE="0666", OWNER="root", GROUP="root"
+
+LABEL="openambit_rules_end"
diff --git a/src/libambit/libambit_int.h b/src/libambit/libambit_int.h
index f8d0a37..8cf1c25 100644
--- a/src/libambit/libambit_int.h
+++ b/src/libambit/libambit_int.h
@@ -28,127 +28,13 @@
 
 struct ambit_object_s {
     hid_device *handle;
-    uint16_t vendor_id;
-    uint16_t product_id;
     uint16_t sequence_no;
     ambit_device_info_t device_info;
 
-    struct {
-        uint16_t chunk_size;
-        struct {
-            bool initialized;
-            uint32_t first_entry;
-            uint32_t last_entry;
-            uint32_t entries;
-            uint32_t next_free_address;
-            struct {
-                uint32_t current;
-                uint32_t next;
-                uint32_t prev;
-            } current;
-            uint8_t *buffer;
-            uint8_t *chunks_read;
-        } log;
-    } pmem20;
+    struct ambit_device_driver_s *driver;
+    struct ambit_device_driver_data_s *driver_data; // Driver specific struct,
+                                                    // should be defined
+                                                    // locally for each driver
 };
 
-enum ambit_commands_e {
-    ambit_command_device_info        = 0x0000,
-    ambit_command_time               = 0x0300,
-    ambit_command_date               = 0x0302,
-    ambit_command_status             = 0x0306,
-    ambit_command_personal_settings  = 0x0b00,
-    ambit_command_unknown1           = 0x0b04,
-    ambit_command_log_count          = 0x0b06,
-    ambit_command_log_head_first     = 0x0b07,
-    ambit_command_log_head_peek      = 0x0b08,
-    ambit_command_log_head_step      = 0x0b0a,
-    ambit_command_log_head           = 0x0b0b,
-    ambit_command_gps_orbit_head     = 0x0b15,
-    ambit_command_data_write         = 0x0b16,
-    ambit_command_log_read           = 0x0b17,
-    ambit_command_data_tail_len      = 0x0b18,
-    ambit_command_lock_check         = 0x0b19,
-    ambit_command_lock_set           = 0x0b1a,
-    ambit_command_write_start        = 0x0b1b // Really!? Just a guess...
-};
-
-// crc16.c
-uint16_t crc16_ccitt_false(unsigned char *buf, size_t buflen);
-uint16_t crc16_ccitt_false_init(unsigned char *buf, size_t buflen, uint16_t crc);
-
-// personal.c
-int libambit_personal_settings_parse(uint8_t *data, size_t datalen, ambit_personal_settings_t *settings);
-
-// pmem20.c
-int libambit_pmem20_init(ambit_object_t *object, uint16_t chunk_size);
-int libambit_pmem20_deinit(ambit_object_t *object);
-int libambit_pmem20_log_init(ambit_object_t *object);
-int libambit_pmem20_log_deinit(ambit_object_t *object);
-int libambit_pmem20_log_next_header(ambit_object_t *object, ambit_log_header_t *log_header);
-ambit_log_entry_t *libambit_pmem20_log_read_entry(ambit_object_t *object);
-int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_header_t *log_header);
-int libambit_pmem20_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen);
-
-// protocol.c
-int libambit_protocol_command(ambit_object_t *object, uint16_t command, uint8_t *data, size_t datalen, uint8_t **reply_data, size_t *replylen, uint8_t legacy_format);
-void libambit_protocol_free(uint8_t *data);
-
-// debug.c
-typedef enum debug_level_e {
-    debug_level_err,
-    debug_level_warn,
-    debug_level_info
-} debug_level_t;
-void debug_printf(debug_level_t level, const char *file, int line, const char *func, const char *fmt, ...);
-#ifdef DEBUG_PRINT_ERROR
-#define LOG_ERROR(fmt, ...) debug_printf(debug_level_err, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
-#else
-#define LOG_ERROR(fmt, ...)
-#endif
-#ifdef DEBUG_PRINT_WARNING
-#define LOG_WARNING(fmt, ...) debug_printf(debug_level_warn, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
-#else
-#define LOG_WARNING(fmt, ...)
-#endif
-#ifdef DEBUG_PRINT_INFO
-#define LOG_INFO(fmt, ...) debug_printf(debug_level_info, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
-#else
-#define LOG_INFO(fmt, ...)
-#endif
-
-// static helpers
-static inline uint8_t read8(uint8_t *buf, size_t offset)
-{
-    return buf[offset];
-}
-
-static inline uint16_t read16(uint8_t *buf, size_t offset)
-{
-    return (buf[offset] | (buf[offset+1] << 8));
-}
-
-static inline uint32_t read32(uint8_t *buf, size_t offset)
-{
-    return (buf[offset] | (buf[offset+1] << 8) | (buf[offset+2] << 16) | (buf[offset+3] << 24));
-}
-
-static inline uint8_t read8inc(uint8_t *buf, size_t *offset)
-{
-    *offset += 1;
-    return buf[(*offset)-1];
-}
-
-static inline uint16_t read16inc(uint8_t *buf, size_t *offset)
-{
-    *offset += 2;
-    return (buf[(*offset)-2] | (buf[(*offset)-1] << 8));
-}
-
-static inline uint32_t read32inc(uint8_t *buf, size_t *offset)
-{
-    *offset += 4;
-    return (buf[(*offset)-4] | (buf[(*offset)-3] << 8) | (buf[(*offset)-2] << 16) | (buf[(*offset)-1] << 24));
-}
-
 #endif /* __LIBAMBIT_INT_H__ */
diff --git a/src/libambit/personal.c b/src/libambit/personal.c
index 9cfb66c..f4b6d10 100644
--- a/src/libambit/personal.c
+++ b/src/libambit/personal.c
@@ -19,8 +19,8 @@
  * Contributors:
  *
  */
-#include "libambit.h"
-#include "libambit_int.h"
+#include "personal.h"
+#include "utils.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -102,9 +102,7 @@ int libambit_personal_settings_parse(uint8_t *data, size_t datalen, ambit_person
     offset += 3;
 
     settings->alti_baro_mode = read8inc(data, &offset);
-
-    offset += 1;
-
+    settings->storm_alarm = read8inc(data, &offset);
     settings->fused_alti_disabled = read8inc(data, &offset);
 
     offset = 0x80;
@@ -116,6 +114,10 @@ int libambit_personal_settings_parse(uint8_t *data, size_t datalen, ambit_person
         settings->bikepod_calibration3 = read16inc(data, &offset);
         settings->footpod_calibration = read16inc(data, &offset);
         settings->automatic_bikepower_calib = read8inc(data, &offset);
+        settings->automatic_footpod_calib = read8inc(data, &offset);
+
+        offset = 0xba;
+        settings->training_program = read8inc(data, &offset);
     }
 
     return 0;
diff --git a/src/libambit/personal.h b/src/libambit/personal.h
new file mode 100644
index 0000000..a678d80
--- /dev/null
+++ b/src/libambit/personal.h
@@ -0,0 +1,31 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __PERSONAL_H__
+#define __PERSONAL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include "libambit.h"
+
+int libambit_personal_settings_parse(uint8_t *data, size_t datalen, ambit_personal_settings_t *settings);
+
+#endif /* __PERSONAL_H__ */
diff --git a/src/libambit/pmem20.c b/src/libambit/pmem20.c
index 5cd0e5d..53d216a 100644
--- a/src/libambit/pmem20.c
+++ b/src/libambit/pmem20.c
@@ -19,8 +19,11 @@
  * Contributors:
  *
  */
-#include "libambit.h"
-#include "libambit_int.h"
+#include "pmem20.h"
+#include "protocol.h"
+#include "sha256.h"
+#include "utils.h"
+#include "debug.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -29,8 +32,6 @@
 /*
  * Local definitions
  */
-#define PMEM20_LOG_START                  0x000f4240
-#define PMEM20_LOG_SIZE                   0x0029f630 /* 2 750 000 */
 #define PMEM20_LOG_WRAP_START_OFFSET      0x00000012
 #define PMEM20_LOG_WRAP_BUFFER_MARGIN     0x00010000 /* Max theoretical size of sample */
 #define PMEM20_LOG_HEADER_MIN_LEN                512 /* Header actually longer, but not interesting*/
@@ -46,10 +47,11 @@ typedef struct __attribute__((__packed__)) periodic_sample_spec_s {
 /*
  * Static functions
  */
-static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_entry_t *log_entry, size_t *sample_count);
-static int read_upto(ambit_object_t *object, uint32_t address, uint32_t length);
-static int read_log_chunk(ambit_object_t *object, uint32_t address);
-static int write_data_chunk(ambit_object_t *object, uint32_t address, size_t buffer_count, uint8_t **buffers, size_t *buffer_sizes);
+static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_entry_t *log_entry, size_t *sample_count, int32_t *time_compensators);
+static void correct_samples(ambit_log_entry_t *log_entry, int32_t *time_compensators);
+static int read_upto(libambit_pmem20_t *object, uint32_t address, uint32_t length);
+static int read_log_chunk(libambit_pmem20_t *object, uint32_t address, uint32_t length, uint8_t *buffer);
+static int write_data_chunk(ambit_object_t *object, uint32_t address, size_t buffer_count, const uint8_t **buffers, const size_t *buffer_sizes);
 static void add_time(ambit_date_time_t *intime, int32_t offset, ambit_date_time_t *outtime);
 static int is_leap(unsigned int y);
 static void to_timeval(ambit_date_time_t *ambit_time, struct timeval *timeval);
@@ -63,53 +65,58 @@ static void to_timeval(ambit_date_time_t *ambit_time, struct timeval *timeval);
 /*
  * Public functions
  */
-int libambit_pmem20_init(ambit_object_t *object, uint16_t chunk_size)
+int libambit_pmem20_init(libambit_pmem20_t *object, ambit_object_t *ambit_object, uint16_t chunk_size)
 {
-    object->pmem20.chunk_size = chunk_size;
+    object->ambit_object = ambit_object;
+    object->chunk_size = chunk_size;
 
     return 0;
 }
 
-int libambit_pmem20_log_init(ambit_object_t *object)
+int libambit_pmem20_log_init(libambit_pmem20_t *object, uint32_t mem_start, uint32_t mem_size)
 {
     int ret = -1;
     size_t offset;
 
     // Allocate buffer for complete memory
-    if (object->pmem20.log.buffer != NULL) {
-        free(object->pmem20.log.buffer);
+    if (object->log.buffer != NULL) {
+        free(object->log.buffer);
     }
-    if (object->pmem20.log.chunks_read != NULL) {
-        free(object->pmem20.log.chunks_read);
+    if (object->log.chunks_read != NULL) {
+        free(object->log.chunks_read);
     }
-    memset(&object->pmem20.log, 0, sizeof(object->pmem20.log));
+    memset(&object->log, 0, sizeof(object->log));
 
-    object->pmem20.log.buffer = malloc(PMEM20_LOG_SIZE + PMEM20_LOG_WRAP_BUFFER_MARGIN);
-    object->pmem20.log.chunks_read = malloc((PMEM20_LOG_SIZE/object->pmem20.chunk_size)+1);
+    // Set memory structure
+    object->log.mem_start = mem_start;
+    object->log.mem_size = mem_size;
 
-    if (object->pmem20.log.buffer != NULL && object->pmem20.log.chunks_read != NULL) {
+    object->log.buffer = malloc(object->log.mem_size + PMEM20_LOG_WRAP_BUFFER_MARGIN);
+    object->log.chunks_read = malloc((object->log.mem_size/object->chunk_size)+1);
+
+    if (object->log.buffer != NULL && object->log.chunks_read != NULL) {
         // Set all chunks to NOT read
-        memset(object->pmem20.log.chunks_read, 0, (PMEM20_LOG_SIZE/object->pmem20.chunk_size)+1);
+        memset(object->log.chunks_read, 0, (object->log.mem_size/object->chunk_size)+1);
 
         // Read initial log header
         LOG_INFO("Reading first log data chunk");
-        ret = read_log_chunk(object, PMEM20_LOG_START);
-        
+        ret = read_log_chunk(object, object->log.mem_start, object->chunk_size, object->log.buffer);
+
         if (ret == 0) {
             // Parse PMEM header
             offset = 0;
-            object->pmem20.log.last_entry = read32inc(object->pmem20.log.buffer, &offset);
-            object->pmem20.log.first_entry = read32inc(object->pmem20.log.buffer, &offset);
-            object->pmem20.log.entries = read32inc(object->pmem20.log.buffer, &offset);
-            object->pmem20.log.next_free_address = read32inc(object->pmem20.log.buffer, &offset);
-            object->pmem20.log.current.current = PMEM20_LOG_START;
-            object->pmem20.log.current.next = object->pmem20.log.first_entry;
-            object->pmem20.log.current.prev = PMEM20_LOG_START;
+            object->log.last_entry = read32inc(object->log.buffer, &offset);
+            object->log.first_entry = read32inc(object->log.buffer, &offset);
+            object->log.entries = read32inc(object->log.buffer, &offset);
+            object->log.next_free_address = read32inc(object->log.buffer, &offset);
+            object->log.current.current = object->log.mem_start;
+            object->log.current.next = object->log.first_entry;
+            object->log.current.prev = object->log.mem_start;
 
-            LOG_INFO("log data header read, entries=%d, first_entry=%08x, last_entry=%08x, next_free_address=%08x", object->pmem20.log.entries, object->pmem20.log.first_entry, object->pmem20.log.last_entry, object->pmem20.log.next_free_address);
+            LOG_INFO("log data header read, entries=%d, first_entry=%08x, last_entry=%08x, next_free_address=%08x", object->log.entries, object->log.first_entry, object->log.last_entry, object->log.next_free_address);
 
             // Set initialized
-            object->pmem20.log.initialized = true;
+            object->log.initialized = true;
         }
         else {
             LOG_WARNING("Failed to read first data chunk");
@@ -119,20 +126,20 @@ int libambit_pmem20_log_init(ambit_object_t *object)
     return ret;
 }
 
-int libambit_pmem20_deinit(ambit_object_t *object)
+int libambit_pmem20_deinit(libambit_pmem20_t *object)
 {
-    if (object->pmem20.log.buffer != NULL) {
-        free(object->pmem20.log.buffer);
+    if (object->log.buffer != NULL) {
+        free(object->log.buffer);
     }
-    if (object->pmem20.log.chunks_read != NULL) {
-        free(object->pmem20.log.chunks_read);
+    if (object->log.chunks_read != NULL) {
+        free(object->log.chunks_read);
     }
-    memset(&object->pmem20.log, 0, sizeof(object->pmem20.log));
+    memset(&object->log, 0, sizeof(object->log));
 
     return 0;
 }
 
-int libambit_pmem20_log_next_header(ambit_object_t *object, ambit_log_header_t *log_header)
+int libambit_pmem20_log_next_header(libambit_pmem20_t *object, ambit_log_header_t *log_header)
 {
     int ret = -1;
     size_t buffer_offset;
@@ -140,29 +147,29 @@ int libambit_pmem20_log_next_header(ambit_object_t *object, ambit_log_header_t *
 
     LOG_INFO("Reading header of next log entry");
 
-    if (!object->pmem20.log.initialized) {
+    if (!object->log.initialized) {
         LOG_ERROR("Trying to get next log without initialization");
         return -1;
     }
 
     // Check if we reached end of entries
-    if (object->pmem20.log.current.current == object->pmem20.log.current.next) {
+    if (object->log.current.current == object->log.current.next) {
         LOG_INFO("No more entries to read");
         return 0;
     }
 
-    if (read_upto(object, object->pmem20.log.current.next, PMEM20_LOG_HEADER_MIN_LEN) == 0) {
-        buffer_offset = (object->pmem20.log.current.next - PMEM20_LOG_START);
+    if (read_upto(object, object->log.current.next, PMEM20_LOG_HEADER_MIN_LEN) == 0) {
+        buffer_offset = (object->log.current.next - object->log.mem_start);
         // First check that header seems to be correctly present
-        if (strncmp((char*)object->pmem20.log.buffer + buffer_offset, "PMEM", 4) == 0) {
-            object->pmem20.log.current.current = object->pmem20.log.current.next;
+        if (strncmp((char*)object->log.buffer + buffer_offset, "PMEM", 4) == 0) {
+            object->log.current.current = object->log.current.next;
             buffer_offset += 4;
-            object->pmem20.log.current.next = read32inc(object->pmem20.log.buffer, &buffer_offset);
-            object->pmem20.log.current.prev = read32inc(object->pmem20.log.buffer, &buffer_offset);
-            tmp_len = read16inc(object->pmem20.log.buffer, &buffer_offset);
+            object->log.current.next = read32inc(object->log.buffer, &buffer_offset);
+            object->log.current.prev = read32inc(object->log.buffer, &buffer_offset);
+            tmp_len = read16inc(object->log.buffer, &buffer_offset);
             buffer_offset += tmp_len;
-            tmp_len = read16inc(object->pmem20.log.buffer, &buffer_offset);
-            if (libambit_pmem20_log_parse_header(object->pmem20.log.buffer + buffer_offset, tmp_len, log_header) == 0) {
+            tmp_len = read16inc(object->log.buffer, &buffer_offset);
+            if (libambit_pmem20_log_parse_header(object->log.buffer + buffer_offset, tmp_len, log_header) == 0) {
                 LOG_INFO("Log entry header parsed");
                 ret = 1;
             }
@@ -180,61 +187,72 @@ int libambit_pmem20_log_next_header(ambit_object_t *object, ambit_log_header_t *
 
     // Unset initialized of something went wrong
     if (ret < 0) {
-        object->pmem20.log.initialized = false;
+        object->log.initialized = false;
     }
 
     return ret;
 }
 
-ambit_log_entry_t *libambit_pmem20_log_read_entry(ambit_object_t *object)
+ambit_log_entry_t *libambit_pmem20_log_read_entry(libambit_pmem20_t *object)
 {
     // Note! We assume that the caller has called libambit_pmem20_log_next_header just before
     uint8_t *periodic_sample_spec;
     uint16_t tmp_len, sample_len;
-    size_t buffer_offset, sample_count = 0, i;
+    size_t buffer_offset, sample_count = 0;
     ambit_log_entry_t *log_entry;
-    ambit_log_sample_t *last_periodic = NULL, *utcsource = NULL, *altisource = NULL;
-    ambit_date_time_t utcbase;
-    uint32_t altisource_index = 0;
-    uint32_t last_base_lat = 0, last_base_long = 0;
-    uint32_t last_small_lat = 0, last_small_long = 0;
-    uint32_t last_ehpe = 0;
+    int32_t *time_compensators;
 
-    if (!object->pmem20.log.initialized) {
+    if (!object->log.initialized) {
         LOG_ERROR("Trying to get log entry without initialization");
         return NULL;
     }
 
     // Allocate log entry
     if ((log_entry = calloc(1, sizeof(ambit_log_entry_t))) == NULL) {
-        object->pmem20.log.initialized = false;
+        object->log.initialized = false;
         return NULL;
     }
+    log_entry->header.activity_name = NULL;
 
-    LOG_INFO("Reading log entry from address=%08x", object->pmem20.log.current.current);
+    LOG_INFO("Reading log entry from address=%08x", object->log.current.current);
 
-    buffer_offset = (object->pmem20.log.current.current - PMEM20_LOG_START);
+    buffer_offset = (object->log.current.current - object->log.mem_start);
     buffer_offset += 12;
     // Read samples content definition
-    tmp_len = read16inc(object->pmem20.log.buffer, &buffer_offset);
-    periodic_sample_spec = object->pmem20.log.buffer + buffer_offset;
+    tmp_len = read16inc(object->log.buffer, &buffer_offset);
+    periodic_sample_spec = object->log.buffer + buffer_offset;
     buffer_offset += tmp_len;
     // Parse header
-    tmp_len = read16inc(object->pmem20.log.buffer, &buffer_offset);
-    if (libambit_pmem20_log_parse_header(object->pmem20.log.buffer + buffer_offset, tmp_len, &log_entry->header) != 0) {
+    tmp_len = read16inc(object->log.buffer, &buffer_offset);
+    if (libambit_pmem20_log_parse_header(object->log.buffer + buffer_offset, tmp_len, &log_entry->header) != 0) {
         LOG_ERROR("Failed to parse log entry header correctly");
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
+        }
         free(log_entry);
-        object->pmem20.log.initialized = false;
+        object->log.initialized = false;
         return NULL;
     }
     buffer_offset += tmp_len;
     // Now that we know number of samples, allocate space for them!
     if ((log_entry->samples = calloc(log_entry->header.samples_count, sizeof(ambit_log_sample_t))) == NULL) {
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
+        }
         free(log_entry);
-        object->pmem20.log.initialized = false;
+        object->log.initialized = false;
         return NULL;
     }
     log_entry->samples_count = log_entry->header.samples_count;
+    if ((time_compensators = calloc(log_entry->header.samples_count, sizeof(int32_t))) == NULL) {
+        free(log_entry->samples);
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
+        }
+        free(log_entry);
+        object->log.initialized = false;
+        return NULL;
+    }
 
     LOG_INFO("Log entry got %d samples, reading", log_entry->samples_count);
 
@@ -247,100 +265,141 @@ ambit_log_entry_t *libambit_pmem20_log_read_entry(ambit_object_t *object)
            to the end of the buffer. */
 
         // First check for log area wrap
-        if (buffer_offset >= PMEM20_LOG_SIZE - 1) {
-            read_upto(object, PMEM20_LOG_START + PMEM20_LOG_WRAP_START_OFFSET, 2);
-            sample_len = read16(object->pmem20.log.buffer, PMEM20_LOG_WRAP_START_OFFSET);
+        if (buffer_offset >= object->log.mem_size - 1) {
+            read_upto(object, object->log.mem_start + PMEM20_LOG_WRAP_START_OFFSET, 2);
+            sample_len = read16(object->log.buffer, PMEM20_LOG_WRAP_START_OFFSET);
         }
-        else if (buffer_offset == PMEM20_LOG_SIZE - 2) {
-            read_upto(object, PMEM20_LOG_START + PMEM20_LOG_WRAP_START_OFFSET, 1);
-            sample_len = object->pmem20.log.buffer[buffer_offset] | (object->pmem20.log.buffer[PMEM20_LOG_WRAP_START_OFFSET] << 8);
+        else if (buffer_offset == object->log.mem_size - 2) {
+            read_upto(object, object->log.mem_start + PMEM20_LOG_WRAP_START_OFFSET, 1);
+            sample_len = object->log.buffer[buffer_offset] | (object->log.buffer[PMEM20_LOG_WRAP_START_OFFSET] << 8);
         }
         else {
-            read_upto(object, PMEM20_LOG_START + buffer_offset, 2);
-            sample_len = read16(object->pmem20.log.buffer, buffer_offset);
+            read_upto(object, object->log.mem_start + buffer_offset, 2);
+            sample_len = read16(object->log.buffer, buffer_offset);
         }
 
         // Read all data
-        if (buffer_offset + 2 < (PMEM20_LOG_SIZE-1)) {
-            read_upto(object, PMEM20_LOG_START + buffer_offset + 2, sample_len);
+        if (buffer_offset + 2 < (object->log.mem_size-1)) {
+            read_upto(object, object->log.mem_start + buffer_offset + 2, sample_len);
         }
-        if (buffer_offset + 2 + sample_len > PMEM20_LOG_SIZE) {
-            read_upto(object, PMEM20_LOG_START + PMEM20_LOG_WRAP_START_OFFSET, (buffer_offset + 2 + sample_len) - PMEM20_LOG_SIZE);
-            memcpy(object->pmem20.log.buffer + PMEM20_LOG_SIZE, object->pmem20.log.buffer + PMEM20_LOG_WRAP_START_OFFSET, (buffer_offset + 2 + sample_len) - PMEM20_LOG_SIZE);
+        if (buffer_offset + 2 + sample_len > object->log.mem_size) {
+            read_upto(object, object->log.mem_start + PMEM20_LOG_WRAP_START_OFFSET, (buffer_offset + 2 + sample_len) - object->log.mem_size);
+            memcpy(object->log.buffer + object->log.mem_size, object->log.buffer + PMEM20_LOG_WRAP_START_OFFSET, (buffer_offset + 2 + sample_len) - object->log.mem_size);
         }
 
-        if (parse_sample(object->pmem20.log.buffer, buffer_offset, &periodic_sample_spec, log_entry, &sample_count) == 1) {
-            // Calculate times
-            if (log_entry->samples[sample_count-1].type == ambit_log_sample_type_periodic) {
-                last_periodic = &log_entry->samples[sample_count-1];
-            }
-            else if (last_periodic != NULL) {
-                log_entry->samples[sample_count-1].time += last_periodic->time;
-            }
-            else {
-                log_entry->samples[sample_count-1].time = 0;
-            }
+        parse_sample(object->log.buffer, buffer_offset, &periodic_sample_spec, log_entry, &sample_count, time_compensators);
+        buffer_offset += 2 + sample_len;
+        // Wrap
+        if (buffer_offset >= object->log.mem_size) {
+            buffer_offset = PMEM20_LOG_WRAP_START_OFFSET + (buffer_offset - object->log.mem_size);
+        }
+    }
 
-            if (utcsource == NULL && log_entry->samples[sample_count-1].type == ambit_log_sample_type_gps_base) {
-                utcsource = &log_entry->samples[sample_count-1];
-                // Calculate UTC base time
-                add_time(&utcsource->u.gps_base.utc_base_time, 0-utcsource->time, &utcbase);
-            }
+    correct_samples(log_entry, time_compensators);
 
-            // Calculate positions
-            if (log_entry->samples[sample_count-1].type == ambit_log_sample_type_gps_base) {
-                last_base_lat = log_entry->samples[sample_count-1].u.gps_base.latitude;
-                last_base_long = log_entry->samples[sample_count-1].u.gps_base.longitude;
-                last_small_lat = log_entry->samples[sample_count-1].u.gps_base.latitude;
-                last_small_long = log_entry->samples[sample_count-1].u.gps_base.longitude;
-                last_ehpe = log_entry->samples[sample_count-1].u.gps_base.ehpe;
-            }
-            else if (log_entry->samples[sample_count-1].type == ambit_log_sample_type_gps_small) {
-                log_entry->samples[sample_count-1].u.gps_small.latitude = last_base_lat + log_entry->samples[sample_count-1].u.gps_small.latitude*10;
-                log_entry->samples[sample_count-1].u.gps_small.longitude = last_base_long + log_entry->samples[sample_count-1].u.gps_small.longitude*10;
-                last_small_lat = log_entry->samples[sample_count-1].u.gps_small.latitude;
-                last_small_long = log_entry->samples[sample_count-1].u.gps_small.longitude;
-                last_ehpe = log_entry->samples[sample_count-1].u.gps_small.ehpe;
-            }
-            else if (log_entry->samples[sample_count-1].type == ambit_log_sample_type_gps_tiny) {
-                log_entry->samples[sample_count-1].u.gps_tiny.latitude = last_small_lat + log_entry->samples[sample_count-1].u.gps_tiny.latitude*10;
-                log_entry->samples[sample_count-1].u.gps_tiny.longitude = last_small_long + log_entry->samples[sample_count-1].u.gps_tiny.longitude*10;
-                log_entry->samples[sample_count-1].u.gps_tiny.ehpe = (last_ehpe > 700 ? 700 : last_ehpe);
-                last_small_lat = log_entry->samples[sample_count-1].u.gps_tiny.latitude;
-                last_small_long = log_entry->samples[sample_count-1].u.gps_tiny.longitude;
-            }
+    free(time_compensators);
 
-            if (altisource == NULL && log_entry->samples[sample_count-1].type == ambit_log_sample_type_altitude_source) {
-                altisource = &log_entry->samples[sample_count-1];
-                altisource_index = sample_count-1;
-            }
+    return log_entry;
+}
+
+ambit_log_entry_t *libambit_pmem20_log_read_entry_address(libambit_pmem20_t *object, uint32_t address, uint32_t length)
+{
+    uint8_t *buffer;
+    uint8_t *periodic_sample_spec;
+    uint32_t next_address;
+    uint32_t buffer_read = 0, read_length;
+    uint16_t tmp_len, sample_len;
+    size_t buffer_offset, sample_count = 0;
+    ambit_log_entry_t *log_entry;
+    int32_t *time_compensators;
+
+    // Allocate log entry
+    if ((log_entry = calloc(1, sizeof(ambit_log_entry_t))) == NULL) {
+        object->log.initialized = false;
+        return NULL;
+    }
+
+    // Allocate temporary log buffer
+    if ((buffer = calloc(1, length)) == NULL) {
+        object->log.initialized = false;
+        free(log_entry);
+        return NULL;
+    }
+
+    LOG_INFO("Reading log entry from address=%08x", address);
+    log_entry->header.activity_name = NULL;
+
+    // Handle wrap in "the middle" of the log
+    next_address = address;
+    while (buffer_read < length) {
+        if (next_address >= object->log.mem_start + object->log.mem_size) {
+            next_address = object->log.mem_start + PMEM20_LOG_WRAP_START_OFFSET;
         }
-        buffer_offset += 2 + sample_len;
-        // Wrap
-        if (buffer_offset >= PMEM20_LOG_SIZE) {
-            buffer_offset = PMEM20_LOG_WRAP_START_OFFSET + (buffer_offset - PMEM20_LOG_SIZE);
+        if (length - buffer_read >= object->chunk_size) {
+            read_length = object->chunk_size;
+        }
+        else {
+            read_length = length - buffer_read;
         }
+        if (next_address + read_length > object->log.mem_start + object->log.mem_size) {
+            read_length = object->log.mem_start + object->log.mem_size - next_address;
+        }
+
+        read_log_chunk(object, next_address, read_length, buffer + buffer_read);
+
+        next_address += read_length;
+        buffer_read += read_length;
     }
 
-    // Loop through samples again and correct times etc
-    for (sample_count = 0; sample_count < log_entry->header.samples_count; sample_count++) {
-        // Set UTC times (if UTC source found)
-        if (utcsource != NULL) {
-            add_time(&utcbase, log_entry->samples[sample_count].time, &log_entry->samples[sample_count].utc_time);
+    buffer_offset = 12;
+    // Read samples content definition
+    tmp_len = read16inc(buffer, &buffer_offset);
+    periodic_sample_spec = buffer + buffer_offset;
+    buffer_offset += tmp_len;
+    // Parse header
+    tmp_len = read16inc(buffer, &buffer_offset);
+    if (libambit_pmem20_log_parse_header(buffer + buffer_offset, tmp_len, &log_entry->header) != 0) {
+        LOG_ERROR("Failed to parse log entry header correctly");
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
         }
-        // Correct altitude based on altitude offset in altitude source
-        if (altisource != NULL && log_entry->samples[sample_count].type == ambit_log_sample_type_periodic && sample_count < altisource_index) {
-            for (i=0; i<log_entry->samples[sample_count].u.periodic.value_count; i++) {
-                if (log_entry->samples[sample_count].u.periodic.values[i].type == ambit_log_sample_periodic_type_sealevelpressure) {
-                    log_entry->samples[sample_count].u.periodic.values[i].u.sealevelpressure += altisource->u.altitude_source.pressure_offset;
-                }
-                if (log_entry->samples[sample_count].u.periodic.values[i].type == ambit_log_sample_periodic_type_altitude) {
-                    log_entry->samples[sample_count].u.periodic.values[i].u.altitude += altisource->u.altitude_source.altitude_offset;
-                }
-            }
+        free(log_entry);
+        object->log.initialized = false;
+        return NULL;
+    }
+    buffer_offset += tmp_len;
+    // Now that we know number of samples, allocate space for them!
+    if ((log_entry->samples = calloc(log_entry->header.samples_count, sizeof(ambit_log_sample_t))) == NULL) {
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
+        }
+        free(log_entry);
+        object->log.initialized = false;
+        return NULL;
+    }
+    log_entry->samples_count = log_entry->header.samples_count;
+    if ((time_compensators = calloc(log_entry->header.samples_count, sizeof(int32_t))) == NULL) {
+        free(log_entry->samples);
+        if (log_entry->header.activity_name) {
+            free(log_entry->header.activity_name);
         }
+        free(log_entry);
+        object->log.initialized = false;
+        return NULL;
+    }
+
+    LOG_INFO("Log entry got %d samples, reading", log_entry->samples_count);
+
+    // OK, so we are at start of samples, get them all!
+    while (sample_count < log_entry->samples_count) {
+        sample_len = read16(buffer, buffer_offset);
+
+        parse_sample(buffer, buffer_offset, &periodic_sample_spec, log_entry, &sample_count, time_compensators);
+        buffer_offset += 2 + sample_len;
     }
 
+    correct_samples(log_entry, time_compensators);
+
     return log_entry;
 }
 
@@ -378,8 +437,11 @@ int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_he
     log_header->heartrate_max = read8inc(data, &offset);
     log_header->peak_training_effect = read8inc(data, &offset);
     log_header->activity_type = read8inc(data, &offset);
-    memcpy(log_header->activity_name, data + offset, 16);
-    log_header->activity_name[16] = 0;
+    if (log_header->activity_name) {
+        free(log_header->activity_name);
+    }
+    log_header->activity_name = utf8memconv((char *)data + offset, 16,
+                                            "ISO-8859-15");
     offset += 16;
     log_header->heartrate_min = read8inc(data, &offset);
 
@@ -394,9 +456,10 @@ int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_he
     log_header->cadence_max = read8inc(data, &offset);
     log_header->cadence_avg = read8inc(data, &offset);
 
-    memcpy(log_header->unknown3, data+offset, 4);
-    offset += 4;
+    memcpy(log_header->unknown3, data+offset, 2);
+    offset += 2;
 
+    log_header->swimming_pool_lengths = read16inc(data, &offset);
     log_header->speed_max_time = read32inc(data, &offset);
     log_header->altitude_max_time = read32inc(data, &offset);
     log_header->altitude_min_time = read32inc(data, &offset);
@@ -405,10 +468,7 @@ int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_he
     log_header->temperature_max_time = read32inc(data, &offset);
     log_header->temperature_min_time = read32inc(data, &offset);
     log_header->cadence_max_time = read32inc(data, &offset);
-
-    memcpy(log_header->unknown4, data+offset, 4);
-    offset += 4;
-
+    log_header->swimming_pool_length = read32inc(data, &offset);
     log_header->first_fix_time = read16inc(data, &offset)*1000;
     log_header->battery_start = read8inc(data, &offset);
     log_header->battery_end = read8inc(data, &offset);
@@ -426,13 +486,16 @@ int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_he
     return 0;
 }
 
-int libambit_pmem20_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_t datalen)
+int libambit_pmem20_gps_orbit_write(libambit_pmem20_t *object, const uint8_t *data, size_t datalen, bool include_sha256_hash)
 {
-    int ret = -1;
-    uint8_t *bufptrs[2];
+    int i, ret = -1;
+    const uint8_t *bufptrs[2];
     size_t bufsizes[2];
+    uint8_t *tailbuf;
+    size_t tail_datalen = 8;
     uint8_t startheader[4];
-    uint8_t tailbuf[8];
+    sha256_ctx ctx;
+    uint8_t hash[32];
     uint32_t *_sizeptr = (uint32_t*)&startheader[0];
     uint32_t address = PMEM20_GPS_ORBIT_START;
     size_t offset = 0;
@@ -441,29 +504,45 @@ int libambit_pmem20_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_
     bufptrs[0] = startheader;
     bufsizes[0] = 4;
     bufptrs[1] = data;
-    bufsizes[1] = object->pmem20.chunk_size - 4; // We assume that data is
-                                                 // always > chunk_size
+    bufsizes[1] = object->chunk_size - 4; // We assume that data is
+                                          // always > chunk_size
 
     // Write first chunk (including length)
-    ret = write_data_chunk(object, address, 2, bufptrs, bufsizes);
+    ret = write_data_chunk(object->ambit_object, address, 2, bufptrs, bufsizes);
     offset += bufsizes[1];
-    address += object->pmem20.chunk_size;
+    address += object->chunk_size;
 
     // Write rest of the chunks
     while (ret == 0 && offset < datalen) {
         bufptrs[0] = data + offset;
-        bufsizes[0] = (datalen - offset > object->pmem20.chunk_size ? object->pmem20.chunk_size : datalen - offset);
+        bufsizes[0] = (datalen - offset > object->chunk_size ? object->chunk_size : datalen - offset);
 
-        ret = write_data_chunk(object, address, 1, bufptrs, bufsizes);
+        ret = write_data_chunk(object->ambit_object, address, 1, bufptrs, bufsizes);
         offset += bufsizes[0];
         address += bufsizes[0];
     }
 
     // Write tail length (or what is really!?)
     if (ret == 0) {
-        *((uint32_t*)(&tailbuf[0])) = htole32(PMEM20_GPS_ORBIT_START);
-        *((uint32_t*)(&tailbuf[4])) = htole32(bufsizes[0]);
-        ret = libambit_protocol_command(object, ambit_command_data_tail_len, tailbuf, sizeof(tailbuf), NULL, NULL, 0);
+        // Handle hash (if wanted)
+        if (include_sha256_hash) {
+            sha256_init(&ctx);
+            sha256_update(&ctx, startheader, sizeof(startheader));
+            sha256_update(&ctx, data, datalen);
+            sha256_final(&ctx, hash);
+            tail_datalen += 64;
+        }
+        if ((tailbuf = malloc(tail_datalen + 1)) != NULL) {
+            *((uint32_t*)(&tailbuf[0])) = htole32(PMEM20_GPS_ORBIT_START);
+            *((uint32_t*)(&tailbuf[4])) = htole32(bufsizes[0]);
+            if (include_sha256_hash) {
+                for (i=0; i<32; i++) {
+                    sprintf((char*)tailbuf+8+i*2, "%02X", hash[i]);
+                }
+            }
+            ret = libambit_protocol_command(object->ambit_object, ambit_command_data_tail_len, tailbuf, tail_datalen, NULL, NULL, 0);
+            free(tailbuf);
+        }
     }
 
     return ret;
@@ -473,7 +552,7 @@ int libambit_pmem20_gps_orbit_write(ambit_object_t *object, uint8_t *data, size_
  * Parse the given sample
  * \return number of samples added (1 or 0)
  */
-static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_entry_t *log_entry, size_t *sample_count)
+static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_entry_t *log_entry, size_t *sample_count, int32_t *time_compensators)
 {
     int ret = 0;
     size_t int_offset = offset;
@@ -728,16 +807,51 @@ static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_e
             log_entry->samples[*sample_count].u.time.minute = read8inc(buf, &int_offset);
             log_entry->samples[*sample_count].u.time.second = read8inc(buf, &int_offset);
             break;
+          case 0x14:
+            log_entry->samples[*sample_count].type = ambit_log_sample_type_swimming_turn;
+            int_offset += 1;
+            // Time compensation offset in 0.1 second format, convert to ms
+            time_compensators[*sample_count] = 0 - read16inc(buf, &int_offset) * 100;
+            int_offset += 1;
+            log_entry->samples[*sample_count].u.swimming_turn.distance = read32inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.swimming_turn.lengths = read16inc(buf, &int_offset);
+            int_offset += 18;
+            log_entry->samples[*sample_count].u.swimming_turn.classification[0] = read16inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.swimming_turn.classification[1] = read16inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.swimming_turn.classification[2] = read16inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.swimming_turn.classification[3] = read16inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.swimming_turn.style = read8inc(buf, &int_offset);
+            break;
+          case 0x15:
+            log_entry->samples[*sample_count].type = ambit_log_sample_type_swimming_stroke;
+            // Time compensation offset in 0.1 second format, convert to ms
+            time_compensators[*sample_count] = 0 - read16inc(buf, &int_offset) * 100;
+            break;
           case 0x18:
             log_entry->samples[*sample_count].type = ambit_log_sample_type_activity;
             log_entry->samples[*sample_count].u.activity.activitytype = read16inc(buf, &int_offset);
             log_entry->samples[*sample_count].u.activity.custommode = read32inc(buf, &int_offset);
             break;
+          case 0x1a:
+            log_entry->samples[*sample_count].type = ambit_log_sample_type_cadence_source;
+            log_entry->samples[*sample_count].u.cadence_source = read8inc(buf, &int_offset);
+            break;
           case 0x1b:
             log_entry->samples[*sample_count].type = ambit_log_sample_type_position;
             log_entry->samples[*sample_count].u.position.latitude = read32inc(buf, &int_offset);
             log_entry->samples[*sample_count].u.position.longitude = read32inc(buf, &int_offset);
             break;
+          case 0x1c:
+            log_entry->samples[*sample_count].type = ambit_log_sample_type_fwinfo;
+            memcpy(log_entry->samples[*sample_count].u.fwinfo.version, buf + int_offset, 4);
+            int_offset += 4;
+            log_entry->samples[*sample_count].u.fwinfo.build_date.year = read16inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.fwinfo.build_date.month = read8inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.fwinfo.build_date.day = read8inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.fwinfo.build_date.hour = read8inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.fwinfo.build_date.minute = read8inc(buf, &int_offset);
+            log_entry->samples[*sample_count].u.fwinfo.build_date.msec = read16inc(buf, &int_offset);
+            break;
           default:
             LOG_WARNING("Found unknown episodic sample type (0x%02x)", episodic_type);
             log_entry->samples[*sample_count].type = ambit_log_sample_type_unknown;
@@ -763,30 +877,129 @@ static int parse_sample(uint8_t *buf, size_t offset, uint8_t **spec, ambit_log_e
     return ret;
 }
 
-static int read_upto(ambit_object_t *object, uint32_t address, uint32_t length)
+static void correct_samples(ambit_log_entry_t *log_entry, int32_t *time_compensators)
+{
+    size_t sample_count, i;
+    ambit_log_sample_t *last_periodic = NULL, *utcsource = NULL, *altisource = NULL;
+    ambit_date_time_t utcbase;
+    uint32_t altisource_index = 0;
+    uint32_t last_base_lat = 0, last_base_long = 0;
+    uint32_t last_small_lat = 0, last_small_long = 0;
+    uint32_t last_ehpe = 0;
+    ambit_log_sample_t tmpsample;
+
+    for (sample_count = 0; sample_count < log_entry->header.samples_count; sample_count++) {
+        // Calculate times
+        if (log_entry->samples[sample_count].type == ambit_log_sample_type_periodic) {
+            last_periodic = &log_entry->samples[sample_count];
+        }
+        else if (last_periodic != NULL) {
+            log_entry->samples[sample_count].time += last_periodic->time;
+        }
+        else {
+            log_entry->samples[sample_count].time = 0;
+        }
+        // Correct with time_compensators
+        if (time_compensators[sample_count] < 0 && log_entry->samples[sample_count].time < (0 - time_compensators[sample_count])) {
+            // Avoid negative times, never set to less than 0
+            log_entry->samples[sample_count].time = 0;
+        }
+        else {
+            log_entry->samples[sample_count].time += time_compensators[sample_count];
+        }
+
+        if (utcsource == NULL && log_entry->samples[sample_count].type == ambit_log_sample_type_gps_base) {
+            utcsource = &log_entry->samples[sample_count];
+            // Calculate UTC base time
+            add_time(&utcsource->u.gps_base.utc_base_time, 0-utcsource->time, &utcbase);
+        }
+
+        // Calculate positions
+        if (log_entry->samples[sample_count].type == ambit_log_sample_type_gps_base) {
+            last_base_lat = log_entry->samples[sample_count].u.gps_base.latitude;
+            last_base_long = log_entry->samples[sample_count].u.gps_base.longitude;
+            last_small_lat = log_entry->samples[sample_count].u.gps_base.latitude;
+            last_small_long = log_entry->samples[sample_count].u.gps_base.longitude;
+            last_ehpe = log_entry->samples[sample_count].u.gps_base.ehpe;
+        }
+        else if (log_entry->samples[sample_count].type == ambit_log_sample_type_gps_small) {
+            log_entry->samples[sample_count].u.gps_small.latitude = last_base_lat + log_entry->samples[sample_count].u.gps_small.latitude*10;
+            log_entry->samples[sample_count].u.gps_small.longitude = last_base_long + log_entry->samples[sample_count].u.gps_small.longitude*10;
+            last_small_lat = log_entry->samples[sample_count].u.gps_small.latitude;
+            last_small_long = log_entry->samples[sample_count].u.gps_small.longitude;
+            last_ehpe = log_entry->samples[sample_count].u.gps_small.ehpe;
+        }
+        else if (log_entry->samples[sample_count].type == ambit_log_sample_type_gps_tiny) {
+            log_entry->samples[sample_count].u.gps_tiny.latitude = last_small_lat + log_entry->samples[sample_count].u.gps_tiny.latitude*10;
+            log_entry->samples[sample_count].u.gps_tiny.longitude = last_small_long + log_entry->samples[sample_count].u.gps_tiny.longitude*10;
+            log_entry->samples[sample_count].u.gps_tiny.ehpe = (last_ehpe > 700 ? 700 : last_ehpe);
+            last_small_lat = log_entry->samples[sample_count].u.gps_tiny.latitude;
+            last_small_long = log_entry->samples[sample_count].u.gps_tiny.longitude;
+        }
+
+        if (altisource == NULL && log_entry->samples[sample_count].type == ambit_log_sample_type_altitude_source) {
+            altisource = &log_entry->samples[sample_count];
+            altisource_index = sample_count;
+        }
+    }
+
+    // Loop through samples again and correct times etc
+    for (sample_count = 0; sample_count < log_entry->header.samples_count; sample_count++) {
+        // Set UTC times (if UTC source found)
+        if (utcsource != NULL) {
+            add_time(&utcbase, log_entry->samples[sample_count].time, &log_entry->samples[sample_count].utc_time);
+        }
+        // Correct altitude based on altitude offset in altitude source
+        if (altisource != NULL && log_entry->samples[sample_count].type == ambit_log_sample_type_periodic && sample_count < altisource_index) {
+            for (i=0; i<log_entry->samples[sample_count].u.periodic.value_count; i++) {
+                if (log_entry->samples[sample_count].u.periodic.values[i].type == ambit_log_sample_periodic_type_sealevelpressure) {
+                    log_entry->samples[sample_count].u.periodic.values[i].u.sealevelpressure += altisource->u.altitude_source.pressure_offset;
+                }
+                if (log_entry->samples[sample_count].u.periodic.values[i].type == ambit_log_sample_periodic_type_altitude) {
+                    log_entry->samples[sample_count].u.periodic.values[i].u.altitude += altisource->u.altitude_source.altitude_offset;
+                }
+            }
+        }
+    }
+
+    // Rearrange samples in respect to time values
+    for (sample_count = 1; sample_count < log_entry->header.samples_count; sample_count++) {
+        // Look for bad sorted samples
+        if (log_entry->samples[sample_count].time < log_entry->samples[sample_count-1].time) {
+            // Find out new position of sample
+            for (i = sample_count - 1; i > 0; i--) {
+                if (log_entry->samples[sample_count].time >= log_entry->samples[i-1].time) {
+                    break;
+                }
+            }
+            memcpy(&tmpsample, &log_entry->samples[sample_count], sizeof(ambit_log_sample_t));
+            memmove(&log_entry->samples[i+1], &log_entry->samples[i], sizeof(ambit_log_sample_t)*(sample_count-i));
+            memcpy(&log_entry->samples[i], &tmpsample, sizeof(ambit_log_sample_t));
+        }
+    }
+}
+
+static int read_upto(libambit_pmem20_t *object, uint32_t address, uint32_t length)
 {
-    uint32_t start_address = address - ((address - PMEM20_LOG_START) % object->pmem20.chunk_size);
+    uint32_t start_address = address - ((address - object->log.mem_start) % object->chunk_size);
 
     while (start_address < address + length) {
-        if (object->pmem20.log.chunks_read[(start_address - PMEM20_LOG_START)/object->pmem20.chunk_size] == 0) {
-            if (read_log_chunk(object, start_address) != 0) {
+        if (object->log.chunks_read[(start_address - object->log.mem_start)/object->chunk_size] == 0) {
+            if (read_log_chunk(object, start_address, object->chunk_size, object->log.buffer + (start_address - object->log.mem_start)) != 0) {
                 return -1;
             }
-            object->pmem20.log.chunks_read[(start_address - PMEM20_LOG_START)/object->pmem20.chunk_size] = 1;
+            object->log.chunks_read[(start_address - object->log.mem_start)/object->chunk_size] = 1;
         }
-        start_address += object->pmem20.chunk_size;
+        start_address += object->chunk_size;
     }
 
     return 0;
 }
 
-static int read_log_chunk(ambit_object_t *object, uint32_t address)
+static int read_log_chunk(libambit_pmem20_t *object, uint32_t address, uint32_t length, uint8_t *buffer)
 {
     int ret = -1;
 
-    uint8_t *buffer = object->pmem20.log.buffer + (address - PMEM20_LOG_START);
-    uint32_t length = object->pmem20.chunk_size;
-
     uint8_t *reply = NULL;
     size_t replylen = 0;
 
@@ -794,14 +1007,14 @@ static int read_log_chunk(ambit_object_t *object, uint32_t address)
     uint32_t *_address = (uint32_t*)&send_data[0];
     uint32_t *_length = (uint32_t*)&send_data[4];
 
-    if ((address + object->pmem20.chunk_size) > (PMEM20_LOG_START + PMEM20_LOG_SIZE)) {
-        length = PMEM20_LOG_START + PMEM20_LOG_SIZE - address;
+    if ((address + object->chunk_size) > (object->log.mem_start + object->log.mem_size)) {
+        length = object->log.mem_start + object->log.mem_size - address;
     }
 
     *_address = htole32(address);
     *_length = htole32(length);
 
-    if (libambit_protocol_command(object, ambit_command_log_read, send_data, sizeof(send_data), &reply, &replylen, 0) == 0 &&
+    if (libambit_protocol_command(object->ambit_object, ambit_command_log_read, send_data, sizeof(send_data), &reply, &replylen, 0) == 0 &&
         replylen == length + 8) {
         memcpy(buffer, reply + 8, length);
         ret = 0;
@@ -812,7 +1025,7 @@ static int read_log_chunk(ambit_object_t *object, uint32_t address)
     return ret;
 }
 
-static int write_data_chunk(ambit_object_t *object, uint32_t address, size_t buffer_count, uint8_t **buffers, size_t *buffer_sizes)
+static int write_data_chunk(ambit_object_t *object, uint32_t address, size_t buffer_count, const uint8_t **buffers, const size_t *buffer_sizes)
 {
     int ret = -1;
 
diff --git a/src/libambit/pmem20.h b/src/libambit/pmem20.h
new file mode 100644
index 0000000..a59824e
--- /dev/null
+++ b/src/libambit/pmem20.h
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __PMEM20_H__
+#define __PMEM20_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include "libambit.h"
+
+typedef struct libambit_pmem20_s {
+    uint16_t chunk_size;
+    struct {
+        bool initialized;
+        uint32_t mem_start;
+        uint32_t mem_size;
+        uint32_t first_entry;
+        uint32_t last_entry;
+        uint32_t entries;
+        uint32_t next_free_address;
+        struct {
+            uint32_t current;
+            uint32_t next;
+            uint32_t prev;
+        } current;
+        uint8_t *buffer;
+        uint8_t *chunks_read;
+    } log;
+    ambit_object_t *ambit_object;
+} libambit_pmem20_t;
+
+int libambit_pmem20_init(libambit_pmem20_t *object, ambit_object_t *ambit_object, uint16_t chunk_size);
+int libambit_pmem20_deinit(libambit_pmem20_t *object);
+int libambit_pmem20_log_init(libambit_pmem20_t *object, uint32_t mem_start, uint32_t mem_size);
+int libambit_pmem20_log_deinit(libambit_pmem20_t *object);
+int libambit_pmem20_log_next_header(libambit_pmem20_t *object, ambit_log_header_t *log_header);
+ambit_log_entry_t *libambit_pmem20_log_read_entry(libambit_pmem20_t *object);
+ambit_log_entry_t *libambit_pmem20_log_read_entry_address(libambit_pmem20_t *object, uint32_t address, uint32_t length);
+int libambit_pmem20_log_parse_header(uint8_t *data, size_t datalen, ambit_log_header_t *log_header);
+int libambit_pmem20_gps_orbit_write(libambit_pmem20_t *object, const uint8_t *data, size_t datalen, bool include_sha256_hash);
+
+#endif /* __PMEM20_H__ */
diff --git a/src/libambit/protocol.c b/src/libambit/protocol.c
index 192d29a..3d318c6 100644
--- a/src/libambit/protocol.c
+++ b/src/libambit/protocol.c
@@ -19,8 +19,10 @@
  * Contributors:
  *
  */
-#include "libambit.h"
+#include "protocol.h"
 #include "libambit_int.h"
+#include "crc16.h"
+
 #include "hidapi/hidapi.h"
 
 #include <stdlib.h>
@@ -104,8 +106,8 @@ int libambit_protocol_command(ambit_object_t *object, uint16_t command, uint8_t
     msg->MP = 0x5d;
     msg->parts_seq = htole16(packet_count);
     msg->command = htobe16(command);
-    msg->send_recv = htole16(legacy_format ? 1 : 5);
-    msg->format = htole16(legacy_format ? 0 : 9); // TODO!!!
+    msg->send_recv = htole16(legacy_format == 1 ? 1 : legacy_format == 2 ? 0x15 : 5);
+    msg->format = htole16(legacy_format == 1 ? 0 : 9);
     msg->sequence = htole16(object->sequence_no);
     msg->payload_len = htole32(datalen);
     packet_payload_len = fmin(42, datalen);
diff --git a/src/libambit/protocol.h b/src/libambit/protocol.h
new file mode 100644
index 0000000..c57a181
--- /dev/null
+++ b/src/libambit/protocol.h
@@ -0,0 +1,63 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __PROTOCOL_H__
+#define __PROTOCOL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include "libambit.h"
+
+enum ambit_commands_e {
+    ambit_command_device_info           = 0x0000,
+    ambit_command_time                  = 0x0300,
+    ambit_command_date                  = 0x0302,
+    ambit_command_status                = 0x0306,
+    ambit_command_personal_settings     = 0x0b00,
+    ambit_command_unknown2              = 0x0b02,
+    ambit_command_unknown1              = 0x0b04,
+    ambit_command_log_count             = 0x0b06,
+    ambit_command_log_head_first        = 0x0b07,
+    ambit_command_log_head_peek         = 0x0b08,
+    ambit_command_log_head_step         = 0x0b0a,
+    ambit_command_log_head              = 0x0b0b,
+    ambit_command_gps_orbit_head        = 0x0b15,
+    ambit_command_data_write            = 0x0b16,
+    ambit_command_log_read              = 0x0b17,
+    ambit_command_data_tail_len         = 0x0b18,
+    ambit_command_lock_check            = 0x0b19,
+    ambit_command_lock_set              = 0x0b1a,
+    ambit_command_write_start           = 0x0b1b, // Really!? Just a guess...
+    ambit_command_ambit3_memory_map     = 0x0b21,
+    ambit_command_ambit3_settings       = 0x1100,
+    ambit_command_ambit3_settings_write = 0x1101,
+    ambit_command_ambit3_log_headers    = 0x1200,
+    ambit_command_ambit3_log_synced     = 0x1201
+};
+
+/**
+ * Write command to device
+ * \param legacy_format 0=normal, 1=legacy, 2=version 2
+ */
+int libambit_protocol_command(ambit_object_t *object, uint16_t command, uint8_t *data, size_t datalen, uint8_t **reply_data, size_t *replylen, uint8_t legacy_format);
+void libambit_protocol_free(uint8_t *data);
+
+#endif /* __PROTOCOL_H__ */
diff --git a/src/libambit/sbem0102.c b/src/libambit/sbem0102.c
new file mode 100644
index 0000000..9ecd855
--- /dev/null
+++ b/src/libambit/sbem0102.c
@@ -0,0 +1,249 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "sbem0102.h"
+#include "protocol.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Local definitions
+ */
+
+
+/*
+ * Static functions
+ */
+
+
+/*
+ * Static data
+ */
+
+
+/*
+ * Public functions
+ */
+int libambit_sbem0102_init(libambit_sbem0102_t *object, ambit_object_t *ambit_object, uint16_t chunk_size)
+{
+    object->ambit_object = ambit_object;
+    object->chunk_size = chunk_size;
+
+    return 0;
+}
+
+int libambit_sbem0102_deinit(libambit_sbem0102_t *object)
+{
+    return 0;
+}
+
+int libambit_sbem0102_write(libambit_sbem0102_t *object, uint16_t command, libambit_sbem0102_data_t *data)
+{
+    int ret = -1;
+    uint8_t *send_data;
+    size_t offset = 0;
+    uint8_t *reply = NULL;
+    size_t replylen = 0;
+    static uint8_t header[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 'S', 'B', 'E', 'M', '0', '1', '0', '2' };
+
+    // TODO: We have no idea how to deal with multiple packets at the moment,
+    // just fail for now
+    if (data != NULL && data->size > object->chunk_size) {
+        return -1;
+    }
+
+    // Calculate size of buffer, and allocate it
+    send_data = malloc(sizeof(header) + (data != NULL ? data->size : 0));
+    if (send_data == NULL) {
+        return -1;
+    }
+
+    // Prepare initial header
+    memcpy(send_data, header, sizeof(header));
+    offset += sizeof(header);
+
+    if (data != NULL && data->data != NULL && data->size > 0) {
+        memcpy(send_data+offset, data->data, data->size);
+        offset += data->size;
+    }
+
+    ret = libambit_protocol_command(object->ambit_object, command, send_data, offset, &reply, &replylen, 0);
+
+    free(send_data);
+    libambit_protocol_free(reply);
+
+    return ret;
+}
+
+int libambit_sbem0102_command_request(libambit_sbem0102_t *object, uint16_t command, libambit_sbem0102_data_t *data_objects, libambit_sbem0102_data_t *reply_data)
+{
+    int ret = -1;
+    uint8_t *send_data = NULL;
+    size_t offset = 0;
+    uint8_t *reply = NULL;
+    size_t replylen = 0;
+
+    static uint8_t header[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 'S', 'B', 'E', 'M', '0', '1', '0', '2' };
+    static uint8_t special_header[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 'S', 'B', 'E', 'M', '0', '1', '0', '2' };
+
+    // TODO: We have no idea how to deal with multiple packets at the moment,
+    // just fail for now
+    if (data_objects != NULL && data_objects->size > object->chunk_size) {
+        return -1;
+    }
+
+    // Calculate size of buffer, and allocate it
+    // TODO: log headers seems to have a different format than the rest, treat
+    // it here until the mystery of the 2 extra bytes is really solved
+    if (command == ambit_command_ambit3_log_headers) {
+        send_data = malloc(sizeof(special_header) + (data_objects != NULL ? data_objects->size : 0));
+        if (send_data == NULL) {
+            return -1;
+        }
+        memcpy(send_data, special_header, sizeof(special_header));
+        offset += sizeof(special_header);
+    }
+    else {
+        send_data = malloc(sizeof(header) + (data_objects != NULL ? data_objects->size : 0));
+        if (send_data == NULL) {
+            return -1;
+        }
+        memcpy(send_data, header, sizeof(header));
+        offset += sizeof(header);
+    }
+
+    // Add data objects
+    if (data_objects != NULL && data_objects->data != NULL && data_objects->size > 0) {
+        memcpy(send_data+offset, data_objects->data, data_objects->size);
+        offset += data_objects->size;
+    }
+
+    // Reset reply data before starting to fill it
+    libambit_sbem0102_data_free(reply_data);
+
+    if (libambit_protocol_command(object->ambit_object, command, send_data, offset, &reply, &replylen, 0) == 0) {
+        // Check that the reply contains an SBEM0102 header
+        if (replylen >= sizeof(header) && memcmp(reply + 6, header + 6, 8) == 0) {
+            if (replylen > sizeof(header)) {
+                // Copy message to reply_data object
+                reply_data->data = malloc(replylen - sizeof(header));
+                memcpy(reply_data->data, reply + sizeof(header), replylen - sizeof(header));
+                reply_data->size = replylen - sizeof(header);
+
+                // Check if this reply was just a part (5th byte is the current
+                // guess on how to determine)
+                while (reply[4] != 0x01) {
+                    // Guess number 2: first 4 bytes seems to be copied from
+                    // the reply when asking for more data, what the f*ck does
+                    // they represent!?
+                    memcpy(send_data, reply, 4);
+
+                    // Free old reply before calling again
+                    libambit_protocol_free(reply);
+
+                    if (libambit_protocol_command(object->ambit_object, command, send_data, offset, &reply, &replylen, 0) != 0 ||
+                        replylen < 6) {
+                        libambit_sbem0102_data_free(reply_data);
+                        break;
+                    }
+
+                    if (replylen > 6) {
+                        reply_data->data = realloc(reply_data->data, reply_data->size + replylen - 6);
+                        memcpy(reply_data->data + reply_data->size, reply + 6, replylen - 6);
+                        reply_data->size += replylen - 6;
+                    }
+                }
+            }
+
+            ret = 0;
+        }
+
+        libambit_protocol_free(reply);
+    }
+
+    free(send_data);
+
+    return ret;
+}
+
+int libambit_sbem0102_command_request_raw(libambit_sbem0102_t *object, uint16_t command, uint8_t *data, size_t datalen, libambit_sbem0102_data_t *reply_data)
+{
+    int ret = -1;
+    uint8_t *reply = NULL;
+    size_t replylen = 0;
+
+    static uint8_t header[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 'S', 'B', 'E', 'M', '0', '1', '0', '2' };
+
+    // Reset reply data before starting to fill it
+    libambit_sbem0102_data_free(reply_data);
+
+    if (libambit_protocol_command(object->ambit_object, command, data, datalen, &reply, &replylen, 0) == 0) {
+        // Check that the reply contains an SBEM0102 header
+        if (replylen >= sizeof(header) && memcmp(reply + 6, header + 6, 8) == 0) {
+            if (replylen > sizeof(header)) {
+                // Copy message to reply_data object
+                reply_data->data = malloc(replylen - sizeof(header));
+                memcpy(reply_data->data, reply + sizeof(header), replylen - sizeof(header));
+                reply_data->size = replylen - sizeof(header);
+            }
+
+            ret = 0;
+        }
+
+        libambit_protocol_free(reply);
+    }
+
+    return ret;
+}
+
+void libambit_sbem0102_data_init(libambit_sbem0102_data_t *data)
+{
+    if (data != NULL) {
+        memset(data, 0, sizeof(libambit_sbem0102_data_t));
+    }
+}
+
+void libambit_sbem0102_data_free(libambit_sbem0102_data_t *data)
+{
+    if (data != NULL) {
+        if (data->data != NULL) {
+            free(data->data);
+        }
+        memset(data, 0, sizeof(libambit_sbem0102_data_t));
+    }
+}
+
+void libambit_sbem0102_data_add(libambit_sbem0102_data_t *object, uint8_t id, uint8_t *data, uint8_t datalen)
+{
+    if (object != NULL) {
+        object->data = realloc(object->data, object->size + 2 + datalen);
+        if (object->data != NULL) {
+            object->data[object->size] = id;
+            object->data[object->size+1] = datalen;
+            if (datalen > 0 && data != NULL) {
+                memcpy(object->data+2+object->size, data, datalen);
+            }
+            object->size += 2 + datalen;
+        }
+    }
+}
diff --git a/src/libambit/sbem0102.h b/src/libambit/sbem0102.h
new file mode 100644
index 0000000..184a30f
--- /dev/null
+++ b/src/libambit/sbem0102.h
@@ -0,0 +1,173 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __SBEM0102_H__
+#define __SBEM0102_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include "libambit.h"
+
+typedef struct libambit_sbem0102_s {
+    uint16_t chunk_size;
+    ambit_object_t *ambit_object;
+} libambit_sbem0102_t;
+
+typedef struct libambit_sbem0102_data_s {
+    uint8_t *data;
+    size_t size;
+    uint8_t *read_ptr;
+} libambit_sbem0102_data_t;
+
+
+/**
+ * Initialize SBEM0102 object
+ * \param object Object to intialize
+ * \param ambit_object Corresponding ambit_object
+ * \param chunk_size Maximum chunk size of messages
+ * \return 0 on success, else -1
+ */
+int libambit_sbem0102_init(libambit_sbem0102_t *object, ambit_object_t *ambit_object, uint16_t chunk_size);
+
+/**
+ * Deinitialize SBEM0102 object
+ * \object Object to deintialize
+ * \return 0 on success, else -1
+ */
+int libambit_sbem0102_deinit(libambit_sbem0102_t *object);
+
+/**
+ * Write data to device in SBEM0102 format
+ * \param object libambit object
+ * \param command Command to send
+ * \param data data objects to append to request
+ * \return 0 on success, else -1
+ */
+int libambit_sbem0102_write(libambit_sbem0102_t *object, uint16_t command, libambit_sbem0102_data_t *data);
+
+/**
+ * Request read of complete SBEM0102 message from device
+ * \param object libambit object
+ * \param command Command to send
+ * \param data_objects objects to append to request
+ * \param reply_data Data in reply. After data in object has been used, user
+ * should call libambit_sbem0102_data_free()
+ * \return 0 on success, else -1
+ */
+int libambit_sbem0102_command_request(libambit_sbem0102_t *object, uint16_t command, libambit_sbem0102_data_t *data_objects, libambit_sbem0102_data_t *reply_data);
+
+/**
+ * Request read of complete SBEM0102 message from device, but without SBEM data
+ * in request
+ * \param object libambit object
+ * \param command Command to send
+ * \param data raw data to append to request
+ * \param reply_data Data in reply. After data in object has been used, user
+ * should call libambit_sbem0102_data_free()
+ * \return 0 on success, else -1
+ */
+int libambit_sbem0102_command_request_raw(libambit_sbem0102_t *object, uint16_t command, uint8_t *data, size_t datalen, libambit_sbem0102_data_t *reply_data);
+
+/**
+ * Free content of data objects
+ * NOTE! The object itself is not freed
+ * \param data Data object of which to free data in
+ */
+void libambit_sbem0102_data_init(libambit_sbem0102_data_t *data);
+
+/**
+ * Free content of data objects
+ * NOTE! The object itself is not freed
+ * \param data Data object of which to free data in
+ */
+void libambit_sbem0102_data_free(libambit_sbem0102_data_t *data);
+
+/**
+ * Append id:data pair to data object
+ * \param object Data object to append value to
+ * \param id data id to add
+ * \param data data buffer to add
+ * \param datalen length of databuffer
+ */
+void libambit_sbem0102_data_add(libambit_sbem0102_data_t *object, uint8_t id, uint8_t *data, uint8_t datalen);
+
+/**
+ * Reset internal read iterator
+ * \param object Object to iterate over
+ */
+static inline void libambit_sbem0102_data_reset(libambit_sbem0102_data_t *object)
+{
+    object->read_ptr = NULL;
+}
+
+/**
+ * Get data id of current element in iteration
+ * \param object Object to iterate over
+ * \return Current elements id
+ */
+static inline uint8_t libambit_sbem0102_data_id(libambit_sbem0102_data_t *object)
+{
+    return object->read_ptr[0];
+}
+
+/**
+ * Get data length of current element in iteration
+ * \param object Object to iterate over
+ * \return Current elements data length
+ */
+static inline uint8_t libambit_sbem0102_data_len(libambit_sbem0102_data_t *object)
+{
+    return object->read_ptr[1];
+}
+
+/**
+ * Get data pointer of current element in iteration
+ * \param object Object to iterate over
+ * \return Current elements data pointer
+ */
+static inline const uint8_t *libambit_sbem0102_data_ptr(libambit_sbem0102_data_t *object)
+{
+    return &object->read_ptr[2];
+}
+
+
+/**
+ * Iterate to next data entry
+ * \param object Object to iterate over
+ * \return 0 on success, else -1
+ */
+static inline int libambit_sbem0102_data_next(libambit_sbem0102_data_t *object)
+{
+    // Initial state
+    if (object->read_ptr == NULL) {
+        object->read_ptr = object->data;
+        return 0;
+    }
+    // Loop state
+    if (object->data + object->size > object->read_ptr + 2 + libambit_sbem0102_data_len(object)) {
+        object->read_ptr += 2 + libambit_sbem0102_data_len(object);
+        return 0;
+    }
+    // Exit state
+    return -1;
+}
+
+#endif /* __SBEM0102_H__ */
diff --git a/src/libambit/sha256.c b/src/libambit/sha256.c
new file mode 100644
index 0000000..e934330
--- /dev/null
+++ b/src/libambit/sha256.c
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 <string.h>
+
+#include "sha256.h"
+
+/*
+ * Local definitions
+ */
+#define ROTLEFT(a,b)  (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+#define CH(x,y,z)     (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z)    (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x)        (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x)        (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x)       (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x)       (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+
+/*
+ * Static functions
+ */
+static void sha256_transform(sha256_ctx *ctx, const uint8_t *data);
+
+/*
+ * Static variables
+ */
+static const uint32_t h[8] = {
+    0x6a09e667,
+    0xbb67ae85,
+    0x3c6ef372,
+    0xa54ff53a,
+    0x510e527f,
+    0x9b05688c,
+    0x1f83d9ab,
+    0x5be0cd19
+};
+
+static const uint32_t k[SHA256_BLOCK_SIZE] = {
+    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+/*
+ * Public functions
+ */
+void sha256(const uint8_t *data, size_t len, uint8_t *hash)
+{
+    sha256_ctx ctx;
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, data, len);
+    sha256_final(&ctx, hash);
+}
+
+void sha256_init(sha256_ctx *ctx)
+{
+    size_t i;
+    ctx->datalen = 0;
+    ctx->bitlen = 0;
+    for (i=0; i<8; i++) {
+        ctx->h[i] = h[i];
+    }
+}
+
+void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
+{
+    size_t i;
+
+    for (i=0; i<len; i++) {
+        ctx->data[ctx->datalen++] = data[i];
+        if (ctx->datalen == SHA256_BLOCK_SIZE) {
+            sha256_transform(ctx, ctx->data);
+            ctx->bitlen += 512;
+            ctx->datalen = 0;
+        }
+    }
+}
+
+void sha256_final(sha256_ctx *ctx, uint8_t *hash)
+{
+    uint32_t i;
+
+    i = ctx->datalen;
+
+    // Pad data left in buffer
+    if (i < 56) {
+        // There is room for the appending length in this chunk, pad up until 56 byte
+        ctx->data[i++] = 0x80;
+        while (i < 56) {
+            ctx->data[i++] = 0x00;
+        }
+    }
+    else {
+        // No room for length, transform this chunk and use an empty one for length
+        ctx->data[i++] = 0x80;
+        while (i < 64) {
+            ctx->data[i++] = 0x00;
+        }
+        sha256_transform(ctx, ctx->data);
+        memset(ctx->data, 0, 56);
+    }
+
+    // Append total length to last buffer
+    ctx->bitlen += ctx->datalen << 3;
+    for (i=0; i<8; i++) {
+        ctx->data[63-i] = ctx->bitlen >> (8*i);
+    }
+    sha256_transform(ctx, ctx->data);
+
+    // Get hash (stored as 8 (4-byte) words)
+    for (i=0; i<8; i++) {
+        hash[(i<<2)]   = ctx->h[i] >> 24;
+        hash[(i<<2)+1] = ctx->h[i] >> 16;
+        hash[(i<<2)+2] = ctx->h[i] >> 8;
+        hash[(i<<2)+3] = ctx->h[i];
+    }
+}
+
+static void sha256_transform(sha256_ctx *ctx, const uint8_t *data)
+{
+    size_t i;
+    uint32_t m[64];
+    uint32_t th[8];
+    uint32_t t1, t2;
+
+    for (i=0; i<16; i++) {
+        m[i] = (data[(i<<2)] << 24) | (data[(i<<2)+1] << 16) | (data[(i<<2)+2] << 8) | (data[(i<<2)+3]);
+    }
+    for (i=16; i<64; i++) {
+        m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16];
+    }
+    for (i=0; i<8; i++) {
+        th[i] = ctx->h[i];
+    }
+    for (i=0; i<64; i++) {
+        t1 = th[7] + EP1(th[4]) + CH(th[4], th[5], th[6]) + k[i] + m[i];
+        t2 = EP0(th[0]) + MAJ(th[0], th[1], th[2]);
+        th[7] = th[6];
+        th[6] = th[5];
+        th[5] = th[4];
+        th[4] = th[3] + t1;
+        th[3] = th[2];
+        th[2] = th[1];
+        th[1] = th[0];
+        th[0] = t1 + t2;
+    }
+    for (i=0; i<8; i++) {
+        ctx->h[i] += th[i];
+    }
+}
diff --git a/src/libambit/sha256.h b/src/libambit/sha256.h
new file mode 100644
index 0000000..03aeb5b
--- /dev/null
+++ b/src/libambit/sha256.h
@@ -0,0 +1,42 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __SHA256_H__
+#define __SHA256_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define SHA256_BLOCK_SIZE (512 / 8)
+
+typedef struct {
+    uint8_t  data[SHA256_BLOCK_SIZE];
+    uint32_t datalen;
+    uint64_t bitlen;
+    uint32_t h[8];
+} sha256_ctx;
+
+void sha256(const uint8_t *data, size_t len, uint8_t *hash);
+void sha256_init(sha256_ctx *ctx);
+void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len);
+void sha256_final(sha256_ctx *ctx, uint8_t *hash);
+
+#endif /* __SHA256_H__ */
diff --git a/src/libambit/utils.c b/src/libambit/utils.c
new file mode 100644
index 0000000..f263f34
--- /dev/null
+++ b/src/libambit/utils.c
@@ -0,0 +1,205 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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 "utils.h"
+#include "debug.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <iconv.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static int date_get_num(const char **pp, int n_min, int n_max, int len_max)
+{
+    int i, val, c;
+    const char *p;
+    p = *pp;
+    val = 0;
+    for(i = 0; i < len_max; i++) {
+        c = *p;
+        if (!isdigit(c))
+            break;
+        val = (val * 10) + c - '0';
+        p++;
+    }
+    /* no number read ? */
+    if (p == *pp)
+        return -1;
+    if (val < n_min || val > n_max)
+        return -1;
+    *pp = p;
+    return val;
+}
+char *libambit_strptime(const char *p, const char *fmt, struct tm *dt)
+{
+    int c, val;
+    for(;;) {
+        /* consume time string until a non whitespace char is found */
+        while (isspace(*fmt)) {
+            while (isspace(*p)) {
+                p++;
+            }
+            fmt++;
+        }
+        c = *fmt++;
+        if (c == '\0') {
+            return (char *)p;
+        } else if (c == '%') {
+            c = *fmt++;
+            switch(c) {
+              case 'H':
+              case 'J':
+                val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_hour = val;
+                break;
+              case 'M':
+                val = date_get_num(&p, 0, 59, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_min = val;
+                break;
+              case 'S':
+                val = date_get_num(&p, 0, 59, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_sec = val;
+                break;
+              case 'Y':
+                val = date_get_num(&p, 0, 9999, 4);
+                if (val == -1)
+                    return NULL;
+                dt->tm_year = val - 1900;
+                break;
+              case 'm':
+                val = date_get_num(&p, 1, 12, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_mon = val - 1;
+                break;
+              case 'd':
+                val = date_get_num(&p, 1, 31, 2);
+                if (val == -1)
+                    return NULL;
+                dt->tm_mday = val;
+                break;
+              case '%':
+                goto match;
+              default:
+                return NULL;
+            }
+        } else {
+          match:
+            if (c != *p)
+                return NULL;
+            p++;
+        }
+    }
+}
+
+/* return number representation of hex, or on error 0xff */
+static uint8_t hextob(char ch)
+{
+    if (ch >= '0' && ch <= '9')
+        return (ch - '0');
+    else if (ch >= 'A' && ch <= 'F')
+        return (ch - 'A' + 10);
+    else if (ch >= 'a' && ch <= 'f')
+        return (ch - 'a' + 10);
+    else
+        return 0xff;
+}
+int libambit_htob(const char *hex_string, uint8_t *binary, size_t binary_size)
+{
+    int i = 0;
+    uint8_t ch;
+    size_t bytes_written = 0;
+
+    if (hex_string[0] == '\0' || strlen(hex_string) % 2 != 0) {
+        return -1;
+    }
+
+    while (bytes_written < binary_size && *hex_string != '\0') {
+        if ((ch = hextob(*(hex_string++))) == 0xff)
+            return -1;
+        binary[i] = ch << 4;
+        if ((ch = hextob(*(hex_string++))) == 0xff)
+            return -1;
+        binary[i++] |= ch;
+    }
+
+    return i;
+}
+
+char * utf8memconv(const char *src, size_t n, const char *encoding)
+{
+    char *rv = NULL;
+    iconv_t cd = (iconv_t) -1;
+
+    if (src) {
+        cd = iconv_open("UTF-8", (encoding ? encoding : "ASCII"));
+        if ((iconv_t) -1 == cd) {
+            LOG_ERROR("iconv_open: %s", strerror(errno));
+        }
+        else {
+            size_t ilen = n;
+            size_t olen = n * 4 + 1;
+            char  *ibuf = (char *)src;
+            char  *obuf = (char *)malloc(olen * sizeof(char));
+
+            if (obuf) {
+                size_t n = olen;
+                size_t sz;
+
+                rv = obuf;
+                sz = iconv(cd, &ibuf, &ilen, &obuf, &olen);
+
+                if ((size_t) -1 == sz) {
+                    LOG_ERROR("iconv: %s", strerror(errno));
+                    free(rv);
+                    rv = NULL;
+                }
+                else {      /* we're good, terminate string */
+                    rv[n - olen] = '\0';
+                    rv = realloc(rv, strlen(rv) + 1);
+                }
+            }
+        }
+    }
+
+    if ((iconv_t) -1 != cd) {
+        iconv_close(cd);
+    }
+
+    return rv;
+}
+
+char * utf8wcsconv(const wchar_t *src)
+{
+    size_t len = wcslen(src) * sizeof(wchar_t);
+
+    return utf8memconv((char *)src, len, "WCHAR_T");
+}
diff --git a/src/libambit/utils.h b/src/libambit/utils.h
new file mode 100644
index 0000000..317632a
--- /dev/null
+++ b/src/libambit/utils.h
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2014 Emil Ljungdahl
+ *
+ * This file is part of libambit.
+ *
+ * libambit 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:
+ *
+ */
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <time.h>
+#include <wchar.h>
+
+/**
+ * Reduced implementation of the Unix specific strptime
+ */
+char *libambit_strptime(const char *p, const char *fmt, struct tm *dt);
+
+/**
+ * Hex string to binary conversion
+ * \param Hex string to parse
+ * \param binary Buffer to store parsed hex data
+ * \param binary_size Length of buffer
+ * \return Number of converted bytes, or -1 if error occured
+ */
+int libambit_htob(const char *hex_string, uint8_t *binary, size_t binary_size);
+
+/**
+ * Converts \a n octets to a UTF-8 encoded string.
+ *
+ * The caller gets to manage the memory associated with the returned
+ * string.  In case \a encoding is \c NULL, ASCII will be assumed.
+ */
+char * utf8memconv(const char *src, size_t n, const char *encoding);
+
+/**
+ * Converts a wide character string to a UTF-8 encoded one.
+ *
+ * The caller get s to manage the memory associated with the returned
+ * string.
+ */
+char * utf8wcsconv(const wchar_t *src);
+
+// static helpers
+static inline uint8_t read8(const uint8_t *buf, size_t offset)
+{
+    return buf[offset];
+}
+
+static inline uint16_t read16(const uint8_t *buf, size_t offset)
+{
+    return (buf[offset] | (buf[offset+1] << 8));
+}
+
+static inline uint32_t read32(const uint8_t *buf, size_t offset)
+{
+    return (buf[offset] | (buf[offset+1] << 8) | (buf[offset+2] << 16) | (buf[offset+3] << 24));
+}
+
+static inline uint8_t read8inc(const uint8_t *buf, size_t *offset)
+{
+    *offset += 1;
+    return buf[(*offset)-1];
+}
+
+static inline uint16_t read16inc(const uint8_t *buf, size_t *offset)
+{
+    *offset += 2;
+    return (buf[(*offset)-2] | (buf[(*offset)-1] << 8));
+}
+
+static inline uint32_t read32inc(const uint8_t *buf, size_t *offset)
+{
+    *offset += 4;
+    return (buf[(*offset)-4] | (buf[(*offset)-3] << 8) | (buf[(*offset)-2] << 16) | (buf[(*offset)-1] << 24));
+}
+
+#endif /* __UTILS_H__ */
diff --git a/src/movescount/CMakeLists.txt b/src/movescount/CMakeLists.txt
new file mode 100644
index 0000000..d9cdd28
--- /dev/null
+++ b/src/movescount/CMakeLists.txt
@@ -0,0 +1,87 @@
+#  CMakeLists.txt -- build specification for the movescount library
+#  Copyright (C) 2015 Olaf Meeuwissen
+#
+#  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/>.
+
+
+cmake_minimum_required(VERSION 2.8.5)
+
+project(movescount CXX) 
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../openambit/cmake")
+
+find_package(Qt4 REQUIRED
+  COMPONENTS QtCore QtNetwork)
+find_package(QJSON 0.8.0 REQUIRED)
+find_package(ZLIB REQUIRED)
+find_package(libambit REQUIRED)
+
+include(${QT_USE_FILE})
+include(GNUInstallDirs)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include_directories(
+  ../libambit/
+  ${QJSON_INCLUDE_DIR}
+  ${ZLIB_INCLUDE_DIRS}
+  )
+
+link_directories(
+  ../libambit/
+  )
+
+add_library (
+  movescount
+  SHARED
+  deviceinfo.cpp
+  logentry.cpp
+  logstore.cpp
+  movescount.cpp
+  movescountjson.cpp
+  movescountlogdirentry.cpp
+  movescountxml.cpp
+  movescountlogchecker.cpp
+  )
+
+target_link_libraries(
+  movescount
+  ${LIBAMBIT_LIBS}
+  ${QJSON_LIBRARIES}
+  ${ZLIB_LIBRARIES}
+  Qt4::QtNetwork
+  Qt4::QtCore
+  )
+
+set_target_properties(movescount
+  PROPERTIES
+  VERSION 0.3.0
+  SOVERSION 0
+  )
+install(TARGETS
+  movescount
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+install(FILES
+  deviceinfo.h
+  logentry.h
+  logstore.h
+  movescount.h
+  movescountxml.h
+  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/movescount
+  )
diff --git a/src/movescount/deviceinfo.cpp b/src/movescount/deviceinfo.cpp
new file mode 100644
index 0000000..60da4ef
--- /dev/null
+++ b/src/movescount/deviceinfo.cpp
@@ -0,0 +1,42 @@
+/*
+ * (C) Copyright 2014 Olaf Meeuwissen
+ *
+ * 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 "deviceinfo.h"
+
+DeviceInfo&
+DeviceInfo::operator=(const ambit_device_info_t& devinfo)
+{
+    this->name   = QString::fromUtf8(devinfo.name);
+    this->model  = QString::fromUtf8(devinfo.model);
+    this->serial = QString::fromUtf8(devinfo.serial);
+
+    this->fw_version[0] = devinfo.fw_version[0];
+    this->fw_version[1] = devinfo.fw_version[1];
+    this->fw_version[2] = devinfo.fw_version[2] | (devinfo.fw_version[3] << 8);
+    this->hw_version[0] = devinfo.hw_version[0];
+    this->hw_version[1] = devinfo.hw_version[1];
+    this->hw_version[2] = devinfo.hw_version[2] | (devinfo.hw_version[3] << 8);
+
+    this->access_status = devinfo.access_status;
+    this->is_supported  = devinfo.is_supported;
+
+    return *this;
+}
diff --git a/src/openambit/logentry.h b/src/movescount/deviceinfo.h
similarity index 58%
copy from src/openambit/logentry.h
copy to src/movescount/deviceinfo.h
index 7ed148f..27e64a5 100644
--- a/src/openambit/logentry.h
+++ b/src/movescount/deviceinfo.h
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2013 Emil Ljungdahl
+ * (C) Copyright 2014 Olaf Meeuwissen
  *
  * This file is part of Openambit.
  *
@@ -19,34 +19,26 @@
  * Contributors:
  *
  */
-#ifndef LOGENTRY_H
-#define LOGENTRY_H
+#ifndef DEVICEINFO_H
+#define DEVICEINFO_H
+
+#include <QString>
 
-#include <QDateTime>
 #include <libambit.h>
 
-class LogEntry
+struct DeviceInfo
 {
-public:
-    explicit LogEntry();
-    LogEntry(const LogEntry &other);
-    ~LogEntry();
+    QString name;
+    QString model;
+    QString serial;
 
-    LogEntry& operator=(const LogEntry &rhs);
+    int fw_version[3];
+    int hw_version[3];
 
-    QString toHtml();
-    bool isUploaded();
+    int access_status;
+    bool is_supported;
 
-    QString device;
-    QDateTime time;
-    QString movescountId;
-    ambit_device_info_t *deviceInfo;
-    ambit_personal_settings_t *personalSettings;
-    ambit_log_entry_t *logEntry;
-signals:
-    
-public slots:
-    
+    DeviceInfo& operator= (const ambit_device_info_t& devinfo);
 };
 
-#endif // LOGENTRY_H
+#endif // DEVICEINFO_H
diff --git a/src/openambit/logentry.cpp b/src/movescount/logentry.cpp
similarity index 72%
rename from src/openambit/logentry.cpp
rename to src/movescount/logentry.cpp
index 2190516..fbc7db3 100644
--- a/src/openambit/logentry.cpp
+++ b/src/movescount/logentry.cpp
@@ -22,7 +22,6 @@
 #include "logentry.h"
 
 LogEntry::LogEntry() :
-    deviceInfo(NULL),
     personalSettings(NULL),
     logEntry(NULL)
 {
@@ -35,14 +34,7 @@ LogEntry::LogEntry(const LogEntry &other)
     device = other.device;
     time = other.time;
     movescountId = other.movescountId;
-
-    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;
-    }
+    deviceInfo = other.deviceInfo;
 
     if (other.personalSettings != NULL) {
         personalSettings = (ambit_personal_settings_t*)malloc(sizeof(ambit_personal_settings_t));
@@ -55,6 +47,9 @@ LogEntry::LogEntry(const LogEntry &other)
     if (other.logEntry != NULL) {
         logEntry = (ambit_log_entry_t*)malloc(sizeof(ambit_log_entry_t));
         memcpy(logEntry, other.logEntry, sizeof(ambit_log_entry_t));
+        if (other.logEntry->header.activity_name) {
+            logEntry->header.activity_name = strdup(other.logEntry->header.activity_name);
+        }
         if (other.logEntry->samples != NULL) {
             logEntry->samples = (ambit_log_sample_t*)malloc(sizeof(ambit_log_sample_t)*other.logEntry->samples_count);
             memcpy(logEntry->samples, other.logEntry->samples, sizeof(ambit_log_sample_t)*other.logEntry->samples_count);
@@ -100,11 +95,6 @@ LogEntry::~LogEntry()
 {
     u_int32_t i;
 
-    if (deviceInfo != NULL) {
-        free(deviceInfo);
-        deviceInfo = NULL;
-    }
-
     if (personalSettings != NULL) {
         free(personalSettings);
         personalSettings = NULL;
@@ -143,37 +133,3 @@ bool LogEntry::isUploaded(){
     }
     return true;
 }
-
-QString LogEntry::toHtml(){
-    QString log_html;
-
-    log_html += "<h1>" + QString::fromLatin1(this->logEntry->header.activity_name) + "</h1>";
-    if (this->isUploaded()){
-        log_html += "<a href='http://www.movescount.com/moves/move" + this->movescountId + "'>see on movescount.com</a>";
-    }
-    else {
-        log_html += "Not uploaded yet";
-    }
-    log_html += "<h2>Details</h2>";
-    log_html += "<h4>" + this->time.toString() + "</h4>";
-    log_html += "<h4>Duration: " + QTime(0, 0, 0,0 ).addMSecs(this->logEntry->header.duration).toString("HH:mm:ss") + "</h4>";
-    log_html += "<h4>Distance: " + QString::number(this->logEntry->header.distance) + " m</h4>";
-    log_html += "<h2>Training values</h2>";
-    log_html += "<h4>Avg HR: " + QString::number(this->logEntry->header.heartrate_avg) + " bpm</h4>";
-    log_html += "<h4>Max HR: " + QString::number(this->logEntry->header.heartrate_max) + " bpm</h4>";
-    log_html += "<h4>Min HR: " + QString::number(this->logEntry->header.heartrate_min) + " bpm</h4>";
-    log_html += "<h4>PTE: " + QString::number(this->logEntry->header.peak_training_effect/10.0) + "</h4>";
-    log_html += "<h2>Device</h2>";
-    log_html += "<h4>Name: " + QString(this->deviceInfo->name) + "</h4>";
-    log_html += "<h4>Variant: " + QString(this->deviceInfo->model) + "</h4>";
-    log_html += "<h4>Serial: " + QString(this->deviceInfo->serial) + "</h4>";
-    //log_string += "Device info: " + QString::number(this->deviceInfo->fw_version) + "\n";
-    //log_string += "Device info: " + QString::number(this->deviceInfo->hw_version) + "\n";
-
-    //log_string += "Personal Settings: " + this->personalSettings + "\n";
-
-
-    return log_html;
-}
-
-
diff --git a/src/openambit/logentry.h b/src/movescount/logentry.h
similarity index 95%
rename from src/openambit/logentry.h
rename to src/movescount/logentry.h
index 7ed148f..89bb842 100644
--- a/src/openambit/logentry.h
+++ b/src/movescount/logentry.h
@@ -25,6 +25,8 @@
 #include <QDateTime>
 #include <libambit.h>
 
+#include "deviceinfo.h"
+
 class LogEntry
 {
 public:
@@ -34,13 +36,12 @@ public:
 
     LogEntry& operator=(const LogEntry &rhs);
 
-    QString toHtml();
     bool isUploaded();
 
     QString device;
     QDateTime time;
     QString movescountId;
-    ambit_device_info_t *deviceInfo;
+    DeviceInfo deviceInfo;
     ambit_personal_settings_t *personalSettings;
     ambit_log_entry_t *logEntry;
 signals:
diff --git a/src/openambit/logstore.cpp b/src/movescount/logstore.cpp
similarity index 86%
rename from src/openambit/logstore.cpp
rename to src/movescount/logstore.cpp
index fe03fe3..dc33042 100644
--- a/src/openambit/logstore.cpp
+++ b/src/movescount/logstore.cpp
@@ -46,8 +46,12 @@ static sample_type_names_t sampleTypeNames[] = {
     { ambit_log_sample_type_gps_small, "gps-small" },
     { ambit_log_sample_type_gps_tiny, "gps-tiny" },
     { ambit_log_sample_type_time, "time" },
+    { ambit_log_sample_type_swimming_turn, "swimming-turn" },
+    { ambit_log_sample_type_swimming_stroke, "swimming-stroke" },
     { ambit_log_sample_type_activity, "activity" },
+    { ambit_log_sample_type_cadence_source, "cadence-source" },
     { ambit_log_sample_type_position, "position" },
+    { ambit_log_sample_type_fwinfo, "fwinfo" },
     { ambit_log_sample_type_unknown, "unknown" },
     { (ambit_log_sample_type_t)0, "" }
 };
@@ -58,8 +62,12 @@ typedef struct sample_distance_source_name_s {
 } sample_distance_source_name_t;
 
 static sample_distance_source_name_t sampleDistanceSourceNames[] = {
+    { 0x00, "Bikepod" },
+    { 0x01, "Footpod" },
     { 0x02, "GPS" },
     { 0x03, "Wrist" },
+    { 0x04, "Indoorswimming" },
+    { 0x05, "Outdoorswimming" },
     { 0, "" }
 };
 
@@ -89,18 +97,43 @@ static sample_lap_event_type_t sampleLapEventTypeNames[] = {
     { 0, "" }
 };
 
+typedef struct sample_cadence_source_name_s {
+    u_int8_t source_id;
+    QString XMLName;
+} sample_cadence_source_name_t;
+
+static sample_cadence_source_name_t sampleCadenceSourceNames[] = {
+    { 0x40, "Wrist" },
+    { 0, "" }
+};
+
+typedef struct sample_swimming_style_name_s {
+    u_int8_t source_id;
+    QString XMLName;
+} sample_swimming_style_name_t;
+
+static sample_swimming_style_name_t sampleSwimmingStyleNames[] = {
+    { 0x00, "Other" },
+    { 0x01, "Butterfly" },
+    { 0x02, "Backstroke" },
+    { 0x03, "Breaststroke" },
+    { 0x04, "Freestyle" },
+    { 0x05, "Drill" },
+    { 0, "" }
+};
+
 LogStore::LogStore(QObject *parent) :
     QObject(parent)
 {
     storagePath = QString(getenv("HOME")) + "/.openambit";
 }
 
-LogEntry *LogStore::store(ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry)
+LogEntry *LogStore::store(const DeviceInfo& deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *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));
 
-    return storeInternal(QString(deviceInfo->serial), dateTime, deviceInfo, personalSettings, logEntry);
+    return storeInternal(deviceInfo.serial, dateTime, deviceInfo, personalSettings, logEntry);
 }
 
 LogEntry *LogStore::store(LogEntry *entry)
@@ -178,7 +211,7 @@ QString LogStore::logEntryPath(QString device, QDateTime time)
     return storagePath + "/log_" + device + "_" + time.toString("yyyy_MM_dd_hh_mm_ss") + ".log";
 }
 
-LogEntry *LogStore::storeInternal(QString serial, QDateTime dateTime, ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry, QString movescountId)
+LogEntry *LogStore::storeInternal(QString serial, QDateTime dateTime, const DeviceInfo& deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry, QString movescountId)
 {
     LogEntry *retEntry = new LogEntry();
 
@@ -190,6 +223,9 @@ LogEntry *LogStore::storeInternal(QString serial, QDateTime dateTime, ambit_devi
     logfile.open(QIODevice::ReadOnly);
     XMLReader reader(retEntry);
     if (!reader.read(&logfile)) {
+        if (retEntry->logEntry && retEntry->logEntry->header.activity_name) {
+            free(retEntry->logEntry->header.activity_name);
+        }
         delete retEntry;
         retEntry = NULL;
     }
@@ -304,35 +340,28 @@ void LogStore::XMLReader::readDeviceInfo()
 
     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().toLatin1().data());
+            logEntry->deviceInfo.serial = xml.readElementText().toUtf8();
         }
         else if (xml.name() == "Model") {
-            strcpy(logEntry->deviceInfo->model, xml.readElementText().toLatin1().data());
+            logEntry->deviceInfo.model = xml.readElementText().toUtf8();
         }
         else if (xml.name() == "Name") {
-            strcpy(logEntry->deviceInfo->name, xml.readElementText().toLatin1().data());
+            logEntry->deviceInfo.name = xml.readElementText().toUtf8();
         }
         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;
+                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();
             }
         }
         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;
+                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();
             }
         }
         else {
@@ -470,6 +499,9 @@ void LogStore::XMLReader::readPersonalSettings()
         else if (xml.name() == "AltiBaroMode") {
             logEntry->personalSettings->alti_baro_mode = xml.readElementText().toUInt();
         }
+        else if (xml.name() == "StormAlarm") {
+            logEntry->personalSettings->storm_alarm = xml.readElementText().toUInt();
+        }
         else if (xml.name() == "FusedAltiDisabled") {
             logEntry->personalSettings->fused_alti_disabled = xml.readElementText().toUInt();
         }
@@ -488,6 +520,12 @@ void LogStore::XMLReader::readPersonalSettings()
         else if (xml.name() == "AutomaticBikePowerCalibration") {
             logEntry->personalSettings->automatic_bikepower_calib = xml.readElementText().toUInt();
         }
+        else if (xml.name() == "AutomaticFootPODCalibration") {
+            logEntry->personalSettings->automatic_footpod_calib = xml.readElementText().toUInt();
+        }
+        else if (xml.name() == "TrainingProgram") {
+            logEntry->personalSettings->training_program = xml.readElementText().toUInt();
+        }
         else {
             xml.skipCurrentElement();
         }
@@ -627,10 +665,9 @@ void LogStore::XMLReader::readLogHeader()
             logEntry->logEntry->header.activity_type = xml.readElementText().toUInt();
         }
         else if (xml.name() == "Activity") {
-            QByteArray ba = xml.readElementText().toLatin1();
+            QByteArray ba = xml.readElementText().toUtf8();
             const char *c_str = ba.data();
-            strncpy(logEntry->logEntry->header.activity_name, c_str, 16);
-            logEntry->logEntry->header.activity_name[16] = 0;
+            logEntry->logEntry->header.activity_name = strdup(c_str);
         }
         else if (xml.name() == "Temperature") {
             while (xml.readNextStartElement()) {
@@ -672,6 +709,19 @@ void LogStore::XMLReader::readLogHeader()
         else if (xml.name() == "DistanceBeforeCalibrationChange") {
             logEntry->logEntry->header.distance_before_calib = xml.readElementText().toUInt();
         }
+        else if (xml.name() == "Swimming") {
+            while (xml.readNextStartElement()) {
+                if (xml.name() == "PoolLengths") {
+                    logEntry->logEntry->header.swimming_pool_lengths = xml.readElementText().toUInt();
+                }
+                else if (xml.name() == "PoolLength") {
+                    logEntry->logEntry->header.swimming_pool_length = xml.readElementText().toUInt();
+                }
+                else {
+                    xml.skipCurrentElement();
+                }
+            }
+        }
         else if (xml.name() == "Unknown1") {
             QByteArray val = xml.readElementText().toLocal8Bit();
             const char *c_str = val.data();
@@ -695,7 +745,7 @@ void LogStore::XMLReader::readLogHeader()
                 sscanf(c_str, "%2hhx", &logEntry->logEntry->header.cadence_avg);
                 c_str += 2 * sizeof(char);
             }
-            for (int i=0; i<4 && i<val.length()/2; i++) {
+            for (int i=0; i<2 && i<val.length()/2; i++) {
                 sscanf(c_str, "%2hhx", &logEntry->logEntry->header.unknown3[i]);
                 c_str += 2 * sizeof(char);
             }
@@ -714,10 +764,6 @@ void LogStore::XMLReader::readLogHeader()
                 }
                 logEntry->logEntry->header.cadence_max_time = cadence_max_time;
             }
-            for (int i=0; i<4 && i<val.length()/2; i++) {
-                sscanf(c_str, "%2hhx", &logEntry->logEntry->header.unknown4[i]);
-                c_str += 2 * sizeof(char);
-            }
         }
         else if (xml.name() == "Unknown5") {
             QByteArray val = xml.readElementText().toLocal8Bit();
@@ -993,6 +1039,39 @@ void LogStore::XMLReader::readLogSamples()
                             xml.skipCurrentElement();
                         }
                         break;
+                    case ambit_log_sample_type_swimming_turn:
+                        if (xml.name() == "Distance") {
+                            logEntry->logEntry->samples[sampleCount].u.swimming_turn.distance = xml.readElementText().toInt();
+                        }
+                        else if (xml.name() == "Lengths") {
+                            logEntry->logEntry->samples[sampleCount].u.swimming_turn.lengths = xml.readElementText().toInt();
+                        }
+                        else if (xml.name() == "Classification") {
+                            int itemCount = 0;
+                            while(xml.readNextStartElement()) {
+                                if (xml.name() == "Item" && itemCount < (int)(sizeof(logEntry->logEntry->samples[sampleCount].u.swimming_turn.classification)/sizeof(logEntry->logEntry->samples[sampleCount].u.swimming_turn.classification[0]))) {
+                                    logEntry->logEntry->samples[sampleCount].u.swimming_turn.classification[itemCount++] = xml.readElementText().toInt();
+                                }
+                                else {
+                                    /* Should not get here! */
+                                    xml.skipCurrentElement();
+                                }
+                            }
+                        }
+                        else if (xml.name() == "Style") {
+                            int styleId = xml.attributes().value("id").toString().toUInt();
+                            logEntry->logEntry->samples[sampleCount].u.swimming_turn.style = styleId;
+                            xml.skipCurrentElement();
+                        }
+                        else {
+                            /* Should not get here! */
+                            xml.skipCurrentElement();
+                        }
+                        break;
+                    case ambit_log_sample_type_swimming_stroke:
+                        /* Should not get here! */
+                        xml.skipCurrentElement();
+                        break;
                     case ambit_log_sample_type_activity:
                         if (xml.name() == "ActivityType") {
                             logEntry->logEntry->samples[sampleCount].u.activity.activitytype = xml.readElementText().toUInt();
@@ -1005,6 +1084,17 @@ void LogStore::XMLReader::readLogSamples()
                             xml.skipCurrentElement();
                         }
                         break;
+                    case ambit_log_sample_type_cadence_source:
+                        if (xml.name() == "CadenceSource") {
+                            int cadenceId = xml.attributes().value("id").toString().toUInt();
+                            logEntry->logEntry->samples[sampleCount].u.cadence_source = cadenceId;
+                            xml.skipCurrentElement();
+                        }
+                        else {
+                            /* Should not get here! */
+                            xml.skipCurrentElement();
+                        }
+                        break;
                     case ambit_log_sample_type_position:
                         if (xml.name() == "Latitude") {
                             logEntry->logEntry->samples[sampleCount].u.position.latitude = xml.readElementText().toInt();
@@ -1017,6 +1107,33 @@ void LogStore::XMLReader::readLogSamples()
                             xml.skipCurrentElement();
                         }
                         break;
+                    case ambit_log_sample_type_fwinfo:
+                    {
+                        QRegExp versionRX("([0-9]+)\\.([0-9]+)\\.([0-9]+)");
+
+                        if (xml.name() == "Version") {
+                            if (versionRX.indexIn(xml.readElementText()) >= 0) {
+                                logEntry->logEntry->samples[sampleCount].u.fwinfo.version[0] = versionRX.cap(1).toInt();
+                                logEntry->logEntry->samples[sampleCount].u.fwinfo.version[1] = versionRX.cap(2).toInt();
+                                logEntry->logEntry->samples[sampleCount].u.fwinfo.version[2] = versionRX.cap(3).toInt() & 0xff;
+                                logEntry->logEntry->samples[sampleCount].u.fwinfo.version[3] = (versionRX.cap(3).toInt() >> 8) & 0xff;
+                            }
+                        }
+                        else if (xml.name() == "BuildDate") {
+                            QDateTime datetime = QDateTime::fromString(xml.readElementText(), Qt::ISODate);
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.year = datetime.date().year();
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.month = datetime.date().month();
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.day = datetime.date().day();
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.hour = datetime.time().hour();
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.minute = datetime.time().minute();
+                            logEntry->logEntry->samples[sampleCount].u.fwinfo.build_date.msec = datetime.time().second()*1000 + datetime.time().msec();
+                        }
+                        else {
+                            /* Should not get here! */
+                            xml.skipCurrentElement();
+                        }
+                        break;
+                    }
                     case ambit_log_sample_type_unknown:
                         if (xml.name() == "Data") {
                             QByteArray val = xml.readElementText().toLocal8Bit();
@@ -1027,6 +1144,7 @@ void LogStore::XMLReader::readLogSamples()
                                     sscanf(c_str, "%2hhx", &logEntry->logEntry->samples[sampleCount].u.unknown.data[i]);
                                     c_str += 2 * sizeof(char);
                                 }
+                                logEntry->logEntry->samples[sampleCount].u.unknown.datalen = val.length()/2;
                             }
                         }
                         else {
@@ -1234,7 +1352,7 @@ void LogStore::XMLReader::readPeriodicSample(QList<ambit_log_sample_periodic_val
 }
 
 
-LogStore::XMLWriter::XMLWriter(ambit_device_info_t *deviceInfo, QDateTime time, QString movescountId, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry) :
+LogStore::XMLWriter::XMLWriter(const DeviceInfo& deviceInfo, QDateTime time, QString movescountId, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry) :
     deviceInfo(deviceInfo), time(time), movescountId(movescountId), personalSettings(personalSettings), logEntry(logEntry)
 {
     xml.setAutoFormatting(true);
@@ -1251,7 +1369,7 @@ bool LogStore::XMLWriter::write(QIODevice *device)
     xml.writeStartElement("openambitlog");
     xml.writeAttribute("version", "1.0");
 
-    xml.writeTextElement("SerialNumber", QString("%1").arg(deviceInfo->serial));
+    xml.writeTextElement("SerialNumber", deviceInfo.serial);
     xml.writeTextElement("Time", time.toString(Qt::ISODate));
     xml.writeTextElement("MovescountId", QString("%1").arg(movescountId));
     ret = writeDeviceInfo();
@@ -1268,11 +1386,11 @@ bool LogStore::XMLWriter::write(QIODevice *device)
 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.writeTextElement("Serial", deviceInfo.serial);
+    xml.writeTextElement("Model", deviceInfo.model);
+    xml.writeTextElement("Name", deviceInfo.name);
+    xml.writeTextElement("FWVersion", QString("%1.%2.%3").arg(deviceInfo.fw_version[0]).arg(deviceInfo.fw_version[1]).arg(deviceInfo.fw_version[2]));
+    xml.writeTextElement("HWVersion", QString("%1.%2.%3").arg(deviceInfo.hw_version[0]).arg(deviceInfo.hw_version[1]).arg(deviceInfo.hw_version[2]));
     xml.writeEndElement();
 
     return true;
@@ -1321,12 +1439,15 @@ bool LogStore::XMLWriter::writePersonalSettings()
     xml.writeTextElement("IsMale", QString("%1").arg(personalSettings->is_male));
     xml.writeTextElement("Length", QString("%1").arg(personalSettings->length));
     xml.writeTextElement("AltiBaroMode", QString("%1").arg(personalSettings->alti_baro_mode));
+    xml.writeTextElement("StormAlarm", QString("%1").arg(personalSettings->storm_alarm));
     xml.writeTextElement("FusedAltiDisabled", QString("%1").arg(personalSettings->fused_alti_disabled));
     xml.writeTextElement("BikePODCalibration", QString("%1").arg(personalSettings->bikepod_calibration));
     xml.writeTextElement("BikePODCalibration2", QString("%1").arg(personalSettings->bikepod_calibration2));
     xml.writeTextElement("BikePODCalibration3", QString("%1").arg(personalSettings->bikepod_calibration3));
     xml.writeTextElement("FootPODCalibration", QString("%1").arg(personalSettings->footpod_calibration));
     xml.writeTextElement("AutomaticBikePowerCalibration", QString("%1").arg(personalSettings->automatic_bikepower_calib));
+    xml.writeTextElement("AutomaticFootPODCalibration", QString("%1").arg(personalSettings->automatic_footpod_calib));
+    xml.writeTextElement("TrainingProgram", QString("%1").arg(personalSettings->training_program));
 
     xml.writeEndElement();
 
@@ -1372,7 +1493,7 @@ bool LogStore::XMLWriter::writeLogEntry()
     xml.writeEndElement();
     xml.writeTextElement("PeakTrainingEffect", QString("%1").arg(logEntry->header.peak_training_effect));
     xml.writeTextElement("ActivityType", QString("%1").arg(logEntry->header.activity_type));
-    xml.writeTextElement("Activity", QString::fromLatin1(logEntry->header.activity_name));
+    xml.writeTextElement("Activity", QString::fromUtf8(logEntry->header.activity_name));
     xml.writeStartElement("Temperature");
     xml.writeTextElement("Max", QString("%1").arg(logEntry->header.temperature_max));
     xml.writeTextElement("Min", QString("%1").arg(logEntry->header.temperature_min));
@@ -1386,6 +1507,10 @@ bool LogStore::XMLWriter::writeLogEntry()
     xml.writeTextElement("BatteryChargeAtStart", QString("%1").arg(logEntry->header.battery_start));
     xml.writeTextElement("BatteryCharge", QString("%1").arg(logEntry->header.battery_end));
     xml.writeTextElement("DistanceBeforeCalibrationChange", QString("%1").arg(logEntry->header.distance_before_calib));
+    xml.writeStartElement("Swimming");
+    xml.writeTextElement("PoolLengths", QString("%1").arg(logEntry->header.swimming_pool_lengths));
+    xml.writeTextElement("PoolLength", QString("%1").arg(logEntry->header.swimming_pool_length));
+    xml.writeEndElement();
 
     QString hexstring;
     hexstring = hexstring.sprintf("%02x%02x%02x%02x%02x", logEntry->header.unknown1[0],
@@ -1396,16 +1521,9 @@ bool LogStore::XMLWriter::writeLogEntry()
     xml.writeTextElement("Unknown1", hexstring);
     hexstring = hexstring.sprintf("%02x", logEntry->header.unknown2);
     xml.writeTextElement("Unknown2", hexstring);
-    hexstring = hexstring.sprintf("%02x%02x%02x%02x", logEntry->header.unknown3[0],
-                                                      logEntry->header.unknown3[1],
-                                                      logEntry->header.unknown3[2],
-                                                      logEntry->header.unknown3[3]);
+    hexstring = hexstring.sprintf("%02x%02x", logEntry->header.unknown3[0],
+                                              logEntry->header.unknown3[1]);
     xml.writeTextElement("Unknown3", hexstring);
-    hexstring = hexstring.sprintf("%02x%02x%02x%02x", logEntry->header.unknown4[0],
-                                                      logEntry->header.unknown4[1],
-                                                      logEntry->header.unknown4[2],
-                                                      logEntry->header.unknown4[3]);
-    xml.writeTextElement("Unknown4", hexstring);
     hexstring = hexstring.sprintf("%02x%02x%02x%02x", logEntry->header.unknown5[0],
                                                       logEntry->header.unknown5[1],
                                                       logEntry->header.unknown5[2],
@@ -1455,6 +1573,8 @@ bool LogStore::XMLWriter::writeLogSample(ambit_log_sample_t *sample)
     sample_distance_source_name_t *distance_source_name;
     sample_altitude_source_name_t *altitude_source_name;
     sample_lap_event_type_t *lap_type_name;
+    sample_cadence_source_name_t *cadence_source_name;
+    sample_swimming_style_name_t *swimming_style_name;
     int i;
 
     xml.writeStartElement("Sample");
@@ -1583,14 +1703,60 @@ bool LogStore::XMLWriter::writeLogSample(ambit_log_sample_t *sample)
         xml.writeTextElement("TimeRef", timeref.toString(Qt::ISODate));
         break;
     }
+    case ambit_log_sample_type_swimming_turn:
+    {
+        xml.writeTextElement("Distance", QString("%1").arg(sample->u.swimming_turn.distance));
+        xml.writeTextElement("Lengths", QString("%1").arg(sample->u.swimming_turn.lengths));
+        xml.writeStartElement("Classification");
+        for (size_t i=0; i<(sizeof(sample->u.swimming_turn.classification)/sizeof(sample->u.swimming_turn.classification[0])); i++) {
+            xml.writeTextElement("Item", QString("%1").arg(sample->u.swimming_turn.classification[i]));
+        }
+        xml.writeEndElement();
+        xml.writeStartElement("Style");
+        xml.writeAttribute("id", QString("%1").arg(sample->u.swimming_turn.style));
+        for (swimming_style_name = &sampleSwimmingStyleNames[0]; swimming_style_name->XMLName != ""; swimming_style_name++) {
+            if (swimming_style_name->source_id == sample->u.swimming_turn.style) {
+                xml.writeCharacters(QString(swimming_style_name->XMLName));
+                break;
+            }
+        }
+        xml.writeEndElement();
+        break;
+    }
+    case ambit_log_sample_type_swimming_stroke:
+        break;
     case ambit_log_sample_type_activity:
+    {
         xml.writeTextElement("ActivityType", QString("%1").arg(sample->u.activity.activitytype));
         xml.writeTextElement("CustomModeId", QString("%1").arg(sample->u.activity.custommode));
         break;
+    }
+    case ambit_log_sample_type_cadence_source:
+    {
+        xml.writeStartElement("CadenceSource");
+        xml.writeAttribute("id", QString("%1").arg(sample->u.cadence_source));
+        for (cadence_source_name = &sampleCadenceSourceNames[0]; cadence_source_name->XMLName != ""; cadence_source_name++) {
+            if (cadence_source_name->source_id == sample->u.cadence_source) {
+                xml.writeCharacters(QString(cadence_source_name->XMLName));
+                break;
+            }
+        }
+        xml.writeEndElement();
+        break;
+    }
     case ambit_log_sample_type_position:
+    {
         xml.writeTextElement("Latitude", QString("%1").arg(sample->u.position.latitude));
         xml.writeTextElement("Longitude", QString("%1").arg(sample->u.position.longitude));
         break;
+    }
+    case ambit_log_sample_type_fwinfo:
+    {
+        xml.writeTextElement("Version", QString("%1.%2.%3").arg((int)sample->u.fwinfo.version[0]).arg((int)sample->u.fwinfo.version[1]).arg((int)sample->u.fwinfo.version[2] | ((int)sample->u.fwinfo.version[3] << 8)));
+        QDateTime dateTime(QDate(sample->u.fwinfo.build_date.year, sample->u.fwinfo.build_date.month, sample->u.fwinfo.build_date.day), QTime(sample->u.fwinfo.build_date.hour, sample->u.fwinfo.build_date.minute, 0).addMSecs(sample->u.fwinfo.build_date.msec));
+        xml.writeTextElement("BuildDate", dateTime.toString(Qt::ISODate));
+        break;
+    }
     case ambit_log_sample_type_unknown:
     {
         QString data = "";
diff --git a/src/openambit/logstore.h b/src/movescount/logstore.h
similarity index 85%
rename from src/openambit/logstore.h
rename to src/movescount/logstore.h
index 1ada21f..e9a0934 100644
--- a/src/openambit/logstore.h
+++ b/src/movescount/logstore.h
@@ -30,6 +30,7 @@
 #include <QXmlStreamWriter>
 #include <libambit.h>
 
+#include "deviceinfo.h"
 #include "logentry.h"
 
 class LogStore : public QObject
@@ -45,7 +46,7 @@ public:
     };
 
     explicit LogStore(QObject *parent = 0);
-    LogEntry *store(ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
+    LogEntry *store(const DeviceInfo& deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
     LogEntry *store(LogEntry *entry);
     void storeMovescountId(QString device, QDateTime time, QString movescountId);
     bool logExists(QString device, ambit_log_header_t *logHeader);
@@ -59,7 +60,7 @@ public slots:
 
 private:
     QString logEntryPath(QString device, QDateTime time);
-    LogEntry *storeInternal(QString serial, QDateTime dateTime, ambit_device_info_t *deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry, QString movescountId = "");
+    LogEntry *storeInternal(QString serial, QDateTime dateTime, const DeviceInfo& deviceInfo, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry, QString movescountId = "");
     LogEntry *readInternal(QString path);
 
     QString storagePath;
@@ -89,7 +90,7 @@ private:
     class XMLWriter
     {
     public:
-        XMLWriter(ambit_device_info_t *deviceInfo, QDateTime time, QString movescountId, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
+        XMLWriter(const DeviceInfo& deviceInfo, QDateTime time, QString movescountId, ambit_personal_settings_t *personalSettings, ambit_log_entry_t *logEntry);
         bool write(QIODevice *device);
 
     private:
@@ -99,7 +100,7 @@ private:
         bool writeLogSample(ambit_log_sample_t *sample);
         bool writePeriodicSample(ambit_log_sample_t *sample);
 
-        ambit_device_info_t *deviceInfo;
+        DeviceInfo deviceInfo;
         QDateTime time;
         QString movescountId;
         QXmlStreamWriter xml;
diff --git a/src/openambit/movescount/movescount.cpp b/src/movescount/movescount.cpp
similarity index 92%
rename from src/openambit/movescount/movescount.cpp
rename to src/movescount/movescount.cpp
index 94d3016..9b24537 100644
--- a/src/openambit/movescount/movescount.cpp
+++ b/src/movescount/movescount.cpp
@@ -102,9 +102,9 @@ QString MovesCount::generateUserkey()
     return retString;
 }
 
-void MovesCount::setDevice(ambit_device_info_t *device_info)
+void MovesCount::setDevice(const DeviceInfo& device_info)
 {
-    memcpy(&this->device_info, device_info, sizeof(ambit_device_info_t));
+    this->device_info = device_info;
 }
 
 bool MovesCount::isAuthorized()
@@ -209,7 +209,7 @@ void MovesCount::authCheckFinished()
 
 void MovesCount::firmwareReplyFinished()
 {
-    u_int8_t fw_version[4];
+    u_int8_t fw_version[3];
 
     if (firmwareCheckReply != NULL) {
         if (firmwareCheckReply->error() == QNetworkReply::NoError) {
@@ -217,8 +217,8 @@ void MovesCount::firmwareReplyFinished()
             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));
+                     (fw_version[1] == device_info.fw_version[1] && (fw_version[2] > device_info.fw_version[2]))))) {
+                    emit newerFirmwareExists(QByteArray((const char*)fw_version, 3));
                 }
             }
         }
@@ -274,7 +274,7 @@ void MovesCount::getDeviceSettingsInThread()
 {
     QNetworkReply *reply;
 
-    reply = syncGET("/userdevices/" + QString("%1").arg(device_info.serial), "", true);
+    reply = syncGET("/userdevices/" + device_info.serial, "", true);
 
     if (checkReplyAuthorization(reply)) {
         QByteArray _data = reply->readAll();
@@ -315,7 +315,7 @@ void MovesCount::checkLatestFirmwareVersionInThread()
                                       .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);
+                                      .arg(device_info.hw_version[2]), "", false);
         connect(firmwareCheckReply, SIGNAL(finished()), this, SLOT(firmwareReplyFinished()));
     }
 }
@@ -333,6 +333,11 @@ void MovesCount::writeLogInThread(LogEntry *logEntry)
 
     jsonParser.generateLogData(logEntry, output);
 
+#ifdef QT_DEBUG
+    // Write json data to storage
+    writeJsonToStorage("log-" + logEntry->device + "-" + logEntry->time.toString("yyyy-MM-ddThh_mm_ss") + ".json", output);
+#endif
+
     reply = syncPOST("/moves/", "", output, true);
 
     if (reply->error() == QNetworkReply::NoError) {
@@ -440,3 +445,17 @@ QNetworkReply *MovesCount::syncPOST(QString path, QString additionalHeaders, QBy
 
     return reply;
 }
+
+#ifdef QT_DEBUG
+#include <QDir>
+void MovesCount::writeJsonToStorage(QString filename, QByteArray &data)
+{
+    QString storagePath = QString(getenv("HOME")) + "/.openambit/movescount";
+    if (QDir().mkpath(storagePath)) {
+        QFile logfile(storagePath + "/" + filename);
+        logfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
+        logfile.write(data);
+        logfile.close();
+    }
+}
+#endif
diff --git a/src/openambit/movescount/movescount.h b/src/movescount/movescount.h
similarity index 94%
rename from src/openambit/movescount/movescount.h
rename to src/movescount/movescount.h
index 456a2a3..f599d64 100644
--- a/src/openambit/movescount/movescount.h
+++ b/src/movescount/movescount.h
@@ -31,6 +31,7 @@
 
 #include <libambit.h>
 
+#include "deviceinfo.h"
 #include "logentry.h"
 #include "logstore.h"
 #include "movescountjson.h"
@@ -49,7 +50,7 @@ public:
     void setUsername(QString username);
     void setUserkey(QString userkey);
     QString generateUserkey();
-    void setDevice(ambit_device_info_t *device_info);
+    void setDevice(const DeviceInfo& device_info);
 
     bool isAuthorized();
     int getOrbitalData(u_int8_t **data);
@@ -95,6 +96,10 @@ private:
     QNetworkReply *asyncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth);
     QNetworkReply *syncPOST(QString path, QString additionalHeaders, QByteArray &postData, bool auth);
 
+#ifdef QT_DEBUG
+    void writeJsonToStorage(QString filename, QByteArray &data);
+#endif
+
     bool exiting;
     bool authorized;
 
@@ -104,7 +109,7 @@ private:
     QString userkey;
     QString model;
     QString serial;
-    ambit_device_info_t device_info;
+    DeviceInfo device_info;
 
     QNetworkAccessManager *manager;
     QNetworkReply *firmwareCheckReply;
diff --git a/src/openambit/movescount/movescountjson.cpp b/src/movescount/movescountjson.cpp
similarity index 73%
rename from src/openambit/movescount/movescountjson.cpp
rename to src/movescount/movescountjson.cpp
index 92f4c72..9656d5b 100644
--- a/src/openambit/movescount/movescountjson.cpp
+++ b/src/movescount/movescountjson.cpp
@@ -34,7 +34,7 @@ MovesCountJSON::MovesCountJSON(QObject *parent) :
 {
 }
 
-int MovesCountJSON::parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[4])
+int MovesCountJSON::parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[3])
 {
     QJson::Parser parser;
     bool ok;
@@ -50,8 +50,7 @@ int MovesCountJSON::parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_ver
         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;
+            fw_version[2] = rx.cap(3).toInt();
             return 0;
         }
     }
@@ -103,10 +102,24 @@ int MovesCountJSON::parseLogDirReply(QByteArray &input, QList<MovesCountLogDirEn
     return -1;
 }
 
+/**
+ * @brief MovesCountJSON::generateLogData
+ * @param logEntry
+ * @param output
+ * @return
+ * @note Fucked up facts about movescount:
+ *  - The periodic samples timestamps are truncated to 10th of milliseconds by movescount
+ *  - That would be fine, if it wasn't for the swimming logs where the periodic entries
+ *    are matched to the time of entries in the marksContent list (which has ms precision).
+ *  - Some of the entries that should match in marksContent are virtual created entries,
+ *    generated here. This can lead to time collisions.
+ *  - To compensate for the collisions, samples might need to be shifted in time,
+ *    hence the fuzz with dateTimeCompensate
+ */
 int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
 {
     QJson::Serializer serializer;
-    bool ok;
+    bool ok, inPause = false;
     QVariantMap content;
     QVariantList IBIContent;
     QVariantList marksContent;
@@ -114,6 +127,8 @@ int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
     QVariantList GPSSamplesContent;
     QByteArray uncompressedData, compressedData;
     ambit_log_sample_t *sample;
+    QDateTime prevMarksDateTime;
+    QDateTime prevPeriodicSamplesDateTime;
 
     QDateTime localBaseTime(QDate(logEntry->logEntry->header.date_time.year,
                                   logEntry->logEntry->header.date_time.month,
@@ -123,14 +138,15 @@ int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
 
     // Loop through content
     QList<int> order = rearrangeSamples(logEntry);
-    foreach(int index, order) {
-        sample = &logEntry->logEntry->samples[index];
+    for (int i=0; i<order.length(); i++) {
+        sample = &logEntry->logEntry->samples[order[i]];
 
         switch(sample->type) {
         case ambit_log_sample_type_periodic:
         {
             QVariantMap tmpMap;
-            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            prevPeriodicSamplesDateTime = dateTimeRound(dateTimeCompensate(dateTimeRound(localBaseTime.addMSecs(sample->time), 10), prevPeriodicSamplesDateTime, 0), 10);
+            tmpMap.insert("LocalTime", dateTimeString(prevPeriodicSamplesDateTime));
             writePeriodicSample(sample, tmpMap);
             periodicSamplesContent.append(tmpMap);
             break;
@@ -178,7 +194,13 @@ int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
             case 0x00: /* autolap = 5 */
             {
                 QVariantMap tmpMap;
-                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                if (sample->time > 0) {
+                    prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+                }
+                else {
+                    prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+                }
+                tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
                 tmpMap.insert("Type", 5);
                 marksContent.append(tmpMap);
                 break;
@@ -186,45 +208,162 @@ int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
             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);
+                // Try to remove strange manual lap events at end after pause/stop
+                // A lap during a pause doesn't make sense anyway?
+                if (!inPause) {
+                    QVariantMap tmpMap;
+                    if (sample->time > 0) {
+                        prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+                    }
+                    else {
+                        prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+                    }
+                    tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
+                    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) {
+                    prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+                    tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
                     tmpMap.insert("Type", 1);
                 }
+                else {
+                    prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+                    tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
+                }
                 marksContent.append(tmpMap);
+
+                inPause = false;
                 break;
             }
             case 0x1e: /* pause = 2 */
             {
                 QVariantMap tmpMap;
-                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                if (sample->time > 0) {
+                    prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+                }
+                else {
+                    prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+                }
+                tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
                 tmpMap.insert("Type", 2);
                 marksContent.append(tmpMap);
+
+                inPause = true;
                 break;
             }
             case 0x14: /* high interval = 3 */
             case 0x15: /* low interval = 3 */
             {
                 QVariantMap tmpMap;
-                tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+                if (sample->time > 0) {
+                    prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+                }
+                else {
+                    prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+                }
+                tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
                 tmpMap.insert("Type", 3);
                 marksContent.append(tmpMap);
                 break;
             }
             };
             break;
+        case ambit_log_sample_type_swimming_turn:
+        {
+            int nextIndex;
+            ambit_log_sample_t *next_swimming_turn = NULL;
+            uint8_t style = 0;
+            QDateTime sampleDateTime;
+            if (sample->time > 0) {
+                sampleDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+            }
+            else {
+                sampleDateTime = localBaseTime.addMSecs(sample->time);
+            }
+
+            // Find next swimming turn, to check what marks to generate
+            for (nextIndex=i+1; nextIndex<order.length(); nextIndex++) {
+                next_swimming_turn = &logEntry->logEntry->samples[order[nextIndex]];
+                if (next_swimming_turn->type == ambit_log_sample_type_swimming_turn) {
+                    break;
+                }
+            }
+            if (nextIndex == order.length()) {
+                next_swimming_turn = NULL;
+            }
+            if (next_swimming_turn == NULL || sample->u.swimming_turn.style != next_swimming_turn->u.swimming_turn.style) {
+                QVariantMap tmpMap;
+                QVariantList calibration;
+                tmpMap.insert("LocalTime", dateTimeString(sampleDateTime));
+                tmpMap.insert("Type", 7);
+                tmpMap.insert("SwimmingStyle", sample->u.swimming_turn.style);
+                for (size_t k=0; k<sizeof(sample->u.swimming_turn.classification)/sizeof(sample->u.swimming_turn.classification[0]); k++) {
+                    calibration.append(sample->u.swimming_turn.classification[k]);
+                }
+                tmpMap.insert("SwimmingStyleCalibration", calibration);
+                marksContent.append(tmpMap);
+
+                if (next_swimming_turn != NULL) {
+                    style = next_swimming_turn->u.swimming_turn.style;
+                }
+                else {
+                    style = 0;
+                }
+
+                // Add some time to timestamp
+                sampleDateTime = sampleDateTime.addMSecs(5);
+            }
+            else {
+                style = sample->u.swimming_turn.style;
+            }
+
+            sampleDateTime = dateTimeRound(dateTimeCompensate(dateTimeCompensate(dateTimeRound(sampleDateTime, 10), prevMarksDateTime, 0), prevPeriodicSamplesDateTime, 0), 10);
+
+            QVariantMap tmpMap, attribMap;
+            QVariantList attributes;
+            tmpMap.insert("LocalTime", dateTimeString(sampleDateTime));
+            tmpMap.insert("Type", 5);
+            tmpMap.insert("SwimmingStyle", style);
+            attribMap.insert("Name", "type");
+            attribMap.insert("Value", "swimmingturn");
+            attributes.append(attribMap);
+            tmpMap.insert("Attributes", attributes);
+            marksContent.append(tmpMap);
+
+            QVariantMap periodicMap;
+            periodicMap.insert("Distance", sample->u.swimming_turn.distance / 100);
+            periodicMap.insert("LocalTime", dateTimeString(sampleDateTime));
+            periodicSamplesContent.append(periodicMap);
+
+            prevPeriodicSamplesDateTime = prevMarksDateTime = sampleDateTime;
+
+            break;
+        }
+        case ambit_log_sample_type_swimming_stroke:
+        {
+            QVariantMap tmpMap;
+            prevPeriodicSamplesDateTime = dateTimeRound(dateTimeCompensate(dateTimeRound(localBaseTime.addMSecs(sample->time), 10), prevPeriodicSamplesDateTime, 0), 10);
+            tmpMap.insert("LocalTime", dateTimeString(prevPeriodicSamplesDateTime));
+            tmpMap.insert("SwimmingStrokeType", 0);
+            periodicSamplesContent.append(tmpMap);
+            break;
+        }
         case ambit_log_sample_type_activity:
         {
             QVariantMap tmpMap;
-            tmpMap.insert("LocalTime", dateTimeString(localBaseTime.addMSecs(sample->time)));
+            if (sample->time > 0) {
+                prevMarksDateTime = dateTimeCompensate(localBaseTime.addMSecs(sample->time), prevMarksDateTime, 1);
+            }
+            else {
+                prevMarksDateTime = localBaseTime.addMSecs(sample->time);
+            }
+            tmpMap.insert("LocalTime", dateTimeString(prevMarksDateTime));
             tmpMap.insert("NextActivityID", sample->u.activity.activitytype);
             tmpMap.insert("Type", 8);
             marksContent.append(tmpMap);
@@ -246,8 +385,8 @@ int MovesCountJSON::generateLogData(LogEntry *logEntry, QByteArray &output)
     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("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);
@@ -434,7 +573,9 @@ bool MovesCountJSON::writePeriodicSample(ambit_log_sample_t *sample, QVariantMap
             }
             break;
         case ambit_log_sample_periodic_type_sealevelpressure:
-            output.insert("SeaLevelPressure", (int)round((double)value->u.sealevelpressure/10.0));
+            if (value->u.sealevelpressure >= 8500 && value->u.sealevelpressure <= 11000) {
+                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);
@@ -595,3 +736,21 @@ QString MovesCountJSON::dateTimeString(QDateTime dateTime)
         return dateTime.toString("yyyy-MM-ddThh:mm:ss");
     }
 }
+
+QDateTime MovesCountJSON::dateTimeRound(QDateTime dateTime, int msecRoundFactor)
+{
+    if (msecRoundFactor != 1) {
+        return dateTime.addMSecs(qRound(1.0*dateTime.time().msec()/msecRoundFactor)*msecRoundFactor - dateTime.time().msec());
+    }
+    else {
+        return dateTime;
+    }
+}
+
+QDateTime MovesCountJSON::dateTimeCompensate(QDateTime dateTime, QDateTime prevDateTime, int minOffset)
+{
+    if (dateTime <= prevDateTime) {
+        return prevDateTime.addMSecs(minOffset);
+    }
+    return dateTime;
+}
diff --git a/src/openambit/movescount/movescountjson.h b/src/movescount/movescountjson.h
similarity index 90%
rename from src/openambit/movescount/movescountjson.h
rename to src/movescount/movescountjson.h
index caf7de2..f16405a 100644
--- a/src/openambit/movescount/movescountjson.h
+++ b/src/movescount/movescountjson.h
@@ -36,7 +36,7 @@ class MovesCountJSON : public QObject
 public:
     explicit MovesCountJSON(QObject *parent = 0);
 
-    int parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[4]);
+    int parseFirmwareVersionReply(QByteArray &input, u_int8_t fw_version[3]);
     int parseLogReply(QByteArray &input, QString &moveId);
     int parseLogDirReply(QByteArray &input, QList<MovesCountLogDirEntry> &entries);
 
@@ -52,6 +52,8 @@ private:
     int compressData(QByteArray &content, QByteArray &output);
     QList<int> rearrangeSamples(LogEntry *logEntry);
     QString dateTimeString(QDateTime dateTime);
+    QDateTime dateTimeRound(QDateTime dateTime, int msecRoundFactor);
+    QDateTime dateTimeCompensate(QDateTime dateTime, QDateTime prevDateTime, int minOffset);
 };
 
 #endif // MOVESCOUNTJSON_H
diff --git a/src/openambit/movescount/movescountlogchecker.cpp b/src/movescount/movescountlogchecker.cpp
similarity index 100%
rename from src/openambit/movescount/movescountlogchecker.cpp
rename to src/movescount/movescountlogchecker.cpp
diff --git a/src/openambit/movescount/movescountlogchecker.h b/src/movescount/movescountlogchecker.h
similarity index 100%
rename from src/openambit/movescount/movescountlogchecker.h
rename to src/movescount/movescountlogchecker.h
diff --git a/src/openambit/movescount/movescountlogdirentry.cpp b/src/movescount/movescountlogdirentry.cpp
similarity index 100%
rename from src/openambit/movescount/movescountlogdirentry.cpp
rename to src/movescount/movescountlogdirentry.cpp
diff --git a/src/openambit/movescount/movescountlogdirentry.h b/src/movescount/movescountlogdirentry.h
similarity index 100%
rename from src/openambit/movescount/movescountlogdirentry.h
rename to src/movescount/movescountlogdirentry.h
diff --git a/src/openambit/movescount/movescountxml.cpp b/src/movescount/movescountxml.cpp
similarity index 99%
rename from src/openambit/movescount/movescountxml.cpp
rename to src/movescount/movescountxml.cpp
index 6d1ea33..0b72408 100644
--- a/src/openambit/movescount/movescountxml.cpp
+++ b/src/movescount/movescountxml.cpp
@@ -241,7 +241,7 @@ bool MovesCountXML::XMLWriter::writeLogEntry()
         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::fromLatin1(logEntry->logEntry->header.activity_name));
+    xml.writeTextElement("Activity", QString::fromUtf8(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));
diff --git a/src/openambit/movescount/movescountxml.h b/src/movescount/movescountxml.h
similarity index 100%
rename from src/openambit/movescount/movescountxml.h
rename to src/movescount/movescountxml.h
diff --git a/src/openambit/CMakeLists.txt b/src/openambit/CMakeLists.txt
index 79450ba..1e654aa 100644
--- a/src/openambit/CMakeLists.txt
+++ b/src/openambit/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8.5)
-project (OPENAMBIT)
+project (OPENAMBIT CXX)
 
-set (OPENAMBIT_VERSION 0.3)
+set (OPENAMBIT_VERSION HEAD)
 
 # Where to lookup modules
 set(CMAKE_MODULE_PATH "${OPENAMBIT_SOURCE_DIR}/cmake")
@@ -10,46 +10,43 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
 
 find_package(Qt4 REQUIRED)
 find_package(libambit REQUIRED)
+find_package(Movescount REQUIRED)
 find_package(UDev REQUIRED)
-find_package(ZLIB REQUIRED)
-find_package(QJSON 0.8.0 REQUIRED)
 
 include(${QT_USE_FILE})
 include(GNUInstallDirs)
 
 include_directories (
-  ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
   ${QT_QTCORE_INCLUDE_DIR}
   ${QT_QTGUI_INCLUDE_DIR}
   ${QT_QTNETWORK_INCLUDE_DIR}
   ${LIBAMBIT_INCLUDE_DIR}
+  ..
 )
 
 link_directories(
   ${LIBAMBIT_LIBS_DIR}
-)
-
-set ( openambit_HDRS
-  logentry.h
+  ${MOVESCOUNT_LIBS_DIR}
 )
 
 set ( openambit_SRCS
+  confirmbetadialog.cpp
+  devicemanager.cpp
+  logview.cpp
   main.cpp
   mainwindow.cpp
-  devicemanager.cpp
-  settingsdialog.cpp
   settings.cpp
-  logstore.cpp
-  logentry.cpp
-  udevlistener.cpp
-  confirmbetadialog.cpp
+  settingsdialog.cpp
+  signalhandler.cpp
   single_application.cpp
+  udevlistener.cpp
 )
 
 set ( openambit_UIS
+  confirmbetadialog.ui
   mainwindow.ui
   settingsdialog.ui
-  confirmbetadialog.ui
 )
 
 set ( openambit_RSCS
@@ -57,24 +54,45 @@ set ( openambit_RSCS
 )
 
 set ( openambit_MOCS
-  mainwindow.h
+  confirmbetadialog.h
   devicemanager.h
-  settingsdialog.h
+  logview.h
+  mainwindow.h
   settings.h
-  logstore.h
-  udevlistener.h
-  confirmbetadialog.h
+  settingsdialog.h
+  signalhandler.h
   single_application.h
+  udevlistener.h
 )
 
+set (FILES_TO_TRANSLATE ${openambit_SRCS} ${openambit_UIS} ${openambit_MOCS})
+
 set ( APP_ICON ${PROJECT_SOURCE_DIR}/icons/icon_disconnected.png )
 
-set ( CMAKE_INSTALL_UDEVRULESDIR /lib/udev/rules.d
-      CACHE PATH "Where to install udev rules"
-)
-mark_as_advanced ( CMAKE_INSTALL_UDEVRULESDIR )
+######### Translations
+file (GLOB TRANSLATIONS_FILES translations/*.ts)
+
+option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts")
+if (UPDATE_TRANSLATIONS)
+  qt4_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES})
+else (UPDATE_TRANSLATIONS)
+  qt4_add_translation(QM_FILES ${TRANSLATIONS_FILES})
+endif (UPDATE_TRANSLATIONS)
+
+# Create translations QRC file - ts.qrc
+set(TRANSLATIONS_QRC "${CMAKE_CURRENT_BINARY_DIR}/ts.qrc")
+file(WRITE ${TRANSLATIONS_QRC} "<RCC>\n\t<qresource prefix=\"/translations\">")
+foreach(QM_FILE ${QM_FILES})
+    get_filename_component(QM_FILE_NAME ${QM_FILE} NAME)
+    file(APPEND ${TRANSLATIONS_QRC} "\n\t\t<file alias=\"${QM_FILE_NAME}\">${QM_FILE_NAME}</file>")
+endforeach()
+file(APPEND ${TRANSLATIONS_QRC} "\n\t</qresource>\n</RCC>")
+list(APPEND openambit_RSCS ${TRANSLATIONS_QRC})
 
-add_subdirectory("${PROJECT_SOURCE_DIR}/movescount")
+# prevent the generated files from being deleted during make clean
+set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM true)
+
+######### Translations
 
 QT4_WRAP_UI(UIS ${openambit_UIS})
 QT4_ADD_RESOURCES(RSCS ${openambit_RSCS})
@@ -82,17 +100,14 @@ QT4_WRAP_CPP(MOCS ${openambit_MOCS})
 
 add_definitions( -DAPP_VERSION="${OPENAMBIT_VERSION}" )
 
-add_executable ( openambit ${openambit_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS} )
+add_executable ( openambit ${openambit_SRCS} ${UIS} ${RSCS} ${MOCS} )
 
-target_link_libraries ( openambit  ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${LIBAMBIT_LIBS} ${UDEV_LIBS} ${ZLIB_LIBRARY} ${QJSON_LIBRARIES} )
+target_link_libraries ( openambit  ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${LIBAMBIT_LIBS} ${MOVESCOUNT_LIBS} ${UDEV_LIBS} )
 
 install ( TARGETS openambit DESTINATION ${CMAKE_INSTALL_BINDIR} )
-install ( FILES ${OPENAMBIT_SOURCE_DIR}/deployment/99-suunto-ambit.rules
-          DESTINATION ${CMAKE_INSTALL_UDEVRULESDIR}
-          COMPONENT system
-)
 install ( FILES ${OPENAMBIT_SOURCE_DIR}/deployment/openambit.desktop
           DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications )
 install ( FILES ${APP_ICON}
           DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps
           RENAME openambit.png )
+
diff --git a/src/openambit/cmake/FindMovescount.cmake b/src/openambit/cmake/FindMovescount.cmake
new file mode 100644
index 0000000..9582ddb
--- /dev/null
+++ b/src/openambit/cmake/FindMovescount.cmake
@@ -0,0 +1,29 @@
+# - Find Movescount
+# If found, this will define
+#
+# MOVESCOUNT_FOUND - system has the movescount library
+# MOVESCOUNT_INCLUDE_DIR - the movescount include directory
+# MOVESCOUNT_LIBS - the movescount libraries
+
+find_path(MOVESCOUNT_INCLUDE_DIR NAMES movescount.h
+  PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../movescount NO_DEFAULT_PATH
+)
+find_path(MOVESCOUNT_INCLUDE_DIR NAMES movescount.h)
+
+find_library(MOVESCOUNT_LIBS NAMES movescount
+  PATHS ${CMAKE_CURRENT_BINARY_DIR}/../movescount-build NO_DEFAULT_PATH
+)
+find_library(MOVESCOUNT_LIBS NAMES movescount)
+
+if(MOVESCOUNT_INCLUDE_DIR AND MOVESCOUNT_LIBS)
+  set(MOVESCOUNT_FOUND TRUE CACHE INTERNAL "Movescount found")
+  message(STATUS "Found Movescount: ${MOVESCOUNT_INCLUDE_DIR}, ${MOVESCOUNT_LIBS}")
+else(MOVESCOUNT_INCLUDE_DIR AND LIBMOVESCOUNT_LIBS)
+  set(MOVESCOUNT_FOUND FALSE CACHE INTERNAL "Movescount found")
+  set(MOVESCOUNT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../)
+  set(MOVESCOUNT_LIBS ${CMAKE_CURRENT_BINARY_DIR}/../movescount/libmovescount.so.0)
+  message(STATUS
+    "Movescount not found, building from source in ${MOVESCOUNT_INCLUDE_DIR}")
+endif(MOVESCOUNT_INCLUDE_DIR AND MOVESCOUNT_LIBS)
+
+mark_as_advanced(MOVESCOUNT_INCLUDE_DIR MOVESCOUNT_LIBS)
diff --git a/src/openambit/cmake/Findlibambit.cmake b/src/openambit/cmake/Findlibambit.cmake
index 3e19b15..b0c2ceb 100644
--- a/src/openambit/cmake/Findlibambit.cmake
+++ b/src/openambit/cmake/Findlibambit.cmake
@@ -6,26 +6,24 @@
 # LIBAMBIT_LIBS - the libambit libraries
 
 find_path(LIBAMBIT_INCLUDE_DIR NAMES libambit.h
-  PATHS
-  ../libambit
-)
-
-find_library(LIBAMBIT_LIBS_PATH NAMES libambit.so
-  PATHS
-  ../../libambit-build
+  PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../libambit NO_DEFAULT_PATH
 )
+find_path(LIBAMBIT_INCLUDE_DIR NAMES libambit.h)
 
 find_library(LIBAMBIT_LIBS NAMES ambit
-  PATHS
-  ../../libambit-build
+  PATHS ${CMAKE_CURRENT_BINARY_DIR}/../libambit-build NO_DEFAULT_PATH
 )
+find_library(LIBAMBIT_LIBS NAMES ambit)
 
 if(LIBAMBIT_INCLUDE_DIR AND LIBAMBIT_LIBS)
   set(LIBAMBIT_FOUND TRUE CACHE INTERNAL "libambit found")
   message(STATUS "Found libambit: ${LIBAMBIT_INCLUDE_DIR}, ${LIBAMBIT_LIBS}")
 else(LIBAMBIT_INCLUDE_DIR AND LIBAMBIT_LIBS)
   set(LIBAMBIT_FOUND FALSE CACHE INTERNAL "libambit found")
-  message(STATUS "libambit not found.")
+  set(LIBAMBIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libambit/)
+  set(LIBAMBIT_LIBS ${CMAKE_CURRENT_BINARY_DIR}/../libambit/libambit.so.0)
+  message(STATUS
+    "libambit not found, building from source in ${LIBAMBIT_INCLUDE_DIR}")
 endif(LIBAMBIT_INCLUDE_DIR AND LIBAMBIT_LIBS)
 
 mark_as_advanced(LIBAMBIT_INCLUDE_DIR LIBAMBIT_LIBS)
diff --git a/src/openambit/debian/changelog b/src/openambit/debian/changelog
deleted file mode 100644
index 49b3547..0000000
--- a/src/openambit/debian/changelog
+++ /dev/null
@@ -1,11 +0,0 @@
-openambit (0.3-1) trusty; urgency=medium
-
-  * New upstream release
-
- -- Emil Ljungdahl <emil at openambit.org>  Mon, 15 Sep 2014 23:10:37 +0200
-
-openambit (0.2-1) saucy; urgency=low
-
-  * Initial release
-
- -- Emil Ljungdahl <emil at openambit.org>  Thu, 30 Jan 2014 16:21:42 +0100
diff --git a/src/openambit/debian/compat b/src/openambit/debian/compat
deleted file mode 100644
index 45a4fb7..0000000
--- a/src/openambit/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-8
diff --git a/src/openambit/debian/control b/src/openambit/debian/control
deleted file mode 100644
index 0994f7b..0000000
--- a/src/openambit/debian/control
+++ /dev/null
@@ -1,17 +0,0 @@
-Source: openambit
-Priority: extra
-Maintainer: Emil Ljungdahl <emil at openambit.org>
-Build-Depends: debhelper (>= 9), cmake (>= 2.8.5), libudev-dev, libqjson-dev, zlib1g-dev,
- libambit-dev (= 0.3-1), libqt4-dev
-Standards-Version: 3.9.4
-Section: utils
-Homepage: http://openambit.org/
-#Vcs-Git: git://git.debian.org/collab-maint/openambit.git
-#Vcs-Browser: http://git.debian.org/?p=collab-maint/openambit.git;a=summary
-
-Package: openambit
-Architecture: any
-Depends: libqt4-core, libqt4-gui, libqt4-network, ${shlibs:Depends}, ${misc:Depends}
-Description: Synchronize your Suunto Ambit series device
- Openambit is GUI application for synchronizing the Suunto Ambit series
- of devices with your PC and Suuntos cloudservice movescount.com
diff --git a/src/openambit/debian/copyright b/src/openambit/debian/copyright
deleted file mode 100644
index 5021eac..0000000
--- a/src/openambit/debian/copyright
+++ /dev/null
@@ -1,39 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: openambit
-Source: http://openambit.org/
-
-Files: *
-Copyright: 2014 Emil Ljungdahl <emil at openambit.org>
-License: GPL-3
- libambit 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/>.
-
-Files: debian/*
-Copyright: 2014 Emil Ljungdahl <emil at openambit.org>
-License: GPL-2+
- This package 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 2 of the License, or
- (at your option) any later version.
- .
- This package 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/>
- .
- On Debian systems, the complete text of the GNU General
- Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
-
diff --git a/src/openambit/debian/docs b/src/openambit/debian/docs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/openambit/debian/rules b/src/openambit/debian/rules
deleted file mode 100755
index b760bee..0000000
--- a/src/openambit/debian/rules
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-# Sample debian/rules that uses debhelper.
-# This file was originally written by Joey Hess and Craig Small.
-# As a special exception, when this file is copied by dh-make into a
-# dh-make output file, you may use that output file without restriction.
-# This special exception was added by Craig Small in version 0.37 of dh-make.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-%:
-	dh $@ 
diff --git a/src/openambit/debian/source/format b/src/openambit/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/src/openambit/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/src/openambit/deployment/99-suunto-ambit.rules b/src/openambit/deployment/99-suunto-ambit.rules
deleted file mode 100644
index edb4c78..0000000
--- a/src/openambit/deployment/99-suunto-ambit.rules
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Suunto Ambit / Ambit 2 UDEV rules
-# Change the permissions for devices to 0666 (work readable/writeable)
-#
-
-# Bluebird (a.k.a Suunto Ambit)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0010", MODE="0666"
-
-# Duck (a.k.a Suunto Ambit2)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0019", MODE="0666"
-
-# Colibri (a.k.a Suunto Ambit2 S)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="001a", MODE="0666"
-
-# Emu (a.k.a Suunto Ambit3 Peak)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="001b", MODE="0666"
-
-# Finch (a.k.a Suunto Ambit3 Sport)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="001c", MODE="0666"
-
-# Greentit (a.k.a Suunto Ambit2 R)
-SUBSYSTEMS=="usb", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="001d", MODE="0666"
diff --git a/src/openambit/deployment/openambit.desktop b/src/openambit/deployment/openambit.desktop
index 3b425d0..8f0d452 100644
--- a/src/openambit/deployment/openambit.desktop
+++ b/src/openambit/deployment/openambit.desktop
@@ -1,9 +1,9 @@
 [Desktop Entry]
-Version=0.3
+Version=1.0
 Type=Application
 Name=Openambit
 Comment=Open source synchronization for Suunto Ambit series
 TryExec=openambit
 Exec=openambit
 Icon=openambit
-Categories=Utility;Education;Sports
+Categories=Utility;Education;Sports;
diff --git a/src/openambit/devicemanager.cpp b/src/openambit/devicemanager.cpp
index 25f452d..ee4f04a 100644
--- a/src/openambit/devicemanager.cpp
+++ b/src/openambit/devicemanager.cpp
@@ -59,15 +59,17 @@ void DeviceManager::detect()
     mutex.lock();
     if (this->deviceObject != NULL) {
         libambit_close(this->deviceObject);
+        this->deviceObject = NULL;
+        emit deviceRemoved();
     }
-    this->deviceObject = libambit_detect();
 
-    if (this->deviceObject != NULL && (res = libambit_device_info_get(this->deviceObject, &this->currentDeviceInfo)) == 0) {
-        emit deviceDetected(this->currentDeviceInfo, libambit_device_supported(this->deviceObject));
-    }
-    else {
-        emit deviceRemoved();
+    ambit_device_info_t *devinfo = libambit_enumerate();
+    if (devinfo) {
+        this->currentDeviceInfo = *devinfo;
+        emit deviceDetected(this->currentDeviceInfo);
+        this->deviceObject = libambit_new(devinfo);
     }
+    libambit_free_enumeration(devinfo);
     mutex.unlock();
 
     if (res == 0) {
@@ -171,7 +173,7 @@ void DeviceManager::logMovescountID(QString device, QDateTime time, QString move
 int DeviceManager::log_skip_cb(void *ref, ambit_log_header_t *log_header)
 {
     DeviceManager *manager = static_cast<DeviceManager*> (ref);
-    if (manager->logStore.logExists(QString(manager->currentDeviceInfo.serial), log_header)) {
+    if (manager->logStore.logExists(manager->currentDeviceInfo.serial, log_header)) {
         return 0;
     }
     return 1;
@@ -180,7 +182,7 @@ 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(&manager->currentDeviceInfo, &manager->currentPersonalSettings, log_entry);
+    LogEntry *entry = manager->logStore.store(manager->currentDeviceInfo, &manager->currentPersonalSettings, log_entry);
     if (entry != NULL) {
         //! TODO: make this optional, only used for debugging
         manager->movesCountXML.writeLog(entry);
diff --git a/src/openambit/devicemanager.h b/src/openambit/devicemanager.h
index d8487cd..d7bc1c6 100644
--- a/src/openambit/devicemanager.h
+++ b/src/openambit/devicemanager.h
@@ -30,9 +30,9 @@
 #include <QSocketNotifier>
 
 #include "settings.h"
-#include "logstore.h"
-#include "movescount/movescount.h"
-#include "movescount/movescountxml.h"
+#include <movescount/logstore.h>
+#include <movescount/movescount.h>
+#include <movescount/movescountxml.h>
 #include "udevlistener.h"
 #include <libambit.h>
 
@@ -46,7 +46,7 @@ public:
     ~DeviceManager();
     void start();
 signals:
-    void deviceDetected(ambit_device_info_t deviceInfo, bool supported);
+    void deviceDetected(const DeviceInfo& deviceInfo);
     void deviceRemoved(void);
     void deviceCharge(quint8 percent);
     void syncFinished(bool success);
@@ -67,7 +67,7 @@ private:
     ambit_object_t *deviceObject;
     UdevListener *udevListener;
 
-    ambit_device_info_t currentDeviceInfo;
+    DeviceInfo currentDeviceInfo;
     ambit_personal_settings_t currentPersonalSettings;
 
     int syncParts;
diff --git a/src/openambit/logview.cpp b/src/openambit/logview.cpp
new file mode 100644
index 0000000..df8abb9
--- /dev/null
+++ b/src/openambit/logview.cpp
@@ -0,0 +1,54 @@
+#include "logview.h"
+
+LogView::LogView(QWidget *parent):
+    QTextBrowser(parent)
+{
+}
+
+void LogView::showLog(LogEntry *entry)
+{
+    QString log_html;
+
+    if (entry != NULL && entry->logEntry != NULL) {
+        log_html += "<h1>" + QString::fromUtf8(entry->logEntry->header.activity_name) + "</h1>";
+        if (entry->isUploaded()){
+            log_html += "<a href='http://www.movescount.com/moves/move" + entry->movescountId + "'>" + tr("see on movescount.com") + "</a>";
+        }
+        else {
+            log_html += tr("Not uploaded yet");
+        }
+        log_html += "<h2>" + tr("Details") + "</h2>";
+        log_html += "<h4>" + entry->time.toString() + "</h4>";
+        log_html += "<h4>" + tr("Duration: %1").arg(msecToHHMMSS(entry->logEntry->header.duration)) + "</h4>";
+        log_html += "<h4>" + tr("Distance: %1 m").arg(QString::number(entry->logEntry->header.distance)) + "</h4>";
+        log_html += "<h2>" + tr("Training values") + "</h2>";
+        log_html += "<h4>" + tr("Avg HR: %1 bpm").arg(QString::number(entry->logEntry->header.heartrate_avg)) + "</h4>";
+        log_html += "<h4>" + tr("Max HR: %1 bpm").arg(QString::number(entry->logEntry->header.heartrate_max)) + "</h4>";
+        log_html += "<h4>" + tr("Min HR: %1 bpm").arg(QString::number(entry->logEntry->header.heartrate_min)) + "</h4>";
+        log_html += "<h4>" + tr("PTE: %1").arg(QString::number(entry->logEntry->header.peak_training_effect/10.0)) + "</h4>";
+        log_html += "<h2>" + tr("Device") + "</h2>";
+        log_html += "<h4>" + tr("Name: %1").arg(entry->deviceInfo.name) + "</h4>";
+        log_html += "<h4>" + tr("Variant: %1").arg(entry->deviceInfo.model) + "</h4>";
+        log_html += "<h4>" + tr("Serial: %1").arg(entry->deviceInfo.serial) + "</h4>";
+
+        this->setHtml(log_html);
+    }
+}
+
+void LogView::hideLog()
+{
+    this->setHtml("");
+}
+
+QString LogView::msecToHHMMSS(quint32 msec)
+{
+    quint32 hours;
+    quint8 minutes;
+    quint8 seconds;
+
+    hours = msec / (3600000);
+    minutes = (msec - hours*3600000) / 60000;
+    seconds = (msec - hours*3600000 - minutes*60000) / 1000;
+
+    return QString("%1:%2:%3").arg(hours, 2, 10, QChar('0')).arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0'));
+}
diff --git a/src/openambit/logview.h b/src/openambit/logview.h
new file mode 100644
index 0000000..8041606
--- /dev/null
+++ b/src/openambit/logview.h
@@ -0,0 +1,26 @@
+#ifndef LOGVIEW_H
+#define LOGVIEW_H
+
+#include <QTextBrowser>
+
+#include <movescount/logentry.h>
+
+class LogView : public QTextBrowser
+{
+    Q_OBJECT
+public:
+    explicit LogView(QWidget *parent = 0);
+
+    void showLog(LogEntry *entry);
+    void hideLog();
+
+signals:
+
+public slots:
+
+private:
+    QString msecToHHMMSS(quint32 msec);
+
+};
+
+#endif // LOGVIEW_H
diff --git a/src/openambit/main.cpp b/src/openambit/main.cpp
index 3b73ed7..cf8ce6c 100644
--- a/src/openambit/main.cpp
+++ b/src/openambit/main.cpp
@@ -19,13 +19,43 @@
  * Contributors:
  *
  */
+#include <unistd.h>
 #include "mainwindow.h"
 #include <QSettings>
+#include <QTranslator>
+#include <QLibraryInfo>
 
 #include "single_application.h"
+#include "signalhandler.h"
+
+static void initTranslations(void);
 
 int main(int argc, char *argv[])
 {
+    // Handle foreground arguments
+    // NOTE: It would be preferable to handle all arguments at the same place,
+    // but fork needs to be done before Qt initialize it seems
+    bool background = true;
+    for (int i=0; i<argc; i++) {
+        if (strcmp(argv[i], "-f") == 0) {
+            background = false;
+            break;
+        }
+    }
+    if (background) {
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
+        // Windows
+#else
+        // Fork for background running
+        if ( fork() > 0 ) {
+            // Exit the parent process
+            return 0;
+        }
+        // Set the child to the new process group leader
+        setsid();
+#endif
+    }
+
     SingleApplication a(argc, argv, "openambit_single_application_lock");
 
     if (a.isRunning()) {
@@ -38,12 +68,50 @@ int main(int argc, char *argv[])
     QCoreApplication::setOrganizationName("Openambit");
     QCoreApplication::setApplicationName("Openambit");
 
+    // Handle forced localisation / translation
+    Q_FOREACH(QString argu, a.arguments()) {
+        const static QString localeParam = "-locale:";
+        if (argu.startsWith(localeParam)) {
+           QLocale::setDefault(QLocale(argu.mid(sizeof(localeParam))));
+           break;
+        }
+    }
+
+    // Initialize translations
+    initTranslations();
+
     MainWindow w;
 
     // Connect single application message bus
     QObject::connect(&a, SIGNAL(messageAvailable(QString)), &w, SLOT(singleApplicationMsgRecv(QString)));
 
+    // Handle signals
+    SignalHandler sigHandler;
+    QObject::connect(&sigHandler, SIGNAL(signalReceived(int)), &w, SLOT(closeRequested()));
+
     w.show();
     
     return a.exec();
 }
+
+static void initTranslations(void)
+{
+    QLocale locale;
+    QTranslator *qtTranslator = new QTranslator();
+    qtTranslator->load("qt_" + locale.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+    if (qtTranslator->isEmpty()) {
+        delete qtTranslator;
+    }
+    else {
+        qApp->installTranslator(qtTranslator);
+    }
+
+    QTranslator *openambitTranslator = new QTranslator();
+    openambitTranslator->load(":/translations/openambit_" + locale.name());
+    if (openambitTranslator->isEmpty()) {
+        delete openambitTranslator;
+    }
+    else {
+        qApp->installTranslator(openambitTranslator);
+    }
+}
diff --git a/src/openambit/mainwindow.cpp b/src/openambit/mainwindow.cpp
index d170aeb..ed8e985 100644
--- a/src/openambit/mainwindow.cpp
+++ b/src/openambit/mainwindow.cpp
@@ -91,8 +91,8 @@ MainWindow::MainWindow(QWidget *parent) :
     // Setup device manager
     deviceManager = new DeviceManager();
     deviceManager->moveToThread(&deviceWorkerThread);
-    qRegisterMetaType<ambit_device_info_t>("ambit_device_info_t");
-    connect(deviceManager, SIGNAL(deviceDetected(ambit_device_info_t,bool)), this, SLOT(deviceDetected(ambit_device_info_t,bool)), Qt::QueuedConnection);
+    qRegisterMetaType<DeviceInfo>("DeviceInfo");
+    connect(deviceManager, SIGNAL(deviceDetected(const DeviceInfo&)), this, SLOT(deviceDetected(const DeviceInfo&)), Qt::QueuedConnection);
     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);
@@ -171,7 +171,13 @@ void MainWindow::hideEvent(QHideEvent *event)
 
 void MainWindow::closeEvent(QCloseEvent *event)
 {
-    if (!sysTraySupported() || forceClose) {
+    //check if there is a settings for running in background
+    settings.beginGroup("generalSettings");
+    bool RunInBg;
+    RunInBg = settings.value("runningBackground", true).toBool();
+    settings.endGroup();
+
+    if (!sysTraySupported() || forceClose || !RunInBg) {
         trayIcon->setVisible(false);
         event->accept();
     }
@@ -230,12 +236,19 @@ void MainWindow::syncNowClicked()
     startSync();
 }
 
-void MainWindow::deviceDetected(ambit_device_info_t deviceInfo, bool supported)
+void MainWindow::deviceDetected(const DeviceInfo& deviceInfo)
 {
+    if (0 != deviceInfo.access_status) {
+        ui->labelNotSupported->setText(strerror(deviceInfo.access_status));
+    }
+    else {
+        // FIXME Should be gotten from the UI file, really
+        ui->labelNotSupported->setText(tr("Device not supported yet!"));
+    }
     ui->labelDeviceDetected->setText(deviceInfo.name);
     ui->labelSerial->setText(deviceInfo.serial);
     trayIcon->setIcon(QIcon(":/icon_connected"));
-    if (!supported) {
+    if (0 != deviceInfo.access_status || !deviceInfo.is_supported) {
         ui->labelNotSupportedIcon->setHidden(false);
         ui->labelNotSupported->setHidden(false);
         ui->labelMovescountAuthIcon->setHidden(true);
@@ -264,22 +277,23 @@ void MainWindow::deviceDetected(ambit_device_info_t deviceInfo, bool supported)
 
         movesCountSetup();
         if (movesCount != NULL) {
-            movesCount->setDevice(&deviceInfo);
+            movesCount->setDevice(deviceInfo);
             settings.beginGroup("movescountSettings");
             if (settings.value("checkNewVersions", true).toBool()) {
                 movesCount->checkLatestFirmwareVersion();
             }
-            if (settings.value("movescountEnable", true).toBool()) {
+            if (settings.value("movescountEnable", false).toBool()) {
                 movesCount->getDeviceSettings();
             }
             settings.endGroup();
         }
 
         settings.beginGroup("syncSettings");
-        if (settings.value("syncAutomatically", false).toBool()) {
+        bool syncAutomatically = settings.value("syncAutomatically", false).toBool();
+        settings.endGroup();
+        if (syncAutomatically) {
             startSync();
         }
-        settings.endGroup();
     }
 }
 
@@ -300,12 +314,14 @@ void MainWindow::deviceRemoved(void)
     trayIconSyncAction->setDisabled(true);
     ui->syncProgressBar->setHidden(true);
 
+    trayIcon->toolTip();
     trayIcon->setIcon(QIcon(":/icon_disconnected"));
 }
 
 void MainWindow::deviceCharge(quint8 percent)
 {
     ui->chargeIndicator->setValue(percent);
+    trayIcon->setToolTip(QString(tr("Charging %1%")).arg(percent));
 }
 
 void MainWindow::syncFinished(bool success)
@@ -362,11 +378,12 @@ void MainWindow::syncProgressInform(QString message, bool error, bool newRow, qu
         }
     }
     ui->syncProgressBar->setValue(percentDone);
+    trayIcon->setToolTip(QString(tr("Downloading %1%")).arg(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->setText(QString(tr("Newer firmware exists (%1.%2.%3)")).arg((int)fw_version[0]).arg((int)fw_version[1]).arg((int)(fw_version[2])));
     ui->labelNewFirmware->setHidden(false);
     ui->labelNewFirmwareIcon->setHidden(false);
 }
@@ -386,7 +403,7 @@ void MainWindow::logItemSelected(QListWidgetItem *current,QListWidgetItem *previ
     if (current != NULL) {
         logEntry = logStore.read(current->data(Qt::UserRole).toString());
         if (logEntry != NULL) {
-            ui->logDetail->setHtml(logEntry->toHtml());
+            ui->logDetail->showLog(logEntry);
         }
 
         delete logEntry;
@@ -449,7 +466,7 @@ void MainWindow::startSync()
     syncOrbit = settings.value("syncOrbit", true).toBool();
     settings.endGroup();
     settings.beginGroup("movescountSettings");
-    syncMovescount = settings.value("movescountEnable", true).toBool();
+    syncMovescount = settings.value("movescountEnable", false).toBool();
     settings.endGroup();
 
     trayIcon->setIcon(QIcon(":/icon_syncing"));
@@ -466,11 +483,11 @@ void MainWindow::movesCountSetup()
     bool movescountEnable = false;
 
     settings.beginGroup("syncSettings");
-    syncOrbit = settings.value("syncOrbit").toBool();
+    syncOrbit = settings.value("syncOrbit", true).toBool();
     settings.endGroup();
 
     settings.beginGroup("movescountSettings");
-    movescountEnable = settings.value("movescountEnable").toBool();
+    movescountEnable = settings.value("movescountEnable", false).toBool();
     if (syncOrbit || movescountEnable) {
         if (movesCount == NULL) {
             movesCount = MovesCount::instance();
diff --git a/src/openambit/mainwindow.h b/src/openambit/mainwindow.h
index 40c871b..360845f 100644
--- a/src/openambit/mainwindow.h
+++ b/src/openambit/mainwindow.h
@@ -25,7 +25,8 @@
 #include "devicemanager.h"
 #include "settingsdialog.h"
 #include "confirmbetadialog.h"
-#include "movescount/movescount.h"
+#include <movescount/deviceinfo.h>
+#include <movescount/movescount.h>
 #include <QMainWindow>
 #include <QThread>
 #include <QVBoxLayout>
@@ -50,6 +51,7 @@ signals:
 
 public slots:
     void singleApplicationMsgRecv(QString msg);
+    void closeRequested();
 
 protected:
     void changeEvent(QEvent *event);
@@ -58,7 +60,6 @@ protected:
     void closeEvent(QCloseEvent *event);
 
 private slots:
-    void closeRequested();
     void showHideWindow();
     void trayIconClicked(QSystemTrayIcon::ActivationReason reason);
 
@@ -68,7 +69,7 @@ private slots:
 
     void syncNowClicked();
 
-    void deviceDetected(ambit_device_info_t deviceInfo, bool supported);
+    void deviceDetected(const DeviceInfo& deviceInfo);
     void deviceRemoved();
     void deviceCharge(quint8 percent);
     void syncFinished(bool success);
diff --git a/src/openambit/mainwindow.ui b/src/openambit/mainwindow.ui
index 83f0215..a4a7016 100644
--- a/src/openambit/mainwindow.ui
+++ b/src/openambit/mainwindow.ui
@@ -30,7 +30,7 @@
      </widget>
     </item>
     <item>
-     <widget class="QTextBrowser" name="logDetail">
+     <widget class="LogView" name="logDetail">
       <property name="openExternalLinks">
        <bool>true</bool>
       </property>
diff --git a/src/openambit/movescount/CMakeLists.txt b/src/openambit/movescount/CMakeLists.txt
deleted file mode 100644
index c0a8c32..0000000
--- a/src/openambit/movescount/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-set ( openambit_SRCS
-  ${openambit_SRCS}
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescount.cpp
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountjson.cpp
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountlogdirentry.cpp
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountxml.cpp
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountlogchecker.cpp
-  PARENT_SCOPE
-)
-
-set ( openambit_MOCS
-  ${openambit_MOCS}
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescount.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountjson.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountlogdirentry.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountxml.h
-  ${CMAKE_CURRENT_SOURCE_DIR}/movescountlogchecker.h
-  PARENT_SCOPE
-)
diff --git a/src/openambit/movescount/include.pri b/src/openambit/movescount/include.pri
deleted file mode 100644
index 20de308..0000000
--- a/src/openambit/movescount/include.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-SOURCES += movescount/movescountxml.cpp \
-    movescount/movescountjson.cpp \
-    movescount/movescount.cpp \
-    movescount/movescountlogdirentry.cpp
-
-HEADERS += movescount/movescountxml.h \
-    movescount/movescountjson.h \
-    movescount/movescount.h \
-    movescount/movescountlogdirentry.h
diff --git a/src/openambit/settingsdialog.cpp b/src/openambit/settingsdialog.cpp
index 5ba3cbd..222753f 100644
--- a/src/openambit/settingsdialog.cpp
+++ b/src/openambit/settingsdialog.cpp
@@ -69,6 +69,7 @@ void SettingsDialog::readSettings()
 {
     settings.beginGroup("generalSettings");
     ui->checkBoxSkipBetaCheck->setChecked(settings.value("skipBetaCheck", false).toBool());
+    ui->checkBoxRunningBackground->setChecked(settings.value("runningBackground", true).toBool());
     settings.endGroup();
 
     settings.beginGroup("syncSettings");
@@ -89,6 +90,7 @@ void SettingsDialog::writeSettings()
 {
     settings.beginGroup("generalSettings");
     settings.setValue("skipBetaCheck", ui->checkBoxSkipBetaCheck->isChecked());
+    settings.setValue("runningBackground", ui->checkBoxRunningBackground->isChecked());
     settings.endGroup();
 
     settings.beginGroup("syncSettings");
diff --git a/src/openambit/settingsdialog.ui b/src/openambit/settingsdialog.ui
index 2697ecb..7dca610 100644
--- a/src/openambit/settingsdialog.ui
+++ b/src/openambit/settingsdialog.ui
@@ -105,6 +105,13 @@
                 </property>
                </widget>
               </item>
+              <item row="1" column="0">
+               <widget class="QCheckBox" name="checkBoxRunningBackground">
+                <property name="text">
+                 <string>Continue running in background when Openambit main window is closed</string>
+                </property>
+               </widget>
+              </item>
              </layout>
             </widget>
            </item>
diff --git a/src/openambit/signalhandler.cpp b/src/openambit/signalhandler.cpp
new file mode 100644
index 0000000..f2f6bcc
--- /dev/null
+++ b/src/openambit/signalhandler.cpp
@@ -0,0 +1,172 @@
+#include "signalhandler.h"
+#include "assert.h"
+
+#ifdef SIGNALHANDLER_POSIX
+#include <csignal>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+#ifdef SIGNALHANDLER_WIN32
+#include <windows.h>
+#endif //SIGNALHANDLER_WIN32
+
+#ifdef SIGNALHANDLER_POSIX
+int SignalHandler::POSIX_fd[2];
+#endif //SIGNALHANDLER_POSIX
+
+// Singleton construction
+SignalHandler* sig_handler(NULL);
+
+SignalHandler::SignalHandler(QObject *parent, int mask) :
+    QObject(parent), _mask(mask)
+{
+    assert(sig_handler == NULL);
+    sig_handler = this;
+
+#ifdef SIGNALHANDLER_WIN32
+    SetConsoleCtrlHandler(WIN32_handleFunc, TRUE);
+#endif
+#ifdef SIGNALHANDLER_POSIX
+    // Setup unix singal handling
+    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, POSIX_fd)) {
+        qFatal("Failed to create POSIX Signal handling sockets");
+    }
+    POSIX_ntf = new QSocketNotifier(POSIX_fd[1], QSocketNotifier::Read, this);
+    connect(POSIX_ntf, SIGNAL(activated(int)), this, SLOT(POSIX_socketRecv()));
+#endif //SIGNALHANDLER_POSIX
+
+    for (int i=0; i<signalsCount; i++) {
+        int sigval = 1 << i;
+        if (_mask & sigval) {
+#ifdef SIGNALHANDLER_WIN32
+            sig_registry.insert(sigval);
+#endif
+#ifdef SIGNALHANDLER_POSIX
+            int sig = POSIX_logicalToPhysical(sigval);
+            assert(signal(sig, SignalHandler::POSIX_handleFunc) != SIG_ERR);
+#endif //SIGNALHANDLER_POSIX
+        }
+    }
+}
+
+SignalHandler::~SignalHandler()
+{
+#ifdef SIGNALHANDLER_WIN32
+    SetConsoleCtrlHandler(WIN32_handleFunc, FALSE);
+#endif
+#ifdef SIGNALHANDLER_POSIX
+    for (int i=0;i<signalsCount;i++) {
+        int sigval = 1 << i;
+        if (_mask & sigval) {
+            signal(POSIX_logicalToPhysical(sigval), SIG_DFL);
+        }
+    }
+#endif //SIGNALHANDLER_POSIX
+}
+
+bool SignalHandler::handleSignal(int signal)
+{
+    emit this->signalReceived(signal);
+
+    return true;
+}
+
+#ifdef SIGNALHANDLER_WIN32
+DWORD SignalHandler::WIN32_logicalToPhysical(int signal)
+{
+    switch (signal) {
+        case SignalHandler::SIG_INT: return CTRL_C_EVENT;
+        case SignalHandler::SIG_TERM: return CTRL_BREAK_EVENT;
+        case SignalHandler::SIG_CLOSE: return CTRL_CLOSE_EVENT;
+        default:
+            return ~(unsigned int)0; // SIG_ERR = -1
+    }
+}
+#endif
+#ifdef SIGNALHANDLER_POSIX
+int SignalHandler::POSIX_logicalToPhysical(int signal)
+{
+    switch (signal) {
+        case SignalHandler::SIG_INT: return SIGINT;
+        case SignalHandler::SIG_TERM: return SIGTERM;
+        // In case the client asks for a SIG_CLOSE handler, accept and
+        // bind it to a SIGTERM. Anyway the signal will never be raised
+        case SignalHandler::SIG_CLOSE: return SIGTERM;
+        case SignalHandler::SIG_RELOAD: return SIGHUP;
+        default:
+            return -1; // SIG_ERR = -1
+    }
+}
+#endif //SIGNALHANDLER_POSIX
+
+
+#ifdef SIGNALHANDLER_WIN32
+int SignalHandler::WIN32_physicalToLogical(DWORD signal)
+{
+    switch (signal) {
+        case CTRL_C_EVENT: return SignalHandler::SIG_INT;
+        case CTRL_BREAK_EVENT: return SignalHandler::SIG_TERM;
+        case CTRL_CLOSE_EVENT: return SignalHandler::SIG_CLOSE;
+        default:
+            return SignalHandler::SIG_UNHANDLED;
+    }
+}
+#endif
+#ifdef SIGNALHANDLER_POSIX
+int SignalHandler::POSIX_physicalToLogical(int signal)
+{
+    switch (signal) {
+        case SIGINT: return SignalHandler::SIG_INT;
+        case SIGTERM: return SignalHandler::SIG_TERM;
+        case SIGHUP: return SignalHandler::SIG_RELOAD;
+        default:
+            return SignalHandler::SIG_UNHANDLED;
+    }
+}
+#endif //SIGNALHANDLER_POSIX
+
+
+
+#ifdef SIGNALHANDLER_WIN32
+BOOL WINAPI SignalHandler::WIN32_handleFunc(DWORD signal)
+{
+    if (sig_handler) {
+        int signo = WIN32_physicalToLogical(signal);
+        // The std::set is thread-safe in const reading access and we never
+        // write to it after the program has started so we don't need to
+        // protect this search by a mutex
+        std::set<int>::const_iterator found = sig_registry.find(signo);
+        if (signo != -1 && found != g_registry.end()) {
+            return sig_handler->handleSignal(signo) ? TRUE : FALSE;
+        }
+        else {
+            return FALSE;
+        }
+    }
+    else {
+        return FALSE;
+    }
+}
+#endif
+#ifdef SIGNALHANDLER_POSIX
+void SignalHandler::POSIX_handleFunc(int signal)
+{
+    if (sig_handler) {
+        int signo = POSIX_physicalToLogical(signal);
+        write(POSIX_fd[0], &signo, sizeof(signo));
+    }
+}
+#endif //SIGNALHANDLER_POSIX
+
+#ifdef SIGNALHANDLER_POSIX
+void SignalHandler::POSIX_socketRecv()
+{
+    POSIX_ntf->setEnabled(false);
+
+    int signo;
+    read(POSIX_fd[1], &signo, sizeof(signo));
+    handleSignal(signo);
+
+    POSIX_ntf->setEnabled(true);
+}
+#endif //SIGNALHANDLER_POSIX
diff --git a/src/openambit/signalhandler.h b/src/openambit/signalhandler.h
new file mode 100644
index 0000000..a3f97b9
--- /dev/null
+++ b/src/openambit/signalhandler.h
@@ -0,0 +1,63 @@
+#ifndef SIGNALHANDLER_H
+#define SIGNALHANDLER_H
+
+#include <QObject>
+#include <QSocketNotifier>
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
+#define SIGNALHANDLER_WIN32
+#else
+#define SIGNALHANDLER_POSIX
+#endif
+
+class SignalHandler : public QObject
+{
+    Q_OBJECT
+public:
+    explicit SignalHandler(QObject *parent = 0, int mask = DEFAULT_SIGNALS);
+    virtual ~SignalHandler();
+
+    enum SIGNALS
+    {
+        SIG_UNHANDLED   = 0,    // Physical signal not supported by this class
+        SIG_NOOP        = 1,    // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway)
+        SIG_INT         = 2,    // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit)
+        SIG_TERM        = 4,    // Control+Break (should terminate now without regarding the consquences)
+        SIG_CLOSE       = 8,    // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM]
+        SIG_RELOAD      = 16,   // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP]
+        DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
+    };
+    static const int signalsCount = 6;
+
+    bool handleSignal(int signal);
+
+#ifdef SIGNALHANDLER_WIN32
+    static BOOL WINAPI WIN32_handleFunc(DWORD);
+    static int WIN32_physicalToLogical(DWORD);
+    static DWORD WIN32_logicalToPhysical(int);
+    static std::set<int> sig_registry;
+#endif
+#ifdef SIGNALHANDLER_POSIX
+    static void POSIX_handleFunc(int);
+    static int POSIX_physicalToLogical(int);
+    static int POSIX_logicalToPhysical(int);
+#endif //SIGNALHANDLER_POSIX
+
+signals:
+    void signalReceived(int signal);
+
+public slots:
+#ifdef SIGNALHANDLER_POSIX
+    void POSIX_socketRecv();
+#endif
+
+private:
+    int _mask;
+
+#ifdef SIGNALHANDLER_POSIX
+    static int POSIX_fd[2];
+    QSocketNotifier *POSIX_ntf;
+#endif
+};
+
+#endif // SIGNALHANDLER_H
diff --git a/src/openambit/translations/openambit_de.ts b/src/openambit/translations/openambit_de.ts
new file mode 100644
index 0000000..913b89c
--- /dev/null
+++ b/src/openambit/translations/openambit_de.ts
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE" sourcelanguage="en">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Disclaimer</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Nicht nochmal fragen, ich möchte Openambit wirklich benutzen</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FRÜHE BETA-SOFTWARE: <a href="http://de.wikipedia.org/wiki/Hic_sunt_dracones"><span style=" text-decoration: underline; color:#0000ff;">hic sunt dracones</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Diese Software ist noch in einem frühen Beta-Stadium. Sie lädt möglicherweise ungültige Log-Dateien zu Movescount hoch, die nicht überschrieben werden können oder andere unerwartete Effekte hervorrufen.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit ist freie Software: Du kannst sie weitergeben und verändern </span><span style=" font-family:'Courier New,courier'; color:#008000;">entsprechend den Bedingungen der GNU General Public License, veröffentlicht von der Free Software Foundation, in Version 3 oder (nach dei [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">Dieses Programm wird in der Hoffnung weitergegeben, nützlich zu sein, aber OHNE JEGLICHE GEWÄHRLEISTUNG, insbesondere OHNE MÄNGELHAFTUNG oder die ZUSICHERUNG, dass es FÜR EINEN BESTIMMTEN ZWECK GEEIGNET ist. Für weitere Details wird auf die GNU General Public Licens [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bitte benutze dieses Programm auf <span style=" text-decoration: underline;">eigene Gefahr</span> und nur, wenn du die damit verbundenen Risiken verstanden hast.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wenn du dich entschlossen hast, Openambit zu benutzen, dann <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">melde bitte Fehler</span></a>, damit wir das Programm weiter verbessern können.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Danke </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Lese persönliche Einstellungen</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Setze Datum und Zeit</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Lese Log-Dateien</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>Hole GPS-Bahndaten</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>Schreibe GPS-Bahndaten</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>Fehler beim Holen der GPS-Bahndaten</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Lade Log %1 von %2 herunter</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>auf Movescount.com ansehen</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>Noch nicht hochgeladen</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Details</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Dauer: %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Distanz: %1 m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Trainingswerte</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Durchschnittspuls: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Maximalpuls: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Minimalpuls: %1 bpm</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE: %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Gerät</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Name: %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation>Variante: %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>Seriennummer: %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Gerät</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Kein Gerät gefunden</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Gerät noch nicht unterstützt!</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>Authorisieren bei <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>Ladestand:</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Alle erneut synchronisieren</translation>
+    </message>
+    <message>
+        <source>Sync now</source>
+        <translation>Jetzt synchronisieren</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&Datei</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>&Hilfe</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>Über Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>B&enden</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Einstellungen</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimieren</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>Wiederherstellen</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>Über %1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Version %2</b><br />Unter Verwendung von Qt %3</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Synchronisierung abgeschlossen</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Synchronisierung beendet</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Synchronisierung fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Synchronisierung fehlgeschlagen</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Neuere Firmware verfügbar (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Kontextmenü</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Schreibe Movescount-Datei</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Synchronisierung gestartet</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation>Laden %1%</translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation>Synchronisieren %1%</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>The file is not an openambit version 1.0 file.</source>
+        <translation>Die Datei hat nicht die Openambit-Version 1.0.</translation>
+    </message>
+    <message>
+        <source>%1
+Line %2, column %3</source>
+        <translation>%1
+Zeile %2, Spalte %3</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Allgemein</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Gerätesynchronisierung</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Allgemeine Einstellungen</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Beta-Warnung beim Start nicht anzeigen </translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>Im Hintergrund weiter ausführen wenn das Hauptfenster geschlossen wird</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Einstellungen für die Gerätesynchronisierung</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Zeit vom Computer synchronisieren</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>GPS-Satellitenbahndaten (von Movescount) synchronisieren</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Synchronisierung automatisch starten, wenn ein Gerät angeschlossen ist</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Verbindung zu Movescount</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Auf Movescount nach neuen Versionen suchen</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Debug-Dateien erzeugen (XML-Dateien in ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Logs zu Movescount synchronisieren</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>Email des Movescount-Accounts</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_fr.ts b/src/openambit/translations/openambit_fr.ts
new file mode 100644
index 0000000..e08994b
--- /dev/null
+++ b/src/openambit/translations/openambit_fr.ts
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Avertissement</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Ne plus me poser cette question.</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Läser personliga inställningar</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Skriver datum & tid</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Läser logg-filer</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>Hämtar GPS-data</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>Skriver GPS-data</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>GPS-data gick ej att hämta</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Läser logg %1 av %2</translation>
+    </message>
+</context>
+<context>
+    <name>LogEntry</name>
+    <message>
+        <source>Device</source>
+        <translation type="obsolete">Périphérique</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>voir sur movescount.com</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>Pas encore envoyé</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Détails</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Durée : %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Distance : %1 m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Paramètres physiologiques</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Fréq. cardiaque moy. : %1 puls/mn</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Fréq. cardiaque maxi : %1 puls/mn
+</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Fréq. cardiaque mini : %1 puls/mn
+</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE : %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Périphérique</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Nom : %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation>Variante : %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>N/S : %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Sync now</source>
+        <translation>Synchroniser maintenant</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimiser</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>Restaurer</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>À propos d'%1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Version %2</b><br />Qt %3</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Pas de périphérique détecté</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Synchronisation complète</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Synchronisation terminée</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Échec de synchronisation</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Échec de synchronisation</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Nouveau micrologiciel (firmware) disponible (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Menu contextuel</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Écrire le fichier Movescount</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Début de synchronisation</translation>
+    </message>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Périphérique</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Périphérique non géré</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>S'authentifier sur <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>Charge :</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Tout resynchroniser</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&Fichier</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>&Aide</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>À propos d'Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>&Quitter</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Réglages</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation>Charge %1%</translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>The file is not an openambit version 1.0 file.</source>
+        <translation>Ce fichier n'est pas un fichier Openambit version 1.0</translation>
+    </message>
+    <message>
+        <source>%1
+Line %2, column %3</source>
+        <translation>%1
+Ligne %2, colonne %3</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogue</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Général</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Synchronisation du périphérique</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Réglages généraux</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Ne pas signaler les versions beta au démarrage</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>Poursuivre le fonctionnement en tâche de fond lorsque la fenêtre principale d'Openambit est fermée</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Réglages de synchronisation du périphérique</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Synchroniser l'heure avec l'ordinateur</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>Synchroniser les données orbitales des satellites (depuis Movescount)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Démarrer automatiquement la synchronisation à la connexion du périphérique</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Connexion à Movescount</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Vérifier les nouvelles versions sur Movescount</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Créer des fichiers de débogage (fichiers XML dans ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Synchroniser les informations avec Movescount</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>Adresse électronique (du compte Movescount)</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_it.ts b/src/openambit/translations/openambit_it.ts
new file mode 100644
index 0000000..781a10f
--- /dev/null
+++ b/src/openambit/translations/openambit_it.ts
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="it" sourcelanguage="en">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Attenzione</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Non mi chiedere piu, voglio veramente uasre Openambit</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">SOFTWARE BETA : <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">Si salvi chi puó</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Questo sogtware é molto giovane e potrebbe caricare dei log sbagliati, incancellabili, ecc su movescount</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Perfavore usa questo software <span style=" text-decoration: underline;">a tuo</span> rischio e pericolo solo se capisci i rischi implicati.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Se decidi di usare Openambit, perfavore <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">segnalaci eventuali bachi</span></a> cosi da poterli riparare.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Grazie </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Leggendo impostazioni</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Impostando data/ora</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Leggendo file di log</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>Ottenendo dati orbitali</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>Scrivendo dati orbitali</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>Errore ottenendo dati orbitali</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Sacricando log %1 di %2</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>Vedi su movescount.com</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>Non ancora caricata</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Dettagli</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Durata: %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Distanza: %1</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Valori d'allenamento</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Frequenza cardicaca media: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Frequenza cardicaca max: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Frequenza cardicaca min: %1 bpm</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE: %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Orologio</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Nome: %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation>Variante: %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>Seriale: %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Orologio</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Nessun orologio trovato</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Orologio non ancora supportato!</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>Autorizza su <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>Carica:</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Resincronizza tutto</translation>
+    </message>
+    <message>
+        <source>Sync now</source>
+        <translation>Sincronizza ora</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&File</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>&Aiuto</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>A proposito di Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>E&sci</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Impostazioni</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimizza</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>Ripristina</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>A proposito %1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Versione %2</b><br />Usando Qt %3</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Sincronizzazione completa</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Sincronizzazione completa</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Sincronizzazione fallita</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Sincronizzazione fallita</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Nuovo firmware disponibile (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Menu contestuale</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Scrivi file Movescount</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Sincronizzazione iniziata</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation>Carica %1%</translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>The file is not an openambit version 1.0 file.</source>
+        <translation>Il file non é un file openambit versione 1.0.</translation>
+    </message>
+    <message>
+        <source>%1
+Line %2, column %3</source>
+        <translation>%1
+riga %2, colonna %3</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialogo</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Generale</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Sincronizzazione orologio</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Impostazioni generali</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Salta il controllo beta all'accensione</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>RImani in background anche chiudendo la finestra pincipale</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Impostazioi sincronizzazione</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Sincronizzazione completa</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>Syicronizza dati orbitali (da movescount.com)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Sincronizza auomaticamente quando si connette un orologio</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Connessione Movescount</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Cerca nuove versioni su movescount</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Genera files di debug (XMLs stored in ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Syicronizza dati con movescount.com</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>Email (Account Movescount)</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_ja.ts b/src/openambit/translations/openambit_ja.ts
new file mode 100644
index 0000000..df71c1e
--- /dev/null
+++ b/src/openambit/translations/openambit_ja.ts
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="ja">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit:注意事項</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>再び聞かないで、Openambitをマジで使いたい!</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>個人設定を取り込み中</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>時間・日付を設定中</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>ログファイルを取り込み中</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>軌道情報を取得中</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>軌道情報を転送中</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>軌道情報の取得が失敗しました</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>ログ(%1の%2)を同期中</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>movescount.comでみる</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>未登録</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>詳細</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>時間:%1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>距離:%1m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>平均心拍数:%1bpm</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>最大心拍数:%1bpm</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>最低心拍数:%1bpm</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE:%1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>デバイス</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>名前:%1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>シリアル番号:%1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>デバイス</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>デバイスを見つかりません</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>デバイスはまだ未対応です。</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation><a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>で認証する!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>電荷:</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>すべて同期する</translation>
+    </message>
+    <message>
+        <source>Sync now</source>
+        <translation>同期を開始する</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>ファイル(&F)</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>ヘルプ(&H)</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>Openambitについて</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>終了(&X)</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>設定(&S)</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>最小化</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>戻す</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>%1 について</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>バージョン %2</b><br />Qt %3を使用</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>同期が終了しました</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>同期が終了しました</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>同期が失敗しました</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>同期が失敗しました</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>新しいファームウェア(%1.%2.%3)があります</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>コンテキストメニュー</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Movescountへ転送</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>同期開始</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>ダイヤログ</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>一般</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>デバイスの同期</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>一般設定</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>起動時のベタ版確認を非表示する</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>Openambitのメインウィンドウを閉じてもバックグラウンドで実行し続ける</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>デバイス同期設定</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>時間をパソコンと同期する</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>軌道情報を同期する(Movescountから)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>デバイス接続時に自動的に同期する</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Movescount接続</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>新しいバージョンをチェックする</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>デバグファイルを生成する(~/.openambit/movescount以下にXML形式で保存されます)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>ログをMovescountに登録する</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>電子メール(Movescountアカウント)</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_nl.ts b/src/openambit/translations/openambit_nl.ts
new file mode 100644
index 0000000..4751f0c
--- /dev/null
+++ b/src/openambit/translations/openambit_nl.ts
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="nl">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Waarschuwing</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Niet nogmaals vragen, ik wil Openambit echt gebruiken</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Persoonlijke instelling aan het lezen</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Datum/tijd aan het instellen</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Log bestanden aan het lezen</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>GPS gegevens aan het ophalen</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>GPS gegevens aan het schrijven</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>Fout bij het ophalen van GPS gegevens</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Log %1 van %2 aan het uploaden</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>op movescount.com bekijken</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>nog niet geüpload</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Details</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Duur: %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Afstand: %1 m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Trainingswaarden</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Gemiddelde hartslag: %1 hs/m</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Maximum hartslag: %1 hs/m</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Minimum hartslag: %1 hs/m</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE: %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Apparaat</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Naam: %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation>Variant: %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>Serienummer: %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Apparaat</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Geen apparaat gevonden</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Apparaat nog niet ondersteund!</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>Authoriseren bij<a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>! </translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Alles opnieuw synchroniseren</translation>
+    </message>
+    <message>
+        <source>Sync now</source>
+        <translation>Nu synchroniseren</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&Bestand</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>&Help</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>Over Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>&Afsluiten</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Instellingen</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimaliseren</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>Over %1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Versie %2</b><br />Qt %3</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Synchronisatie compleet</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Synchronisatie beëindigd</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Fout bij het synchroniseren</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Fout bij het synchroniseren</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Nieuwe firmware beschikbaar (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Contextmenu</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Schrijf Movescount bestand</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Synchronisatie gestart</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialoog</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Algemeen</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Apparaatsynchronisatie</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Algemene instellingen</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Beta-waarschuwing bij start niet vertonen</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>In de achtergrond doorgaan als het hoofdvenster wordt gesloten</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Installingen voor de apparaatsynchronisatie</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Tijd met computer synchroniseren</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>GPS gegevens synchroniseren (met Movescount)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Synchornisatie automatisch starten als een apparaat aangesloten is</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Verbinding met Movescount</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Op Movescount een nieuwe versie zoeken</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Debug bestand genereren (XML bestand in ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Logs met Movescount synchroniseren</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>Email (Movescount account)</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_pl.ts b/src/openambit/translations/openambit_pl.ts
new file mode 100644
index 0000000..1a05772
--- /dev/null
+++ b/src/openambit/translations/openambit_pl.ts
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="pl_PL">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Zastrzeżenia</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Nie pytaj ponownie, na prawdę chcę użyć Openambit</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Odczytywanie ustawień osobistych</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Ustawianie daty/czasu</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Odczytywanie logów</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>Pobieranie ustawień satelitów</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>Zapisywnie danych satelitów</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>Nieudane pobranie ustawień satelitów</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Pobieranie logu %1 z %2</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>Zobacz na movescount.com</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>Jeszcze nie przesłano</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Szczegóły</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Czas trwania: %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Dystans: %1 m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Czegóły treningu</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Średnie tętno: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Maksymalne tętno: %1 bpm</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Minimalne tętno: %1 bpm</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE: %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Urządzenie</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Nazwa: %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation type="unfinished">Wariant: %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation type="unfinished">Seria: %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Urządzenie</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Nie znaleziono urządzenia</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Urządzenie jeszcze nie obsługiwane!</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>Autentykacja na <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>Ładowanie:</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Synchronizuj wszystko ponownie</translation>
+    </message>
+    <message>
+        <source>Sync now</source>
+        <translation>Synchronizuj teraz</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&Plik</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>P&omoc</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>O Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>&Wyjście</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Ustawienia</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Zminimalizuj</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>Przywróć</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>O %1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Wersja %2</b><br />Używa Qt %3</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Synchronizacja zakończona</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Synchronizacja zakończona</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Synchronizacja nieudana</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Synchronizacja nieudana</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Istnieje nowa wersja oprogramowania (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Menu kontekstowe</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Zapisz plik Movescount</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Synchronizacja rozpoczęta</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>The file is not an openambit version 1.0 file.</source>
+        <translation>To nie jest plik openambit w wersji 1.0.</translation>
+    </message>
+    <message>
+        <source>%1
+Line %2, column %3</source>
+        <translation>%1
+Linia %2, kolumna %3</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation type="unfinished">Dialog</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Ogólne</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Synchronizacja urządzenia</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Ustawienia ogólne</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Pomiń Beta sprawdzanie przy uruchomieniu</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>Kontynuuj działanie w tle, gdy główne okno Openambit jest zamknięte</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Synchronizacja ustawień urządzenia</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Synchronizuj czas z komputera</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>Synchronizuj dane satelitów (z Movescount)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Rozpoczynij automatyczną synchronizację, gdy urządzenie jest podłączone</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Połączenie z Movescount</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Sprawdź nową wersję w Movescount</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Generuj pliki debug (XMLe trzymane są w ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Synchronizuj treningi z Movescount</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>Email (konto Movescount)</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/openambit/translations/openambit_sv.ts b/src/openambit/translations/openambit_sv.ts
new file mode 100644
index 0000000..9747f37
--- /dev/null
+++ b/src/openambit/translations/openambit_sv.ts
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="sv_SE">
+<context>
+    <name>ConfirmBetaDialog</name>
+    <message>
+        <source>Openambit: Disclaimer</source>
+        <translation>Openambit: Varning</translation>
+    </message>
+    <message>
+        <source>Don't ask me again, I really want to use Openambit</source>
+        <translation>Fråga mig inte igen</translation>
+    </message>
+    <message>
+        <source><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">EARLY BETA SOFTWARE: <a href="http://en.wikipedia.org/wiki/Here_be_dragons"><span style=" text-decoration: underline; color:#0000ff;">here be dragons</span></a></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This software is in early beta stage, it might upload invalid logs to movescount that cannot be overwritten, and do other bizarre things.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#008000;">Openambit</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">is</span><span style=" color:#c0c0c0;"> </span><span style=" color:#008000;">free</span><span style=" color:#c0c0c0;"&gt [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier';"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Courier New,courier'; color:#008000;">This</span><span style=" font-family:'Courier New,courier'; color:#c0c0c0;"> </span><span style=" font-family:'Courier New,courier'; color:#008000;">program</span><span style=" font-family [...]
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please use this software at <span style=" text-decoration: underline;">your own</span> risk and only if you understand the risks involved.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you decide to use Openambit please consider <a href="https://github.com/openambitproject/openambit/issues/new"><span style=" text-decoration: underline; color:#0000ff;">reporting bugs</span></a> so we can make it better.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Thanks </p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Courier New,courier'; color:#008000;"><br /></p></body></html></source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>DeviceManager</name>
+    <message>
+        <source>Reading personal settings</source>
+        <translation>Läser personliga inställningar</translation>
+    </message>
+    <message>
+        <source>Setting date/time</source>
+        <translation>Skriver datum & tid</translation>
+    </message>
+    <message>
+        <source>Reading log files</source>
+        <translation>Läser logg-filer</translation>
+    </message>
+    <message>
+        <source>Fetching orbital data</source>
+        <translation>Hämtar GPS-data</translation>
+    </message>
+    <message>
+        <source>Writing orbital data</source>
+        <translation>Skriver GPS-data</translation>
+    </message>
+    <message>
+        <source>Failed to get orbital data</source>
+        <translation>GPS-data gick ej att hämta</translation>
+    </message>
+    <message>
+        <source>Downloading log %1 of %2</source>
+        <translation>Läser logg %1 av %2</translation>
+    </message>
+</context>
+<context>
+    <name>LogEntry</name>
+    <message>
+        <source>Device</source>
+        <translation type="obsolete">Enhet</translation>
+    </message>
+</context>
+<context>
+    <name>LogView</name>
+    <message>
+        <source>see on movescount.com</source>
+        <translation>se på movescount.com</translation>
+    </message>
+    <message>
+        <source>Not uploaded yet</source>
+        <translation>Ej uppladdad</translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation>Detaljer</translation>
+    </message>
+    <message>
+        <source>Duration: %1</source>
+        <translation>Tid: %1</translation>
+    </message>
+    <message>
+        <source>Distance: %1 m</source>
+        <translation>Sträcka: %1 m</translation>
+    </message>
+    <message>
+        <source>Training values</source>
+        <translation>Träningsdetaljer</translation>
+    </message>
+    <message>
+        <source>Avg HR: %1 bpm</source>
+        <translation>Snittpuls: %1 slag/min</translation>
+    </message>
+    <message>
+        <source>Max HR: %1 bpm</source>
+        <translation>Maxpuls: %1 slag/min</translation>
+    </message>
+    <message>
+        <source>Min HR: %1 bpm</source>
+        <translation>Minpuls: %1 slag/min</translation>
+    </message>
+    <message>
+        <source>PTE: %1</source>
+        <translation>PTE: %1</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Enhet</translation>
+    </message>
+    <message>
+        <source>Name: %1</source>
+        <translation>Modell: %1</translation>
+    </message>
+    <message>
+        <source>Variant: %1</source>
+        <translation>Variant: %1</translation>
+    </message>
+    <message>
+        <source>Serial: %1</source>
+        <translation>Serienummer: %1</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <source>Sync now</source>
+        <translation>Synkronisera</translation>
+    </message>
+    <message>
+        <source>Minimize</source>
+        <translation>Minimera</translation>
+    </message>
+    <message>
+        <source>Restore</source>
+        <translation>Återställ</translation>
+    </message>
+    <message>
+        <source>About %1</source>
+        <translation>Om %1</translation>
+    </message>
+    <message>
+        <source><h2>%1</h2><b>Version %2</b><br />Using Qt %3</source>
+        <translation><h2>%1</h2><b>Version %2</b><br />Qt %3</translation>
+    </message>
+    <message>
+        <source>No device detected</source>
+        <translation>Ingen enhet hittades</translation>
+    </message>
+    <message>
+        <source>Syncronization complete</source>
+        <translation>Synkroniseringen slutförd</translation>
+    </message>
+    <message>
+        <source>Syncronisation finished</source>
+        <translation>Synkroniseringen slutförd</translation>
+    </message>
+    <message>
+        <source>Syncronization failed</source>
+        <translation>Synkroniseringen misslyckades</translation>
+    </message>
+    <message>
+        <source>Syncronisation failed</source>
+        <translation>Synkroniseringen misslyckades</translation>
+    </message>
+    <message>
+        <source>Newer firmware exists (%1.%2.%3)</source>
+        <translation>Det finns en nyare firmware (%1.%2.%3)</translation>
+    </message>
+    <message>
+        <source>Context menu</source>
+        <translation>Snabbval</translation>
+    </message>
+    <message>
+        <source>Write Movescount file</source>
+        <translation>Skriv Movescount-fil</translation>
+    </message>
+    <message>
+        <source>Syncronisation started</source>
+        <translation>Synkronisering startad</translation>
+    </message>
+    <message>
+        <source>Openambit</source>
+        <translation>Openambit</translation>
+    </message>
+    <message>
+        <source>Device</source>
+        <translation>Enhet</translation>
+    </message>
+    <message>
+        <source>Device not supported yet!</source>
+        <translation>Enheten stöds inte än!</translation>
+    </message>
+    <message>
+        <source>Auth on <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</source>
+        <translation>Tillåt Openambit på <a href="http://www.movescount.com"><span style=" text-decoration: underline; color:#0057ae;">movescount.com</span></a>!</translation>
+    </message>
+    <message>
+        <source>Charge:</source>
+        <translation>Laddning:</translation>
+    </message>
+    <message>
+        <source>Resync all</source>
+        <translation>Omsynkronsiera allt</translation>
+    </message>
+    <message>
+        <source>&File</source>
+        <translation>&Arkiv</translation>
+    </message>
+    <message>
+        <source>&Help</source>
+        <translation>&Hjälp</translation>
+    </message>
+    <message>
+        <source>About Openambit...</source>
+        <translation>Om Openambit...</translation>
+    </message>
+    <message>
+        <source>E&xit</source>
+        <translation>A&vsluta</translation>
+    </message>
+    <message>
+        <source>&Settings</source>
+        <translation>&Inställningar</translation>
+    </message>
+    <message>
+        <source>Charging %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloading %1%</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>The file is not an openambit version 1.0 file.</source>
+        <translation>Filen är inte i openambit version 1.0-format.</translation>
+    </message>
+    <message>
+        <source>%1
+Line %2, column %3</source>
+        <translation>%1
+Rad %2, kolumn %3</translation>
+    </message>
+</context>
+<context>
+    <name>SettingsDialog</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation>Generellt</translation>
+    </message>
+    <message>
+        <source>Device sync</source>
+        <translation>Synkronisering</translation>
+    </message>
+    <message>
+        <source>Movescount</source>
+        <translation>Movescount</translation>
+    </message>
+    <message>
+        <source>General settings</source>
+        <translation>Generella inställningar</translation>
+    </message>
+    <message>
+        <source>Skip Beta check at startup</source>
+        <translation>Visa inte beta-varning vid uppstart</translation>
+    </message>
+    <message>
+        <source>Continue running in background when Openambit main window is closed</source>
+        <translation>Låt Openambit fortsätta köra i bakgrunden när fönstret stängs</translation>
+    </message>
+    <message>
+        <source>Device syncronisation settings</source>
+        <translation>Synkroniseringsinställningar</translation>
+    </message>
+    <message>
+        <source>Sync time from computer</source>
+        <translation>Synkronisera enhet med datorns tid</translation>
+    </message>
+    <message>
+        <source>Sync orbital data (from Movescount)</source>
+        <translation>Synkronisera GPS-data (från Movescount)</translation>
+    </message>
+    <message>
+        <source>Start sync automatically when device connected</source>
+        <translation>Starta synkroniseringen automatiskt när enhet ansluts</translation>
+    </message>
+    <message>
+        <source>Movescount connectivity</source>
+        <translation>Movescount-inställningar</translation>
+    </message>
+    <message>
+        <source>Check Movescount for new versions</source>
+        <translation>Leta efter firmware-uppdatering hos Movescount</translation>
+    </message>
+    <message>
+        <source>Generate debug files (XMLs stored in ~/.openambit/movescount)</source>
+        <translation>Generera felsökningsfiler (XML-filer som sparas i ~/.openambit/movescount)</translation>
+    </message>
+    <message>
+        <source>Sync logs with Movescount</source>
+        <translation>Ladda upp loggar till Movescount</translation>
+    </message>
+    <message>
+        <source>Email (Movescount account)</source>
+        <translation>E-post (till ditt Movescount-konto)</translation>
+    </message>
+</context>
+</TS>
diff --git a/tools/movescountXmlDiff.pl b/tools/movescountXmlDiff.pl
index 0548b7d..d37054c 100755
--- a/tools/movescountXmlDiff.pl
+++ b/tools/movescountXmlDiff.pl
@@ -1,157 +1,140 @@
-#!/usr/bin/perl
+#!/usr/bin/perl -w
 
-#use strict;
-#use warnings;
+use strict;
+use warnings;
 
-my $diffText = `diff -w $ARGV[0] $ARGV[1]`;
-
-my @lines = split /\n/, $diffText;
+if ( $#ARGV != 1 ) {
+        die "$0 FILE1 FILE2\n";
+}
 
 my @records;
-my $currentRecordLine;
-my $currentRecordRemoveLines;
-my $currentRecordAddLines;
-my $currentRecordStarted = 0;
+{
+        my @lines = `diff -w $ARGV[0] $ARGV[1]`;
+        chomp @lines;
+        my $currentRecordLine;
+        my $currentRecordRemoveLines;
+        my $currentRecordAddLines;
+        my $currentRecordStarted = 0;
 
-foreach my $line (@lines) {
-    if ($line =~ m/[0-9,\-]+[c|d|a][0-9,\-]+/g) {
-        if ($currentRecordStarted == 1) {
-            my %currentRecord = ( "LinesText" => $currentRecordLine,
-                                  "RemoveLines" => $currentRecordRemoveLines,
-                                  "AddLines" => $currentRecordAddLines
-                );
-            push(@records, \%currentRecord);
+        foreach (@lines) {
+                if ( m/[0-9,\-]+[c|d|a][0-9,\-]+/g) {
+                        if ( $currentRecordStarted ) {
+                                push @records, { 'LinesText' => $currentRecordLine, 'RemoveLines' => $currentRecordRemoveLines, 'AddLines' => $currentRecordAddLines, };
+                        }
+                        $currentRecordLine = $_;
+                        $currentRecordRemoveLines = [];
+                        $currentRecordAddLines = [];
+                        $currentRecordStarted = 1;
+                } elsif ( m/^</g) {
+                        push(@{$currentRecordRemoveLines}, $_);
+                } elsif ( m/^>/g) {
+                        push(@{$currentRecordAddLines}, $_);
+                }
         }
-        $currentRecordLine = $line;
-        $currentRecordRemoveLines = [];
-        $currentRecordAddLines = [];
-        $currentRecordStarted = 1;
-    }
-    elsif ($line =~ m/^</g) {
-        push(@{$currentRecordRemoveLines}, $line);
-    }
-    elsif ($line =~ m/^>/g) {
-        push(@{$currentRecordAddLines}, $line);
-    }
 }
 
-foreach my $entry (@records) {
+my @matchRemove;
+my @matchAdd;
+my $Epsilon = 0.00000000000005;
+foreach (@records) {
     my $printDiff = 1;
 
-    if (scalar @{$entry->{"RemoveLines"}} == scalar @{$entry->{"AddLines"}}) {
-        my $diffFound = scalar @{$entry->{"RemoveLines"}};
-        for ($i = 0; $i < scalar @{$entry->{"RemoveLines"}}; $i++) {
-            if ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<HR>([0-9\.]+)<\/HR>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<HR>([0-9\.]+)<\/HR>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+    if (scalar @{$_->{"RemoveLines"}} == scalar @{$_->{"AddLines"}}) {
+        my $diffFound = scalar @{$_->{"RemoveLines"}};
+        for (my $i = 0; $i < scalar @{$_->{"RemoveLines"}}; $i++) {
+            if ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<HR>([0-9\.]+)<\/HR>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<HR>([0-9\.]+)<\/HR>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Latitude>([\-0-9\.]+)<\/Latitude>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Latitude>([\-0-9\.]+)<\/Latitude>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.000000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.000000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Latitude>([\-0-9\.]+)<\/Latitude>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Latitude>([\-0-9\.]+)<\/Latitude>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Longitude>([\-0-9\.]+)<\/Longitude>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Longitude>([\-0-9\.]+)<\/Longitude>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.000000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.000000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Longitude>([\-0-9\.]+)<\/Longitude>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Longitude>([\-0-9\.]+)<\/Longitude>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Speed>([0-9\.]+)<\/Speed>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Speed>([0-9\.]+)<\/Speed>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Speed>([0-9\.]+)<\/Speed>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Speed>([0-9\.]+)<\/Speed>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<VerticalSpeed>([\-0-9\.]+)<\/VerticalSpeed>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<VerticalSpeed>([\-0-9\.]+)<\/VerticalSpeed>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<VerticalSpeed>([\-0-9\.]+)<\/VerticalSpeed>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<VerticalSpeed>([\-0-9\.]+)<\/VerticalSpeed>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<GPSHeading>([\-0-9\.]+)<\/GPSHeading>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<GPSHeading>([\-0-9\.]+)<\/GPSHeading>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<GPSHeading>([\-0-9\.]+)<\/GPSHeading>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<GPSHeading>([\-0-9\.]+)<\/GPSHeading>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<GPSSpeed>([0-9\.]+)<\/GPSSpeed>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<GPSSpeed>([0-9\.]+)<\/GPSSpeed>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<GPSSpeed>([0-9\.]+)<\/GPSSpeed>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<GPSSpeed>([0-9\.]+)<\/GPSSpeed>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<GPSAltitude>([0-9\.]+)<\/GPSAltitude>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<GPSAltitude>([0-9\.]+)<\/GPSAltitude>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<GPSAltitude>([0-9\.]+)<\/GPSAltitude>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<GPSAltitude>([0-9\.]+)<\/GPSAltitude>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<EHPE>([0-9\.]+)<\/EHPE>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<EHPE>([0-9\.]+)<\/EHPE>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<EHPE>([0-9\.]+)<\/EHPE>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<EHPE>([0-9\.]+)<\/EHPE>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Duration>([0-9\.]+)<\/Duration>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Duration>([0-9\.]+)<\/Duration>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Duration>([0-9\.]+)<\/Duration>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Duration>([0-9\.]+)<\/Duration>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Time>([0-9\.]+)<\/Time>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Time>([0-9\.]+)<\/Time>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Time>([0-9\.]+)<\/Time>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Time>([0-9\.]+)<\/Time>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<EnergyConsumption>([0-9\.]+)<\/EnergyConsumption>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<EnergyConsumption>([0-9\.]+)<\/EnergyConsumption>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<EnergyConsumption>([0-9\.]+)<\/EnergyConsumption>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<EnergyConsumption>([0-9\.]+)<\/EnergyConsumption>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<PeakTrainingEffect>([0-9\.]+)<\/PeakTrainingEffect>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<PeakTrainingEffect>([0-9\.]+)<\/PeakTrainingEffect>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<PeakTrainingEffect>([0-9\.]+)<\/PeakTrainingEffect>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<PeakTrainingEffect>([0-9\.]+)<\/PeakTrainingEffect>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<BatteryCharge>([0-9\.]+)<\/BatteryCharge>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<BatteryCharge>([0-9\.]+)<\/BatteryCharge>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<BatteryCharge>([0-9\.]+)<\/BatteryCharge>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<BatteryCharge>([0-9\.]+)<\/BatteryCharge>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<BatteryChargeAtStart>([0-9\.]+)<\/BatteryChargeAtStart>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<BatteryChargeAtStart>([0-9\.]+)<\/BatteryChargeAtStart>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<BatteryChargeAtStart>([0-9\.]+)<\/BatteryChargeAtStart>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<BatteryChargeAtStart>([0-9\.]+)<\/BatteryChargeAtStart>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Avg>([0-9\.]+)<\/Avg>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Avg>([0-9\.]+)<\/Avg>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Avg>([0-9\.]+)<\/Avg>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Avg>([0-9\.]+)<\/Avg>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<Max>([0-9\.]+)<\/Max>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<Max>([0-9\.]+)<\/Max>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.00000000000005 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.00000000000005) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<Max>([0-9\.]+)<\/Max>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<Max>([0-9\.]+)<\/Max>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  $Epsilon ) {
                     $diffFound--;
                 }
             }
-            #elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2})Z<\/UTC>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2})Z<\/UTC>/g))) {
-            #    if ((@matchRemove[0] - @matchAdd[0]) <= 1 &&
-            #        (@matchRemove[0] - @matchAdd[0]) >= -1) {
+            #elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2})Z<\/UTC>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2})Z<\/UTC>/g))) {
+            #    if (($matchRemove[0] - $matchAdd[0]) <= 1 &&
+            #        ($matchRemove[0] - $matchAdd[0]) >= -1) {
             #        $diffFound--;
             #    }
             #}
-            elsif ((@matchRemove = (@{$entry->{"RemoveLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}\.[0-9]{3})Z<\/UTC>/g)) && (@matchAdd = (@{$entry->{"AddLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}\.[0-9]{3})Z<\/UTC>/g))) {
-                if ((@matchRemove[0] - @matchAdd[0]) < 0.002 &&
-                    (@matchRemove[0] - @matchAdd[0]) > -0.002) {
+            elsif ((@matchRemove = (@{$_->{"RemoveLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}\.[0-9]{3})Z<\/UTC>/g)) && (@matchAdd = (@{$_->{"AddLines"}}[$i] =~ m/<UTC>[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}\.[0-9]{3})Z<\/UTC>/g))) {
+		if ( abs(($matchRemove[0] - $matchAdd[0])) <  0.002 ) {
                     $diffFound--;
                 }
             }
@@ -162,14 +145,14 @@ foreach my $entry (@records) {
     }
 
     if ($printDiff == 1) {
-        print $entry->{"LinesText"}, "\n";
-        foreach my $remLine (@{$entry->{"RemoveLines"}}) {
+        print $_->{"LinesText"}, "\n";
+        foreach my $remLine (@{$_->{"RemoveLines"}}) {
             print $remLine, "\n";
         }
-        if (scalar @{$entry->{"RemoveLines"}} > 0 &&  scalar @{$entry->{"AddLines"}} > 0) {
+        if (scalar @{$_->{"RemoveLines"}} > 0 &&  scalar @{$_->{"AddLines"}} > 0) {
             print "---\n";
         }
-        foreach my $remLine (@{$entry->{"AddLines"}}) {
+        foreach my $remLine (@{$_->{"AddLines"}}) {
             print $remLine, "\n";
         }
     }
diff --git a/tools/openambit2gpx.py b/tools/openambit2gpx.py
index 4f7b813..60e1ebe 100644
--- a/tools/openambit2gpx.py
+++ b/tools/openambit2gpx.py
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 
-""" concerts the *.log files produced by openambit in ~/.openambit/ to standard gpx format.
+""" converts the *.log files produced by openambit in ~/.openambit/ to standard gpx format.
 usage: ./openambit2gpx.py inputfile outputFile
 """
 
@@ -13,9 +13,17 @@ import sys
 ## getting input parameters ##
 ##############################
 
-fileIn=sys.argv[1]
-fileOut=sys.argv[2]
+if len(sys.argv) == 3:
+    fileIn=sys.argv[1]
+    fileOut=sys.argv[2]
+else:
+    sys.stderr.write("""\
+Convert Openambit *.log files to standard GPX format
+usage: {} inputfile outputfile 
 
+Openambit *.log files can normally be found in ~/.openambit/
+""".format(sys.argv[0]))
+    sys.exit(1)
 
 ###########################################
 ## setting variables up, starting output ##
@@ -84,7 +92,7 @@ for element in rootIn.iterfind("Log/Samples/Sample"):
 
     altitude=element.findtext("Altitude") if element.findtext("Altitude")!=None else altitudeLast
     hr=element.findtext("HR") if element.findtext("HR")!=None else hrLast
-    cadence=element.findtext("Cadence") if element.findtext("cadence")!=None else cadenceLast
+    cadence=element.findtext("Cadence") if element.findtext("Cadence")!=None else cadenceLast
     speed=element.findtext("Speed") if element.findtext("Speed")!=None else speedLast
     temp=str(float(element.findtext("Temperature"))/10) if element.findtext("Temperature")!=None else tempLast
     airpressure=element.findtext("SeaLevelPressure") if element.findtext("SeaLevelPressure")!=None else airpressureLast
diff --git a/wireshark_dissector/CMakeLists.txt b/wireshark_dissector/CMakeLists.txt
index d6061aa..45a932b 100644
--- a/wireshark_dissector/CMakeLists.txt
+++ b/wireshark_dissector/CMakeLists.txt
@@ -25,7 +25,7 @@ project(ambit-wireshark-plugin C)
 
 cmake_minimum_required(VERSION 2.6)
 set(CMAKE_BACKWARDS_COMPATIBILITY 2.6)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
 set(CMAKE_INSTALL_LIBDIR ~/.wireshark)
 
 INCLUDE(UseMakeDissectorReg)
@@ -70,15 +70,16 @@ register_dissector_files(plugin.c
 	${DISSECTOR_SRC}
 )
 
-add_library(ambit ${LINK_MODE_MODULE}
+add_library(ws-ambit ${LINK_MODE_MODULE}
 	${PLUGIN_FILES}
 )
-set_target_properties(ambit PROPERTIES PREFIX "")
-set_target_properties(ambit PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}")
+set_target_properties(ws-ambit PROPERTIES OUTPUT_NAME "ambit")
+set_target_properties(ws-ambit PROPERTIES PREFIX "")
+set_target_properties(ws-ambit PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}")
 
-target_link_libraries(ambit ${WIRESHARK_LIBRARIES})
+target_link_libraries(ws-ambit ${WIRESHARK_LIBRARIES})
 
-install(TARGETS ambit
+install(TARGETS ws-ambit
 	LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/plugins NAMELINK_SKIP
 )
 
diff --git a/wireshark_dissector/ambit-dissector.c b/wireshark_dissector/ambit-dissector.c
index f664607..fe6eb16 100644
--- a/wireshark_dissector/ambit-dissector.c
+++ b/wireshark_dissector/ambit-dissector.c
@@ -61,6 +61,10 @@ static gint dissect_ambit_lock_status_get(tvbuff_t *tvb, packet_info *pinfo, pro
 static gint dissect_ambit_lock_status_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
 static gint dissect_ambit_lock_set(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
 static gint dissect_ambit_lock_set_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
+static gint dissect_ambit_gps_data_peek_get(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
+static gint dissect_ambit_gps_data_peek_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
+static gint dissect_ambit_data_write(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
+static gint dissect_ambit_data_write_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
 
 static gint dissect_ambit3_settings_get(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
 static gint dissect_ambit3_settings_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_);
@@ -151,6 +155,7 @@ static int hf_ambit_log_header_sample_count = -1;
 static int hf_ambit_log_header_energy = -1;
 static int hf_ambit_log_header_cadence_max = -1;
 static int hf_ambit_log_header_cadence_avg = -1;
+static int hf_ambit_log_header_swimming_lengths = -1;
 static int hf_ambit_log_header_speed_max_time = -1;
 static int hf_ambit_log_header_alt_max_time = -1;
 static int hf_ambit_log_header_alt_min_time = -1;
@@ -159,6 +164,7 @@ static int hf_ambit_log_header_hr_min_time = -1;
 static int hf_ambit_log_header_temp_max_time = -1;
 static int hf_ambit_log_header_temp_min_time = -1;
 static int hf_ambit_log_header_cadence_max_time = -1;
+static int hf_ambit_log_header_swimming_pool_length = -1;
 static int hf_ambit_log_header_time_first_fix = -1;
 static int hf_ambit_log_header_battery_start = -1;
 static int hf_ambit_log_header_battery_stop = -1;
@@ -238,8 +244,25 @@ static int hf_ambit_log_altitude_source_type = -1;
 static int hf_ambit_log_altitude_source_altitude_offset = -1;
 static int hf_ambit_log_altitude_source_pressure_offset = -1;
 
+static int hf_ambit_log_cadence_source_type = -1;
+
+static int hf_ambit_log_fwinfo_build_date = -1;
+
+static int hf_ambit_log_swimming_turn_distance = -1;
+static int hf_ambit_log_swimming_turn_lengths = -1;
+static int hf_ambit_log_swimming_turn_lengths_wo_change = -1;
+static int hf_ambit_log_swimming_turn_classification0 = -1;
+static int hf_ambit_log_swimming_turn_classification1 = -1;
+static int hf_ambit_log_swimming_turn_classification2 = -1;
+static int hf_ambit_log_swimming_turn_classification3 = -1;
+static int hf_ambit_log_swimming_turn_prev_style = -1;
+
+static int hf_ambit_log_delayed_store = -1;
+
 static int hf_ambit_log_ibi = -1;
 
+static int hf_ambit_gps_data_head = -1;
+
 static gint ett_ambit = -1;
 static gint ett_ambit_data = -1;
 static gint ett_ambit_log_data = -1;
@@ -296,8 +319,12 @@ static const value_string log_samples_time_event_type_vals[] = {
 };
 
 static const value_string log_samples_distance_source_type_vals[] = {
+    { 0x00, "Bikepod" },
+    { 0x01, "Footpod" },
     { 0x02, "GPS" },
     { 0x03, "Wrist" },
+    { 0x04, "Indoorswimming" },
+    { 0x05, "Outdoorswimming" },
     { 0, NULL }
 };
 
@@ -306,6 +333,21 @@ static const value_string log_samples_altitude_source_type_vals[] = {
     { 0, NULL }
 };
 
+static const value_string log_samples_cadence_source_type_vals[] = {
+    { 0x40, "Wrist" },
+    { 0, NULL }
+};
+
+static const value_string log_samples_swimming_style_vals[] = {
+    { 0x00, "Other" },
+    { 0x01, "Butterfly" },
+    { 0x02, "Backstroke" },
+    { 0x03, "Breaststroke" },
+    { 0x04, "Freestyle" },
+    { 0x05, "Drill" },
+    { 0, NULL }
+};
+
 static const ambit_protocol_type_t subdissectors[] = {
     { 0x03000500, "Set time", dissect_ambit_time_write },
     { 0x03000a00, "Time reply", dissect_ambit_time_reply },
@@ -329,6 +371,10 @@ static const ambit_protocol_type_t subdissectors[] = {
     { 0x0b0a0a00, "Log header step reply", dissect_ambit_log_header_step_reply },
     { 0x0b0b0500, "Get log header", dissect_ambit_log_header_get },
     { 0x0b0b0a00, "Log header reply", dissect_ambit_log_header_reply },
+    { 0x0b150500, "GPS data peek request", dissect_ambit_gps_data_peek_get },
+    { 0x0b150a00, "GPS data peek reply", dissect_ambit_gps_data_peek_reply },
+    { 0x0b160500, "Data write", dissect_ambit_data_write },
+    { 0x0b160a00, "Data write reply", dissect_ambit_data_write_reply },
     { 0x0b170500, "Get log data", dissect_ambit_log_data_get },
     { 0x0b170a00, "Log data reply", dissect_ambit_log_data_reply },
     { 0x0b190500, "Get lock status", dissect_ambit_lock_status_get },
@@ -363,7 +409,11 @@ static void dissect_ambit_add_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_t
 {
     proto_item *unknown_item = NULL;
     unknown_item = proto_tree_add_item(tree, hf_ambit_unknown, tvb, offset, len, ENC_LITTLE_ENDIAN);
+#if VERSION_MAJOR >= 1 && VERSION_MINOR >= 11
+    /* TODO port to new expert info API */
+#else
     expert_add_info_format(pinfo, unknown_item, PI_UNDECODED, PI_WARN, "Not dissected yet");
+#endif
 }
 
 static gint dissect_ambit_date_write(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
@@ -640,8 +690,10 @@ static gint dissect_ambit_log_header_reply(tvbuff_t *tvb, packet_info *pinfo, pr
         offset += 1;
         proto_tree_add_item(tree, hf_ambit_log_header_cadence_avg, tvb, offset, 1, ENC_LITTLE_ENDIAN);
         offset += 1;
-        dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 4);
-        offset += 4;
+        dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 2);
+        offset += 2;
+        proto_tree_add_item(tree, hf_ambit_log_header_swimming_lengths, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+        offset += 2;
         proto_tree_add_item(tree, hf_ambit_log_header_speed_max_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
         offset += 4;
         proto_tree_add_item(tree, hf_ambit_log_header_alt_max_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
@@ -658,7 +710,7 @@ static gint dissect_ambit_log_header_reply(tvbuff_t *tvb, packet_info *pinfo, pr
         offset += 4;
         proto_tree_add_item(tree, hf_ambit_log_header_cadence_max_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
         offset += 4;
-        dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 4);
+        proto_tree_add_item(tree, hf_ambit_log_header_swimming_pool_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
         offset += 4;
         proto_tree_add_item(tree, hf_ambit_log_header_time_first_fix, tvb, offset, 2, ENC_LITTLE_ENDIAN);
         offset += 2;
@@ -958,9 +1010,12 @@ static gint dissect_ambit_log_data_content(tvbuff_t *tvb, packet_info *pinfo, pr
     if (offset + 1 >= length) return offset;
     proto_tree_add_item(tree, hf_ambit_log_header_cadence_avg, tvb, offset, 1, ENC_LITTLE_ENDIAN);
     offset += 1;
-    if (offset + 4 >= length) return offset;
-    dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 4);
-    offset += 4;
+    if (offset + 2 >= length) return offset;
+    dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 2);
+    offset += 2;
+    if (offset + 2 >= length) return offset;
+    proto_tree_add_item(tree, hf_ambit_log_header_swimming_lengths, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+    offset += 2;
     if (offset + 4 >= length) return offset;
     proto_tree_add_item(tree, hf_ambit_log_header_speed_max_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
     offset += 4;
@@ -986,7 +1041,7 @@ static gint dissect_ambit_log_data_content(tvbuff_t *tvb, packet_info *pinfo, pr
     proto_tree_add_item(tree, hf_ambit_log_header_cadence_max_time, tvb, offset, 4, ENC_LITTLE_ENDIAN);
     offset += 4;
     if (offset + 4 >= length) return offset;
-    dissect_ambit_add_unknown(tvb, pinfo, tree, offset, 4);
+    proto_tree_add_item(tree, hf_ambit_log_header_swimming_pool_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
     offset += 4;
     if (offset + 2 >= length) return offset;
     proto_tree_add_item(tree, hf_ambit_log_header_time_first_fix, tvb, offset, 2, ENC_LITTLE_ENDIAN);
@@ -1448,6 +1503,64 @@ static gint dissect_ambit_log_data_sample(tvbuff_t *tvb, packet_info *pinfo, pro
                 dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, sample_len - 9);
             }
             break;
+          case 0x14:
+            sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Swimming turn)", (*sampleno)++);
+            sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_time_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 1);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_delayed_store, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 1);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_distance, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_lengths, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 4);
+            offset += 4;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 2);
+            offset += 2;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 8);
+            offset += 8;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_lengths_wo_change, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_classification0, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_classification1, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_classification2, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_classification3, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_prev_style, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, 1);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_swimming_turn_distance, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            break;
+          case 0x15:
+            sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Swimming stroke)", (*sampleno)++);
+            sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_time_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_delayed_store, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            break;
           case 0x18:
             sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Activity)", (*sampleno)++);
             sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
@@ -1467,6 +1580,23 @@ static gint dissect_ambit_log_data_sample(tvbuff_t *tvb, packet_info *pinfo, pro
                 dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, sample_len - 12);
             }
             break;
+          case 0x1a:
+            sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Cadence source)", (*sampleno)++);
+            sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_time_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_cadence_source_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            if (offset < sample_len - 2) {
+                dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, sample_len - 7);
+            }
+            break;
           case 0x1b:
             sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (lat-long)", (*sampleno)++);
             sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
@@ -1490,6 +1620,35 @@ static gint dissect_ambit_log_data_sample(tvbuff_t *tvb, packet_info *pinfo, pro
                 dissect_ambit_add_unknown(tvb, pinfo, sample_tree, offset, sample_len - 14);
             }
             break;
+          case 0x1c:
+            sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Firmware info)", (*sampleno)++);
+            sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
+            offset += 2;
+            proto_tree_add_item(sample_tree, hf_ambit_log_sample_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_time_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+            offset += 4;
+            proto_tree_add_item(sample_tree, hf_ambit_log_other_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
+            offset += 1;
+            {
+                guint8 fw1,fw2;
+                guint16 fw3;
+                fw1 = tvb_get_guint8(tvb, offset);
+                fw2 = tvb_get_guint8(tvb, offset+1);
+                fw3 = tvb_get_letohs(tvb, offset+2);
+                proto_tree_add_string_format_value(sample_tree, hf_ambit_fw_version, tvb, offset, 4, "FW version", "%d.%d.%d", fw1, fw2, fw3);
+                offset += 4;
+                guint16 year = tvb_get_letohs(tvb, offset);
+                guint8 month = tvb_get_guint8(tvb, offset + 2);
+                guint8 day = tvb_get_guint8(tvb, offset + 3);
+                guint8 hour = tvb_get_guint8(tvb, offset + 4);
+                guint8 minute = tvb_get_guint8(tvb, offset + 5);
+                guint16 seconds = tvb_get_letohs(tvb, offset + 6);
+                proto_tree_add_string_format_value(sample_tree, hf_ambit_log_fwinfo_build_date, tvb, offset, 8, "Builddate", "%04d-%02d-%02d %02d:%02d:%2.3f", year, month, day, hour, minute, ((float)seconds/1000.0));
+                offset += 8;
+            }
+            break;
           default:
             sample_ti = proto_tree_add_text(tree, tvb, offset, sample_len + 2, "Sample #%u (Unknown)", (*sampleno)++);
             sample_tree = proto_item_add_subtree(sample_ti, ett_ambit_log_sample);
@@ -1528,6 +1687,29 @@ static gint dissect_ambit_lock_set_reply(tvbuff_t *tvb, packet_info *pinfo, prot
 {
 }
 
+static gint dissect_ambit_gps_data_peek_get(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+}
+
+static gint dissect_ambit_gps_data_peek_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+    proto_tree_add_item(tree, hf_ambit_gps_data_head, tvb, 0, 9, ENC_LITTLE_ENDIAN);
+}
+
+static gint dissect_ambit_data_write(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+    guint32 length = tvb_get_letohl(tvb, 4);
+
+    proto_tree_add_item(tree, hf_ambit_log_data_address, tvb, 0, 4, ENC_LITTLE_ENDIAN);
+    proto_tree_add_item(tree, hf_ambit_log_data_length, tvb, 4, 4, ENC_LITTLE_ENDIAN);
+
+    proto_tree_add_text(tree, tvb, 8, length, "Payload");
+}
+
+static gint dissect_ambit_data_write_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+}
+
 static gint dissect_ambit3_settings_get(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
 {
 }
@@ -2114,6 +2296,8 @@ proto_register_ambit(void)
           { "Cadence max (rpm)", "ambit.log_header.cadence_max", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_cadence_avg,
           { "Cadence avg (rpm)", "ambit.log_header.cadence_avg", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_header_swimming_lengths,
+          { "Swimming pool lengths", "ambit.log_header.swimming_lengths", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_speed_max_time,
           { "Time max speed (ms)", "ambit.log_header.speed_maxtime", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_alt_max_time,
@@ -2130,6 +2314,8 @@ proto_register_ambit(void)
           { "Time min temperature (ms)", "ambit.log_header.temp_mintime", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_cadence_max_time,
           { "Time max cadence (ms)", "ambit.log_header.cadence_maxtime", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_header_swimming_pool_length,
+          { "Swimming pool length (m)", "ambit.log_header.swimming_pool_length", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_time_first_fix,
           { "Time of first fix", "ambit.log_header.time_first_fix", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_header_battery_start,
@@ -2277,9 +2463,37 @@ proto_register_ambit(void)
           { "Altitude offset", "ambit.log_sample.altitude_source.alt_offset", FT_INT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
         { &hf_ambit_log_altitude_source_pressure_offset,
           { "Pressure", "ambit.log_sample.altitude_source.pres_offset", FT_INT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_cadence_source_type,
+          { "Type", "ambit.log_sample.cadence_source.type", FT_UINT8, BASE_HEX, VALS(log_samples_cadence_source_type_vals), 0x0,NULL, HFILL } },
+
+        { &hf_ambit_log_fwinfo_build_date,
+          { "Build date", "ambit.log_sample.fwinfo.builddate", FT_STRING, BASE_NONE, NULL, 0x0,NULL, HFILL } },
+
+        { &hf_ambit_log_swimming_turn_distance,
+          { "Distance (cm)", "ambit.log_sample.swimming_turn.distance", FT_UINT32, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_lengths,
+          { "Total pool lengths", "ambit.log_sample.swimming_turn.lengths", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_lengths_wo_change,
+          { "Total pool lengths w/o style change(!?)", "ambit.log_sample.swimming_turn.lengths_wo_change", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_prev_style,
+          { "Style", "ambit.log_sample.swimming_turn.style", FT_UINT8, BASE_HEX, VALS(log_samples_swimming_style_vals), 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_classification0,
+          { "ClassificationVector[0]", "ambit.log_sample.swimming_turn.classification0", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_classification1,
+          { "ClassificationVector[1]", "ambit.log_sample.swimming_turn.classification1", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_classification2,
+          { "ClassificationVector[2]", "ambit.log_sample.swimming_turn.classification2", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+        { &hf_ambit_log_swimming_turn_classification3,
+          { "ClassificationVector[3]", "ambit.log_sample.swimming_turn.classification3", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+
+        { &hf_ambit_log_delayed_store,
+          { "Log write delay (1/10 s)", "ambit.log_sample.delayed_store", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
 
         { &hf_ambit_log_ibi,
           { "IBI entry", "ambit.log_sample.ibi", FT_UINT16, BASE_DEC, NULL, 0x0,NULL, HFILL } },
+
+        { &hf_ambit_gps_data_head,
+          { "Current GPS position data version", "ambit.gps.data.head", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } },
     };
 
     static gint *ett[] = {
diff --git a/wireshark_dissector/cmake/FindWireshark.cmake b/wireshark_dissector/cmake/FindWireshark.cmake
index 2cfae6e..13b9695 100644
--- a/wireshark_dissector/cmake/FindWireshark.cmake
+++ b/wireshark_dissector/cmake/FindWireshark.cmake
@@ -16,7 +16,7 @@
 # wireshark does not install its library with pkg-config information,
 # so we need to manually find the libraries and headers
 
-FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/column_info.h PATH_SUFFIXES wireshark )
+FIND_PATH( WIRESHARK_INCLUDE_DIRS epan/packet.h PATH_SUFFIXES wireshark )
 FIND_LIBRARY( WIRESHARK_LIBRARIES wireshark PATH_SUFFIXES wireshark )
 
 # Report results
diff --git a/wireshark_dissector/cmake/UseMakeDissectorReg.cmake b/wireshark_dissector/cmake/UseMakeDissectorReg.cmake
index e7e1a73..3a09e05 100644
--- a/wireshark_dissector/cmake/UseMakeDissectorReg.cmake
+++ b/wireshark_dissector/cmake/UseMakeDissectorReg.cmake
@@ -20,14 +20,14 @@ MACRO(REGISTER_DISSECTOR_FILES _outputfile _registertype )
 	    OUTPUT 
 	      ${_outputfile}
 	    COMMAND ${PYTHON_EXECUTABLE}
-	      ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py
+	      ${CMAKE_CURRENT_SOURCE_DIR}/tools/make-dissector-reg.py
 	      ${CMAKE_CURRENT_SOURCE_DIR}
 	      ${_registertype}
 	      ${_sources}
 	    DEPENDS
 	      ${_sources}
-	      ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg
-	      ${CMAKE_SOURCE_DIR}/tools/make-dissector-reg.py
+	      ${CMAKE_CURRENT_SOURCE_DIR}/tools/make-dissector-reg
+	      ${CMAKE_CURRENT_SOURCE_DIR}/tools/make-dissector-reg.py
 	)
 ENDMACRO(REGISTER_DISSECTOR_FILES)
 

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