From 3d8daf1ac6eb62b367deb7f7eda24f660a4851bc Mon Sep 17 00:00:00 2001
From: phfriedl <phfriedl@student.ethz.ch>
Date: Mon, 3 Apr 2017 16:31:38 +0200
Subject: [PATCH] Updated crazyradio client library

---
 .../src/d_fall_pps/crazyradio/CrazyRadio.py   |   8 +-
 .../crazyradio/cfclient/__init__.py           |  37 +-
 .../crazyradio/cfclient/__init__.pyc          | Bin 526 -> 0 bytes
 .../crazyradio/cfclient/cfclient.pyc          | Bin 3443 -> 0 bytes
 .../crazyradio/cfclient/configs/config.json   |  32 +-
 .../cfclient/configs/input/Generic_OS_X.json  |   0
 .../cfclient/configs/input/Joystick.json      | 190 ++---
 .../cfclient/configs/input/PS3_Mode_1.json    |   0
 .../cfclient/configs/input/PS3_Mode_2.json    |   0
 .../cfclient/configs/input/PS3_Mode_3.json    |  98 +--
 .../cfclient/configs/input/PS4_Mode_1.json    | 106 +--
 .../cfclient/configs/input/PS4_Mode_2.json    | 106 +--
 .../configs/input/PS4_shoulder_btns_yaw.json  |   0
 .../cfclient/configs/input/xbox360_mode1.json | 174 ++---
 .../cfclient/configs/log/stabilizer.json      |   0
 .../cfclient/{cfclient.py => gui.py}          |  66 +-
 .../crazyradio/cfclient/headless.py           | 173 +++++
 .../crazyradio/cfclient/icon-256.png          | Bin
 .../crazyradio/cfclient/resources/map.html    |  14 +
 .../crazyradio/cfclient/resources/map.js      |  25 +
 .../crazyradio/cfclient/ui/__init__.py        |  10 +-
 .../crazyradio/cfclient/ui/__init__.pyc       | Bin 467 -> 0 bytes
 .../cfclient/ui/dialogs/__init__.py           |   0
 .../cfclient/ui/dialogs/__init__.pyc          | Bin 171 -> 0 bytes
 .../crazyradio/cfclient/ui/dialogs/about.py   | 122 ++--
 .../crazyradio/cfclient/ui/dialogs/about.pyc  | Bin 6672 -> 0 bytes
 .../crazyradio/cfclient/ui/dialogs/about.ui   |   0
 .../cfclient/ui/dialogs/bootloader.py         |  52 +-
 .../cfclient/ui/dialogs/bootloader.pyc        | Bin 11724 -> 0 bytes
 .../cfclient/ui/dialogs/bootloader.ui         |   0
 .../cfclient/ui/dialogs/cf1config.py          |  51 +-
 .../cfclient/ui/dialogs/cf1config.pyc         | Bin 11202 -> 0 bytes
 .../cfclient/ui/dialogs/cf1config.ui          |   0
 .../cfclient/ui/dialogs/cf2config.py          |  36 +-
 .../cfclient/ui/dialogs/cf2config.pyc         | Bin 4257 -> 0 bytes
 .../cfclient/ui/dialogs/cf2config.ui          |   0
 .../cfclient/ui/dialogs/connectiondialogue.py | 122 ----
 .../ui/dialogs/connectiondialogue.pyc         | Bin 4769 -> 0 bytes
 .../cfclient/ui/dialogs/connectiondialogue.ui | 102 ---
 .../ui/dialogs/inputconfigdialogue.py         | 272 +++----
 .../ui/dialogs/inputconfigdialogue.pyc        | Bin 19318 -> 0 bytes
 .../ui/dialogs/inputconfigdialogue.ui         |  10 +-
 .../cfclient/ui/dialogs/logconfigdialogue.py  |  78 +-
 .../cfclient/ui/dialogs/logconfigdialogue.pyc | Bin 11145 -> 0 bytes
 .../cfclient/ui/dialogs/logconfigdialogue.ui  |   0
 .../d_fall_pps/crazyradio/cfclient/ui/main.py | 539 +++++++++-----
 .../crazyradio/cfclient/ui/main.pyc           | Bin 22709 -> 0 bytes
 .../d_fall_pps/crazyradio/cfclient/ui/main.ui | 203 ++++--
 .../crazyradio/cfclient/ui/pluginhelper.py    |   7 +-
 .../crazyradio/cfclient/ui/pluginhelper.pyc   | Bin 857 -> 0 bytes
 .../d_fall_pps/crazyradio/cfclient/ui/tab.py  |  28 +-
 .../d_fall_pps/crazyradio/cfclient/ui/tab.pyc | Bin 2814 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/ConsoleTab.py |  60 +-
 .../cfclient/ui/tabs/ConsoleTab.pyc           | Bin 1935 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/ExampleTab.py |  26 +-
 .../cfclient/ui/tabs/ExampleTab.pyc           | Bin 4045 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/FlightTab.py  | 295 ++++----
 .../crazyradio/cfclient/ui/tabs/FlightTab.pyc | Bin 22594 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/GpsTab.py     | 265 ++-----
 .../crazyradio/cfclient/ui/tabs/GpsTab.pyc    | Bin 8654 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/LEDTab.py     |  44 +-
 .../crazyradio/cfclient/ui/tabs/LEDTab.pyc    | Bin 7144 -> 0 bytes
 .../cfclient/ui/tabs/LogBlockDebugTab.py      |  40 +-
 .../cfclient/ui/tabs/LogBlockDebugTab.pyc     | Bin 3746 -> 0 bytes
 .../cfclient/ui/tabs/LogBlockTab.py           |  54 +-
 .../cfclient/ui/tabs/LogBlockTab.pyc          | Bin 14996 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/LogTab.py     |  38 +-
 .../crazyradio/cfclient/ui/tabs/LogTab.pyc    | Bin 2830 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/ParamTab.py   |  52 +-
 .../crazyradio/cfclient/ui/tabs/ParamTab.pyc  | Bin 10768 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/PlotTab.py    |  80 ++-
 .../crazyradio/cfclient/ui/tabs/PlotTab.pyc   | Bin 9626 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/__init__.py   |  52 +-
 .../crazyradio/cfclient/ui/tabs/__init__.pyc  | Bin 1101 -> 0 bytes
 .../crazyradio/cfclient/ui/tabs/consoleTab.ui |  43 +-
 .../crazyradio/cfclient/ui/tabs/exampleTab.ui |   0
 .../crazyradio/cfclient/ui/tabs/flightTab.ui  |  24 +-
 .../crazyradio/cfclient/ui/tabs/gpsTab.ui     |  82 ++-
 .../crazyradio/cfclient/ui/tabs/ledTab.ui     |   0
 .../cfclient/ui/tabs/locopositioning_tab.py   | 671 ++++++++++++++++++
 .../cfclient/ui/tabs/locopositioning_tab.ui   | 338 +++++++++
 .../cfclient/ui/tabs/logBlockDebugTab.ui      |   0
 .../cfclient/ui/tabs/logBlockTab.ui           |   0
 .../crazyradio/cfclient/ui/tabs/logTab.ui     |   0
 .../crazyradio/cfclient/ui/tabs/paramTab.ui   |   0
 .../crazyradio/cfclient/ui/tabs/plotTab.ui    |   0
 .../cfclient/ui/toolboxes/ConsoleToolbox.py   |  48 +-
 .../cfclient/ui/toolboxes/ConsoleToolbox.pyc  | Bin 2448 -> 0 bytes
 .../cfclient/ui/toolboxes/CrtpSharkToolbox.py |  93 +--
 .../ui/toolboxes/CrtpSharkToolbox.pyc         | Bin 5286 -> 0 bytes
 .../ui/toolboxes/DebugDriverToolbox.py        |  40 +-
 .../ui/toolboxes/DebugDriverToolbox.pyc       | Bin 4458 -> 0 bytes
 .../cfclient/ui/toolboxes/__init__.py         |  36 +-
 .../cfclient/ui/toolboxes/__init__.pyc        | Bin 1136 -> 0 bytes
 .../cfclient/ui/toolboxes/consoleToolbox.ui   |   0
 .../cfclient/ui/toolboxes/crtpSharkToolbox.ui |   0
 .../ui/toolboxes/debugDriverToolbox.ui        |   0
 .../cfclient/ui/widgets/__init__.py           |   9 +-
 .../cfclient/ui/widgets/__init__.pyc          | Bin 238 -> 0 bytes
 .../crazyradio/cfclient/ui/widgets/ai.py      | 161 ++---
 .../crazyradio/cfclient/ui/widgets/ai.pyc     | Bin 8343 -> 0 bytes
 .../cfclient/ui/widgets/hexspinbox.py         |  18 +-
 .../cfclient/ui/widgets/hexspinbox.pyc        | Bin 2777 -> 0 bytes
 .../crazyradio/cfclient/ui/widgets/plotter.ui |   0
 .../cfclient/ui/widgets/plotwidget.py         | 124 ++--
 .../cfclient/ui/widgets/plotwidget.pyc        | Bin 10686 -> 0 bytes
 .../crazyradio/cfclient/utils/__init__.py     |   6 +-
 .../crazyradio/cfclient/utils/__init__.pyc    | Bin 190 -> 0 bytes
 .../crazyradio/cfclient/utils/config.py       |  21 +-
 .../crazyradio/cfclient/utils/config.pyc      | Bin 3450 -> 0 bytes
 .../cfclient/utils/config_manager.py          |  88 ++-
 .../cfclient/utils/config_manager.pyc         | Bin 3562 -> 0 bytes
 .../crazyradio/cfclient/utils/guiconfig.pyc   | Bin 1832 -> 0 bytes
 .../crazyradio/cfclient/utils/input.pyc       | Bin 11733 -> 0 bytes
 .../cfclient/utils/input/__init__.py          | 176 +++--
 .../cfclient/utils/input/__init__.pyc         | Bin 13812 -> 0 bytes
 .../utils/input/inputinterfaces/__init__.py   |  44 +-
 .../utils/input/inputinterfaces/__init__.pyc  | Bin 3290 -> 0 bytes
 .../utils/input/inputinterfaces/leapmotion.py |  44 +-
 .../input/inputinterfaces/leapmotion.pyc      | Bin 6071 -> 0 bytes
 .../utils/input/inputinterfaces/wiimote.py    |  22 +-
 .../utils/input/inputinterfaces/wiimote.pyc   | Bin 6087 -> 0 bytes
 .../utils/input/inputinterfaces/zmqpull.py    |  33 +-
 .../utils/input/inputinterfaces/zmqpull.pyc   | Bin 4432 -> 0 bytes
 .../utils/input/inputreaderinterface.py       |  49 +-
 .../utils/input/inputreaderinterface.pyc      | Bin 8721 -> 0 bytes
 .../utils/input/inputreaders/__init__.py      |  37 +-
 .../utils/input/inputreaders/__init__.pyc     | Bin 4311 -> 0 bytes
 .../utils/input/inputreaders/linuxjsdev.py    |  45 +-
 .../utils/input/inputreaders/linuxjsdev.pyc   | Bin 9030 -> 0 bytes
 .../utils/input/inputreaders/pysdl2.py        |  92 +--
 .../utils/input/inputreaders/pysdl2.pyc       | Bin 8270 -> 0 bytes
 .../cfclient/utils/input/mux/__init__.py      |  35 +-
 .../cfclient/utils/input/mux/__init__.pyc     | Bin 3102 -> 0 bytes
 .../cfclient/utils/input/mux/nomux.py         |   9 +-
 .../cfclient/utils/input/mux/nomux.pyc        | Bin 1267 -> 0 bytes
 .../cfclient/utils/input/mux/takeovermux.py   |  16 +-
 .../cfclient/utils/input/mux/takeovermux.pyc  | Bin 1396 -> 0 bytes
 .../utils/input/mux/takeoverselectivemux.py   |  15 +-
 .../utils/input/mux/takeoverselectivemux.pyc  | Bin 2001 -> 0 bytes
 .../cfclient/utils/joystick/__init__.pyc      | Bin 245 -> 0 bytes
 .../cfclient/utils/joystick/linuxjsdev.pyc    | Bin 9305 -> 0 bytes
 .../cfclient/utils/logconfigreader.py         |  30 +-
 .../cfclient/utils/logconfigreader.pyc        | Bin 4251 -> 0 bytes
 .../cfclient/utils/logdatawriter.py           |  15 +-
 .../cfclient/utils/logdatawriter.pyc          | Bin 3823 -> 0 bytes
 .../cfclient/utils/periodictimer.py           |   9 +-
 .../cfclient/utils/periodictimer.pyc          | Bin 2914 -> 0 bytes
 .../cfclient/utils/pysdl2reader.pyc           | Bin 5784 -> 0 bytes
 .../crazyradio/cfclient/utils/singleton.py    |   6 +-
 .../crazyradio/cfclient/utils/singleton.pyc   | Bin 899 -> 0 bytes
 .../cfclient/utils/zmq_led_driver.py          |  11 +-
 .../cfclient/utils/zmq_led_driver.pyc         | Bin 3608 -> 0 bytes
 .../crazyradio/cfclient/utils/zmq_param.py    |  20 +-
 .../crazyradio/cfclient/utils/zmq_param.pyc   | Bin 3797 -> 0 bytes
 .../d_fall_pps/crazyradio/cflib/__init__.pyc  | Bin 1182 -> 1185 bytes
 .../crazyradio/cflib/crazyflie/__init__.pyc   | Bin 15562 -> 15661 bytes
 .../crazyradio/cflib/crazyflie/commander.pyc  | Bin 2173 -> 2188 bytes
 .../crazyradio/cflib/crazyflie/console.pyc    | Bin 1678 -> 1690 bytes
 .../crazyradio/cflib/crazyflie/log.pyc        | Bin 19930 -> 20023 bytes
 .../crazyradio/cflib/crazyflie/mem.pyc        | Bin 27976 -> 28147 bytes
 .../crazyradio/cflib/crazyflie/param.pyc      | Bin 11522 -> 11588 bytes
 .../cflib/crazyflie/platformservice.pyc       | Bin 1580 -> 1592 bytes
 .../crazyradio/cflib/crazyflie/toc.pyc        | Bin 7071 -> 7119 bytes
 .../crazyradio/cflib/crazyflie/toccache.pyc   | Bin 3809 -> 3830 bytes
 .../crazyradio/cflib/crtp/__init__.pyc        | Bin 2559 -> 2574 bytes
 .../crazyradio/cflib/crtp/crtpdriver.pyc      | Bin 3669 -> 3705 bytes
 .../crazyradio/cflib/crtp/crtpstack.pyc       | Bin 5176 -> 5224 bytes
 .../crazyradio/cflib/crtp/debugdriver.pyc     | Bin 27858 -> 27966 bytes
 .../crazyradio/cflib/crtp/exceptions.pyc      | Bin 1069 -> 1078 bytes
 .../crazyradio/cflib/crtp/radiodriver.pyc     | Bin 12349 -> 12421 bytes
 .../crazyradio/cflib/crtp/serialdriver.pyc    | Bin 1867 -> 1885 bytes
 .../crazyradio/cflib/crtp/udpdriver.pyc       | Bin 3552 -> 3582 bytes
 .../crazyradio/cflib/crtp/usbdriver.pyc       | Bin 7434 -> 7482 bytes
 .../crazyradio/cflib/drivers/__init__.pyc     | Bin 254 -> 257 bytes
 .../crazyradio/cflib/drivers/cfusb.pyc        | Bin 5866 -> 5902 bytes
 .../crazyradio/cflib/drivers/crazyradio.pyc   | Bin 9622 -> 9682 bytes
 .../crazyradio/cflib/utils/__init__.pyc       | Bin 241 -> 244 bytes
 .../crazyradio/cflib/utils/callbacks.pyc      | Bin 1737 -> 1755 bytes
 179 files changed, 3843 insertions(+), 2334 deletions(-)
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/config.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Generic_OS_X.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Joystick.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_1.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_2.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_3.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_1.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_2.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_shoulder_btns_yaw.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/xbox360_mode1.json
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/log/stabilizer.json
 rename pps_ws/src/d_fall_pps/crazyradio/cfclient/{cfclient.py => gui.py} (75%)
 mode change 100755 => 100644
 create mode 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/headless.py
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/icon-256.png
 create mode 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.html
 create mode 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.js
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.ui
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/consoleTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/exampleTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/flightTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/gpsTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ledTab.ui
 create mode 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.py
 create mode 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockDebugTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/paramTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/plotTab.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/consoleToolbox.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/crtpSharkToolbox.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/debugDriverToolbox.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotter.ui
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/guiconfig.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/__init__.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/linuxjsdev.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.pyc
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/pysdl2reader.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.pyc
 mode change 100755 => 100644 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.py
 delete mode 100755 pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.pyc

diff --git a/pps_ws/src/d_fall_pps/crazyradio/CrazyRadio.py b/pps_ws/src/d_fall_pps/crazyradio/CrazyRadio.py
index 1734c465..1ee59cb1 100755
--- a/pps_ws/src/d_fall_pps/crazyradio/CrazyRadio.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/CrazyRadio.py
@@ -94,7 +94,7 @@ class PPSRadioClient:
 
 def motorCommandCallback(data):
     """Callback for motor controller actions"""
-    cf_client._send_to_commander(0, 0, 0, 0, data.cmd1 * 10000, data.cmd2 * 10000, data.cmd3 * 10000, data.cmd4 * 10000, CONTROLLER_MOTOR)
+    cf_client._send_to_commander(0, 0, 0, 0, data.cmd1 * 1000, data.cmd2 * 1000, data.cmd3 * 1000, data.cmd4 * 1000, CONTROLLER_MOTOR)
     rospy.loginfo("motor controller callback: %s, %s, %s, %s", data.cmd1, data.cmd2, data.cmd3, data.cmd4)
 
 def angleCommandCallback(data):
@@ -121,13 +121,17 @@ if __name__ == '__main__':
         available=[]
         available = cflib.crtp.scan_interfaces()
         rospy.loginfo("Crazyflies found:")
+        for i in available:
+            rospy.loginfo("----------------------------------------------------------------")
+            rospy.loginfo(i[0])
         for i in available:
             print i[0]
         if len(available) > 0:
             global cf_client
 
             #TODO: load address from parameters
-            cf_client = PPSRadioClient(available[0][0])
+            cf_client = PPSRadioClient("radio://0/72/2M")
+            #cf_client = PPSRadioClient(available[0][0])
             time.sleep(2.0)
             #TODO: change publisher name if not correct
             rospy.Subscriber("/PPSClient/MotorCommand", MotorCommand, motorCommandCallback)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.py
old mode 100755
new mode 100644
index e3208939..bedfb2dc
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.py
@@ -24,21 +24,28 @@
 #  this program; if not, write to the Free Software Foundation, Inc., 51
 #  Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
-from .cfclient import main
+import os
+from appdirs import AppDirs
+import sys
 
-try:
-    from .version import VERSION
-except:
-    try:
-        import subprocess
-        VERSION = subprocess.check_output(["git", "describe"])
-    except:
-        VERSION = "dev"
+# Path used all over the application
+if not hasattr(sys, 'frozen'):
+    module_path = os.path.dirname(__file__)
+else:
+    module_path = os.path.dirname(sys.executable)
+config_path = AppDirs("cfclient", "Bitcraze").user_config_dir
 
+# Locate the sdl2 lib on Windows (should be in cfclient/thirst_party/)
+if os.name == 'nt':
+    os.environ["PYSDL2_DLL_PATH"] = os.path.join(module_path, "third_party")
+
+if not hasattr(sys, 'frozen'):
+    import pkg_resources
     try:
-        import subprocess
-        ret = subprocess.call(["git", "diff", "--quiet", "HEAD"])
-        if ret > 0:
-            VERSION += "+"
-    except:
-        VERSION += "+"
+        VERSION = pkg_resources.require("cfclient")[0].version
+    except pkg_resources.DistributionNotFound:
+        VERSION = "dev"
+else:
+    import json
+    with open(os.path.join(module_path, "version.json")) as f:
+        VERSION = json.load(f)['version']
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/__init__.pyc
deleted file mode 100755
index 8c79f1b6984af0d16b764ba41f46662cedd7fbf9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 526
zcmZWk-AV#M7(L^zu9-rCHz9Nv2%=tg6H%a0HwFqSd$Z`yXp{S+JF~)G_X<5huhB)X
z6!ZY~%~*8N{G8#OnRC8xoX<w>qvKCQ{ERZ4H?-9|0jI?f0WpKmz>21oN{C8`9rzB|
zEO`NAthfMoz+FTxd>6vSQyH9A1?v)?$?jm5G|W@(8Imx}i@`rr#hR+%N8mNAU2F9q
zJn&;|Tx72hRHu$hlL5?jZzl6kBR)6T)XJpYpg%}P&^Dl5f_Nd51M`SYhvUip!$^M7
z7-@%;wbZ&wCl@Nr<Wg9Xi@h~-xmqdX>vng!6xxb+!`p!*4cZjxw2j+FgsU);BGF@e
zX>5CuDVZi?+f9uGl`pqh8VaR!ooM(d!cCCodYd1z!$lO?4l<$JCgu-Ri)gRckL0rd
tTd5xeGLbq6dfURba22OKkHocktIi2dN)Br>hi09f5!Q&;S&Q~5v2TZ$VWa>6

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.pyc
deleted file mode 100755
index 6054b91a78b93015ac313504f2b88b0f3a1b2edb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/config.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/config.json
old mode 100755
new mode 100644
index c78d5b0e..bb92591e
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/config.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/config.json
@@ -1,16 +1,16 @@
 {
   "writable" : {
-    "input_device": "", 
-    "link_uri": "", 
-    "flightmode": "Normal", 
-    "open_tabs": "Flight Control", 
-    "trim_pitch": 0.0, 
-    "slew_limit": 45, 
-    "slew_rate": 30, 
-    "trim_roll": 0.0, 
-    "max_thrust": 80, 
-    "min_thrust": 25, 
-    "max_yaw": 200, 
+    "input_device": "",
+    "link_uri": "",
+    "flightmode": "Normal",
+    "open_tabs": "Flight Control",
+    "trim_pitch": 0.0,
+    "slew_limit": 45,
+    "slew_rate": 30,
+    "trim_roll": 0.0,
+    "max_thrust": 80,
+    "min_thrust": 25,
+    "max_yaw": 200,
     "max_rp": 30,
     "client_side_xmode": false,
     "auto_reconnect": false,
@@ -21,11 +21,11 @@
     "enable_zmq_input": false
   },
   "read-only" : {
-    "normal_slew_limit": 45, 
-    "normal_slew_rate": 30, 
-    "normal_max_thrust": 80, 
-    "normal_min_thrust": 25, 
-    "normal_max_yaw": 200, 
+    "normal_slew_limit": 45,
+    "normal_slew_rate": 30,
+    "normal_max_thrust": 80,
+    "normal_min_thrust": 25,
+    "normal_max_yaw": 200,
     "normal_max_rp": 30,
     "default_cf_channel": 10,
     "default_cf_speed": 0,
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Generic_OS_X.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Generic_OS_X.json
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Joystick.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Joystick.json
old mode 100755
new mode 100644
index 00e1a5ed..42299c4a
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Joystick.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/Joystick.json
@@ -1,95 +1,95 @@
-{
-  "inputconfig": {
-    "inputdevice": {
-      "updateperiod": 10, 
-      "springythrottle": false,
-      "name": "Joystick", 
-      "axis": [
-        {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 3, 
-          "key": "thrust", 
-          "name": "thrust"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 2, 
-          "key": "yaw", 
-          "name": "yaw"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 0, 
-          "key": "roll", 
-          "name": "roll"
-        }, 
-        {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 1, 
-          "key": "pitch", 
-          "name": "pitch"
-        }, 
-        {
-          "scale": 1.0,
-          "type": "Input.HAT",
-          "id": 0,
-          "key": "trim",
-          "name": "trim"
-        },
-        {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 4, 
-          "key": "pitchNeg",
-          "name": "pitchNeg"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 5, 
-          "key": "pitchPos",
-          "name": "pitchPos"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 1, 
-          "key": "estop", 
-          "name": "killswitch"
-        }, 
-        {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 2, 
-          "key": "rollNeg",
-          "name": "rollNeg"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 3, 
-          "key": "rollPos",
-          "name": "rollPos"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 0, 
-          "key": "althold", 
-          "name": "althold"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 6, 
-          "key": "exit", 
-          "name": "exitapp"
-        }
-      ]
-    }
-  }
-}
+{
+  "inputconfig": {
+    "inputdevice": {
+      "updateperiod": 10,
+      "springythrottle": false,
+      "name": "Joystick",
+      "axis": [
+        {
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 3,
+          "key": "thrust",
+          "name": "thrust"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 2,
+          "key": "yaw",
+          "name": "yaw"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 0,
+          "key": "roll",
+          "name": "roll"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 1,
+          "key": "pitch",
+          "name": "pitch"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.HAT",
+          "id": 0,
+          "key": "trim",
+          "name": "trim"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 4,
+          "key": "pitchNeg",
+          "name": "pitchNeg"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 5,
+          "key": "pitchPos",
+          "name": "pitchPos"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 1,
+          "key": "estop",
+          "name": "killswitch"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 2,
+          "key": "rollNeg",
+          "name": "rollNeg"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 3,
+          "key": "rollPos",
+          "name": "rollPos"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 0,
+          "key": "althold",
+          "name": "althold"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 6,
+          "key": "exit",
+          "name": "exitapp"
+        }
+      ]
+    }
+  }
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_1.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_1.json
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_2.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_2.json
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_3.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_3.json
old mode 100755
new mode 100644
index 18fea844..2a55cb98
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_3.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS3_Mode_3.json
@@ -1,83 +1,83 @@
 {
   "inputconfig": {
     "inputdevice": {
-      "updateperiod": 10, 
-      "name": "PS3_Mode_3", 
+      "updateperiod": 10,
+      "name": "PS3_Mode_3",
       "axis": [
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 1, 
-          "key": "thrust", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 1,
+          "key": "thrust",
           "name": "thrust"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
           "ids": [
-            12, 
+            12,
             13
-          ], 
-          "key": "yaw", 
+          ],
+          "key": "yaw",
           "name": "yaw"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 2, 
-          "key": "roll", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 2,
+          "key": "roll",
           "name": "roll"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 3, 
-          "key": "pitch", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 3,
+          "key": "pitch",
           "name": "pitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 6, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 6,
           "key": "pitchNeg",
           "name": "pitchNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 4, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 4,
           "key": "pitchPos",
           "name": "pitchPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 14, 
-          "key": "estop", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 14,
+          "key": "estop",
           "name": "killswitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 7, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 7,
           "key": "rollNeg",
           "name": "rollNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 5, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 5,
           "key": "rollPos",
           "name": "rollPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 12, 
-          "key": "exit", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 12,
+          "key": "exit",
           "name": "exitapp"
         }
       ]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_1.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_1.json
old mode 100755
new mode 100644
index 15e0010d..d8c58825
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_1.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_1.json
@@ -1,87 +1,87 @@
 {
   "inputconfig": {
     "inputdevice": {
-      "updateperiod": 10, 
-      "name": "PS4_Mode_1", 
+      "updateperiod": 10,
+      "name": "PS4_Mode_1",
       "axis": [
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 5, 
-          "key": "thrust", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 5,
+          "key": "thrust",
           "name": "thrust"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 2, 
-          "key": "yaw", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 2,
+          "key": "yaw",
           "name": "yaw"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 0, 
-          "key": "roll", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 0,
+          "key": "roll",
           "name": "roll"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 1, 
-          "key": "pitch", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 1,
+          "key": "pitch",
           "name": "pitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 1, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 1,
           "key": "pitchNeg",
           "name": "pitchNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 3, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 3,
           "key": "pitchPos",
           "name": "pitchPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 12, 
-          "key": "estop", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 12,
+          "key": "estop",
           "name": "killswitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 0, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 0,
           "key": "rollNeg",
           "name": "rollNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 2, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 2,
           "key": "rollPos",
           "name": "rollPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 5, 
-          "key": "althold", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 5,
+          "key": "althold",
           "name": "althold"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 8, 
-          "key": "exit", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 8,
+          "key": "exit",
           "name": "exitapp"
         }
       ]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_2.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_2.json
old mode 100755
new mode 100644
index f369ebdc..6b9ef6a1
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_2.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_Mode_2.json
@@ -1,87 +1,87 @@
 {
   "inputconfig": {
     "inputdevice": {
-      "updateperiod": 10, 
-      "name": "PS4_Mode_2", 
+      "updateperiod": 10,
+      "name": "PS4_Mode_2",
       "axis": [
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 1, 
-          "key": "thrust", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 1,
+          "key": "thrust",
           "name": "thrust"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 0, 
-          "key": "yaw", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 0,
+          "key": "yaw",
           "name": "yaw"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 2, 
-          "key": "roll", 
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 2,
+          "key": "roll",
           "name": "roll"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 5, 
-          "key": "pitch", 
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 5,
+          "key": "pitch",
           "name": "pitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 1, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 1,
           "key": "pitchNeg",
           "name": "pitchNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 3, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 3,
           "key": "pitchPos",
           "name": "pitchPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 7, 
-          "key": "estop", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 7,
+          "key": "estop",
           "name": "killswitch"
-        }, 
+        },
         {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": 0, 
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": 0,
           "key": "rollNeg",
           "name": "rollNeg"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 2, 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 2,
           "key": "rollPos",
           "name": "rollPos"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 4, 
-          "key": "althold", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 4,
+          "key": "althold",
           "name": "althold"
-        }, 
+        },
         {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 8, 
-          "key": "exit", 
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 8,
+          "key": "exit",
           "name": "exitapp"
         }
       ]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_shoulder_btns_yaw.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/PS4_shoulder_btns_yaw.json
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/xbox360_mode1.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/xbox360_mode1.json
old mode 100755
new mode 100644
index 0ca5d032..57691456
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/xbox360_mode1.json
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/input/xbox360_mode1.json
@@ -1,87 +1,87 @@
-{
-  "inputconfig": {
-    "inputdevice": {
-      "updateperiod": 10, 
-      "name": "xbox360_mode1_linux", 
-      "axis": [
-        {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 4, 
-          "key": "thrust", 
-          "name": "thrust"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 3, 
-          "key": "yaw", 
-          "name": "yaw"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.AXIS", 
-          "id": 0, 
-          "key": "roll", 
-          "name": "roll"
-        }, 
-        {
-          "scale": -1.0, 
-          "type": "Input.AXIS", 
-          "id": 1, 
-          "key": "pitch", 
-          "name": "pitch"
-        }, 
-        {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "pitchNeg",
-          "name": "pitchNeg"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "pitchPos",
-          "name": "pitchPos"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "estop", 
-          "name": "killswitch"
-        }, 
-        {
-          "scale": -1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "rollNeg",
-          "name": "rollNeg"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "rollPos",
-          "name": "rollPos"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": 5, 
-          "key": "althold", 
-          "name": "althold"
-        }, 
-        {
-          "scale": 1.0, 
-          "type": "Input.BUTTON", 
-          "id": -1, 
-          "key": "exit", 
-          "name": "exitapp"
-        }
-      ]
-    }
-  }
-}
\ No newline at end of file
+{
+  "inputconfig": {
+    "inputdevice": {
+      "updateperiod": 10,
+      "name": "xbox360_mode1_linux",
+      "axis": [
+        {
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 4,
+          "key": "thrust",
+          "name": "thrust"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 3,
+          "key": "yaw",
+          "name": "yaw"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.AXIS",
+          "id": 0,
+          "key": "roll",
+          "name": "roll"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.AXIS",
+          "id": 1,
+          "key": "pitch",
+          "name": "pitch"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "pitchNeg",
+          "name": "pitchNeg"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "pitchPos",
+          "name": "pitchPos"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "estop",
+          "name": "killswitch"
+        },
+        {
+          "scale": -1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "rollNeg",
+          "name": "rollNeg"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "rollPos",
+          "name": "rollPos"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": 5,
+          "key": "althold",
+          "name": "althold"
+        },
+        {
+          "scale": 1.0,
+          "type": "Input.BUTTON",
+          "id": -1,
+          "key": "exit",
+          "name": "exitapp"
+        }
+      ]
+    }
+  }
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/log/stabilizer.json b/pps_ws/src/d_fall_pps/crazyradio/cfclient/configs/log/stabilizer.json
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/gui.py
old mode 100755
new mode 100644
similarity index 75%
rename from pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.py
rename to pps_ws/src/d_fall_pps/crazyradio/cfclient/gui.py
index 81b3594b..7c0526e3
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/cfclient.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/gui.py
@@ -26,9 +26,6 @@
 
 """Initialization of the PC Client GUI."""
 
-__author__ = 'Bitcraze AB'
-__all__ = ['']
-
 import sys
 import os
 import argparse
@@ -36,9 +33,13 @@ import datetime
 
 import logging
 
+import cfclient
 
-def main():
+__author__ = 'Bitcraze AB'
+__all__ = []
 
+
+def main():
     """
     Check starting conditions and start GUI.
 
@@ -47,17 +48,17 @@ def main():
     to stdout and start the GUI.
     """
 
-    # Set ERROR level for PyQt4 logger
-    qtlogger = logging.getLogger('PyQt4')
+    # Set ERROR level for PyQt5 logger
+    qtlogger = logging.getLogger('PyQt5')
     qtlogger.setLevel(logging.ERROR)
 
-    parser = argparse.ArgumentParser(description="cfclient - "
-                                     "Crazyflie graphical control client")
+    parser = argparse.ArgumentParser(
+        description="cfclient - Crazyflie graphical control client")
     parser.add_argument('--debug', '-d', nargs=1, default='info', type=str,
                         help="set debug level "
-                        "[minimal, info, debug, debugfile]")
+                             "[minimal, info, debug, debugfile]")
     args = parser.parse_args()
-    globals().update(vars(args))
+    debug = args.debug
 
     cflogger = logging.getLogger('')
 
@@ -80,28 +81,28 @@ def main():
         logging.basicConfig(level=logging.INFO)
 
     logger = logging.getLogger(__name__)
-    
-    logger.debug("Using config path {}".format(sys.path[1]))
+
+    logger.debug("Using config path {}".format(cfclient.config_path))
     logger.debug("sys.path={}".format(sys.path))
 
     # Try all the imports used in the project here to control what happens....
     try:
-        import usb
+        import usb  # noqa
     except ImportError:
         logger.critical("No pyusb installation found, exiting!")
         sys.exit(1)
 
     if not sys.platform.startswith('linux'):
         try:
-            import sdl2
+            import sdl2  # noqa
         except ImportError:
             logger.critical("No pysdl2 installation found, exiting!")
             sys.exit(1)
 
     try:
-        import PyQt4
+        import PyQt5  # noqa
     except ImportError:
-        logger.critical("No PyQT4 installation found, exiting!")
+        logger.critical("No PyQT5 installation found, exiting!")
         sys.exit(1)
 
     # Disable printouts from STL
@@ -110,28 +111,49 @@ def main():
         os.dup2(os.open('/dev/null', os.O_WRONLY), 1)
         sys.stdout = os.fdopen(stdout, 'w')
         logger.info("Disabling STL printouts")
-    
+
     if os.name == 'nt':
         stdout = os.dup(1)
         os.dup2(os.open('NUL', os.O_WRONLY), 1)
         sys.stdout = os.fdopen(stdout, 'w')
         logger.info("Disabling STL printouts")
 
+    if sys.platform == 'darwin':
+        try:
+            import Foundation
+            bundle = Foundation.NSBundle.mainBundle()
+            if bundle:
+                info = (bundle.localizedInfoDictionary() or
+                        bundle.infoDictionary())
+                if info:
+                    info['CFBundleName'] = 'Crazyflie'
+        except ImportError:
+            logger.info("Foundation not found. Menu will show python as "
+                        "application name")
+
     # Start up the main user-interface
-    from ui.main import MainUI
-    from PyQt4.QtGui import QApplication, QIcon
+    from .ui.main import MainUI
+    from PyQt5.QtWidgets import QApplication
+    from PyQt5.QtGui import QIcon
+
     app = QApplication(sys.argv)
 
-    app.setWindowIcon(QIcon(sys.path[0] + "/cfclient/icon-256.png"))
+    app.setWindowIcon(QIcon(cfclient.module_path + "/icon-256.png"))
     # Make sure the right icon is set in Windows 7+ taskbar
     if os.name == 'nt':
         import ctypes
+
         try:
             myappid = 'mycompany.myproduct.subproduct.version'
-            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
+            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
+                myappid)
         except Exception:
             pass
-    
+
     main_window = MainUI()
     main_window.show()
     sys.exit(app.exec_())
+
+
+if __name__ == "__main__":
+    main()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/headless.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/headless.py
new file mode 100644
index 00000000..29dca85e
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/headless.py
@@ -0,0 +1,173 @@
+# -*- coding: utf-8 -*-
+#
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
+#  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
+#  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
+#   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
+#
+#  Copyright (C) 2013 Bitcraze AB
+#
+#  Crazyflie Nano Quadcopter Client
+#
+#  This program 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 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, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+#  MA  02110-1301, USA.
+"""
+Headless client for the Crazyflie.
+"""
+import logging
+import os
+import signal
+import sys
+
+import cfclient.utils
+import cflib.crtp
+from cfclient.utils.input import JoystickReader
+from cflib.crazyflie import Crazyflie
+
+if os.name == 'posix':
+    print('Disabling standard output for libraries!')
+    stdout = os.dup(1)
+    os.dup2(os.open('/dev/null', os.O_WRONLY), 1)
+    sys.stdout = os.fdopen(stdout, 'w')
+
+# set SDL to use the dummy NULL video driver,
+#   so it doesn't need a windowing system.
+os.environ["SDL_VIDEODRIVER"] = "dummy"
+
+
+class HeadlessClient():
+    """Crazyflie headless client"""
+
+    def __init__(self):
+        """Initialize the headless client and libraries"""
+        cflib.crtp.init_drivers()
+
+        self._jr = JoystickReader(do_device_discovery=False)
+
+        self._cf = Crazyflie(ro_cache=None,
+                             rw_cache=cfclient.config_path + "/cache")
+
+        signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+        self._devs = []
+
+        for d in self._jr.available_devices():
+            self._devs.append(d.name)
+
+    def setup_controller(self, input_config, input_device=0, xmode=False):
+        """Set up the device reader"""
+        # Set up the joystick reader
+        self._jr.device_error.add_callback(self._input_dev_error)
+        print("Client side X-mode: %s" % xmode)
+        if (xmode):
+            self._cf.commander.set_client_xmode(xmode)
+
+        devs = self._jr.available_devices()  # noqa, is this a bug?
+        print("Will use [%s] for input" % self._devs[input_device])
+        self._jr.start_input(self._devs[input_device])
+        self._jr.set_input_map(self._devs[input_device], input_config)
+
+    def controller_connected(self):
+        """ Return True if a controller is connected"""
+        return True if (len(self._jr.available_devices()) > 0) else False
+
+    def list_controllers(self):
+        """List the available controllers and input mapping"""
+        print("\nAvailable controllers:")
+        for i, dev in enumerate(self._devs):
+            print(" - Controller #{}: {}".format(i, dev))
+        print("\nAvailable input mapping:")
+        for map in os.listdir(cfclient.config_path + '/input'):
+            print(" - " + map.split(".json")[0])
+
+    def connect_crazyflie(self, link_uri):
+        """Connect to a Crazyflie on the given link uri"""
+        self._cf.connection_failed.add_callback(self._connection_failed)
+        # 2014-11-25 chad: Add a callback for when we have a good connection.
+        self._cf.connected.add_callback(self._connected)
+        self._cf.param.add_update_callback(
+            group="imu_sensors", name="HMC5883L", cb=(
+                lambda name, found: self._jr.set_alt_hold_available(
+                    eval(found))))
+        self._jr.assisted_control_updated.add_callback(
+            lambda enabled: self._cf.param.set_value("flightmode.althold",
+                                                     enabled))
+
+        self._cf.open_link(link_uri)
+        self._jr.input_updated.add_callback(self._cf.commander.send_setpoint)
+
+    def _connected(self, link):
+        """Callback for a successful Crazyflie connection."""
+        print("Connected to {}".format(link))
+
+    def _connection_failed(self, link, message):
+        """Callback for a failed Crazyflie connection"""
+        print("Connection failed on {}: {}".format(link, message))
+        sys.exit(-1)
+
+    def _input_dev_error(self, message):
+        """Callback for an input device error"""
+        print("Error when reading device: {}".format(message))
+        sys.exit(-1)
+
+
+def main():
+    """Main Crazyflie headless application"""
+    import argparse
+
+    parser = argparse.ArgumentParser(prog="cfheadless")
+    parser.add_argument("-u", "--uri", action="store", dest="uri", type=str,
+                        default="radio://0/10/250K",
+                        help="URI to use for connection to the Crazyradio"
+                             " dongle, defaults to radio://0/10/250K")
+    parser.add_argument("-i", "--input", action="store", dest="input",
+                        type=str, default="PS3_Mode_1",
+                        help="Input mapping to use for the controller,"
+                             "defaults to PS3_Mode_1")
+    parser.add_argument("-d", "--debug", action="store_true", dest="debug",
+                        help="Enable debug output")
+    parser.add_argument("-c", "--controller", action="store", type=int,
+                        dest="controller", default=0,
+                        help="Use controller with specified id,"
+                             " id defaults to 0")
+    parser.add_argument("--controllers", action="store_true",
+                        dest="list_controllers",
+                        help="Only display available controllers and exit")
+    parser.add_argument("-x", "--x-mode", action="store_true",
+                        dest="xmode",
+                        help="Enable client-side X-mode")
+    (args, unused) = parser.parse_known_args()
+
+    if args.debug:
+        logging.basicConfig(level=logging.DEBUG)
+    else:
+        logging.basicConfig(level=logging.INFO)
+
+    headless = HeadlessClient()
+
+    if (args.list_controllers):
+        headless.list_controllers()
+    else:
+        if headless.controller_connected():
+            headless.setup_controller(input_config=args.input,
+                                      input_device=args.controller,
+                                      xmode=args.xmode)
+            headless.connect_crazyflie(link_uri=args.uri)
+        else:
+            print("No input-device connected, exiting!")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/icon-256.png b/pps_ws/src/d_fall_pps/crazyradio/cfclient/icon-256.png
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.html b/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.html
new file mode 100644
index 00000000..1bd5f016
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
+    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
+    <style>
+        body { padding: 0; margin: 0; }
+        html, body, #map { height: 100%; }
+    </style>
+</head>
+<body>
+    <div id="map"></div>
+</body>
+</html>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.js b/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.js
new file mode 100644
index 00000000..8afb80b0
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/resources/map.js
@@ -0,0 +1,25 @@
+var map = L.map('map').setView([55.607526, 13.018219], 16);
+L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png', {
+    maxZoom: 18,
+    attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
+        'tiles Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a>',
+    subdomains: '1',//'1234',
+}).addTo(map);
+
+var cf = L.circle([55.607526, 13.018219], 1, {
+    color: 'blue',
+    fillColor: 'blue',
+    fillOpacity: 1
+}).addTo(map);
+
+var accuracy = L.circle([55.607526, 13.018219], 0, {
+    color: 'red',
+    fillColor: '#f03',
+    fillOpacity: 0.5
+}).addTo(map);
+
+if(typeof MainWindow != 'undefined') {
+    var onMapMove = function() { MainWindow.onMapMove(map.getCenter().lat, map.getCenter().lng) };
+    map.on('move', onMapMove);
+    onMapMove();
+}
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.py
old mode 100755
new mode 100644
index 51d3a306..d81873b0
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.py
@@ -21,18 +21,18 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Create a plugin helper that is passed to all the tabs and toolboxes for easy #
 access to objects that are needed.
 """
 
+from cfclient.ui.pluginhelper import PluginHelper
+
 __author__ = 'Bitcraze AB'
 __all__ = []
 
-from cfclient.ui.pluginhelper import PluginHelper
-
 pluginhelper = PluginHelper()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/__init__.pyc
deleted file mode 100755
index c104e7ddfe707c932c60f7d3a900cc8a2627a688..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 467
zcmYjMF;2uV5Oi|60|k&M=~#&-&BY%;2#$sVAp}&{SdP7SF>>N4b|j9Lj;HY*9suhE
z1eQG+&p5lYv(KZv`FMX)>}RF)y`<wgfo5z?n6P!iw!~AWY0sFQu_j~dj3t<{H!|i-
zXY8?<#~(dGe%+%C2ogFwY)uO_+75dNwG3c9bkcj&5FAKrNks^<@*vx&Ia|3G^ssR~
zp!7R9%cWB2eSGh#XH<b`tR#Dc7Ez-vbALd6S0<=lz9L+$%onX9Au${h+>beK#u#_S
zBFcLNLTIOi2>Hn65Ng-cb+RZM@e{JtMp=VxC<jwc6HNm>kT=!;uNG1L1Aj|bUb_Z)
z^^=cxy&LD?G45_d#g|hDzwCAtqUF|9{I@M13>U(*CJ0fIzfT3v8>a`07pKI16c*_s
IS)|A5H!JmkbpQYW

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.py
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/__init__.pyc
deleted file mode 100755
index 5f70eceb5bdffb7217e4898413ba04e8b69a74cb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 171
zcmZSn%*&N~sw*U!0SXv_v;z<qvjB+{28Lh_kcgiKkYGR~ibH^6`WgATsrpHoCCNpJ
zRjK*~Mfq8&$tA`5AZ}$^PG+iZGLXnCDb_8hEXl~v)6dCF(oar<2<n$+>ZfET=H#ar
h>&M4u=4F<|$Lj&raR3dr$<0qG%}KQbSzipq3;<T1D-Qqw

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.py
old mode 100755
new mode 100644
index b89b6176..4b5d4536
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.py
@@ -20,37 +20,37 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 The about dialog.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['AboutDialog']
-
 import sys
 
-from PyQt4 import Qt, QtCore, QtGui, uic
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4.Qt import *
-
 import cfclient
-
 import cflib.crtp
+from PyQt5.QtCore import QT_VERSION_STR
+from PyQt5.QtCore import PYQT_VERSION_STR
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+
+__author__ = 'Bitcraze AB'
+__all__ = ['AboutDialog']
 
 (about_widget_class,
-about_widget_base_class) = (uic.loadUiType(sys.path[0] +
-                                           '/cfclient/ui/dialogs/about.ui'))
+ about_widget_base_class) = (uic.loadUiType(cfclient.module_path +
+                                            '/ui/dialogs/about.ui'))
 
 DEBUG_INFO_FORMAT = """
 <b>Cfclient</b><br>
 Cfclient version: {version}<br>
 System: {system}<br>
+Python: {pmajor}.{pminor}.{pmicro}<br>
+Qt: {qt_version}<br>
+PyQt: {pyqt_version}<br>
 <br>
 <b>Interface status</b><br>
 {interface_status}
@@ -77,7 +77,7 @@ IMU_SENSORS_FORMAT = "{}: {}<br>"
 SENSOR_TESTS_FORMAT = "{}: {}<br>"
 FIRMWARE_FORMAT = "{:x}{:x} ({})"
 
-CREDITS_FORMAT = U"""
+CREDITS_FORMAT = """
 <b>Contributions</b><br>
 {contribs}
 <br><br>
@@ -91,47 +91,47 @@ CREDITS_FORMAT = U"""
 <a href="http://www.python.org/">Python</a><br>
 """
 
-class AboutDialog(QtGui.QWidget, about_widget_class):
 
+class AboutDialog(QtWidgets.QWidget, about_widget_class):
     _disconnected_signal = pyqtSignal(str)
 
     """Crazyflie client About box for debugging and information"""
+
     def __init__(self, helper, *args):
         super(AboutDialog, self).__init__(*args)
         self.setupUi(self)
         self._close_button.clicked.connect(self.close)
         self._name_label.setText(
-                             self._name_label.text().replace('#version#',
-                                                             cfclient.VERSION))
+            self._name_label.text().replace('#version#', cfclient.VERSION))
 
         self._interface_text = ""
         self._imu_sensors_text = ""
         self._imu_sensor_test_text = ""
-        self._uri = None 
+        self._uri = None
         self._fw_rev0 = None
         self._fw_rev1 = None
         self._fw_modified = None
         self._helper = helper
 
-        helper.cf.param.add_update_callback(group="imu_sensors",
-                                            cb=self._imu_sensors_update)
-        helper.cf.param.add_update_callback(group="imu_tests",
-                                            cb=self._imu_sensor_tests_update)
-        helper.cf.param.add_update_callback(group="firmware",
-                                            cb=self._firmware_update)
+        helper.cf.param.add_update_callback(
+            group="imu_sensors", cb=self._imu_sensors_update)
+        helper.cf.param.add_update_callback(
+            group="imu_tests", cb=self._imu_sensor_tests_update)
+        helper.cf.param.add_update_callback(
+            group="firmware", cb=self._firmware_update)
         helper.cf.connected.add_callback(self._connected)
 
         self._disconnected_signal.connect(self._disconnected)
         helper.cf.disconnected.add_callback(self._disconnected_signal.emit)
 
         # Open the Credits file and show it in the UI
-        credits = U""
+        credits = ""
         try:
-            with open("CREDITS.txt", 'r') as f:
+            with open("CREDITS.txt", encoding='utf-8', mode='r') as f:
                 for line in f:
-                    credits += U"{}<br>".format(line.decode("UTF-8"))
+                    credits += "{}<br>".format(line)
         except IOError:
-            credits = U""
+            credits = ""
 
         self._credits.setHtml(
             CREDITS_FORMAT.format(contribs=credits)
@@ -141,42 +141,48 @@ class AboutDialog(QtGui.QWidget, about_widget_class):
         """Event when the about box is shown"""
         self._interface_text = ""
         interface_status = cflib.crtp.get_interfaces_status()
-        for key in interface_status.keys():
-            self._interface_text += INTERFACE_FORMAT.format(key,
-                                                    interface_status[key])
+        for key in list(interface_status.keys()):
+            self._interface_text += INTERFACE_FORMAT.format(
+                key, interface_status[key])
         firmware = None
 
         self._device_text = ""
         devs = self._helper.inputDeviceReader.available_devices()
         for d in devs:
-            self._device_text += DEVICE_FORMAT.format(d.reader_name,
-                                                      d.id,
-                                                      d.name)
+            self._device_text += DEVICE_FORMAT.format(
+                d.reader_name, d.id, d.name)
         if len(self._device_text) == 0:
             self._device_text = "None<br>"
 
         self._input_readers_text = ""
-        #readers = self._helper.inputDeviceReader.getAvailableDevices()
+        # readers = self._helper.inputDeviceReader.getAvailableDevices()
         for reader in cfclient.utils.input.inputreaders.initialized_readers:
-            self._input_readers_text += INPUT_READER_FORMAT.format(reader.name,
-                                                                   len(reader.devices()))
+            self._input_readers_text += INPUT_READER_FORMAT.format(
+                reader.name, len(reader.devices()))
         if len(self._input_readers_text) == 0:
             self._input_readers_text = "None<br>"
 
         if self._uri:
-            firmware = FIRMWARE_FORMAT.format(self._fw_rev0, self._fw_rev1,
-                                "MODIFIED" if self._fw_modified else "CLEAN")
+            firmware = FIRMWARE_FORMAT.format(
+                self._fw_rev0,
+                self._fw_rev1,
+                "MODIFIED" if self._fw_modified else "CLEAN")
         self._debug_out.setHtml(
-                DEBUG_INFO_FORMAT.format(version=cfclient.VERSION,
-                                         system=sys.platform,
-                                         interface_status=self._interface_text,
-                                         input_devices=self._device_text,
-                                         input_readers=self._input_readers_text,
-                                         uri = self._uri,
-                                         firmware = firmware,
-                                         imu_sensors=self._imu_sensors_text,
-                                         imu_sensor_tests=
-                                            self._imu_sensor_test_text))
+            DEBUG_INFO_FORMAT.format(
+                version=cfclient.VERSION,
+                system=sys.platform,
+                pmajor=sys.version_info.major,
+                pminor=sys.version_info.minor,
+                pmicro=sys.version_info.micro,
+                qt_version=QT_VERSION_STR,
+                pyqt_version=PYQT_VERSION_STR,
+                interface_status=self._interface_text,
+                input_devices=self._device_text,
+                input_readers=self._input_readers_text,
+                uri=self._uri,
+                firmware=firmware,
+                imu_sensors=self._imu_sensors_text,
+                imu_sensor_tests=self._imu_sensor_test_text))
 
     def _connected(self, uri):
         """Callback when Crazyflie is connected"""
@@ -194,16 +200,16 @@ class AboutDialog(QtGui.QWidget, about_widget_class):
     def _imu_sensors_update(self, name, value):
         """Callback for sensor found parameters"""
         param = name[name.index('.') + 1:]
-        if not param in self._imu_sensors_text:
-            self._imu_sensors_text += IMU_SENSORS_FORMAT.format(param,
-                                                                eval(value))
+        if param not in self._imu_sensors_text:
+            self._imu_sensors_text += IMU_SENSORS_FORMAT.format(
+                param, eval(value))
 
     def _imu_sensor_tests_update(self, name, value):
         """Callback for sensor test parameters"""
         param = name[name.index('.') + 1:]
-        if not param in self._imu_sensor_test_text:
-            self._imu_sensor_test_text += SENSOR_TESTS_FORMAT.format(param,
-                                                                 eval(value))
+        if param not in self._imu_sensor_test_text:
+            self._imu_sensor_test_text += SENSOR_TESTS_FORMAT.format(
+                param, eval(value))
 
     def _disconnected(self, uri):
         """Callback for Crazyflie disconnected"""
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.pyc
deleted file mode 100755
index ffef3f1194f284714b174e6d7a4759edd5e8822f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6672
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
MbIc$9P8D+h1&7@*+W-In

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/about.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.py
old mode 100755
new mode 100644
index b593e11d..3fffdd15
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 The bootloader dialog is used to update the Crazyflie firmware and to
@@ -31,27 +31,20 @@ read/write the configuration block in the Crazyflie flash.
 """
 from cflib.bootloader import Bootloader
 
-__author__ = 'Bitcraze AB'
-__all__ = ['BootloaderDialog']
-
-import struct
-import sys
-import time
-
 import logging
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+from PyQt5 import QtWidgets, uic
+from PyQt5.QtCore import pyqtSlot, pyqtSignal, QThread
 
-from cfclient.ui.tab import Tab
+import cfclient
 
-import cflib.crtp
+__author__ = 'Bitcraze AB'
+__all__ = ['BootloaderDialog']
 
-from cflib.bootloader.cloader import Cloader
+logger = logging.getLogger(__name__)
 
-service_dialog_class = uic.loadUiType(sys.path[0] +
-                                      "/cfclient/ui/dialogs/bootloader.ui")[0]
+service_dialog_class = uic.loadUiType(cfclient.module_path +
+                                      "/ui/dialogs/bootloader.ui")[0]
 
 
 class UIState:
@@ -63,9 +56,10 @@ class UIState:
     RESET = 4
 
 
-class BootloaderDialog(QtGui.QWidget, service_dialog_class):
+class BootloaderDialog(QtWidgets.QWidget, service_dialog_class):
     """Tab for update the Crazyflie firmware and for reading/writing the config
     block in flash"""
+
     def __init__(self, helper, *args):
         super(BootloaderDialog, self).__init__(*args)
         self.setupUi(self)
@@ -93,13 +87,13 @@ class BootloaderDialog(QtGui.QWidget, service_dialog_class):
         self.clt.statusChanged.connect(self.statusUpdate)
         # self.clt.updateBootloaderStatusSignal.connect(
         #                                         self.updateBootloaderStatus)
-        self.clt.connectingSignal.connect(lambda:
-                                          self.setUiState(UIState.CONNECTING))
-        self.clt.connectedSignal.connect(lambda:
-                                         self.setUiState(UIState.COLD_CONNECT))
+        self.clt.connectingSignal.connect(
+            lambda: self.setUiState(UIState.CONNECTING))
+        self.clt.connectedSignal.connect(
+            lambda: self.setUiState(UIState.COLD_CONNECT))
         self.clt.failed_signal.connect(lambda m: self._ui_connection_fail(m))
-        self.clt.disconnectedSignal.connect(lambda:
-                                        self.setUiState(UIState.DISCONNECTED))
+        self.clt.disconnectedSignal.connect(
+            lambda: self.setUiState(UIState.DISCONNECTED))
 
         self.clt.start()
 
@@ -165,7 +159,7 @@ class BootloaderDialog(QtGui.QWidget, service_dialog_class):
     def pathBrowse(self):
         filename = ""
         # Fix for crash in X on Ubuntu 14.04
-        filename = QtGui.QFileDialog.getOpenFileName()
+        filename, _ = QtWidgets.QFileDialog.getOpenFileName()
         if filename != "":
             self.imagePathLine.setText(filename)
         pass
@@ -180,7 +174,7 @@ class BootloaderDialog(QtGui.QWidget, service_dialog_class):
             self.clt.program.emit(self.imagePathLine.text(),
                                   self.verifyCheckBox.isChecked())
         else:
-            msgBox = QtGui.QMessageBox()
+            msgBox = QtWidgets.QMessageBox()
             msgBox.setText("Please choose an image file to program.")
 
             msgBox.exec_()
@@ -271,7 +265,7 @@ class CrazyloadThread(QThread):
     def programAction(self, filename, verify):
         targets = {}
         if str(filename).endswith("bin"):
-            targets["stm32"] = ("fw", )
+            targets["stm32"] = ("fw",)
         try:
             self._bl.flash(str(filename), targets)
             self.programmed.emit(True)
@@ -284,4 +278,4 @@ class CrazyloadThread(QThread):
         except Exception:
             pass
         self._bl.close()
-        self.disconnectedSignal.emit()
\ No newline at end of file
+        self.disconnectedSignal.emit()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.pyc
deleted file mode 100755
index 4acfd27a8b9a4ed140627350fa9c21415047d163..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 11724
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
ZtbkvHvv`2ef{Q;TZvIUDWaGlG{t0}=4><q;

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/bootloader.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.py
old mode 100755
new mode 100644
index c7635676..c4ecd003
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.py
@@ -21,32 +21,35 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 The bootloader dialog is used to update the Crazyflie firmware and to
 read/write the configuration block in the Crazyflie flash.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['Cf1ConfigDialog']
-
 import struct
-import sys
 from cflib.bootloader import Bootloader
 
 import logging
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+from PyQt5 import QtWidgets, uic
+from PyQt5.QtCore import pyqtSlot, pyqtSignal, QThread
 
+import cfclient
 from cfclient.utils.config import Config
+from functools import reduce
+
+__author__ = 'Bitcraze AB'
+__all__ = ['Cf1ConfigDialog']
+
+logger = logging.getLogger(__name__)
+
+service_dialog_class = uic.loadUiType(cfclient.module_path +
+                                      "/ui/dialogs/cf1config.ui")[0]
 
-service_dialog_class = uic.loadUiType(sys.path[0] +
-                                      "/cfclient/ui/dialogs/cf1config.ui")[0]
 
 class UIState:
     DISCONNECTED = 0
@@ -57,9 +60,10 @@ class UIState:
     RESET = 4
 
 
-class Cf1ConfigDialog(QtGui.QWidget, service_dialog_class):
+class Cf1ConfigDialog(QtWidgets.QWidget, service_dialog_class):
     """Tab for update the Crazyflie firmware and for reading/writing the config
     block in flash"""
+
     def __init__(self, helper, *args):
         super(Cf1ConfigDialog, self).__init__(*args)
         self.setupUi(self)
@@ -80,13 +84,13 @@ class Cf1ConfigDialog(QtGui.QWidget, service_dialog_class):
         self._cancel_bootloading.clicked.connect(self.close)
 
         self.clt.statusChanged.connect(self.statusUpdate)
-        self.clt.connectingSignal.connect(lambda:
-                                          self.setUiState(UIState.CONNECTING))
-        self.clt.connectedSignal.connect(lambda:
-                                         self.setUiState(UIState.COLD_CONNECT))
+        self.clt.connectingSignal.connect(
+            lambda: self.setUiState(UIState.CONNECTING))
+        self.clt.connectedSignal.connect(
+            lambda: self.setUiState(UIState.COLD_CONNECT))
         self.clt.failed_signal.connect(lambda m: self._ui_connection_fail(m))
-        self.clt.disconnectedSignal.connect(lambda:
-                                        self.setUiState(UIState.DISCONNECTED))
+        self.clt.disconnectedSignal.connect(
+            lambda: self.setUiState(UIState.DISCONNECTED))
         self.clt.updateConfigSignal.connect(self.updateConfig)
 
         self.clt.start()
@@ -219,13 +223,13 @@ class CrazyloadThread(QThread):
             self.failed_signal.emit("{}".format(e))
 
     def checksum256(self, st):
-        return reduce(lambda x, y: x + y, map(ord, st)) % 256
+        return reduce(lambda x, y: x + y, list(st)) % 256
 
     def writeConfigAction(self, channel, speed, rollTrim, pitchTrim):
         data = (0x00, channel, speed, pitchTrim, rollTrim)
         image = struct.pack("<BBBff", *data)
         # Adding some magic:
-        image = "0xBC" + image
+        image = bytearray("0xBC".encode('ISO-8859-1')) + image
         image += struct.pack("B", 256 - self.checksum256(image))
 
         self._bl.write_cf1_config(image)
@@ -234,7 +238,7 @@ class CrazyloadThread(QThread):
         self.statusChanged.emit("Reading config block...", 0)
         data = self._bl.read_cf1_config()
         if (data is not None):
-            if data[0:4] == "0xBC":
+            if data[0:4] == bytearray("0xBC".encode('ISO-8859-1')):
                 # Skip 0xBC and version at the beginning
                 [channel,
                  speed,
@@ -246,7 +250,8 @@ class CrazyloadThread(QThread):
                 speed = Config().get("default_cf_speed")
                 pitchTrim = Config().get("default_cf_trim")
                 rollTrim = Config().get("default_cf_trim")
-                self.statusChanged.emit("Could not find config block, showing defaults", 100)
+                self.statusChanged.emit(
+                    "Could not find config block, showing defaults", 100)
             self.updateConfigSignal.emit(channel, speed, rollTrim, pitchTrim)
         else:
             self.statusChanged.emit("Reading config block failed!", 0)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.pyc
deleted file mode 100755
index ab6c2681b1fd88b2195c184b6971087ffc8feb73..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 11202
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
W8`FrV@M7PrOyf3dvNBgcefOVH0f6NI

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf1config.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.py
old mode 100755
new mode 100644
index 236fb245..7b8f855f
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.py
@@ -20,32 +20,32 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 The bootloader dialog is used to update the Crazyflie firmware and to
 read/write the configuration block in the Crazyflie flash.
 """
+import logging
 
-__author__ = 'Bitcraze AB'
-__all__ = ['CfConfig']
+import cfclient
+from cflib.crazyflie.mem import MemoryElement
 
-import sys
-import logging
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+
+__author__ = 'Bitcraze AB'
+__all__ = ['Cf2ConfigDialog']
 
 logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
-from cflib.crazyflie.mem import MemoryElement
+service_dialog_class = uic.loadUiType(cfclient.module_path +
+                                      "/ui/dialogs/cf2config.ui")[0]
 
-service_dialog_class = uic.loadUiType(sys.path[0] +
-                                      "/cfclient/ui/dialogs/cf2config.ui")[0]
 
-class Cf2ConfigDialog(QtGui.QWidget, service_dialog_class):
+class Cf2ConfigDialog(QtWidgets.QWidget, service_dialog_class):
     """Tab for update the Crazyflie firmware and for reading/writing the config
     block in flash"""
 
@@ -67,7 +67,8 @@ class Cf2ConfigDialog(QtGui.QWidget, service_dialog_class):
         self._write_data_btn.clicked.connect(self._write_data)
 
     def _write_done(self, mem, addr):
-        self._cf.mem.get_mems(MemoryElement.TYPE_I2C)[0].update(self._data_updated)
+        self._cf.mem.get_mems(
+            MemoryElement.TYPE_I2C)[0].update(self._data_updated)
 
     def _data_updated(self, mem):
         self._roll_trim.setValue(mem.elements["roll_trim"])
@@ -76,10 +77,9 @@ class Cf2ConfigDialog(QtGui.QWidget, service_dialog_class):
         self._radio_speed.setCurrentIndex(mem.elements["radio_speed"])
         if "radio_address" in mem.elements:
             self._radio_address.setValue(mem.elements["radio_address"])
-            self._radio_address.setEnabled(True)
         else:
             self._radio_address.setValue(int("0xE7E7E7E7E7", 0))
-            self._radio_address.setEnabled(False)
+        self._radio_address.setEnabled(True)
         self._write_data_btn.setEnabled(True)
 
     def _set_ui_connected(self, link_uri):
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.pyc
deleted file mode 100755
index ad60a1c0724d08baa3898ba4db38cf7d0467ec8c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4257
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
Lci<m*d;Wg_Nz<k{

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/cf2config.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.py
deleted file mode 100755
index dff76f7b..00000000
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-#     ||          ____  _ __
-#  +------+      / __ )(_) /_______________ _____  ___
-#  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
-#  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
-#   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
-#
-#  Copyright (C) 2011-2013 Bitcraze AB
-#
-#  Crazyflie Nano Quadcopter Client
-#
-#  This program 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 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, write to the Free Software Foundation, Inc., 51
-#  Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-"""
-Dialogue that lists available Crazyflies, lets user choose which to connect to.
-"""
-
-__author__ = 'Bitcraze AB'
-__all__ = ['ConnectionDialogue']
-
-import sys
-
-from PyQt4 import QtGui, uic
-from PyQt4.QtCore import pyqtSignal, pyqtSlot, QThread
-
-import cflib.crtp
-
-(connect_widget_class,
-connect_widget_base_class) = (uic.loadUiType(sys.path[0] +
-                                 '/cfclient/ui/dialogs/connectiondialogue.ui'))
-
-
-class ConnectDialogue(QtGui.QWidget, connect_widget_class):
-
-    # Outgoing signal for connecting a Crazyflie
-    requestConnectionSignal = pyqtSignal(str)
-
-    def __init__(self, *args):
-        super(ConnectDialogue, self).__init__(*args)
-        self.setupUi(self)
-
-        self.scanner = ScannerThread()
-        self.scanner.start()
-
-        # Connect signals to slots
-        self.connectButton.clicked.connect(self.openConnection)
-        self.scanButton.clicked.connect(self.rescan)
-        self.cancelButton.clicked.connect(self.cancel)
-        self.interfaceList.itemDoubleClicked.connect(self.interfaceSelected)
-        self.scanner.interfaceFoundSignal.connect(self.foundInterfaces)
-        self.box = None
-        self.address.setValue(0xE7E7E7E7E7)
-
-        self.available_interfaces = []
-
-    def rescan(self):
-        """Disable all buttons and scan signals from Crazyflies."""
-        self.interfaceList.clear()
-        self.interfaceList.addItem("Scanning...")
-        self.scanButton.setEnabled(False)
-        self.cancelButton.setEnabled(False)
-        self.connectButton.setEnabled(False)
-        self.scanner.scanSignal.emit(self.address.value())
-
-    def foundInterfaces(self, interfaces):
-        """
-        Add found interfaces to list and enable buttons in UI.
-        """
-        self.interfaceList.clear()
-        self.available_interfaces = interfaces
-        for i in interfaces:
-            if (len(i[1]) > 0):
-                self.interfaceList.addItem("%s - %s" % (i[0], i[1]))
-            else:
-                self.interfaceList.addItem(i[0])
-        if len(interfaces) > 0:
-            self.interfaceList.setCurrentRow(0)
-            self.connectButton.setEnabled(True)
-        self.cancelButton.setEnabled(True)
-        self.scanButton.setEnabled(True)
-
-    def interfaceSelected(self, listItem):
-        self.requestConnectionSignal.emit(
-                self.available_interfaces[self.interfaceList.currentRow()][0])
-        self.close()
-
-    def openConnection(self):
-        self.interfaceSelected(self.interfaceList.currentItem())
-
-    def cancel(self):
-        self.close()
-
-    def showEvent(self, ev):
-        self.rescan()
-
-
-class ScannerThread(QThread):
-
-    scanSignal = pyqtSignal(object)
-    interfaceFoundSignal = pyqtSignal(object)
-
-    def __init__(self):
-        QThread.__init__(self)
-        self.moveToThread(self)
-        self.scanSignal.connect(self.scan)
-
-    def scan(self, address):
-        self.interfaceFoundSignal.emit(cflib.crtp.scan_interfaces(address))
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.pyc
deleted file mode 100755
index cbacbabb4c9977ebb812ac2b985d07e1c9071eaf..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.ui
deleted file mode 100755
index 3e1f25aa..00000000
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/connectiondialogue.ui
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Form</class>
- <widget class="QWidget" name="Form">
-  <property name="windowModality">
-   <enum>Qt::ApplicationModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>551</width>
-    <height>350</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Connect Crazyflie</string>
-  </property>
-  <layout class="QHBoxLayout" name="horizontalLayout">
-   <item>
-    <layout class="QVBoxLayout" name="verticalLayout">
-     <item>
-      <widget class="QLabel" name="label">
-       <property name="font">
-        <font>
-         <pointsize>16</pointsize>
-        </font>
-       </property>
-       <property name="text">
-        <string>Connect to Crazyflie</string>
-       </property>
-       <property name="alignment">
-        <set>Qt::AlignHCenter|Qt::AlignTop</set>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QListWidget" name="interfaceList"/>
-     </item>
-     <item>
-      <layout class="QHBoxLayout" name="horizontalLayout_2">
-       <item>
-        <widget class="QLabel" name="label_2">
-         <property name="text">
-          <string>Address:</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="HexSpinBox" name="address">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-     <item>
-      <layout class="QGridLayout" name="gridLayout">
-       <item row="1" column="0">
-        <widget class="QPushButton" name="scanButton">
-         <property name="enabled">
-          <bool>true</bool>
-         </property>
-         <property name="text">
-          <string>Scan</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="2">
-        <widget class="QPushButton" name="connectButton">
-         <property name="text">
-          <string>Connect</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QPushButton" name="cancelButton">
-         <property name="text">
-          <string>Cancel</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>HexSpinBox</class>
-   <extends>QSpinBox</extends>
-   <header>cfclient.ui.widgets.hexspinbox</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.py
old mode 100755
new mode 100644
index ec8ed5ac..d1f9c68b
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.py
@@ -7,7 +7,7 @@
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
 #
-#  Copyright (C) 2011-2013 Bitcraze AB
+#  Copyright (C) 2011-2017 Bitcraze AB
 #
 #  Crazyflie Nano Quadcopter Client
 #
@@ -20,41 +20,37 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
-Dialogue used to select and configure an inputdevice. This includes mapping buttons and
-axis to match controls for the Crazyflie.
+Dialogue used to select and configure an inputdevice. This includes mapping
+buttons and axis to match controls for the Crazyflie.
 """
-
-__author__ = 'Bitcraze AB'
-__all__ = ['InputConfigDialogue']
-
-import sys
-import json
 import logging
 
-logger = logging.getLogger(__name__)
-
+import cfclient
+from PyQt5.QtCore import QThread
+from PyQt5.QtCore import QTimer
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtWidgets import QMessageBox
 from cfclient.utils.config_manager import ConfigManager
-from cflib.crtp.exceptions import CommunicationException
+from PyQt5 import Qt
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.Qt import *  # noqa
 
-from PyQt4 import Qt, QtCore, QtGui, uic
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4.Qt import *
+__author__ = 'Bitcraze AB'
+__all__ = ['InputConfigDialogue']
 
-from cfclient.utils.input import JoystickReader
+logger = logging.getLogger(__name__)
 
-(inputconfig_widget_class,
-connect_widget_base_class) = (uic.loadUiType(sys.path[0] +
-                             '/cfclient/ui/dialogs/inputconfigdialogue.ui'))
+(inputconfig_widget_class, connect_widget_base_class) = (
+    uic.loadUiType(cfclient.module_path + '/ui/dialogs/inputconfigdialogue.ui')
+)
 
 
-class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
+class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
 
     def __init__(self, joystickReader, *args):
         super(InputConfigDialogue, self).__init__(*args)
@@ -64,42 +60,76 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
         self._input_device_reader = DeviceReader(self._input)
         self._input_device_reader.start()
 
-        self._input_device_reader.raw_axis_data_signal.connect(self._detect_axis)
-        self._input_device_reader.raw_button_data_signal.connect(self._detect_button)
-        self._input_device_reader.mapped_values_signal.connect(self._update_mapped_values)
+        self._input_device_reader.raw_axis_data_signal.connect(
+            self._detect_axis)
+        self._input_device_reader.raw_button_data_signal.connect(
+            self._detect_button)
+        self._input_device_reader.mapped_values_signal.connect(
+            self._update_mapped_values)
 
         self.cancelButton.clicked.connect(self.close)
         self.saveButton.clicked.connect(self._save_config)
-        
-        self.detectPitch.clicked.connect(lambda : self._axis_detect("pitch", "Pitch axis",
-                                                 "Center the pitch axis then do max %s pitch", ["forward", "backward"]))
-        self.detectRoll.clicked.connect(lambda : self._axis_detect("roll", "Roll axis",
-                                                 "Center the roll axis and then do max %s roll", ["right", "left"]))
-        self.detectYaw.clicked.connect(lambda : self._axis_detect("yaw", "Yaw axis",
-                                                "Center the yaw axis and then do max %s yaw", ["right", "left"]))
-        self.detectThrust.clicked.connect(lambda : self._axis_detect("thrust", "Thrust axis",
-                                                   "Center the thrust axis, and then do max thrust (also used to adjust target altitude in altitude hold mode)"))
-        self.detectPitchPos.clicked.connect(lambda : self._button_detect("pitchPos", "Pitch Cal Positive",
-                                                  "Press the button for Pitch postive calibration"))
-        self.detectPitchNeg.clicked.connect(lambda : self._button_detect("pitchNeg", "Pitch Cal Negative",
-                                                     "Press the button for Pitch negative calibration"))
-        self.detectRollPos.clicked.connect(lambda : self._button_detect("rollPos", "Roll Cal Positive",
-                                                    "Press the button for Roll positive calibration"))
-        self.detectRollNeg.clicked.connect(lambda : self._button_detect("rollNeg", "Roll Cal Negative",
-                                                    "Press the button for Roll negative calibration"))
-        self.detectKillswitch.clicked.connect(lambda : self._button_detect("killswitch", "Killswitch",
-                                                       "Press the button for the killswitch (will disable motors)"))
-        self.detectAlt1.clicked.connect(lambda : self._button_detect("alt1", "Alternative function 1",
-                                                       "The alternative function 1 that will do a callback"))
-        self.detectAlt2.clicked.connect(lambda : self._button_detect("alt2", "Alternative function 2",
-                                                       "The alternative function 2 that will do a callback"))
-        self.detectExitapp.clicked.connect(lambda : self._button_detect("exitapp", "Exit application",
-                                                    "Press the button for exiting the application"))
-        self.detectAltHold.clicked.connect(lambda : self._button_detect("althold", "Altitude hold",
-                                                    "Press the button for altitude hold mode activation (releasing returns to manual mode)"))        
-        self.detectMuxswitch.clicked.connect(lambda: self._button_detect("muxswitch", "Mux Switch",
-                                                     "Press the button for mux switching"))
 
+        self.detectPitch.clicked.connect(
+            lambda: self._axis_detect(
+                "pitch", "Pitch axis",
+                "Center the pitch axis then do max %s pitch",
+                ["forward", "backward"]))
+        self.detectRoll.clicked.connect(
+            lambda: self._axis_detect(
+                "roll", "Roll axis",
+                "Center the roll axis and then do max %s roll",
+                ["right", "left"]))
+        self.detectYaw.clicked.connect(
+            lambda: self._axis_detect(
+                "yaw", "Yaw axis",
+                "Center the yaw axis and then do max %s yaw",
+                ["right", "left"]))
+        self.detectThrust.clicked.connect(
+            lambda: self._axis_detect(
+                "thrust", "Thrust axis",
+                "Center the thrust axis, and then do max thrust"))
+        self.detectPitchPos.clicked.connect(
+            lambda: self._button_detect(
+                "pitchPos", "Pitch Cal Positive",
+                "Press the button for Pitch postive calibration"))
+        self.detectPitchNeg.clicked.connect(
+            lambda: self._button_detect(
+                "pitchNeg", "Pitch Cal Negative",
+                "Press the button for Pitch negative calibration"))
+        self.detectRollPos.clicked.connect(
+            lambda: self._button_detect(
+                "rollPos", "Roll Cal Positive",
+                "Press the button for Roll positive calibration"))
+        self.detectRollNeg.clicked.connect(
+            lambda: self._button_detect(
+                "rollNeg", "Roll Cal Negative",
+                "Press the button for Roll negative calibration"))
+        self.detectKillswitch.clicked.connect(
+            lambda: self._button_detect(
+                "killswitch", "Killswitch",
+                "Press the button for the killswitch (will disable motors)"))
+        self.detectAlt1.clicked.connect(
+            lambda: self._button_detect(
+                "alt1", "Alternative function 1",
+                "The alternative function 1 that will do a callback"))
+        self.detectAlt2.clicked.connect(
+            lambda: self._button_detect(
+                "alt2", "Alternative function 2",
+                "The alternative function 2 that will do a callback"))
+        self.detectExitapp.clicked.connect(
+            lambda: self._button_detect(
+                "exitapp", "Exit application",
+                "Press the button for exiting the application"))
+        self._detect_assisted_control.clicked.connect(
+            lambda: self._button_detect(
+                "assistedControl", "Assisted control",
+                "Press the button for assisted control mode activation "
+                "(releasing returns to manual mode)"))
+        self.detectMuxswitch.clicked.connect(
+            lambda: self._button_detect(
+                "muxswitch", "Mux Switch",
+                "Press the button for mux switching"))
 
         self.configButton.clicked.connect(self._start_configuration)
         self.loadButton.clicked.connect(self._load_config_from_file)
@@ -107,13 +137,14 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
 
         self._popup = None
         self._combined_button = None
-        self._detection_buttons = [self.detectPitch, self.detectRoll,
-                              self.detectYaw, self.detectThrust,
-                              self.detectPitchPos, self.detectPitchNeg,
-                              self.detectRollPos, self.detectRollNeg,
-                              self.detectKillswitch, self.detectExitapp,
-                              self.detectAltHold, self.detectAlt1,
-                              self.detectAlt2, self.detectMuxswitch]
+        self._detection_buttons = [
+            self.detectPitch, self.detectRoll,
+            self.detectYaw, self.detectThrust,
+            self.detectPitchPos, self.detectPitchNeg,
+            self.detectRollPos, self.detectRollNeg,
+            self.detectKillswitch, self.detectExitapp,
+            self._detect_assisted_control, self.detectAlt1,
+            self.detectAlt2, self.detectMuxswitch]
 
         self._button_to_detect = ""
         self._axis_to_detect = ""
@@ -139,10 +170,10 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
 
     @staticmethod
     def _scale(max_value, value):
-        return (value/max_value) * 100
+        return (value / max_value) * 100
 
     def _reset_mapping(self):
-        self._buttonindicators= {
+        self._buttonindicators = {
             "pitchPos": self.pitchPos,
             "pitchNeg": self.pitchNeg,
             "rollPos": self.rollPos,
@@ -151,16 +182,16 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
             "alt1": self.alt1,
             "alt2": self.alt2,
             "exitapp": self.exitapp,
-            "althold": self.althold,
+            "assistedControl": self._assisted_control,
             "muxswitch": self.muxswitch,
-            }
+        }
 
         self._axisindicators = {
             "pitch": self.pitchAxisValue,
             "roll": self.rollAxisValue,
             "yaw": self.yawAxisValue,
             "thrust": self.thrustAxisValue,
-            }
+        }
 
     def _cancel_config_popup(self, button):
         self._axis_to_detect = ""
@@ -171,22 +202,25 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
         self._mined_axis = []
         self._popup = QMessageBox()
         self._popup.directions = directions
-        self._combined_button = QtGui.QPushButton('Combined Axis Detection')
-        self.cancelButton = QtGui.QPushButton('Cancel')
+        self._combined_button = QtWidgets.QPushButton('Combined Axis ' +
+                                                      'Detection')
+        self.cancelButton = QtWidgets.QPushButton('Cancel')
         self._popup.addButton(self.cancelButton, QMessageBox.DestructiveRole)
         self._popup.setWindowTitle(caption)
-        self._popup.setWindowFlags(Qt.Dialog|Qt.MSWindowsFixedSizeDialogHint)
+        self._popup.setWindowFlags(Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)
         if len(directions) > 1:
             self._popup.originalMessage = message
             message = self._popup.originalMessage % directions[0]
             self._combined_button.setCheckable(True)
             self._combined_button.blockSignals(True)
-            self._popup.addButton(self._combined_button, QMessageBox.ActionRole)
+            self._popup.addButton(self._combined_button,
+                                  QMessageBox.ActionRole)
         self._popup.setText(message)
         self._popup.show()
 
     def _start_configuration(self):
-        self._input.enableRawReading(str(self.inputDeviceSelector.currentText()))
+        self._input.enableRawReading(
+            str(self.inputDeviceSelector.currentText()))
         self._input_device_reader.start_reading()
         self._populate_config_dropdown()
         self.profileCombo.setEnabled(True)
@@ -195,19 +229,22 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
 
     def _detect_axis(self, data):
         if (len(self._axis_to_detect) > 0):
-            if self._combined_button and self._combined_button.isChecked() and self.combinedDetection == 0:
+            if (self._combined_button and self._combined_button.isChecked() and
+                    self.combinedDetection == 0):
                 self._combined_button.setDisabled(True)
                 self.combinedDetection = 1
             for a in data:
                 # Axis must go low and high before it's accepted as selected
                 # otherwise maxed out axis (like gyro/acc) in some controllers
-                # will always be selected. Not enforcing negative values makes it
-                # possible to detect split axis (like bumpers on PS3 controller)
+                # will always be selected. Not enforcing negative values makes
+                # it possible to detect split axis (like bumpers on PS3
+                # controller)
                 if a not in self._maxed_axis and abs(data[a]) > 0.8:
                     self._maxed_axis.append(a)
                 if a not in self._mined_axis and abs(data[a]) < 0.1:
                     self._mined_axis.append(a)
-                if a in self._maxed_axis and a in self._mined_axis and len(self._axis_to_detect) > 0:
+                if a in self._maxed_axis and a in self._mined_axis and len(
+                        self._axis_to_detect) > 0:
                     if self.combinedDetection == 0:
                         if data[a] >= 0:
                             self._map_axis(self._axis_to_detect, a, 1.0)
@@ -215,21 +252,23 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
                             self._map_axis(self._axis_to_detect, a, -1.0)
                         self._axis_to_detect = ""
                         self._check_and_enable_saving()
-                        if self._popup != None:
+                        if self._popup is not None:
                             self.cancelButton.click()
-                    elif self.combinedDetection == 2: #finished detection
-                        if self._prev_combined_id != a: # not the same axis again ...
+                    elif self.combinedDetection == 2:  # finished detection
+                        # not the same axis again ...
+                        if self._prev_combined_id != a:
                             self._map_axis(self._axis_to_detect, a, -1.0)
                             self._axis_to_detect = ""
                             self._check_and_enable_saving()
-                            if (self._popup != None):
+                            if (self._popup is not None):
                                 self.cancelButton.click()
                             self.combinedDetection = 0
                     elif self.combinedDetection == 1:
                         self._map_axis(self._axis_to_detect, a, 1.0)
                         self._prev_combined_id = a
                         self.combinedDetection = 2
-                        message = self._popup.originalMessage % self._popup.directions[1]
+                        message = (self._popup.originalMessage %
+                                   self._popup.directions[1])
                         self._popup.setText(message)
 
     def _update_mapped_values(self, mapped_data):
@@ -242,7 +281,7 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
             if v in self._axisindicators:
                 # The sliders used are set to 0-100 and the values from the
                 # input-layer is scaled according to the max settings in
-                # the input-layer. So scale the value and place 0 in the middle.
+                # the input-layer. So scale the value and place 0 in the middle
                 scaled_value = mapped_data.get(v)
                 if v == "thrust":
                     scaled_value = InputConfigDialogue._scale(
@@ -268,7 +307,8 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
         self._input.set_raw_input_map(self._map)
 
     def _map_button(self, function, key_id):
-        # Duplicate buttons is not allowed, remove if there's already one mapped
+        # Duplicate buttons are not allowed, remove if there's already one
+        # mapped
         prev_button = None
         for m in self._map:
             if "key" in self._map[m] and self._map[m]["key"] == function:
@@ -290,7 +330,7 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
                     self._map_button(self._button_to_detect, b)
                     self._button_to_detect = ""
                     self._check_and_enable_saving()
-                    if self._popup != None:
+                    if self._popup is not None:
                         self._popup.close()
 
     def _check_and_enable_saving(self):
@@ -322,7 +362,8 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
         QMessageBox.critical(self, caption, message)
 
     def _load_config_from_file(self):
-        loaded_map = ConfigManager().get_config(self.profileCombo.currentText())
+        loaded_map = ConfigManager().get_config(
+            self.profileCombo.currentText())
         if loaded_map:
             self._input.set_raw_input_map(loaded_map)
             self._map = loaded_map
@@ -330,69 +371,32 @@ class InputConfigDialogue(QtGui.QWidget, inputconfig_widget_class):
             logger.warning("Could not load configfile [%s]",
                            self.profileCombo.currentText())
             self._show_error("Could not load config",
-                           "Could not load config [%s]" %
-                           self.profileCombo.currentText())
+                             "Could not load config [%s]" %
+                             self.profileCombo.currentText())
         self._check_and_enable_saving()
 
     def _delete_configuration(self):
         logger.warning("deleteConfig not implemented")
 
     def _save_config(self):
-        configName = str(self.profileCombo.currentText())
-
-        mapping = {'inputconfig': {'inputdevice': {'axis': []}}}
-
-        # Create intermediate structure for the configuration file
-        funcs = {}
-        for m in self._map:
-            key = self._map[m]["key"]
-            if not key in funcs:
-                funcs[key] = []
-            funcs[key].append(self._map[m])
-
-        # Create a mapping for each axis, take care to handle
-        # split axis configurations
-        for a in funcs:
-            func = funcs[a]
-            axis = {}
-            # Check for split axis
-            if len(func) > 1:
-                axis["ids"] = [func[0]["id"], func[1]["id"]]
-                axis["scale"] = func[1]["scale"]
-            else:
-                axis["id"] = func[0]["id"]
-                axis["scale"] = func[0]["scale"]
-            axis["key"] = func[0]["key"]
-            axis["name"] = func[0]["key"] # Name isn't used...
-            axis["type"] =func[0]["type"]
-            mapping["inputconfig"]["inputdevice"]["axis"].append(axis)
-
-        mapping["inputconfig"]['inputdevice']['name'] = configName
-        mapping["inputconfig"]['inputdevice']['updateperiod'] = 10
-
-        config_name = self.profileCombo.currentText()
-        filename = ConfigManager().configs_dir + "/%s.json" % config_name
-        logger.info("Saving config to [%s]", filename)
-        json_data = open(filename, 'w')
-        json_data.write(json.dumps(mapping, indent=2))
-        json_data.close()
-
-        ConfigManager().conf_needs_reload.call(config_name)
+        config_name = str(self.profileCombo.currentText())
+        ConfigManager().save_config(self._map, config_name)
         self.close()
 
     def showEvent(self, event):
         """Called when dialog is opened"""
-        #self._saved_open_device = self._input.get_device_name()
-        #self._input.stop_input()
+        # self._saved_open_device = self._input.get_device_name()
+        # self._input.stop_input()
         self._input.pause_input()
 
     def closeEvent(self, event):
         """Called when dialog is closed"""
         self._input.stop_raw_reading()
         self._input_device_reader.stop_reading()
-        #self._input.start_input(self._saved_open_device)
+        # self._input.start_input(self._saved_open_device)
         self._input.resume_input()
 
+
 class DeviceReader(QThread):
     """Used for polling data from the Input layer during configuration"""
     raw_axis_data_signal = pyqtSignal(object)
@@ -406,7 +410,7 @@ class DeviceReader(QThread):
         self._read_timer = QTimer()
         self._read_timer.setInterval(25)
 
-        self.connect(self._read_timer, SIGNAL("timeout()"), self._read_input)
+        self._read_timer.timeout.connect(self._read_input)
 
     def stop_reading(self):
         """Stop polling data"""
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.pyc
deleted file mode 100755
index 0b7a51788ba0f7690c7604f11af4892f6bb744af..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 19318
zcmd5^TW}o5b?w<*Jaz#PAVGoxUs@}a1-*cXwiPR;ERmpW(w1Oy0Esdzc|6z|00Zoc
zGqVJ!kZ}~riDNsdRPq(O94E2!kyOelf2PV+`AJohO6B27<?)sORDPUF<u}ebr)PI(
zA<!jLRUiRuqq}c+PxtNn>U(>(_&*bs%eBwGRx{a85&vJrCpqL86Bx6K)G@1$2?}Nd
znSu$5CMcPD(X1k4^Ch!d>gI>c>W~SC%+|08N6b6uGAhuJsh3ToVpc20VYgvZA2W?{
zvpR0eBc?uK8i&m4A=8*NtCOZNWmcz5<FHvhY+H<)`Vq6jzQ|4Yaz|~hZ0g5MW5%q`
z7$-bzwvL;yXto|QLB-4lW9B$!@<zd|&YIN|TuV4*woaOG)~sVi<K|ss-ZAF$tEWsb
zVZzg99Sc6xt3AUNFV9U9FKA{emm<I3+USJUP7(&yv{g;QdRR-Velw`nTFv!nqZ5ZH
zRikFRlLq0<s20vwS2m*rHMM#t2$O2VZ?~i7Ms=-|rmbeez7>BLEihcePivbTDUDn8
zq`KaUtLbJ~U5x#=Zmrj&aK4g^VICKww1%p%df{R^jq(*fZBftf&M^83ewOC2nI@e;
zVxh12O@AYdZS{<*8;wpgs`+WuYQD5v3){@hmDsI-<XV~z>)&E44$~oJKi!E^l1nG5
z*@5_wCv5f*vY%<)O46vd?S_63#t~{v@+6Xl+IkIZXr>FDXdw_LlLaBlqRv)z!g&nL
zPW<5<F5;8?2uTRC#QqrW4+s+b3=-uIg4jTZ1=SCc>eyh|Y=DMK=3PKXOfaNM(B!Z(
zWfP1jQz2Qg{g?^L%8ZkCSTkWjK+GJ<NCni%F()+UR7NQv(_m7~j+kIdnQ0RoR_3S)
zjwo}?1k=jQnBb@~$Bnx@cMPklag8N>h`SMdlD`IaQ~WvRt5{sYY!%Gyg87Cq4$50a
z)jGzxEx1=Q*cSpyL<BP4u!_TG3w)S$LSfWwl?AA<orXf~ShsdOUpvvQJ=Ck6G+SUD
zJHp{!?U7vVbg%YkR{QHl4CR<#(<bSe#|B}AJZxqVR?NeW55h`$*h7P`p*(DM5H_5L
zofw3T<Y6ZVVWWB2sX<sd4?8^wtK?y424Q1)*u#Uc@jR?L2%E^mJ~RkBl!rZ%!AKoH
z*V~=5x!Om2wI9yaKBn5hh?*WJ$C0d_5cM2YdQ9nz(&I`WQaY>jgwm5rPbqy^X;tZI
zrDv3W$ZQ;9#(R=X#LQFO%+us1*35S&ut4r(&Cho;&lrdo)|~5RKEmSGM@9I%=T#_~
zt&g#M>CGq2ouau7_3*5TSBh--3uf!%s(DW7FOuDy8!JWpT~9wT&>c*J32m25`~!6b
za?hLed7-Lly3hY)cd{=qvpjbg487D7XOyKB*vTm*e7>|SBo|~>01-B1HVWn)>KwLQ
zlE7_4*l#8kl&>;ZrLIVxKyeYGG_(prZ3LmdXjTKNlHKZ~NmY=PVg<@%$B%<_6!|s3
zw#|YS+T*D4III_hDb(2<%Ep2ym!RX;Rh4)sEo`<L;lf&`ffm|vYYSbH1u7)zsHd%v
zPo8eyN;g~0g?hC1z9m1paC+zKeq$~0KlvFxo#Juaxn~q|1yH8-q>PM<j78v6DCH2y
z78ZY0<$G{Qptd58Ha63gBi6(9R2XuJygtHQ>e>TCmP?iKGCm&^Nkxot%il?e{LlM4
z`_dTTcf}B3?iBjEB=-jdFH4xpUc7MY#D7e_I>>+T6v1|Euq2Zw-Hba)DsyW^S&I~K
zY@TjxD}kPp6__WT3^?c4lUC1S^n)#oTTT6VBZT2tPoorOA<V;mezR2%s*P3<KK_89
z@+ua6kEkR?Nd{eQCCL#KtPorD>s8c5X>>D8=2;zw2~1!ZyVfq2?Q7e%TQDbYhSi!6
zQ4-5iwZe(i@7d<>kzDtI5nW8@gJNkZ+}ML9)L_ZL(!x*2QZsA!9yGZ$G9{8MH66T!
zTDf<`P;pWGl6ojxB*5Pv@u(?iM>O^TV&%0DjuleN09Ja$a#xlTRvutldHvq8LKA5_
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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.ui
old mode 100755
new mode 100644
index a8032bbd..3d7d4467
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.ui
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/inputconfigdialogue.ui
@@ -92,7 +92,7 @@
          <property name="minimumSize">
           <size>
            <width>0</width>
-           <height>350</height>
+           <height>365</height>
           </size>
          </property>
          <property name="maximumSize">
@@ -507,7 +507,7 @@
             <x>600</x>
             <y>158</y>
             <width>292</width>
-            <height>194</height>
+            <height>202</height>
            </rect>
           </property>
           <layout class="QGridLayout" name="gridLayout_5">
@@ -581,12 +581,12 @@
             </widget>
            </item>
            <item row="1" column="0">
-            <widget class="QCheckBox" name="althold">
+            <widget class="QCheckBox" name="_assisted_control">
              <property name="enabled">
               <bool>false</bool>
              </property>
              <property name="text">
-              <string>Altitude hold</string>
+              <string>Assisted control</string>
              </property>
              <property name="checkable">
               <bool>true</bool>
@@ -594,7 +594,7 @@
             </widget>
            </item>
            <item row="1" column="1">
-            <widget class="QPushButton" name="detectAltHold">
+            <widget class="QPushButton" name="_detect_assisted_control">
              <property name="enabled">
               <bool>false</bool>
              </property>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.py
old mode 100755
new mode 100644
index 31ac80bd..d3996ded
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 This dialogue is used to configure different log configurations that is used to
@@ -31,25 +31,23 @@ enable logging of data from the Crazyflie. These can then be used in different
 views in the UI.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LogConfigDialogue']
-
-import sys
-import os
 import logging
 
-logger = logging.getLogger(__name__)
+import cfclient
+from PyQt5 import Qt, QtWidgets, uic
+from PyQt5.QtCore import *  # noqa
+from PyQt5.QtWidgets import *  # noqa
+from PyQt5.Qt import *  # noqa
+
+from cflib.crazyflie.log import LogConfig
 
-from PyQt4 import Qt, QtCore, QtGui, uic
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4.Qt import *
+__author__ = 'Bitcraze AB'
+__all__ = ['LogConfigDialogue']
 
-from cflib.crazyflie.log import Log, LogVariable, LogConfig
+logger = logging.getLogger(__name__)
 
-(logconfig_widget_class,
-connect_widget_base_class) = (uic.loadUiType(sys.path[0] +
-                                 '/cfclient/ui/dialogs/logconfigdialogue.ui'))
+(logconfig_widget_class, connect_widget_base_class) = (
+    uic.loadUiType(cfclient.module_path + '/ui/dialogs/logconfigdialogue.ui'))
 
 NAME_FIELD = 0
 ID_FIELD = 1
@@ -57,7 +55,7 @@ PTYPE_FIELD = 2
 CTYPE_FIELD = 3
 
 
-class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
+class LogConfigDialogue(QtWidgets.QWidget, logconfig_widget_class):
 
     def __init__(self, helper, *args):
         super(LogConfigDialogue, self).__init__(*args)
@@ -77,7 +75,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
 
         self.loggingPeriod.textChanged.connect(self.periodChanged)
 
-        self.packetSize.setMaximum(30)
+        self.packetSize.setMaximum(26)
         self.currentSize = 0
         self.packetSize.setValue(0)
         self.period = 0
@@ -118,7 +116,14 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
             for leaf in self.getNodeChildren(node):
                 self.currentSize = (self.currentSize +
                                     self.decodeSize(leaf.text(CTYPE_FIELD)))
-        self.packetSize.setValue(self.currentSize)
+        if self.currentSize > 26:
+            self.packetSize.setMaximum(self.currentSize / 26.0 * 100.0)
+            self.packetSize.setFormat("%v%")
+            self.packetSize.setValue(self.currentSize / 26.0 * 100.0)
+        else:
+            self.packetSize.setMaximum(26)
+            self.packetSize.setFormat("%p%")
+            self.packetSize.setValue(self.currentSize)
 
     def addNewVar(self, logTreeItem, target):
         parentName = logTreeItem.parent().text(NAME_FIELD)
@@ -127,7 +132,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
         item = logTreeItem.clone()
 
         if (len(varParent) == 0):
-            newParent = QtGui.QTreeWidgetItem()
+            newParent = QtWidgets.QTreeWidgetItem()
             newParent.setData(0, Qt.DisplayRole, parentName)
             newParent.addChild(item)
             target.addTopLevelItem(newParent)
@@ -137,7 +142,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
             parent.addChild(item)
 
     def moveNodeItem(self, source, target, item):
-        if (item.parent() == None):
+        if (item.parent() is None):
             children = self.getNodeChildren(item)
             for c in children:
                 self.addNewVar(c, target)
@@ -154,7 +159,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
         self.checkAndEnableSaveButton()
 
     def checkAndEnableSaveButton(self):
-        if (self.currentSize > 0 and self.period > 0):
+        if self.currentSize > 0 and self.period > 0 and self.currentSize <= 26:
             self.saveButton.setEnabled(True)
         else:
             self.saveButton.setEnabled(False)
@@ -171,7 +176,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
                 if (parent.child(n).text(NAME_FIELD) == itemName):
                     node = parent.child(n)
                     break
-        if (node != None):
+        if (node is not None):
             self.moveNodeItem(source, target, node)
             return True
         return False
@@ -180,7 +185,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
         self.updateToc()
         self.populateDropDown()
         toc = self.helper.cf.log.toc
-        if (len(toc.toc.keys()) > 0):
+        if (len(list(toc.toc.keys())) > 0):
             self.configNameCombo.setEnabled(True)
         else:
             self.configNameCombo.setEnabled(False)
@@ -197,7 +202,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
             self.period = 0
 
     def showErrorPopup(self, caption, message):
-        self.box = QMessageBox()
+        self.box = QMessageBox()  # noqa
         self.box.setWindowTitle(caption)
         self.box.setText(message)
         # self.box.setButtonText(1, "Ok")
@@ -209,11 +214,11 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
 
         toc = self.helper.cf.log.toc
 
-        for group in toc.toc.keys():
-            groupItem = QtGui.QTreeWidgetItem()
+        for group in list(toc.toc.keys()):
+            groupItem = QtWidgets.QTreeWidgetItem()
             groupItem.setData(NAME_FIELD, Qt.DisplayRole, group)
-            for param in toc.toc[group].keys():
-                item = QtGui.QTreeWidgetItem()
+            for param in list(toc.toc[group].keys()):
+                item = QtWidgets.QTreeWidgetItem()
                 item.setData(NAME_FIELD, Qt.DisplayRole, param)
                 item.setData(ID_FIELD, Qt.DisplayRole,
                              toc.toc[group][param].ident)
@@ -241,7 +246,7 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
         for d in self.helper.logConfigReader.getLogConfigs():
             if (d.name == cText):
                 config = d
-        if (config == None):
+        if (config is None):
             logger.warning("Could not load config")
         else:
             self.resetTrees()
@@ -252,11 +257,11 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
                     parts = v.name.split(".")
                     varParent = parts[0]
                     varName = parts[1]
-                    if self.moveNodeByName(self.logTree,
-                                            self.varTree,
-                                            varParent,
-                                            varName) == False:
-                        logger.warning("Could not find node %s.%s!!", varParent, varName)
+                    if self.moveNodeByName(
+                            self.logTree, self.varTree, varParent,
+                            varName) is False:
+                        logger.warning("Could not find node %s.%s!!",
+                                       varParent, varName)
                 else:
                     logger.warning("Error: Mem vars not supported!")
 
@@ -280,4 +285,3 @@ class LogConfigDialogue(QtGui.QWidget, logconfig_widget_class):
                 completeName = "%s.%s" % (parentName, varName)
                 logconfig.add_variable(completeName, varType)
         return logconfig
-
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.pyc
deleted file mode 100755
index b40dc18a485fa00619560986b8b0610fc644e4df..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 11145
zcmc&)+jAV*T|Pa!&RBQLlC|r#$H`vA7O}FMu-R-aTWd)+c48}XOSXs-Gih}nNiEHE
zkEVNUDcC@<sVtD>IZy=;KvBgLRgi)wsN#)B{tI~Hg;%QJ`@YjXGj=vWQMJNypE>u-
z@ACbA=hr>-?~}DV;Wr<Jrua96-;eQR|A8bjW*4bvc0ChS%mFeL6AhVY*ffXCE;24Z
zY<7ps{D|2dF?PfpjT$><KEaT2HI0~N)wF76w`N)w%<cu#nlQT)rZs7HCymF6Mon|d
zY!|udUT((a#!Pe8wC2q2oM~M&yBAGs-t5jB&rX`7OU4eFqXiR<o295~7P0DgD`t1m
z>|SQw?vjbH@GB<5!mpYL3t!=R?1VXb&Dce=k5f&W9~kqAG2h<3%JXe4Pmv0Ljik1H
z7-#h;4w~sf*Vd8mW;UwlX+2Dn{rI5Uv1r}jw;h}0b#&_02YH+(Sv@}t@_}JBn*@7J
z%bo{ua!^nA>rs#g_5DuTLSI{7>jd9F+i%A9Mt%FxX0{#%2^*67o^@--Nq@!Klh{7Z
z>Zsz_hj(w(vJ2StYMh6d$JTGI=Cdf@OApqx-Sy%i@qgmq#_}-Q@(Pj%c|NM2wX|dN
z5oLd^8|RdWZX7Oq_|2KTz04}rW73?9;rCI{iFvHN>dJ1h7zLC45|Wj0Kg5xee5D(&
zIAUfiAc3P{N!=UWIOZBLcNBA-5Rd+`dKFLhGb9$037Irx8fDT`20~O(M$*Wp5%Q9m
zQ4@_QGe$vU4a9OxnJQ(3H8lg_Vdetmg_#M83^S9I8fK;nN!gt?(UfXtOf;>`tchln
znKRL>G8auWr_8+Zx0Wwr-yzS%W0AgNc(S)~u3VJ;J;-0h997J-iutiI9?C~UhP9sY
zo_WkQhM68oyKrWl)@k6uusX4AjGFfg+Q!XM)g0B#r^f7K^oaSPo1Eh=yx2B6*akh(
zIQE<Dtu!@IJKd|D8K|A@)y|oti(HvA%=c<9Noj==UNo))E~*O}q`5qK(EuGb&`L_z
zMn23mXjuvF-E|4>!=xRA$2p0*m8YHH!1hFk1Sj>g1ti>pOGQ%98&uztcyBn#9!IZM
z`owOek=1+<)9sFR`6oe#`DOGmPA9mT%r^H`l|4pj<uGm8mAyg(SK6KQ$cA~gLWPuK
zf61vr_NDe&ewZdJ&3NyBsUH}??S0q`T6<CO(QU3xnVRtakEit~G1{MILd5Hz%bzKW
zpZ}SBBGer`#aZI3$O}7`UqMc2ly%#-<D+Cmfkq=v;=IuigEE_U+Ye*O!J%!kBM+1F
zSZKRrgUEL71$(xc>8Jv!Ac|JId7dVk0vrjCZRGN4l7M0P1crAkMWN`(3V?BFn?(iH
zIBcd^qlR2F4azCYqJu%TW<hTrwz62Xk_C`4T7ym7iPK1+n%mQS?J!6Vuq*b!snAr`
za0&{%&9~z3yXCQq`@w14>b5jK>~?68)J&N{^P`~IwW5-nO!6*9`<Ku|dKGjIvX`Xb
z90Y*s`4Kls&KqyRoAj!cE8dj~{}xbQs4P@wys9_j^)Qrjzs4~c5<uQ_z#-7nGsmN*
z13N#&ngmV5W#yL%dPU`ES$T_wpr{-#D|ZKmSIf$@KO7jnwM-stNK6Gp@4P3oC28G<
zEaWkvK{oS!SvAr3_U1e9sry&nbz~+wi3jSLsZ$1?x>hur&!7Gh(8z{BJj%;ME_#_u
zd!yb2sQ&U3(i)TgJfV2-m&iO5v>ti%qkyY$5pWn-D*&u_`V}>U>I0pC@9U43%yW+v
zetE>nub3TnhDH0IXDmDY_cMNKb|P94?tWu=9I1l?!cUw$iL)3UjGw0Y-Q2dM{#n|A
z62{Glsw95jynm~4`|hoK>po}6i8D8|&?XVI_gfv{j8Nym<}@GWP=~D~nBz3bmZ1Gy
zc}&~M^U!`}Aq#|f<IQ<B@0zz*{7SvJzaDFU6@>#s6*>JfeHHRb91*dvnCC-uS?IW+
z0r?>sc>MQHmcYTjapi<kjt)Uh)C@`5wX~Z!=QC)xK}hvci@Z}uF)}O1#$}XQPzQ2_
zY>3a3kp6pEv4tn&KByu~-YZ_neNdO_MN1`q8yUb7WVm6>>31dhDuPs?6O=>*T&4V<
ze!XlK>DC`Flip5Om;%BuXv6@#9dQ@kv?uSIos%#06b1Mt^&<5nN;*Z(L6lr4|4o#&
ze`oUFW$_&(LLFKhnU1yXZ*P`T{yMw7g=D~3e61YOw1M+`ME`TZDcXr{8}}u<*)x8t
zL5CI~qjfd_t7|Y9qu%RYNN$itJxTr>6ey&iJjmqn;sZ(*@+--8fW>-P57`a4)9Cyh
zq#rZS<Y$AY#}(80DIF0w#%u+wjncnG6KA*}B^ZL+j@k+H3=l{k9vqxx$FeY07Lr9y
zjloOLu?VoNH|Av~(xY((JfQ6RAEWGlm6g=){WysTU75os66Ai6hljULgD`KNImK$G
ziPi0`X%n9$5@0<bD(u7&6jR_wKN=pxI&P*CiS;;ZH-j@j#TAb<h4&<I(_j>~)Al|4
z#5OgUKxt3gf!mD(T4If6D!gfRq^{)fIBYIBXzNh&?0Fpc+MBA8bjHMFRwwqUtM=DX
zlH{G2_;Gn0cEdi!efKv}(3Qe?m%PiBiOL-8Bt4f&Z>Cc7LW&&^*b~2hMFHsO#1EXM
z6n#e;3so0tLgY@bQWn-9FHq*F&5%oEbWQP2mZ9npU?-WV?qO|m)SudkEX8!#bpEKE
zL?}&D+}i?7tDC?}e);Eny||3qG$dETi*1cl@I7u&Dxh3VbvRiGJjBFhMhL_zv2g?9
z=MacqMlP`kj_nKbLoJ6W+tY9D57zr1a0I7wUbzI&Uqjh{pDpxQ!b2M#-%O%g3bJhV
zeC}m(!kH50vb5U?t-s02Ehcn6WlF+x6)37`dDo;y{0QZYcOIJMX-LvMjLT(sz3_hF
z57+P)lBj%o{_iam9PSr9e@8`J@tp{`qKpn$Kn5l=>fx#!It_3Q(-}vvH<9y65dRty
z=_o+K(KZr0w>!8|@EUYGXl7QPm8g84RP+(0G=GdIBWsO!)w@^`_!HfF+V>g?j!MuV
z=o9tGxiJ80ot{M9kjeCUjhCbqw<z*vzyN*+%@Uq-Jtl8~e}+f5WaEV-I}xdO#J+ul
zUPGFlOHEUTK$y%FSmmryAsRno5qTP((+!#ynjeH@3g_f&<~e){R3U}NW6CQ1dSn1n
z#IO4=w89W>p4>P1zk`bxOdVD|9x|Q366I^8IVlel2%3YwTX3>VtiVCcGLPs}o@K%O
z+sx6t`Hz^~Ve)k*L<0XqCLc2)yL@<A#{V7?=jsqy{2rtH2Pn#N(T>Q((8M{5llk;$
z97a(HlJjJ%t`H>#te$aee}O#|_pi%vW$2(UL8_;{3$QR3z2VQe10Q0DlkO6hCEJ2!
zsX1&0{6{#I<S}XxL@e1{$ilWJkWT|mAAkv0bwO29lmV}j04A&Kyt3^y6r{J)cDD&H
zZM~DW*VCtoi!X3oxbK_~gpR46c^ZnX0+VBVmdT-TQDKr|Ep6?k{%@e?0Dn2qVL4R*
zZU;Oe7^w621+v5R=`Ak*Gpt@Xpv34o?^R+@iPZdEV~<ynI4(KpDcD1niLefVbUb-_
zJYEPVyW{U8_y2>gLj4ZjL%56M-}4;9NDQo#E{o(Ux2zLVS<hZ8u8D*R+<ue-i+Ic(
zm>$pbAabrH@yxHkEK{6J!V!b7R7C;217`UPB+C=Vvd&Xa{V!tGf5el~y*1tt^l=Jl
z&(d()Yi!>^f_w5O;&pL)fid8ZYDEb^**RqW@-T15@ZFe>nbm=w&es}{5Td@!(}Vjq
z%Mj~cO;1I!J^V5x0dDQUgG!%n$2mOq!kgdb1@DFC+s)vhxGm6jx|c)w6=d&kxe2n{
z@u`g%6>^Ptz!WJfWxsC{UEnlm^OcwKEw{1r<d8cWRkG7bJDY%@_CJvpj$ae-qGl?^
zMV*HwQN*uRs2zDCwt#Ct2b#E_&+!!uK~vYk^~at^D3xKv2woxK*uyr~$QRz<bcOUz
z|4x2}9QdVj?4R;#*&i#D{K8l`X}mmQHOx3!&ZzY<?-ES!($UmlpXtx;Gc(v{_OtuU
zxjxwa#qy$ha_j;MpvQc9Ln!ETsVtwYxIPPgm*0WcBB-ixm!C4nxUx^<<i|{i(*7}%
zAtra3e1nOMJZJE~iA09_?z#)K$-RstpsYlGvmcyrH{rAVtZn_9945R}@gAqT&t!uM
z?+5)WfVQE|2c5Lrmi<zWZl3Dl7X&Tc49-)4h4TN5t!A$y0l-$~5d7w)@)f1ixM-Ho
zEW+XQ{iqYkxyF%AB)?FYDXI|W>l8{wUdtF0B%4lwi%p!oX?7r<4y_93;82sk;2a>j
z)xYUs)#9ed4fJ_0bB-&&d)49VO^jY=;Ld-qtj>fOxLAw+!<Zm}>38lP-S)oy?*oqG
zAtfd{R~8*$#ecz5So=xX`bh;(W$nk&LTnK$-oow%Spm|6VvM7{t9t01i;n|%A73p&
z1n!v&FfCKp&>NS2{AVN;qv><+7vKTb&`2czpxFkm;fO%-RR}mbVHRXal*MKmljig%
zYMH{KzpEe@Hh~woxK#t>kVni4FST7fLfC{CC`$}+;ifR+LR3J8SuHxJ6v&~A!zX~X
zd2R8U=kN_L+lwXu+Q~KV<WI`IyVt%b??{SBxQ&cxfpBm$swXMGr3j+pV+vh)-iUNV
zzd<B1dZQwTsy~47FN}<A{f+F#8`<^idYvR|@In2)ZPgJ`$}~0JCbkg@x6$=wArysH
z=u+JGXer&DL(M-#v;QfR-)Bd1m@n)Q?57cV8gvpw|NS;QTxaqGiQXT$_iT7q*+5W^
zaw@FBHuSNCb9Upb0WY{wRtkR*Y>RW>axU6y7p?ssas$CMft^e`_v2h<{|}HAm7bJ1
zmS;X+n`)<6gHH9iDh%J~{TrU_Z6pTx#dtYG8!*TSlP&TW4=*`2{Eo`8T5`_w5JvEr
zQl}GSoH{{Pp-X3gF_~-^Pj_%7+YS4Pm3ET1%rK~MTr-_VhW1*G<>wL5js=Fp=z$jV
z$ehFG7E?(uxrGgd`6Ng6r~D8HFK_wj&VJmqSrr`$5ql%kJHdPjRbj{C{^MZpHa_jy
zvQ4~GhIiylA|*;6=I}jm4+w8#LjMYzH0x<-<xu(0QPsDi^2mXf4af67CJI>HMGS9M
z_;Hd%;e7dB$6m*Pd>IATfTKgWvQB~Hmz}kuruTUIw<y3>#x}_UfD~Xyp$8Vh#)|9}
z01HK65mKO2d2d~RoarqIhK-YA06I8gr!J%_gNB;*$KNPHuGa~{d@Km4Lyc~_94WZ~
z;sWOILD&K#@$k41%0~uv5t4G!z{{2o6oD;*78wsBtXZBw&ga?Whi7@mmm&NytEq1<
zzjgVTb@F;{A}6pQOG^|O&~u6c(56suMJgD~@K>4ql!FOE7`P2TNE3x=s|~N;p1ZF9
zAvQ8Y-p?b$u=oVt#!SP1q1Q442@u-KyK6LP<M9DU4Luu;RvLAiDEf^3>XnpyHb=EJ
z);(mRKo7%x?z<JsT*5@y`$guYEBnmRRQrS<zs`i4>m#3XpZ^;xLa+G{PxdB~(Mol(
zI#sPzN2}x2nd&TlhfuCohpS_#S;Vtctu8CrN~Sg%5iCPVqo9kgg*wGIFO5dfY$8v5
z$`Cf;Ej)FO6ipN0$+@+1vtX(GKSu}uCrD%%HqRd9Uv)t?j&$z$Fk30eYQ6Cw*SCNS
zxR(|DB9KB}mUFTz#K($zH+o+;-N5=jO_I+eIGrGqY0e+U5>hVI4)VjCUu5-UyYW=-
zpBiB^$TA0_?n|7qVK2z6Yjv9QTb%!Qm`I1X+ynOxOJqNHW{Wf*I#K?pj@`(QAFYhy
cW0nc%!bD}d@&(zsTII?RucM=|claCnFUxjt2><{9

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/dialogs/logconfigdialogue.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.py
old mode 100755
new mode 100644
index 0c3b59b2..c33b9ba0
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.py
@@ -20,59 +20,62 @@
 #  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, write to the Free Software Foundation, Inc., 51
 #  Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
 """
 The main file for the Crazyflie control application.
 """
-__author__ = 'Bitcraze AB'
-__all__ = ['MainUI']
-
-import sys
 import logging
+import sys
 
-
-logger = logging.getLogger(__name__)
-
-import PyQt4
-from PyQt4 import QtGui, uic
-from PyQt4.QtCore import pyqtSignal, Qt, pyqtSlot, QDir, QUrl
-from PyQt4.QtGui import QLabel, QActionGroup, QMessageBox, QAction, QDesktopServices, QMenu
-
-from dialogs.connectiondialogue import ConnectDialogue
-from dialogs.inputconfigdialogue import InputConfigDialogue
-from dialogs.cf2config import Cf2ConfigDialog
-from dialogs.cf1config import Cf1ConfigDialog
-from cflib.crazyflie import Crazyflie
-from dialogs.logconfigdialogue import LogConfigDialogue
-
-from cfclient.utils.input import JoystickReader
-from cfclient.utils.zmq_param import ZMQParamAccess
-from cfclient.utils.zmq_led_driver import ZMQLEDDriver
-from cfclient.utils.config import Config
-from cfclient.utils.logconfigreader import LogConfigReader
-from cfclient.utils.config_manager import ConfigManager
-
-import cfclient.ui.toolboxes
+import cfclient
 import cfclient.ui.tabs
+import cfclient.ui.toolboxes
 import cflib.crtp
+from cfclient.ui.dialogs.about import AboutDialog
+from cfclient.ui.dialogs.bootloader import BootloaderDialog
+from cfclient.utils.config import Config
+from cfclient.utils.config_manager import ConfigManager
+from cfclient.utils.input import JoystickReader
+from cfclient.utils.logconfigreader import LogConfigReader
+from cfclient.utils.zmq_led_driver import ZMQLEDDriver
+from cfclient.utils.zmq_param import ZMQParamAccess
+from cflib.crazyflie import Crazyflie
+from cflib.crazyflie.log import LogConfig
+from cflib.crazyflie.mem import MemoryElement
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import QDir
+from PyQt5.QtCore import QThread
+from PyQt5.QtCore import QUrl
+from PyQt5.QtWidgets import QAction
+from PyQt5.QtWidgets import QActionGroup
+from PyQt5.QtGui import QDesktopServices
+from PyQt5.QtWidgets import QLabel
+from PyQt5.QtWidgets import QMenu
+from PyQt5.QtWidgets import QMessageBox
+
+from .dialogs.cf1config import Cf1ConfigDialog
+from .dialogs.cf2config import Cf2ConfigDialog
+from .dialogs.inputconfigdialogue import InputConfigDialogue
+from .dialogs.logconfigdialogue import LogConfigDialogue
 
-from cflib.crazyflie.log import Log, LogVariable, LogConfig
+__author__ = 'Bitcraze AB'
+__all__ = ['MainUI']
 
-from cfclient.ui.dialogs.bootloader import BootloaderDialog
-from cfclient.ui.dialogs.about import AboutDialog
+logger = logging.getLogger(__name__)
 
-from cflib.crazyflie.mem import MemoryElement
+INTERFACE_PROMPT_TEXT = 'Select an interface'
 
 (main_window_class,
-main_windows_base_class) = (uic.loadUiType(sys.path[0] +
-                                           '/cfclient/ui/main.ui'))
+ main_windows_base_class) = (uic.loadUiType(cfclient.module_path +
+                                            '/ui/main.ui'))
 
 
-class MyDockWidget(QtGui.QDockWidget):
+class MyDockWidget(QtWidgets.QDockWidget):
     closed = pyqtSignal()
 
     def closeEvent(self, event):
@@ -84,10 +87,32 @@ class UIState:
     DISCONNECTED = 0
     CONNECTING = 1
     CONNECTED = 2
+    SCANNING = 3
+
+
+class BatteryStates:
+    BATTERY, CHARGING, CHARGED, LOW_POWER = list(range(4))
+
+
+COLOR_BLUE = '#3399ff'
+COLOR_GREEN = '#00ff60'
+COLOR_RED = '#cc0404'
 
 
-class MainUI(QtGui.QMainWindow, main_window_class):
+def progressbar_stylesheet(color):
+    return """
+        QProgressBar {
+            border: 1px solid #333;
+            background-color: transparent;
+        }
 
+        QProgressBar::chunk {
+            background-color: """ + color + """;
+        }
+    """
+
+
+class MainUI(QtWidgets.QMainWindow, main_window_class):
     connectionLostSignal = pyqtSignal(str, str)
     connectionInitiatedSignal = pyqtSignal(str)
     batteryUpdatedSignal = pyqtSignal(int, object, object)
@@ -103,46 +128,55 @@ class MainUI(QtGui.QMainWindow, main_window_class):
     def __init__(self, *args):
         super(MainUI, self).__init__(*args)
         self.setupUi(self)
-        
+
+        # Restore window size if present in the config file
+        try:
+            size = Config().get("window_size")
+            self.resize(size[0], size[1])
+        except KeyError:
+            pass
+
         ######################################################
-        ### By lxrocks
-        ### 'Skinny Progress Bar' tweak for Yosemite
-        ### Tweak progress bar - artistic I am not - so pick your own colors !!!
-        ### Only apply to Yosemite
+        # By lxrocks
+        # 'Skinny Progress Bar' tweak for Yosemite
+        # Tweak progress bar - artistic I am not - so pick your own colors !!!
+        # Only apply to Yosemite
         ######################################################
         import platform
+
         if platform.system() == 'Darwin':
-        
-            (Version,junk,machine) =  platform.mac_ver()
-            logger.info("This is a MAC - checking if we can apply Progress Bar Stylesheet for Yosemite Skinny Bars ")
-            yosemite = (10,10,0)
+
+            (Version, junk, machine) = platform.mac_ver()
+            logger.info("This is a MAC - checking if we can apply Progress "
+                        "Bar Stylesheet for Yosemite Skinny Bars ")
+            yosemite = (10, 10, 0)
             tVersion = tuple(map(int, (Version.split("."))))
-            
+
             if tVersion >= yosemite:
-                logger.info( "Found Yosemite:")
-        
+                logger.info("Found Yosemite - applying stylesheet")
+
                 tcss = """
                     QProgressBar {
-                    border: 2px solid grey;
-                    border-radius: 5px;
-                    text-align: center;
-                }
-                QProgressBar::chunk {
-                     background-color: #05B8CC;
-                 }
+                        border: 1px solid grey;
+                        border-radius: 5px;
+                        text-align: center;
+                    }
+                    QProgressBar::chunk {
+                        background-color: """ + COLOR_BLUE + """;
+                    }
                  """
                 self.setStyleSheet(tcss)
-                
+
             else:
-                logger.info( "Pre-Yosemite")
-        
+                logger.info("Pre-Yosemite - skinny bar stylesheet not applied")
+
         ######################################################
-        
-        self.cf = Crazyflie(ro_cache=sys.path[0] + "/cflib/cache",
-                            rw_cache=sys.path[1] + "/cache")
+
+        self.cf = Crazyflie(ro_cache=None,
+                            rw_cache=cfclient.config_path + "/cache")
 
         cflib.crtp.init_drivers(enable_debug_driver=Config()
-                                                .get("enable_debug_driver"))
+                                .get("enable_debug_driver"))
 
         zmq_params = ZMQParamAccess(self.cf)
         zmq_params.start()
@@ -150,8 +184,9 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         zmq_leds = ZMQLEDDriver(self.cf)
         zmq_leds.start()
 
-        # Create the connection dialogue
-        self.connectDialogue = ConnectDialogue()
+        self.scanner = ScannerThread()
+        self.scanner.interfaceFoundSignal.connect(self.foundInterfaces)
+        self.scanner.start()
 
         # Create and start the Input Reader
         self._statusbar_label = QLabel("No input-device found, insert one to"
@@ -160,70 +195,84 @@ class MainUI(QtGui.QMainWindow, main_window_class):
 
         self.joystickReader = JoystickReader()
         self._active_device = ""
-        #self.configGroup = QActionGroup(self._menu_mappings, exclusive=True)
+        # self.configGroup = QActionGroup(self._menu_mappings, exclusive=True)
 
         self._mux_group = QActionGroup(self._menu_inputdevice, exclusive=True)
 
         # TODO: Need to reload configs
-        #ConfigManager().conf_needs_reload.add_callback(self._reload_configs)
-
-        # Connections for the Connect Dialogue
-        self.connectDialogue.requestConnectionSignal.connect(self.cf.open_link)
+        # ConfigManager().conf_needs_reload.add_callback(self._reload_configs)
 
-        self.cf.connection_failed.add_callback(self.connectionFailedSignal.emit)
+        self.cf.connection_failed.add_callback(
+            self.connectionFailedSignal.emit)
         self.connectionFailedSignal.connect(self._connection_failed)
-        
-        
-        self._input_device_error_signal.connect(self._display_input_device_error)
+
+        self._input_device_error_signal.connect(
+            self._display_input_device_error)
         self.joystickReader.device_error.add_callback(
-                        self._input_device_error_signal.emit)
+            self._input_device_error_signal.emit)
         self._input_discovery_signal.connect(self.device_discovery)
         self.joystickReader.device_discovery.add_callback(
-                        self._input_discovery_signal.emit)
+            self._input_discovery_signal.emit)
+
+        # Hide the 'File' menu on OS X, since its only item, 'Exit', gets
+        # merged into the application menu.
+        if sys.platform == 'darwin':
+            self.menuFile.menuAction().setVisible(False)
 
         # Connect UI signals
-        self.menuItemConnect.triggered.connect(self._connect)
         self.logConfigAction.triggered.connect(self._show_connect_dialog)
+        self.interfaceCombo.currentIndexChanged['QString'].connect(
+            self.interfaceChanged)
         self.connectButton.clicked.connect(self._connect)
-        self.quickConnectButton.clicked.connect(self._quick_connect)
-        self.menuItemQuickConnect.triggered.connect(self._quick_connect)
-        self.menuItemConfInputDevice.triggered.connect(self._show_input_device_config_dialog)
+        self.scanButton.clicked.connect(self._scan)
+        self.menuItemConnect.triggered.connect(self._connect)
+        self.menuItemConfInputDevice.triggered.connect(
+            self._show_input_device_config_dialog)
         self.menuItemExit.triggered.connect(self.closeAppRequest)
-        self.batteryUpdatedSignal.connect(self._update_vbatt)
+        self.batteryUpdatedSignal.connect(self._update_battery)
         self._menuitem_rescandevices.triggered.connect(self._rescan_devices)
-        self._menuItem_openconfigfolder.triggered.connect(self._open_config_folder)
+        self._menuItem_openconfigfolder.triggered.connect(
+            self._open_config_folder)
+
+        self.address.setValue(0xE7E7E7E7E7)
 
         self._auto_reconnect_enabled = Config().get("auto_reconnect")
         self.autoReconnectCheckBox.toggled.connect(
-                                              self._auto_reconnect_changed)
+            self._auto_reconnect_changed)
         self.autoReconnectCheckBox.setChecked(Config().get("auto_reconnect"))
-        
+
         self.joystickReader.input_updated.add_callback(
-                                         self.cf.commander.send_setpoint)
+            self.cf.commander.send_setpoint)
+
+        self.joystickReader.assisted_input_updated.add_callback(
+            self.cf.commander.send_velocity_world_setpoint)
 
         # Connection callbacks and signal wrappers for UI protection
         self.cf.connected.add_callback(self.connectionDoneSignal.emit)
         self.connectionDoneSignal.connect(self._connected)
         self.cf.disconnected.add_callback(self.disconnectedSignal.emit)
-        self.disconnectedSignal.connect(
-                        lambda linkURI: self._update_ui_state(UIState.DISCONNECTED,
-                                                        linkURI))
+        self.disconnectedSignal.connect(self._disconnected)
         self.cf.connection_lost.add_callback(self.connectionLostSignal.emit)
         self.connectionLostSignal.connect(self._connection_lost)
         self.cf.connection_requested.add_callback(
-                                         self.connectionInitiatedSignal.emit)
-        self.connectionInitiatedSignal.connect(
-                           lambda linkURI: self._update_ui_state(UIState.CONNECTING,
-                                                           linkURI))
+            self.connectionInitiatedSignal.emit)
+        self.connectionInitiatedSignal.connect(self._connection_initiated)
         self._log_error_signal.connect(self._logging_error)
 
+        self.batteryBar.setTextVisible(False)
+        self.batteryBar.setStyleSheet(progressbar_stylesheet(COLOR_BLUE))
+
+        self.linkQualityBar.setTextVisible(False)
+        self.linkQualityBar.setStyleSheet(progressbar_stylesheet(COLOR_BLUE))
+
         # Connect link quality feedback
         self.cf.link_quality_updated.add_callback(self.linkQualitySignal.emit)
         self.linkQualitySignal.connect(
-                   lambda percentage: self.linkQualityBar.setValue(percentage))
+            lambda percentage: self.linkQualityBar.setValue(percentage))
 
-        # Set UI state in disconnected buy default
-        self._update_ui_state(UIState.DISCONNECTED)
+        self._selected_interface = None
+        self._initial_scan = True
+        self._scan()
 
         # Parse the log configuration files
         self.logConfigReader = LogConfigReader(self.cf)
@@ -249,39 +298,18 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         self._menu_cf2_config.triggered.connect(self._cf2config_dialog.show)
         self._menu_cf1_config.triggered.connect(self._cf1config_dialog.show)
 
-        # Loading toolboxes (A bit of magic for a lot of automatic)
-        self.toolboxes = []
-        self.toolboxesMenuItem.setMenu(QtGui.QMenu())
-        for t_class in cfclient.ui.toolboxes.toolboxes:
-            toolbox = t_class(cfclient.ui.pluginhelper)
-            dockToolbox = MyDockWidget(toolbox.getName())
-            dockToolbox.setWidget(toolbox)
-            self.toolboxes += [dockToolbox, ]
-
-            # Add menu item for the toolbox
-            item = QtGui.QAction(toolbox.getName(), self)
-            item.setCheckable(True)
-            item.triggered.connect(self.toggleToolbox)
-            self.toolboxesMenuItem.menu().addAction(item)
-
-            dockToolbox.closed.connect(lambda: self.toggleToolbox(False))
-
-            # Setup some introspection
-            item.dockToolbox = dockToolbox
-            item.menuItem = item
-            dockToolbox.dockToolbox = dockToolbox
-            dockToolbox.menuItem = item
-
         # Load and connect tabs
-        self.tabsMenuItem.setMenu(QtGui.QMenu())
+        self.tabsMenuItem = QMenu("Tabs", self.menuView, enabled=True)
+        self.menuView.addMenu(self.tabsMenuItem)
+
+        # self.tabsMenuItem.setMenu(QtWidgets.QMenu())
         tabItems = {}
         self.loadedTabs = []
         for tabClass in cfclient.ui.tabs.available:
             tab = tabClass(self.tabs, cfclient.ui.pluginhelper)
-            item = QtGui.QAction(tab.getMenuName(), self)
-            item.setCheckable(True)
+            item = QtWidgets.QAction(tab.getMenuName(), self, checkable=True)
             item.toggled.connect(tab.toggleVisibility)
-            self.tabsMenuItem.menu().addAction(item)
+            self.tabsMenuItem.addAction(item)
             tabItems[tab.getTabName()] = item
             self.loadedTabs.append(tab)
             if not tab.enabled:
@@ -291,12 +319,38 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         try:
             for tName in Config().get("open_tabs").split(","):
                 t = tabItems[tName]
-                if (t != None and t.isEnabled()):
+                if (t is not None and t.isEnabled()):
                     # Toggle though menu so it's also marked as open there
                     t.toggle()
         except Exception as e:
             logger.warning("Exception while opening tabs [{}]".format(e))
 
+        # Loading toolboxes (A bit of magic for a lot of automatic)
+        self.toolboxesMenuItem = QMenu("Toolboxes", self.menuView,
+                                       enabled=True)
+        self.menuView.addMenu(self.toolboxesMenuItem)
+
+        self.toolboxes = []
+        for t_class in cfclient.ui.toolboxes.toolboxes:
+            toolbox = t_class(cfclient.ui.pluginhelper)
+            dockToolbox = MyDockWidget(toolbox.getName())
+            dockToolbox.setWidget(toolbox)
+            self.toolboxes += [dockToolbox, ]
+
+            # Add menu item for the toolbox
+            item = QtWidgets.QAction(toolbox.getName(), self)
+            item.setCheckable(True)
+            item.triggered.connect(self.toggleToolbox)
+            self.toolboxesMenuItem.addAction(item)
+
+            dockToolbox.closed.connect(lambda: self.toggleToolbox(False))
+
+            # Setup some introspection
+            item.dockToolbox = dockToolbox
+            item.menuItem = item
+            dockToolbox.dockToolbox = dockToolbox
+            dockToolbox.menuItem = item
+
         # References to all the device sub-menus in the "Input device" menu
         self._all_role_menus = ()
         # Used to filter what new devices to add default mapping to
@@ -315,54 +369,127 @@ class MainUI(QtGui.QMainWindow, main_window_class):
             node.toggled.connect(self._mux_selected)
             self._mux_group.addAction(node)
             self._menu_inputdevice.addAction(node)
-            self._all_mux_nodes += (node, )
+            self._all_mux_nodes += (node,)
             mux_subnodes = ()
             for name in m.supported_roles():
                 sub_node = QMenu("    {}".format(name),
-                                   self._menu_inputdevice,
-                                   enabled=False)
+                                 self._menu_inputdevice,
+                                 enabled=False)
                 self._menu_inputdevice.addMenu(sub_node)
-                mux_subnodes += (sub_node, )
+                mux_subnodes += (sub_node,)
                 self._all_role_menus += ({"muxmenu": node,
-                                          "rolemenu": sub_node}, )
+                                          "rolemenu": sub_node},)
             node.setData((m, mux_subnodes))
 
         self._mapping_support = True
 
-    def _update_ui_state(self, newState, linkURI=""):
-        self.uiState = newState
-        if newState == UIState.DISCONNECTED:
+    def interfaceChanged(self, interface):
+        if interface == INTERFACE_PROMPT_TEXT:
+            self._selected_interface = None
+        else:
+            self._selected_interface = interface
+        self._update_ui_state()
+
+    def foundInterfaces(self, interfaces):
+        selected_interface = self._selected_interface
+
+        self.interfaceCombo.clear()
+        self.interfaceCombo.addItem(INTERFACE_PROMPT_TEXT)
+
+        formatted_interfaces = []
+        for i in interfaces:
+            if len(i[1]) > 0:
+                interface = "%s - %s" % (i[0], i[1])
+            else:
+                interface = i[0]
+            formatted_interfaces.append(interface)
+        self.interfaceCombo.addItems(formatted_interfaces)
+
+        if self._initial_scan:
+            self._initial_scan = False
+
+            try:
+                if len(Config().get("link_uri")) > 0:
+                    formatted_interfaces.index(Config().get("link_uri"))
+                    selected_interface = Config().get("link_uri")
+            except KeyError:
+                #  The configuration for link_uri was not found
+                pass
+            except ValueError:
+                #  The saved URI was not found while scanning
+                pass
+
+        if len(interfaces) == 1 and selected_interface is None:
+            selected_interface = interfaces[0][0]
+
+        newIndex = 0
+        if selected_interface is not None:
+            try:
+                newIndex = formatted_interfaces.index(selected_interface) + 1
+            except ValueError:
+                pass
+
+        self.interfaceCombo.setCurrentIndex(newIndex)
+
+        self.uiState = UIState.DISCONNECTED
+        self._update_ui_state()
+
+    def _update_ui_state(self):
+        if self.uiState == UIState.DISCONNECTED:
             self.setWindowTitle("Not connected")
+            canConnect = self._selected_interface is not None
             self.menuItemConnect.setText("Connect to Crazyflie")
+            self.menuItemConnect.setEnabled(canConnect)
             self.connectButton.setText("Connect")
-            self.menuItemQuickConnect.setEnabled(True)
+            self.connectButton.setToolTip(
+                "Connect to the Crazyflie on the selected interface")
+            self.connectButton.setEnabled(canConnect)
+            self.scanButton.setText("Scan")
+            self.scanButton.setEnabled(True)
+            self.address.setEnabled(True)
             self.batteryBar.setValue(3000)
             self._menu_cf2_config.setEnabled(False)
             self._menu_cf1_config.setEnabled(True)
             self.linkQualityBar.setValue(0)
             self.menuItemBootloader.setEnabled(True)
             self.logConfigAction.setEnabled(False)
-            if len(Config().get("link_uri")) > 0:
-                self.quickConnectButton.setEnabled(True)
-        if newState == UIState.CONNECTED:
-            s = "Connected on %s" % linkURI
+            self.interfaceCombo.setEnabled(True)
+        elif self.uiState == UIState.CONNECTED:
+            s = "Connected on %s" % self._selected_interface
             self.setWindowTitle(s)
             self.menuItemConnect.setText("Disconnect")
+            self.menuItemConnect.setEnabled(True)
             self.connectButton.setText("Disconnect")
+            self.connectButton.setToolTip("Disconnect from the Crazyflie")
+            self.scanButton.setEnabled(False)
             self.logConfigAction.setEnabled(True)
             # Find out if there's an I2C EEPROM, otherwise don't show the
             # dialog.
             if len(self.cf.mem.get_mems(MemoryElement.TYPE_I2C)) > 0:
                 self._menu_cf2_config.setEnabled(True)
             self._menu_cf1_config.setEnabled(False)
-        if newState == UIState.CONNECTING:
-            s = "Connecting to {} ...".format(linkURI)
+        elif self.uiState == UIState.CONNECTING:
+            s = "Connecting to {} ...".format(self._selected_interface)
             self.setWindowTitle(s)
             self.menuItemConnect.setText("Cancel")
+            self.menuItemConnect.setEnabled(True)
             self.connectButton.setText("Cancel")
-            self.quickConnectButton.setEnabled(False)
+            self.connectButton.setToolTip("Cancel connecting to the Crazyflie")
+            self.scanButton.setEnabled(False)
+            self.address.setEnabled(False)
             self.menuItemBootloader.setEnabled(False)
-            self.menuItemQuickConnect.setEnabled(False)
+            self.interfaceCombo.setEnabled(False)
+        elif self.uiState == UIState.SCANNING:
+            self.setWindowTitle("Scanning ...")
+            self.connectButton.setText("Connect")
+            self.menuItemConnect.setEnabled(False)
+            self.connectButton.setText("Connect")
+            self.connectButton.setEnabled(False)
+            self.scanButton.setText("Scanning...")
+            self.scanButton.setEnabled(False)
+            self.address.setEnabled(False)
+            self.menuItemBootloader.setEnabled(False)
+            self.interfaceCombo.setEnabled(False)
 
     @pyqtSlot(bool)
     def toggleToolbox(self, display):
@@ -386,34 +513,46 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         self._active_device = ""
         self.joystickReader.stop_input()
 
-        #for c in self._menu_mappings.actions():
+        # for c in self._menu_mappings.actions():
         #    c.setEnabled(False)
-        #devs = self.joystickReader.available_devices()
-        #if (len(devs) > 0):
+        # devs = self.joystickReader.available_devices()
+        # if (len(devs) > 0):
         #    self.device_discovery(devs)
 
     def _show_input_device_config_dialog(self):
         self.inputConfig = InputConfigDialogue(self.joystickReader)
         self.inputConfig.show()
-        
+
     def _auto_reconnect_changed(self, checked):
-        self._auto_reconnect_enabled = checked 
+        self._auto_reconnect_enabled = checked
         Config().set("auto_reconnect", checked)
         logger.info("Auto reconnect enabled: {}".format(checked))
 
     def _show_connect_dialog(self):
         self.logConfigDialogue.show()
 
-    def _update_vbatt(self, timestamp, data, logconf):
+    def _update_battery(self, timestamp, data, logconf):
         self.batteryBar.setValue(int(data["pm.vbat"] * 1000))
 
-    def _connected(self, linkURI):
-        self._update_ui_state(UIState.CONNECTED, linkURI)
+        color = COLOR_BLUE
+        # TODO firmware reports fully-charged state as 'Battery',
+        # rather than 'Charged'
+        if data["pm.state"] in [BatteryStates.CHARGING, BatteryStates.CHARGED]:
+            color = COLOR_GREEN
+        elif data["pm.state"] == BatteryStates.LOW_POWER:
+            color = COLOR_RED
 
-        Config().set("link_uri", str(linkURI))
+        self.batteryBar.setStyleSheet(progressbar_stylesheet(color))
+
+    def _connected(self):
+        self.uiState = UIState.CONNECTED
+        self._update_ui_state()
+
+        Config().set("link_uri", str(self._selected_interface))
 
         lg = LogConfig("Battery", 1000)
         lg.add_variable("pm.vbat", "float")
+        lg.add_variable("pm.state", "int8_t")
         try:
             self.cf.log.add_config(lg)
             lg.data_received_cb.add_callback(self.batteryUpdatedSignal.emit)
@@ -422,23 +561,25 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         except KeyError as e:
             logger.warning(str(e))
 
-        mem = self.cf.mem.get_mems(MemoryElement.TYPE_DRIVER_LED)[0]
-        mem.write_data(self._led_write_done)
+        mems = self.cf.mem.get_mems(MemoryElement.TYPE_DRIVER_LED)
+        if len(mems) > 0:
+            mems[0].write_data(self._led_write_done)
 
-        #self._led_write_test = 0
+    def _disconnected(self):
+        self.uiState = UIState.DISCONNECTED
+        self._update_ui_state()
 
-        #mem.leds[self._led_write_test] = [10, 20, 30]
-        #mem.write_data(self._led_write_done)
+    def _connection_initiated(self):
+        self.uiState = UIState.CONNECTING
+        self._update_ui_state()
 
     def _led_write_done(self, mem, addr):
         logger.info("LED write done callback")
-        #self._led_write_test += 1
-        #mem.leds[self._led_write_test] = [10, 20, 30]
-        #mem.write_data(self._led_write_done)
 
     def _logging_error(self, log_conf, msg):
         QMessageBox.about(self, "Log error", "Error when starting log config"
-                " [{}]: {}".format(log_conf.name, msg))
+                                             " [{}]: {}".format(log_conf.name,
+                                                                msg))
 
     def _connection_lost(self, linkURI, msg):
         if not self._auto_reconnect_enabled:
@@ -446,32 +587,44 @@ class MainUI(QtGui.QMainWindow, main_window_class):
                 warningCaption = "Communication failure"
                 error = "Connection lost to {}: {}".format(linkURI, msg)
                 QMessageBox.critical(self, warningCaption, error)
-                self._update_ui_state(UIState.DISCONNECTED, linkURI)
+                self.uiState = UIState.DISCONNECTED
+                self._update_ui_state()
         else:
-            self._quick_connect()
+            self._connect()
 
     def _connection_failed(self, linkURI, error):
         if not self._auto_reconnect_enabled:
             msg = "Failed to connect on {}: {}".format(linkURI, error)
             warningCaption = "Communication failure"
             QMessageBox.critical(self, warningCaption, msg)
-            self._update_ui_state(UIState.DISCONNECTED, linkURI)
+            self.uiState = UIState.DISCONNECTED
+            self._update_ui_state()
         else:
-            self._quick_connect()
+            self._connect()
 
     def closeEvent(self, event):
         self.hide()
         self.cf.close_link()
         Config().save_file()
 
+    def resizeEvent(self, event):
+        Config().set("window_size", [event.size().width(),
+                                     event.size().height()])
+
     def _connect(self):
         if self.uiState == UIState.CONNECTED:
             self.cf.close_link()
         elif self.uiState == UIState.CONNECTING:
             self.cf.close_link()
-            self._update_ui_state(UIState.DISCONNECTED)
+            self.uiState = UIState.DISCONNECTED
+            self._update_ui_state()
         else:
-            self.connectDialogue.show()
+            self.cf.open_link(self._selected_interface)
+
+    def _scan(self):
+        self.uiState = UIState.SCANNING
+        self._update_ui_state()
+        self.scanner.scanSignal.emit(self.address.value())
 
     def _display_input_device_error(self, error):
         self.cf.close_link()
@@ -482,11 +635,11 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         reference to the raw mux object as well as to the associated device
         sub-nodes"""
         if not checked:
-            (mux, sub_nodes) = self.sender().data().toPyObject()
+            (mux, sub_nodes) = self.sender().data()
             for s in sub_nodes:
                 s.setEnabled(False)
         else:
-            (mux, sub_nodes) = self.sender().data().toPyObject()
+            (mux, sub_nodes) = self.sender().data()
             for s in sub_nodes:
                 s.setEnabled(True)
             self.joystickReader.set_mux(mux=mux)
@@ -518,13 +671,13 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         if len(self.joystickReader.available_devices()) > 0:
             mux = self.joystickReader._selected_mux
             msg = "Using {} mux with ".format(mux.name)
-            for key in mux._devs.keys()[:-1]:
+            for key in list(mux._devs.keys())[:-1]:
                 if mux._devs[key]:
                     msg += "{}, ".format(self._get_dev_status(mux._devs[key]))
                 else:
                     msg += "N/A, "
             # Last item
-            key = mux._devs.keys()[-1]
+            key = list(mux._devs.keys())[-1]
             if mux._devs[key]:
                 msg += "{}".format(self._get_dev_status(mux._devs[key]))
             else:
@@ -537,22 +690,22 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         """Called when a new input device has been selected from the menu. The
         data in the menu object is the associated map menu (directly under the
         item in the menu) and the raw device"""
-        (map_menu, device, mux_menu) = self.sender().data().toPyObject()
+        (map_menu, device, mux_menu) = self.sender().data()
         if not checked:
             if map_menu:
                 map_menu.setEnabled(False)
-            # Do not close the device, since we don't know exactly
-            # how many devices the mux can have open. When selecting a
-            # new mux the old one will take care of this.
+                # Do not close the device, since we don't know exactly
+                # how many devices the mux can have open. When selecting a
+                # new mux the old one will take care of this.
         else:
             if map_menu:
                 map_menu.setEnabled(True)
 
-            (mux, sub_nodes) = mux_menu.data().toPyObject()
+            (mux, sub_nodes) = mux_menu.data()
             for role_node in sub_nodes:
                 for dev_node in role_node.children():
                     if type(dev_node) is QAction and dev_node.isChecked():
-                        if device.id == dev_node.data().toPyObject()[1].id \
+                        if device.id == dev_node.data()[1].id \
                                 and dev_node is not self.sender():
                             dev_node.setChecked(False)
 
@@ -562,8 +715,9 @@ class MainUI(QtGui.QMainWindow, main_window_class):
 
             Config().set("input_device", str(device.name))
 
-            self._mapping_support = self.joystickReader.start_input(device.name,
-                                                                    role_in_mux)
+            self._mapping_support = self.joystickReader.start_input(
+                device.name,
+                role_in_mux)
         self._update_input_device_footer()
 
     def _inputconfig_selected(self, checked):
@@ -574,7 +728,7 @@ class MainUI(QtGui.QMainWindow, main_window_class):
             return
 
         selected_mapping = str(self.sender().text())
-        device = self.sender().data().toPyObject().data().toPyObject()[1]
+        device = self.sender().data().data()[1]
         self.joystickReader.set_input_map(device.name, selected_mapping)
         self._update_input_device_footer()
 
@@ -612,7 +766,7 @@ class MainUI(QtGui.QMainWindow, main_window_class):
                         # select the default mapping for it.
                         if d not in self._available_devices:
                             last_map = Config().get("device_config_mapping")
-                            if last_map.has_key(d.name) and last_map[d.name] == c:
+                            if d.name in last_map and last_map[d.name] == c:
                                 node.setChecked(True)
                     role_menu.addMenu(map_node)
                 dev_node.setData((map_node, d, mux_menu))
@@ -622,12 +776,12 @@ class MainUI(QtGui.QMainWindow, main_window_class):
         # a new one is inserted
         self._available_devices = ()
         for d in devs:
-            self._available_devices += (d, )
+            self._available_devices += (d,)
 
         # Only enable MUX nodes if we have enough devies to cover
         # the roles
         for mux_node in self._all_mux_nodes:
-            (mux, sub_nodes) = mux_node.data().toPyObject()
+            (mux, sub_nodes) = mux_node.data()
             if len(mux.supported_roles()) <= len(self._available_devices):
                 mux_node.setEnabled(True)
 
@@ -652,16 +806,25 @@ class MainUI(QtGui.QMainWindow, main_window_class):
 
         self._update_input_device_footer()
 
-    def _quick_connect(self):
-        try:
-            self.cf.open_link(Config().get("link_uri"))
-        except KeyError:
-            self.cf.open_link("")
-
     def _open_config_folder(self):
-        QDesktopServices.openUrl(QUrl("file:///" +
-                                      QDir.toNativeSeparators(sys.path[1])))
+        QDesktopServices.openUrl(
+            QUrl("file:///" +
+                 QDir.toNativeSeparators(cfclient.config_path)))
 
     def closeAppRequest(self):
         self.close()
         sys.exit(0)
+
+
+class ScannerThread(QThread):
+
+    scanSignal = pyqtSignal(object)
+    interfaceFoundSignal = pyqtSignal(object)
+
+    def __init__(self):
+        QThread.__init__(self)
+        self.moveToThread(self)
+        self.scanSignal.connect(self.scan)
+
+    def scan(self, address):
+        self.interfaceFoundSignal.emit(cflib.crtp.scan_interfaces(address))
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.pyc
deleted file mode 100755
index 354b7bcf1879459e213634c9b237de32a70a699e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 22709
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
Ye;eYII)iYSpfrc4HGF*2H`@EZ0V+4lQ2+n{

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.ui
old mode 100755
new mode 100644
index 25cd15f6..3e9d5270
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.ui
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/main.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>872</width>
-    <height>641</height>
+    <height>671</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -22,16 +22,36 @@
      <layout class="QVBoxLayout" name="verticalLayout_2">
       <item>
        <layout class="QGridLayout" name="gridLayout_2">
-        <item row="0" column="1">
-         <widget class="QPushButton" name="quickConnectButton">
-          <property name="enabled">
+        <item row="0" column="0">
+         <widget class="QComboBox" name="interfaceCombo">
+          <property name="minimumSize">
+           <size>
+            <width>160</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="editable">
            <bool>false</bool>
           </property>
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Quickconnect using the last connection parameters&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QPushButton" name="connectButton">
+          <property name="minimumSize">
+           <size>
+            <width>60</width>
+            <height>0</height>
+           </size>
           </property>
-          <property name="text">
-           <string>Quick Connect</string>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QPushButton" name="scanButton">
+          <property name="minimumSize">
+           <size>
+            <width>50</width>
+            <height>0</height>
+           </size>
           </property>
          </widget>
         </item>
@@ -48,11 +68,18 @@
           </property>
          </spacer>
         </item>
-        <item row="0" column="5">
+        <item row="0" column="6">
+         <widget class="QLabel" name="linkQualityLabel">
+          <property name="text">
+           <string>Link Quality:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="7">
          <widget class="QProgressBar" name="linkQualityBar">
           <property name="minimumSize">
            <size>
-            <width>150</width>
+            <width>30</width>
             <height>0</height>
            </size>
           </property>
@@ -76,27 +103,24 @@
           </property>
          </widget>
         </item>
-        <item row="0" column="0">
-         <widget class="QPushButton" name="connectButton">
-          <property name="toolTip">
-           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Connect to a Crazyflie&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-          </property>
+        <item row="0" column="4">
+         <widget class="QLabel" name="batteryLabel">
           <property name="text">
-           <string>Connect</string>
+           <string>Battery:</string>
           </property>
          </widget>
         </item>
-        <item row="0" column="4">
+        <item row="0" column="5">
          <widget class="QProgressBar" name="batteryBar">
           <property name="minimumSize">
            <size>
-            <width>150</width>
+            <width>30</width>
             <height>0</height>
            </size>
           </property>
           <property name="maximumSize">
            <size>
-            <width>150</width>
+            <width>100</width>
             <height>16777215</height>
            </size>
           </property>
@@ -123,26 +147,101 @@
           </property>
          </widget>
         </item>
-        <item row="0" column="2">
-         <widget class="QCheckBox" name="autoReconnectCheckBox">
-          <property name="mouseTracking">
-           <bool>false</bool>
-          </property>
-          <property name="text">
-           <string>Auto Reconnect</string>
-          </property>
-          <property name="checked">
-           <bool>false</bool>
-          </property>
-         </widget>
-        </item>
        </layout>
       </item>
       <item>
-       <widget class="QTabWidget" name="tabs">
-        <property name="currentIndex">
-         <number>-1</number>
+       <widget class="QGroupBox" name="groupBox">
+        <layout class="QHBoxLayout" stretch="0,0,1">
+         <item>
+          <widget class="QLabel" name="addressLabel">
+           <property name="text">
+            <string>Address:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="HexSpinBox" name="address">
+           <property name="minimumSize">
+            <size>
+             <width>140</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QCheckBox" name="autoReconnectCheckBox">
+           <property name="mouseTracking">
+            <bool>false</bool>
+           </property>
+           <property name="text">
+            <string>Auto Reconnect</string>
+           </property>
+           <property name="checked">
+            <bool>false</bool>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <widget class="QScrollArea" name="scrollArea">
+        <property name="autoFillBackground">
+         <bool>false</bool>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::NoFrame</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Sunken</enum>
+        </property>
+        <property name="lineWidth">
+         <number>1</number>
+        </property>
+        <property name="verticalScrollBarPolicy">
+         <enum>Qt::ScrollBarAsNeeded</enum>
         </property>
+        <property name="widgetResizable">
+         <bool>true</bool>
+        </property>
+        <widget class="QWidget" name="scrollAreaWidgetContents">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>0</y>
+           <width>852</width>
+           <height>500</height>
+          </rect>
+         </property>
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_3">
+          <property name="sizeConstraint">
+           <enum>QLayout::SetNoConstraint</enum>
+          </property>
+          <property name="margin">
+           <number>0</number>
+          </property>
+          <item row="0" column="0">
+           <widget class="QTabWidget" name="tabs">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="currentIndex">
+             <number>-1</number>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
        </widget>
       </item>
      </layout>
@@ -169,8 +268,6 @@
     <property name="title">
      <string>View</string>
     </property>
-    <addaction name="tabsMenuItem"/>
-    <addaction name="toolboxesMenuItem"/>
    </widget>
    <widget class="QMenu" name="menuHelp">
     <property name="title">
@@ -186,12 +283,11 @@
     <addaction name="separator"/>
     <addaction name="_menuItem_openconfigfolder"/>
    </widget>
-   <widget class="QMenu" name="menuCrazyflie">
+   <widget class="QMenu" name="menuConnect">
     <property name="title">
-     <string>Crazyflie</string>
+     <string>Connect</string>
     </property>
     <addaction name="menuItemConnect"/>
-    <addaction name="menuItemQuickConnect"/>
     <addaction name="menuItemBootloader"/>
     <addaction name="_menu_cf2_config"/>
     <addaction name="_menu_cf1_config"/>
@@ -205,7 +301,7 @@
     <addaction name="separator"/>
    </widget>
    <addaction name="menuFile"/>
-   <addaction name="menuCrazyflie"/>
+   <addaction name="menuConnect"/>
    <addaction name="_menu_inputdevice"/>
    <addaction name="menuSettings"/>
    <addaction name="menuView"/>
@@ -221,9 +317,6 @@
    <property name="text">
     <string>Exit</string>
    </property>
-   <property name="menuRole">
-    <enum>QAction::NoRole</enum>
-   </property>
   </action>
   <action name="menuItemRegulation">
    <property name="checkable">
@@ -265,11 +358,6 @@
     <enum>QAction::NoRole</enum>
    </property>
   </action>
-  <action name="menuItemQuickConnect">
-   <property name="text">
-    <string>Quick connect</string>
-   </property>
-  </action>
   <action name="menuItemConfInputDevice">
    <property name="text">
     <string>Configure device mapping</string>
@@ -288,16 +376,6 @@
     <string>Console</string>
    </property>
   </action>
-  <action name="toolboxesMenuItem">
-   <property name="text">
-    <string>Toolboxes</string>
-   </property>
-  </action>
-  <action name="tabsMenuItem">
-   <property name="text">
-    <string>Tabs</string>
-   </property>
-  </action>
   <action name="logConfigAction">
    <property name="enabled">
     <bool>false</bool>
@@ -370,6 +448,13 @@
    </property>
   </action>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>HexSpinBox</class>
+   <extends>QSpinBox</extends>
+   <header>cfclient.ui.widgets.hexspinbox</header>
+  </customwidget>
+ </customwidgets>
  <resources/>
  <connections/>
 </ui>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.py
old mode 100755
new mode 100644
index 36cdde03..0fabf3db
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Used for passing objects to tabs and toolboxes.
@@ -35,6 +35,7 @@ __all__ = ['PluginHelper']
 
 class PluginHelper():
     """Used for passing objects to tabs and toolboxes"""
+
     def __init__(self):
         self.cf = None
         self.menu = None
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/pluginhelper.pyc
deleted file mode 100755
index 06a84b6b0cc14e0ab6ae757a2f890ea9d224a53a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 857
zcmcgpv2N5r5FMX`;SLZbUE(5&u1L<JM+lOJ>J&Lp<eHW3UHcZTcP;N)B8UzuK8@eW
z5AbGvN@@zQHP18aH#5)A>HW)9|NGach7MPX=X-=d2S}nFFri&SazP!E1t;<e$&`K)
z{UEyCr6iB&W}R`@8^G$bS2Azim=Bfr+IG3Czo;hoJh(hmwa+UnkvmhnugY&${yDlX
zb!f)wo60|2h8L)>&D3f8QJF!F59$&oBK&KBf;#8|LQ%qUAf>!nFPN|a{GE=5hjVcM
z6~dnYF#bD{h<iA}s`&(8P55eV*shO&fnn>c3Ot}`W8Et|g;%JJ>#m$_byuoNsxkIO
zhF7LtgFq4dHL_ywdR5d1LyBQ^(Y}KHxoeG97Y)D$e=*#Jy|abUb<wo*VKM1qh~Dj^
zcN=h?VW<$=>LA1!a?k&Yk|pk0`b@A@uY?Gz$nKq-43|%1DP1E($$gJv|DECzd*~G5
v+0-n_lI^^f%W?@gsH`R!Fg~cPjDbqL{x2${uWx6g-W_9U^fg;#$uj)|`F7C(

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.py
old mode 100755
new mode 100644
index 3913e341..ebcd60b9
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.py
@@ -21,27 +21,28 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Superclass for all tabs that implements common functions.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['Tab']
-
 import logging
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+from PyQt5 import QtWidgets
+from PyQt5.QtCore import pyqtSlot
 
 from cfclient.utils.config import Config
 
+__author__ = 'Bitcraze AB'
+__all__ = ['Tab']
+
+logger = logging.getLogger(__name__)
 
-class Tab(QtGui.QWidget):
+
+class Tab(QtWidgets.QWidget):
     """Superclass for all tabs that implements common functions."""
 
     def __init__(self):
@@ -60,7 +61,7 @@ class Tab(QtGui.QWidget):
                 s = Config().get("open_tabs")
                 if (len(s) > 0):
                     s += ","
-            except Exception as e:
+            except Exception:
                 logger.warning("Exception while adding tab to config and "
                                "reading tab config")
             # Check this since tabs in config are opened when app is started
@@ -72,7 +73,7 @@ class Tab(QtGui.QWidget):
             self.tabWidget.removeTab(self.tabWidget.indexOf(self))
             try:
                 parts = Config().get("open_tabs").split(",")
-            except Exception as e:
+            except Exception:
                 logger.warning("Exception while removing tab from config and "
                                "reading tab config")
                 parts = []
@@ -90,3 +91,6 @@ class Tab(QtGui.QWidget):
     def getTabName(self):
         """Return the name of the tab that will be shown in the tab"""
         return self.tabName
+
+    def is_visible(self):
+        return self.tabWidget.currentWidget() == self
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tab.pyc
deleted file mode 100755
index a18916cffa5e79aa6b00b247f4326c0ec69183ce..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2814
zcmcIm>yFz*6h32Tvq`$?Zd+O|s;K*;B|_~+q98z^Lc5@XXcy|NS{eyOjy*{x>r3jH
zunpS&Di6R9UV!)LTk!z!o#VJv`~Xz3j%PA+=JuWMT*m(I-Og9>HxFW3KR*6HN3p-5
zN{EK26%7?79!=5kDDf$2Q0mjrC+*X`L3)FpVW=rX8<cKR)}mpHvNjFdlyzv>A;rs@
zl%Aq&i-ud2b!ph8>@*EeQ?^aRZOV3NxKqvBr1T7BXK8pAeUEgT=I3Yv3@!SZ=o!(Y
z;cE<H&}%c)Pf&FR%Y`oEG_p3B6lD;lY2c!<4cshpfyoxB&UEf<5Eofi<iTW_$IcYF
z-R;;@Sby8NxQu?%!L8elIXH;M<_|pkJ?^<Cs{3xQD7D*==AEUHc}o-bSmHbpyB7Wy
ztH*AT7S46*j+y3B>Na`G!K~C#A{!3AzO#SpZcjlh{k<Zem}!izJiOy=6nhhuhABV*
zYFI!q4NQN{JxF3=Y9sLICKJSs7KH<WXg|h2uS`?SFu5=vdnoojR1UAAW1Q{L++))y
zphJHIb61T9fijlBKX87J)!Mhb%YOe>k2w)aE!!_dkA%a~$mGV2MnW14xgTX(24Kad
zbQ+j?P%gF1(0MdYby9K3BUY!A9`7cVy@OVNR%E(AUK_f<D2us{o$a&TSCiD}>oF?$
z$o0j_&5FFAnsGm#RKot!^Z{dcu?pE;`Y4udP3oL#;}^49>?Q0BLeH-t>sV3woRy#B
z6*{;rJb^H#>ZwPo4+yRV>JUmWB&-M_b0+P?r^5!7kGKnqeu%N0=wTjE15R_;q4Jp2
zQ=b%gn71gASX8;9@A;@UFFV{66j<LBEN!~L+pG`m@S*P1`Z$L5_&FZ|?DiM6#=cc6
z(d7mp;#I3l^&U0w`Dw<;8Z-d$>I;Zh)XNYzW%ZPJ76Ywlc(O~!4f^7TtMpX-g|TnY
zp-<%v#k#k+E5IM$P<S7*(0_@jHobBApVWd*Ne2$d_Os_v4Q9nrfLt*%iAJ74fq~)C
za6!&1#X{#Jh^!G2`~Ee_HD5l7^@5W}a5OWi4x%J6`IJ`&u0Vp}C=Q}L2{_X0kxFdY
zO|Dq`8UFshO{ufu$9nptEV6&uibLp%y=EBLes3GKzy^$mCYfp{IR)4bqOoKmh|uKN
z30XZ!Up$TXN#XY_e1S<8r^R%tO9`-}sLX*a+^SdF^-AkXSt;l>pT!|<@<c!Rc2Y(5
zA~mkZu@Ua@Y95bgIzH41atCZ7b(L5bQR%Aw;$))N2?Xes>IcS}u>m#&AW(2RBfqKM
zR88fpv-q7++v<#uqAqz&brI4_kaWEcW^~ayuU=O%Yfu-7dseTCnt`MvNxPwT%Q6=y
z%VB_^nA8qeT~J2`_tjVj7A~0wrkcsAPPPcU*t2Re{1ak^;{yJ0Z=GNtpeyc5-hWW?
zBg}p!CE>1>X6#uftz&orhv1W@R!qJh*7ptD1@{f#*`rZbB+Hb$Y|YUqDdN#c5`QR{
zJ>M|nqDaH5XoT-@#XJ9H7-{{lw+^<aYbcfhHdWJWH_u;gH+r1N!go=vkw;71UF8ep
z_zqgPIhYZ_609)uU5V|GfrfAKa#rlS)qVGV$nG3+q6#@RI5vz7>{eeuA!{!@gc8(D
zQP|>{jHSLXcbCqjcDG7<Rl?zk_p96_7ySv+B{u!Evf|CRajxaSX(Ei<-j>?-E~=il
G<Npc0m~_|x

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.py
old mode 100755
new mode 100644
index a90e1bed..88a6061e
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.py
@@ -21,35 +21,36 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 The console tab is used as a console for printouts from the Crazyflie.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['ConsoleTab']
-
-import time
-import sys
-
 import logging
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import pyqtSlot, pyqtSignal
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
 
+import cfclient
 from cfclient.ui.tab import Tab
 
-console_tab_class = uic.loadUiType(sys.path[0] +
-                                   "/cfclient/ui/tabs/consoleTab.ui")[0]
+__author__ = 'Bitcraze AB'
+__all__ = ['ConsoleTab']
+
+logger = logging.getLogger(__name__)
+
+console_tab_class = uic.loadUiType(cfclient.module_path +
+                                   "/ui/tabs/consoleTab.ui")[0]
 
 
 class ConsoleTab(Tab, console_tab_class):
     """Console tab for showing printouts from Crazyflie"""
-    update = pyqtSignal(str)
+    _connected_signal = pyqtSignal(str)
+    _disconnected_signal = pyqtSignal(str)
+    _update = pyqtSignal(str)
 
     def __init__(self, tabWidget, helper, *args):
         super(ConsoleTab, self).__init__(*args)
@@ -59,14 +60,37 @@ class ConsoleTab(Tab, console_tab_class):
         self.menuName = "Console"
 
         self.tabWidget = tabWidget
-        self.helper = helper
+        self._helper = helper
+
+        # Always wrap callbacks from Crazyflie API though QT Signal/Slots
+        # to avoid manipulating the UI when rendering it
+        self._connected_signal.connect(self._connected)
+        self._disconnected_signal.connect(self._disconnected)
+        self._update.connect(self.printText)
 
-        self.update.connect(self.printText)
+        self._helper.cf.console.receivedChar.add_callback(self._update.emit)
+        self._helper.cf.connected.add_callback(self._connected_signal.emit)
+        self._helper.cf.disconnected.add_callback(
+            self._disconnected_signal.emit)
 
-        self.helper.cf.console.receivedChar.add_callback(self.update.emit)
+        self._clearButton.clicked.connect(self.clear)
+        self._dumpSystemLoadButton.clicked.connect(
+            lambda enabled:
+            self._helper.cf.param.set_value("system.taskDump", '1'))
 
     def printText(self, text):
         # Make sure we get printouts from the Crazyflie into the log (such as
         # build version and test ok/fail)
         logger.debug("[%s]", text)
         self.console.insertPlainText(text)
+
+    def clear(self):
+        self.console.clear()
+
+    def _connected(self, link_uri):
+        """Callback when the Crazyflie has been connected"""
+        self._dumpSystemLoadButton.setEnabled(True)
+
+    def _disconnected(self, link_uri):
+        """Callback for when the Crazyflie has been disconnected"""
+        self._dumpSystemLoadButton.setEnabled(False)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ConsoleTab.pyc
deleted file mode 100755
index 979bf106dc4e463400fc56259c980787123275fa..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1935
zcmcgsOONA35H35fNhYshmRVNfkpoCMuoHw3Cxl>vv>ecA*U1WDge=GIByIe{-3Ee&
z({e)mEiU{WegJ$`P6i3iOO&ou^`lbteP4I$&(R?J<JWaW$4?8tpJ15ZVPYa5)*;`a
z*rgpDm*N)1ZAx3@!)g3B`R$Y6A-_YaLrIrZk6z%&nJjfE?Nc@&e?Zwe`R9}k$sdx#
zDY}%7C>xVMrffp~q?zqeI;HG_{0nl_kdjwOwJEuz_>3OKeR_!8?D`M5Hg!Sj0c}y<
zfPNu*LG+dXDi^w%pL08(!wlAYHH(Ve6seloa5K|pRvQ)1LNg2R7q&$;D=VGbqPAwX
zt%_`Bac)_KKOMHIR@Vc=8E>?WFr{Xn-q-=+Ws`RuZuDRH+|C(E+l6^%mqn#)N8Bg1
zw!Bj7XzuckGnn%5on57cl|&NgT^^=$hd1zU&Way0Z^100ZG<{<yQuX7ZJ5QeC+xaL
zUf#$bPJe@8-i1-15_rJ^s}>{4)O46!z~y%tLw0)Pt)z7G9!?#b60jH-voC(o`R?EN
z++!1Qv26_geS%?rhOziMbO%;kN?f{Y(QiZ!;-n?B4)~V!04i#n4&60Qm+o+aDCn_G
z&M4`NGvN9qM~{+oN}!JsCF9eki7cbtm7siUd#K~s&3wu=F&(BZRpr5HXb1wGYa0Zz
z*(h6=&$ajf`8LdyaFwaNmY~na!p)aD-YF|Y?^TL?;?`vxS|x`;POc(rdB5mtt$wtY
z$%(e74Xj8z#8jmsrN3A4avxSQ5yo*4g=xA8qi-!Et1@lp>_}u(y7fkgyzyx&tafIO
zfW(*;yv4rA)M9f~?4qoS1QkIyCrv+Y1Z5tV2fHuwMXERdRoM|fR#|!QxSbC%45LZT
zl{0etPG82Q8*zI)SO-fC^EM20kU)bV)?q0Kdr$;KfS5&aPnY2azkbJj({#$WC@pq7
zfXlSSYE$pLOU^if(Ye9G(=^mMLo0-P4|!E!;wc0#8IBA5!)F*$Ikl$FoG-R0CJ1tf
z2eRU4A_%e~u2T+Kl0gs`Q4o0CmfUn>E03EJd_B(kPw_98Q2Z6Wk72m*uG4jfZht(#
zLg4YMbF4nBA&~06dMFdV;H+^$m~L}0(i#(nw?cG}8}fzl=e@!C9&tWy`RU=A{lMdA
z&SSNBd|qTP3)jud>2dl7Ax7r(`r)a&#{KhH98z3bgz<B|K9oudDnq-s3?MEb->(3h
tgD4G+ksJR%!72*)sNwwMH&Kmw4W{dMaaV?bc<4;r*PSbO>Q0?;>u)c4xyS$j

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.py
old mode 100755
new mode 100644
index e34870a9..9c455d4f
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.py
@@ -32,25 +32,23 @@ with the necessary QT Signals to wrap Crazyflie API callbacks and also
 connects the connected/disconnected callbacks.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['ExampleTab']
-
 import logging
-import sys
-
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import pyqtSlot, pyqtSignal, QThread, Qt
-from PyQt4.QtGui import QMessageBox
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtWidgets import QMessageBox
 
+import cfclient
 from cfclient.ui.tab import Tab
 
-from cflib.crazyflie.log import LogConfig, Log
-from cflib.crazyflie.param import Param
+__author__ = 'Bitcraze AB'
+__all__ = ['ExampleTab']
+
+logger = logging.getLogger(__name__)
+
+example_tab_class = uic.loadUiType(cfclient.module_path +
+                                   "/ui/tabs/exampleTab.ui")[0]
 
-example_tab_class = uic.loadUiType(sys.path[0] +
-                                "/cfclient/ui/tabs/exampleTab.ui")[0]
 
 class ExampleTab(Tab, example_tab_class):
     """Tab for plotting logging data"""
@@ -110,4 +108,4 @@ class ExampleTab(Tab, example_tab_class):
 
         QMessageBox.about(self, "Example error",
                           "Error when using log config"
-                          " [{0}]: {1}".format(log_conf.name, msg))
\ No newline at end of file
+                          " [{0}]: {1}".format(log_conf.name, msg))
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ExampleTab.pyc
deleted file mode 100755
index 8ef24d306d402aa0303d10941dfbb52747162bff..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.py
old mode 100755
new mode 100644
index 8995debb..6bc9fc99
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.py
@@ -21,47 +21,45 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 The flight control tab shows telemetry data and flight settings.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['FlightTab']
-
-import sys
-
 import logging
-logger = logging.getLogger(__name__)
-
-from time import time
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QVariant
-from PyQt4.QtGui import QMessageBox
-
-from cflib.crazyflie import Crazyflie
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
+from PyQt5.QtWidgets import QMessageBox
 
+import cfclient
 from cfclient.ui.widgets.ai import AttitudeIndicator
 
 from cfclient.utils.config import Config
-from cflib.crazyflie.log import Log, LogVariable, LogConfig
+from cflib.crazyflie.log import LogConfig
+
+from cfclient.utils.input import JoystickReader
 
 from cfclient.ui.tab import Tab
 
-from cflib.crazyflie.mem import MemoryElement
+PARAM_NAME_ALT_HOLD_TARGET = "posCtlAlt.targetZ"
+PARAM_NAME_ESTIMATED_Z = "posEstimatorAlt.estimatedZ"
+
+__author__ = 'Bitcraze AB'
+__all__ = ['FlightTab']
+
+logger = logging.getLogger(__name__)
 
-flight_tab_class = uic.loadUiType(sys.path[0] +
-                                  "/cfclient/ui/tabs/flightTab.ui")[0]
+flight_tab_class = uic.loadUiType(cfclient.module_path +
+                                  "/ui/tabs/flightTab.ui")[0]
 
 MAX_THRUST = 65365.0
 
 
 class FlightTab(Tab, flight_tab_class):
-
     uiSetupReadySignal = pyqtSignal()
 
     _motor_data_signal = pyqtSignal(int, object, object)
@@ -72,10 +70,11 @@ class FlightTab(Tab, flight_tab_class):
     _input_updated_signal = pyqtSignal(float, float, float, float)
     _rp_trim_updated_signal = pyqtSignal(float, float)
     _emergency_stop_updated_signal = pyqtSignal(bool)
+    _assisted_control_updated_signal = pyqtSignal(bool)
 
     _log_error_signal = pyqtSignal(object, str)
 
-    #UI_DATA_UPDATE_FPS = 10
+    # UI_DATA_UPDATE_FPS = 10
 
     connectionFinishedSignal = pyqtSignal(str)
     disconnectedSignal = pyqtSignal(str)
@@ -101,16 +100,19 @@ class FlightTab(Tab, flight_tab_class):
 
         self._input_updated_signal.connect(self.updateInputControl)
         self.helper.inputDeviceReader.input_updated.add_callback(
-                                     self._input_updated_signal.emit)
+            self._input_updated_signal.emit)
         self._rp_trim_updated_signal.connect(self.calUpdateFromInput)
         self.helper.inputDeviceReader.rp_trim_updated.add_callback(
-                                     self._rp_trim_updated_signal.emit)
+            self._rp_trim_updated_signal.emit)
         self._emergency_stop_updated_signal.connect(self.updateEmergencyStop)
         self.helper.inputDeviceReader.emergency_stop_updated.add_callback(
-                                     self._emergency_stop_updated_signal.emit)
-        
-        self.helper.inputDeviceReader.althold_updated.add_callback(
-                    lambda enabled: self.helper.cf.param.set_value("flightmode.althold", enabled))
+            self._emergency_stop_updated_signal.emit)
+
+        self.helper.inputDeviceReader.assisted_control_updated.add_callback(
+            self._assisted_control_updated_signal.emit)
+
+        self._assisted_control_updated_signal.connect(
+            self._assisted_control_updated)
 
         self._imu_data_signal.connect(self._imu_data_received)
         self._baro_data_signal.connect(self._baro_data_received)
@@ -121,12 +123,14 @@ class FlightTab(Tab, flight_tab_class):
 
         # Connect UI signals that are in this tab
         self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange)
+        self._assist_mode_combo.currentIndexChanged.connect(
+                                            self._assist_mode_changed)
         self.minThrust.valueChanged.connect(self.minMaxThrustChanged)
         self.maxThrust.valueChanged.connect(self.minMaxThrustChanged)
         self.thrustLoweringSlewRateLimit.valueChanged.connect(
-                                      self.thrustLoweringSlewRateLimitChanged)
+            self.thrustLoweringSlewRateLimitChanged)
         self.slewEnableLimit.valueChanged.connect(
-                                      self.thrustLoweringSlewRateLimitChanged)
+            self.thrustLoweringSlewRateLimitChanged)
         self.targetCalRoll.valueChanged.connect(self._trim_roll_changed)
         self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed)
         self.maxAngle.valueChanged.connect(self.maxAngleChanged)
@@ -139,73 +143,71 @@ class FlightTab(Tab, flight_tab_class):
         self.clientXModeCheckbox.setChecked(Config().get("client_side_xmode"))
 
         self.crazyflieXModeCheckbox.clicked.connect(
-                             lambda enabled:
-                             self.helper.cf.param.set_value("flightmode.x",
-                                                            str(enabled)))
+            lambda enabled:
+            self.helper.cf.param.set_value("flightmode.x",
+                                           str(enabled)))
         self.helper.cf.param.add_update_callback(
-                        group="flightmode", name="xmode",
-                        cb=( lambda name, checked:
-                        self.crazyflieXModeCheckbox.setChecked(eval(checked))))
+            group="flightmode", name="xmode",
+            cb=(lambda name, checked:
+                self.crazyflieXModeCheckbox.setChecked(eval(checked))))
 
         self.ratePidRadioButton.clicked.connect(
-                    lambda enabled:
-                    self.helper.cf.param.set_value("flightmode.ratepid",
-                                                   str(enabled)))
+            lambda enabled:
+            self.helper.cf.param.set_value("flightmode.ratepid",
+                                           str(enabled)))
 
         self.angularPidRadioButton.clicked.connect(
-                    lambda enabled:
-                    self.helper.cf.param.set_value("flightmode.ratepid",
-                                                   str(not enabled)))
+            lambda enabled:
+            self.helper.cf.param.set_value("flightmode.ratepid",
+                                           str(not enabled)))
 
         self._led_ring_headlight.clicked.connect(
-                    lambda enabled:
-                    self.helper.cf.param.set_value("ring.headlightEnable",
-                                                   str(enabled)))
+            lambda enabled:
+            self.helper.cf.param.set_value("ring.headlightEnable",
+                                           str(enabled)))
 
         self.helper.cf.param.add_update_callback(
-                    group="flightmode", name="ratepid",
-                    cb=(lambda name, checked:
-                    self.ratePidRadioButton.setChecked(eval(checked))))
+            group="flightmode", name="ratepid",
+            cb=(lambda name, checked:
+                self.ratePidRadioButton.setChecked(eval(checked))))
 
         self.helper.cf.param.add_update_callback(
-                    group="cpu", name="flash",
-                    cb=self._set_enable_client_xmode)
+            group="cpu", name="flash",
+            cb=self._set_enable_client_xmode)
 
         self.helper.cf.param.add_update_callback(
-                    group="ring", name="headlightEnable",
-                    cb=(lambda name, checked:
-                    self._led_ring_headlight.setChecked(eval(checked))))
-
-        self.helper.cf.param.add_update_callback(
-                    group="flightmode", name="althold",
-                    cb=(lambda name, enabled:
-                    self.helper.inputDeviceReader.enable_alt_hold(eval(enabled))))
+            group="ring", name="headlightEnable",
+            cb=(lambda name, checked:
+                self._led_ring_headlight.setChecked(eval(checked))))
 
         self._ledring_nbr_effects = 0
 
         self.helper.cf.param.add_update_callback(
-                        group="ring",
-                        name="neffect",
-                        cb=(lambda name, value: self._set_neffect(eval(value))))
+            group="ring",
+            name="effect",
+            cb=self._ring_effect_updated)
 
         self.helper.cf.param.add_update_callback(
-                        group="imu_sensors",
-                        cb=self._set_available_sensors)
+            group="imu_sensors",
+            cb=self._set_available_sensors)
 
-        self.helper.cf.param.all_updated.add_callback(self._ring_populate_dropdown)
+        self.helper.cf.param.all_updated.add_callback(
+            self._ring_populate_dropdown)
 
         self.logBaro = None
         self.logAltHold = None
 
         self.ai = AttitudeIndicator()
         self.verticalLayout_4.addWidget(self.ai)
-        self.splitter.setSizes([1000,1])
+        self.splitter.setSizes([1000, 1])
 
         self.targetCalPitch.setValue(Config().get("trim_pitch"))
         self.targetCalRoll.setValue(Config().get("trim_roll"))
 
-        self.helper.inputDeviceReader.alt1_updated.add_callback(self.alt1_updated)
-        self.helper.inputDeviceReader.alt2_updated.add_callback(self.alt2_updated)
+        self.helper.inputDeviceReader.alt1_updated.add_callback(
+            self.alt1_updated)
+        self.helper.inputDeviceReader.alt2_updated.add_callback(
+            self.alt2_updated)
         self._tf_state = 0
         self._ring_effect = 0
 
@@ -222,8 +224,8 @@ class FlightTab(Tab, flight_tab_class):
             self.clientXModeCheckbox.setChecked(False)
 
     def _set_limiting_enabled(self, rp_limiting_enabled,
-                                    yaw_limiting_enabled,
-                                    thrust_limiting_enabled):
+                              yaw_limiting_enabled,
+                              thrust_limiting_enabled):
         self.maxAngle.setEnabled(rp_limiting_enabled)
         self.targetCalRoll.setEnabled(rp_limiting_enabled)
         self.targetCalPitch.setEnabled(rp_limiting_enabled)
@@ -233,15 +235,12 @@ class FlightTab(Tab, flight_tab_class):
         self.slewEnableLimit.setEnabled(thrust_limiting_enabled)
         self.thrustLoweringSlewRateLimit.setEnabled(thrust_limiting_enabled)
 
-    def _set_neffect(self, n):
-        self._ledring_nbr_effects = n
-
     def thrustToPercentage(self, thrust):
         return ((thrust / MAX_THRUST) * 100.0)
 
     def uiSetupReady(self):
         flightComboIndex = self.flightModeCombo.findText(
-                             Config().get("flightmode"), Qt.MatchFixedString)
+            Config().get("flightmode"), Qt.MatchFixedString)
         if (flightComboIndex < 0):
             self.flightModeCombo.setCurrentIndex(0)
             self.flightModeCombo.currentIndexChanged.emit(0)
@@ -249,9 +248,19 @@ class FlightTab(Tab, flight_tab_class):
             self.flightModeCombo.setCurrentIndex(flightComboIndex)
             self.flightModeCombo.currentIndexChanged.emit(flightComboIndex)
 
+        try:
+            assistmodeComboIndex = Config().get("assistedControl")
+            self._assist_mode_combo.setCurrentIndex(assistmodeComboIndex)
+            self._assist_mode_combo.currentIndexChanged.emit(
+                                                assistmodeComboIndex)
+        except KeyError:
+            self._assist_mode_combo.setCurrentIndex(0)
+            self._assist_mode_combo.currentIndexChanged.emit(0)
+
     def _logging_error(self, log_conf, msg):
-        QMessageBox.about(self, "Log error", "Error when starting log config"
-                " [%s]: %s" % (log_conf.name, msg))
+        QMessageBox.about(self, "Log error",
+                          "Error when starting log config [%s]: %s" % (
+                              log_conf.name, msg))
 
     def _motor_data_received(self, timestamp, data, logconf):
         if self.isVisible():
@@ -259,25 +268,26 @@ class FlightTab(Tab, flight_tab_class):
             self.actualM2.setValue(data["motor.m2"])
             self.actualM3.setValue(data["motor.m3"])
             self.actualM4.setValue(data["motor.m4"])
-        
+
     def _baro_data_received(self, timestamp, data, logconf):
         if self.isVisible():
-            self.actualASL.setText(("%.2f" % data["baro.aslLong"]))
-            self.ai.setBaro(data["baro.aslLong"])
-        
+            estimated_z = data[PARAM_NAME_ESTIMATED_Z]
+            self.actualASL.setText(("%.2f" % estimated_z))
+            self.ai.setBaro(estimated_z, self.is_visible())
+
     def _althold_data_received(self, timestamp, data, logconf):
         if self.isVisible():
-            target = data["altHold.target"]
-            if target>0:
+            target = data[PARAM_NAME_ALT_HOLD_TARGET]
+            if target > 0:
                 if not self.targetASL.isEnabled():
-                    self.targetASL.setEnabled(True) 
+                    self.targetASL.setEnabled(True)
                 self.targetASL.setText(("%.2f" % target))
-                self.ai.setHover(target)    
+                self.ai.setHover(target, self.is_visible())
             elif self.targetASL.isEnabled():
                 self.targetASL.setEnabled(False)
-                self.targetASL.setText("Not set")   
-                self.ai.setHover(0)    
-        
+                self.targetASL.setText("Not set")
+                self.ai.setHover(0, self.is_visible())
+
     def _imu_data_received(self, timestamp, data, logconf):
         if self.isVisible():
             self.actualRoll.setText(("%.2f" % data["stabilizer.roll"]))
@@ -285,10 +295,10 @@ class FlightTab(Tab, flight_tab_class):
             self.actualYaw.setText(("%.2f" % data["stabilizer.yaw"]))
             self.actualThrust.setText("%.2f%%" %
                                       self.thrustToPercentage(
-                                                      data["stabilizer.thrust"]))
-    
+                                          data["stabilizer.thrust"]))
+
             self.ai.setRollPitch(-data["stabilizer.roll"],
-                                 data["stabilizer.pitch"])
+                                 data["stabilizer.pitch"], self.is_visible())
 
     def connected(self, linkURI):
         # IMU & THRUST
@@ -325,10 +335,6 @@ class FlightTab(Tab, flight_tab_class):
         except AttributeError as e:
             logger.warning(str(e))
 
-        if self.helper.cf.mem.ow_search(vid=0xBC, pid=0x01):
-            self._led_ring_effect.setEnabled(True)
-            self._led_ring_headlight.setEnabled(True)
-
     def _set_available_sensors(self, name, available):
         logger.info("[%s]: %s", name, available)
         available = eval(available)
@@ -342,21 +348,22 @@ class FlightTab(Tab, flight_tab_class):
                 if (not self.logBaro and not self.logAltHold):
                     # The sensor is available, set up the logging
                     self.logBaro = LogConfig("Baro", 200)
-                    self.logBaro.add_variable("baro.aslLong", "float")
+                    self.logBaro.add_variable(PARAM_NAME_ESTIMATED_Z, "float")
 
                     try:
                         self.helper.cf.log.add_config(self.logBaro)
                         self.logBaro.data_received_cb.add_callback(
-                                self._baro_data_signal.emit)
+                            self._baro_data_signal.emit)
                         self.logBaro.error_cb.add_callback(
-                                self._log_error_signal.emit)
+                            self._log_error_signal.emit)
                         self.logBaro.start()
                     except KeyError as e:
                         logger.warning(str(e))
                     except AttributeError as e:
                         logger.warning(str(e))
                     self.logAltHold = LogConfig("AltHold", 200)
-                    self.logAltHold.add_variable("altHold.target", "float")
+                    self.logAltHold.add_variable(PARAM_NAME_ALT_HOLD_TARGET,
+                                                 "float")
 
                     try:
                         self.helper.cf.log.add_config(self.logAltHold)
@@ -367,7 +374,7 @@ class FlightTab(Tab, flight_tab_class):
                         self.logAltHold.start()
                     except KeyError as e:
                         logger.warning(str(e))
-                    except AttributeError:
+                    except AttributeError as e:
                         logger.warning(str(e))
 
     def disconnected(self, linkURI):
@@ -388,33 +395,42 @@ class FlightTab(Tab, flight_tab_class):
         self.logBaro = None
         self.logAltHold = None
         self._led_ring_effect.setEnabled(False)
+        self._led_ring_effect.clear()
+        try:
+            self._led_ring_effect.currentIndexChanged.disconnect(
+                self._ring_effect_changed)
+        except TypeError:
+            # Signal was not connected
+            pass
+        self._led_ring_effect.setCurrentIndex(-1)
         self._led_ring_headlight.setEnabled(False)
 
-
     def minMaxThrustChanged(self):
         self.helper.inputDeviceReader.min_thrust = self.minThrust.value()
         self.helper.inputDeviceReader.max_thrust = self.maxThrust.value()
-        if (self.isInCrazyFlightmode == True):
+        if (self.isInCrazyFlightmode is True):
             Config().set("min_thrust", self.minThrust.value())
             Config().set("max_thrust", self.maxThrust.value())
 
     def thrustLoweringSlewRateLimitChanged(self):
-        self.helper.inputDeviceReader.thrust_slew_rate = self.thrustLoweringSlewRateLimit.value()
-        self.helper.inputDeviceReader.thrust_slew_limit = self.slewEnableLimit.value()
-        if (self.isInCrazyFlightmode == True):
+        self.helper.inputDeviceReader.thrust_slew_rate = (
+            self.thrustLoweringSlewRateLimit.value())
+        self.helper.inputDeviceReader.thrust_slew_limit = (
+            self.slewEnableLimit.value())
+        if (self.isInCrazyFlightmode is True):
             Config().set("slew_limit", self.slewEnableLimit.value())
             Config().set("slew_rate", self.thrustLoweringSlewRateLimit.value())
 
     def maxYawRateChanged(self):
         logger.debug("MaxYawrate changed to %d", self.maxYawRate.value())
         self.helper.inputDeviceReader.max_yaw_rate = self.maxYawRate.value()
-        if (self.isInCrazyFlightmode == True):
+        if (self.isInCrazyFlightmode is True):
             Config().set("max_yaw", self.maxYawRate.value())
 
     def maxAngleChanged(self):
         logger.debug("MaxAngle changed to %d", self.maxAngle.value())
         self.helper.inputDeviceReader.max_rp_angle = self.maxAngle.value()
-        if (self.isInCrazyFlightmode == True):
+        if (self.isInCrazyFlightmode is True):
             Config().set("max_rp", self.maxAngle.value())
 
     def _trim_pitch_changed(self, value):
@@ -456,7 +472,7 @@ class FlightTab(Tab, flight_tab_class):
         if emergencyStop:
             self.setMotorLabelsEnabled(False)
             self.emergency_stop_label.setText(
-                      self.emergencyStopStringWithText("Kill switch active"))
+                self.emergencyStopStringWithText("Kill switch active"))
         else:
             self.setMotorLabelsEnabled(True)
             self.emergency_stop_label.setText("")
@@ -464,7 +480,7 @@ class FlightTab(Tab, flight_tab_class):
     def flightmodeChange(self, item):
         Config().set("flightmode", str(self.flightModeCombo.itemText(item)))
         logger.debug("Changed flightmode to %s",
-                    self.flightModeCombo.itemText(item))
+                     self.flightModeCombo.itemText(item))
         self.isInCrazyFlightmode = False
         if (item == 0):  # Normal
             self.maxAngle.setValue(Config().get("normal_max_rp"))
@@ -472,7 +488,7 @@ class FlightTab(Tab, flight_tab_class):
             self.minThrust.setValue(Config().get("normal_min_thrust"))
             self.slewEnableLimit.setValue(Config().get("normal_slew_limit"))
             self.thrustLoweringSlewRateLimit.setValue(
-                                              Config().get("normal_slew_rate"))
+                Config().get("normal_slew_rate"))
             self.maxYawRate.setValue(Config().get("normal_max_yaw"))
         if (item == 1):  # Advanced
             self.maxAngle.setValue(Config().get("max_rp"))
@@ -480,7 +496,7 @@ class FlightTab(Tab, flight_tab_class):
             self.minThrust.setValue(Config().get("min_thrust"))
             self.slewEnableLimit.setValue(Config().get("slew_limit"))
             self.thrustLoweringSlewRateLimit.setValue(
-                                                  Config().get("slew_rate"))
+                Config().get("slew_rate"))
             self.maxYawRate.setValue(Config().get("max_yaw"))
             self.isInCrazyFlightmode = True
 
@@ -495,6 +511,26 @@ class FlightTab(Tab, flight_tab_class):
         self.slewEnableLimit.setEnabled(newState)
         self.maxYawRate.setEnabled(newState)
 
+    def _assist_mode_changed(self, item):
+        mode = None
+
+        if (item == 0):  # Altitude hold
+            mode = JoystickReader.ASSISTED_CONTROL_ALTHOLD
+        if (item == 1):  # Position hold
+            mode = JoystickReader.ASSISTED_CONTROL_POSHOLD
+
+        self.helper.inputDeviceReader.set_assisted_control(mode)
+        Config().set("assistedControl", mode)
+
+    def _assisted_control_updated(self, enabled):
+        if self.helper.inputDeviceReader.get_assisted_control() == \
+                    JoystickReader.ASSISTED_CONTROL_POSHOLD:
+            self.targetThrust.setEnabled(not enabled)
+            self.targetRoll.setEnabled(not enabled)
+            self.targetPitch.setEnabled(not enabled)
+        else:
+            self.helper.cf.param.set_value("flightmode.althold", str(enabled))
+
     @pyqtSlot(bool)
     def changeXmode(self, checked):
         self.helper.cf.commander.set_client_xmode(checked)
@@ -503,10 +539,9 @@ class FlightTab(Tab, flight_tab_class):
 
     def alt1_updated(self, state):
         if state:
-            self._ring_effect += 1
-            if self._ring_effect > self._ledring_nbr_effects:
-                self._ring_effect = 0
-            self.helper.cf.param.set_value("ring.effect", str(self._ring_effect))
+            new_index = (self._ring_effect+1) % (self._ledring_nbr_effects+1)
+            self.helper.cf.param.set_value("ring.effect",
+                                           str(new_index))
 
     def alt2_updated(self, state):
         self.helper.cf.param.set_value("ring.headlightEnable", str(state))
@@ -518,6 +553,10 @@ class FlightTab(Tab, flight_tab_class):
         except KeyError:
             return
 
+        # Used only in alt1_updated function
+        self._ring_effect = current
+        self._ledring_nbr_effects = nbr
+
         hardcoded_names = {0: "Off",
                            1: "White spinner",
                            2: "Color spinner",
@@ -530,27 +569,33 @@ class FlightTab(Tab, flight_tab_class):
                            9: "Battery status",
                            10: "Boat lights",
                            11: "Alert",
-                           12: "Gravity"}
+                           12: "Gravity",
+                           13: "LED tab"}
 
-        for i in range(nbr+1):
+        for i in range(nbr + 1):
             name = "{}: ".format(i)
             if i in hardcoded_names:
                 name += hardcoded_names[i]
             else:
                 name += "N/A"
-            self._led_ring_effect.addItem(name, QVariant(i))
+            self._led_ring_effect.addItem(name, i)
+
+        self._led_ring_effect.currentIndexChanged.connect(
+            self._ring_effect_changed)
 
         self._led_ring_effect.setCurrentIndex(current)
-        self._led_ring_effect.currentIndexChanged.connect(self._ring_effect_changed)
-        self.helper.cf.param.add_update_callback(group="ring",
-                                         name="effect",
-                                         cb=self._ring_effect_updated)
+        if self.helper.cf.mem.ow_search(vid=0xBC, pid=0x01):
+            self._led_ring_effect.setEnabled(True)
+            self._led_ring_headlight.setEnabled(True)
 
     def _ring_effect_changed(self, index):
-        i = self._led_ring_effect.itemData(index).toInt()[0]
-        logger.info("Changed effect to {}".format(i))
-        if i != self.helper.cf.param.values["ring"]["effect"]:
-            self.helper.cf.param.set_value("ring.effect", str(i))
+        self._ring_effect = index
+        if index > -1:
+            i = self._led_ring_effect.itemData(index)
+            logger.info("Changed effect to {}".format(i))
+            if i != int(self.helper.cf.param.values["ring"]["effect"]):
+                self.helper.cf.param.set_value("ring.effect", str(i))
 
     def _ring_effect_updated(self, name, value):
-        self._led_ring_effect.setCurrentIndex(int(value))
+        if self.helper.cf.param.is_updated:
+            self._led_ring_effect.setCurrentIndex(int(value))
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/FlightTab.pyc
deleted file mode 100755
index 286da7cc9555d72815377df2eb0c6ba072978286..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.py
old mode 100755
new mode 100644
index 613350a1..77a013ee
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.py
@@ -20,54 +20,35 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+# USA.
 """
 This tab plots different logging data defined by configurations that has been
 pre-configured.
 """
-import math
-
-__author__ = 'Bitcraze AB'
-__all__ = ['GpsTab']
-
-import glob
-import json
 import logging
-import os
-import sys
-
-logger = logging.getLogger(__name__)
-
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from pprint import pprint
-import datetime
-
-#from cfclient.ui.widgets.plotwidget import PlotWidget
-
-from cflib.crazyflie.log import Log, LogVariable, LogConfig
 
+import cfclient
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtWidgets import QMessageBox
 from cfclient.ui.tab import Tab
+from cflib.crazyflie.log import LogConfig
+from PyQt5 import QtCore
+from PyQt5 import QtGui
+from PyQt5 import QtNetwork
+from PyQt5 import QtWebKit
+from PyQt5 import uic
 
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
+__author__ = 'Bitcraze AB'
+__all__ = ['GpsTab']
 
-try:
-    from PyKDE4.marble import *
-    should_enable_tab = True
-except:
-    should_enable_tab = False
+logger = logging.getLogger(__name__)
 
-import sys
+gps_tab_class = uic.loadUiType(cfclient.module_path +
+                               "/ui/tabs/gpsTab.ui")[0]
 
-gps_tab_class = uic.loadUiType(sys.path[0] +
-                                "/cfclient/ui/tabs/gpsTab.ui")[0]
 
 class GpsTab(Tab, gps_tab_class):
     """Tab for plotting logging data"""
@@ -79,7 +60,6 @@ class GpsTab(Tab, gps_tab_class):
     _connected_signal = pyqtSignal(str)
     _console_signal = pyqtSignal(str)
 
-
     def __init__(self, tabWidget, helper, *args):
         super(GpsTab, self).__init__(*args)
         self.setupUi(self)
@@ -90,206 +70,105 @@ class GpsTab(Tab, gps_tab_class):
         self.tabWidget = tabWidget
         self.helper = helper
         self._cf = helper.cf
-        self._got_home_point = False
-        self._line = ""
-
-        if not should_enable_tab:
-            self.enabled = False
-
-        if self.enabled:
-           # create the marble widget
-            #self._marble = Marble.MarbleWidget()
-            self._marble = FancyMarbleWidget()
 
-            # Load the OpenStreetMap map
-            self._marble.setMapThemeId("earth/openstreetmap/openstreetmap.dgml")
+        view = self.view = QtWebKit.QWebView()
 
-            # Enable the cloud cover and enable the country borders
-            self._marble.setShowClouds(True)
-            self._marble.setShowBorders(True)
+        cache = QtNetwork.QNetworkDiskCache()
+        cache.setCacheDirectory(cfclient.config_path + "/cache")
+        view.page().networkAccessManager().setCache(cache)
+        view.page().networkAccessManager()
 
-            # Hide the FloatItems: Compass and StatusBar
-            self._marble.setShowOverviewMap(False)
-            self._marble.setShowScaleBar(False)
-            self._marble.setShowCompass(False)
+        view.page().mainFrame().addToJavaScriptWindowObject("MainWindow", self)
+        view.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
+        view.load(QtCore.QUrl(cfclient.module_path + "/resources/map.html"))
+        view.loadFinished.connect(self.onLoadFinished)
+        view.linkClicked.connect(QtGui.QDesktopServices.openUrl)
 
-            self._marble.setShowGrid(False)
-            self._marble.setProjection(Marble.Mercator)
+        self.map_layout.addWidget(view)
 
-            # Change the map to center on Australia
+        self._reset_max_btn.clicked.connect(self._reset_max)
 
-            self._marble.zoomView(10)
+        # Connect the signals
+        self._log_data_signal.connect(self._log_data_received)
+        self._log_error_signal.connect(self._logging_error)
+        self._connected_signal.connect(self._connected)
+        self._disconnected_signal.connect(self._disconnected)
 
-            # create the slider
-            self.zoomSlider = QSlider(Qt.Horizontal)
+        # Connect the callbacks from the Crazyflie API
+        self.helper.cf.disconnected.add_callback(
+            self._disconnected_signal.emit)
+        self.helper.cf.connected.add_callback(
+            self._connected_signal.emit)
 
-            self._reset_max_btn.clicked.connect(self._reset_max)
-
-            # add all the components
-            #self.gpslayout.addWidget(self._marble)
-            self.map_layout.addWidget(self._marble)
-            # Connect the signals
-            self._log_data_signal.connect(self._log_data_received)
-            self._log_error_signal.connect(self._logging_error)
-            self._connected_signal.connect(self._connected)
-            self._disconnected_signal.connect(self._disconnected)
+        self._max_speed = 0.0
+        self._lat = 0
+        self._long = 0
 
-            # Connect the callbacks from the Crazyflie API
-            self.helper.cf.disconnected.add_callback(
-                self._disconnected_signal.emit)
-            self.helper.cf.connected.add_callback(
-                self._connected_signal.emit)
+    def onLoadFinished(self):
+        with open(cfclient.module_path + "/resources/map.js", 'r') as f:
+            frame = self.view.page().mainFrame()
+            frame.evaluateJavaScript(f.read())
 
-        else:
-            logger.warning("GPS tab not enabled since no Python"
-                           "bindings for Marble was found")
+    @QtCore.pyqtSlot(float, float)
+    def onMapMove(self, lat, lng):
+        return
 
-        self._max_speed = 0.0
+    def panMap(self, lng, lat):
+        frame = self.view.page().mainFrame()
+        frame.evaluateJavaScript('map.panTo(L.latLng({}, {}));'.format(lat,
+                                                                       lng))
 
-        self._fix_types = {
-            0: "No fix",
-            1: "Dead reckoning only",
-            2: "2D-fix",
-            3: "3D-fix",
-            4: "GNSS+dead",
-            5: "Time only fix"
-        }
+    def _place_cf(self, lng, lat, acc):
+        frame = self.view.page().mainFrame()
+        frame.evaluateJavaScript('cf.setLatLng([{}, {}]);'.format(lat, lng))
 
     def _connected(self, link_uri):
-        lg = LogConfig("GPS", 100)
+        lg = LogConfig("GPS", 1000)
         lg.add_variable("gps.lat")
         lg.add_variable("gps.lon")
-        lg.add_variable("gps.hMSL")
-        lg.add_variable("gps.heading")
-        lg.add_variable("gps.gSpeed")
         lg.add_variable("gps.hAcc")
-        lg.add_variable("gps.fixType")
-        try:
-            self._cf.log.add_config(lg)
+        lg.add_variable("gps.hMSL")
+        lg.add_variable("gps.nsat")
+        self._cf.log.add_config(lg)
+        if lg.valid:
             lg.data_received_cb.add_callback(self._log_data_signal.emit)
             lg.error_cb.add_callback(self._log_error_signal.emit)
             lg.start()
-        except KeyError as e:
-            logger.warning(str(e))
-        except AttributeError as e:
-            logger.warning(str(e))
+        else:
+            logger.warning("Could not setup logging block for GPS!")
         self._max_speed = 0.0
 
     def _disconnected(self, link_uri):
         """Callback for when the Crazyflie has been disconnected"""
-        self._got_home_point = False
         return
 
     def _logging_error(self, log_conf, msg):
         """Callback from the log layer when an error occurs"""
         QMessageBox.about(self, "Plot error", "Error when starting log config"
-                " [%s]: %s" % (log_conf.name, msg))
+                          " [%s]: %s" % (log_conf.name, msg))
 
     def _reset_max(self):
         """Callback from reset button"""
         self._max_speed = 0.0
         self._speed_max.setText(str(self._max_speed))
-        self._marble.clear_data()
-
         self._long.setText("")
         self._lat.setText("")
         self._height.setText("")
-
         self._speed.setText("")
         self._heading.setText("")
         self._accuracy.setText("")
-
         self._fix_type.setText("")
 
-
     def _log_data_received(self, timestamp, data, logconf):
         """Callback when the log layer receives new data"""
-
-        long = float(data["gps.lon"])/10000000.0
-        lat = float(data["gps.lat"])/10000000.0
-        alt = float(data["gps.hMSL"])/1000.0
-        speed = float(data["gps.gSpeed"])/1000.0
-        accuracy = float(data["gps.hAcc"])/1000.0
-        fix_type = float(data["gps.fixType"])
-        heading = float(data["gps.heading"])
-
-        self._long.setText(str(long))
-        self._lat.setText(str(lat))
-        self._height.setText(str(alt))
-
-        self._speed.setText(str(speed))
-        self._heading.setText(str(heading))
-        self._accuracy.setText(str(accuracy))
-        if speed > self._max_speed:
-            self._max_speed = speed
-        self._speed_max.setText(str(self._max_speed))
-
-        self._fix_type.setText(self._fix_types[fix_type])
-
-
-        point = Marble.GeoDataCoordinates(long, lat, alt,
-                                             Marble.GeoDataCoordinates.Degree)
-        if not self._got_home_point:
-            self._got_home_point = True
-
-            self._marble.centerOn(point, True)
-            self._marble.zoomView(4000, Marble.Jump)
-
-        self._marble.add_data(long, lat, alt, accuracy,
-                              True if fix_type == 3 else False)
-
-# If Marble is not installed then do not create MarbleWidget subclass
-if should_enable_tab:
-    class FancyMarbleWidget(Marble.MarbleWidget):
-        def __init__(self):
-            Marble.MarbleWidget.__init__(self)
-            self._points = []
-            self._lat = None
-            self._long = None
-            self._height = None
-            self._accu =  None
-
-        def clear_data(self):
-            self._points = []
-            self._lat = None
-            self._long = None
-            self._height = None
-            self._accu =  None
-
-        def add_data(self, long, lat, height, accu, locked):
-            self._points.append([long, lat, height, accu, locked])
+        long = float(data["gps.lon"]) / 10000000.0
+        lat = float(data["gps.lat"]) / 10000000.0
+
+        if self._lat != lat or self._long != long:
+            self._long.setText("{:.6f}".format(long))
+            self._lat.setText("{:.6f}".format(lat))
+            self._nbr_locked_sats.setText(str(data["gps.nsat"]))
+            self._height.setText("{:.2f}".format(float(data["gps.hMSL"])))
+            self._place_cf(long, lat, 1)
             self._lat = lat
             self._long = long
-            self._height = height
-            self._accu =  accu
-            self.update()
-
-        def customPaint(self, painter):
-            if self._lat:
-                current = Marble.GeoDataCoordinates(self._long,
-                                                    self._lat,
-                                                    self._height,
-                                                    Marble.GeoDataCoordinates.Degree)
-
-                #Paint data points
-                for p in self._points:
-                    pos = Marble.GeoDataCoordinates(p[0],
-                                                    p[1],
-                                                    p[2],
-                                                    Marble.GeoDataCoordinates.Degree)
-                    if p[4]:
-                        painter.setPen(Qt.green)
-                    else:
-                        painter.setPen(Qt.red)
-                    painter.drawEllipse(pos, 1, 1)
-
-                # Paint accuracy
-                painter.setPen(Qt.blue)
-                painter.setBrush(QtGui.QBrush(QtGui.QColor(0, 0, 255, 64)))
-                pixel_per_meter = self.radiusFromDistance(self.distance())/(6371.0*1000)
-                painter.drawEllipse(current, self._accu*pixel_per_meter, self._accu*pixel_per_meter, False)
-
-                #Paint Crazyflie
-                painter.setPen(Qt.black)
-                painter.setBrush(Qt.NoBrush)
-                painter.drawText(current, "Crazyflie")
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/GpsTab.pyc
deleted file mode 100755
index b3788bae74fe8f0f52ba0fc1fd4c7819e244ff81..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8654
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
WsjOAlt`g&*t~7vOscipr-uYhv3_p_q

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.py
old mode 100755
new mode 100644
index b51292e6..11893e87
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.py
@@ -30,24 +30,24 @@
 Basic tab to be able to set (and test) colors in the LED-ring.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LEDTab']
-
 import logging
-import sys
-
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtGui, uic
-from PyQt4.QtCore import pyqtSignal
-from PyQt4.QtGui import QColorDialog
+from PyQt5 import QtGui, uic
+from PyQt5.QtCore import pyqtSignal
 
+import cfclient
 from cfclient.ui.tab import Tab
 
 from cflib.crazyflie.mem import MemoryElement
 
-led_tab_class = uic.loadUiType(sys.path[0] +
-                                "/cfclient/ui/tabs/ledTab.ui")[0]
+__author__ = 'Bitcraze AB'
+__all__ = ['LEDTab']
+
+logger = logging.getLogger(__name__)
+
+led_tab_class = uic.loadUiType(cfclient.module_path +
+                               "/ui/tabs/ledTab.ui")[0]
+
 
 class LEDTab(Tab, led_tab_class):
     """Tab for plotting logging data"""
@@ -90,7 +90,7 @@ class LEDTab(Tab, led_tab_class):
                       self._u11,
                       self._u12]
 
-        self._intensity = 1
+        self._intensity = self._intensity_slider.value()
 
         self._u1.clicked.connect(lambda: self._select(0))
         self._u2.clicked.connect(lambda: self._select(1))
@@ -114,8 +114,14 @@ class LEDTab(Tab, led_tab_class):
             self._intensity_slider.setValue)
 
     def _select(self, nbr):
-        col = QColorDialog()
-        col = QtGui.QColorDialog.getColor()
+        col = QtGui.QColor()  # default to invalid
+
+        if self._mem:
+            led = self._mem.leds[nbr]
+            col = QtGui.QColor.fromRgb(led.r, led.g, led.b)
+
+        col = QtGui.QColorDialog.getColor(col)
+
         if col.isValid() and self._mem:
             logger.info(col.red())
             self._mem.leds[nbr].set(r=col.red(), g=col.green(), b=col.blue())
@@ -141,9 +147,11 @@ class LEDTab(Tab, led_tab_class):
 
     def _connected(self, link_uri):
         """Callback when the Crazyflie has been connected"""
-        self._mem = self._helper.cf.mem.get_mems(
-            MemoryElement.TYPE_DRIVER_LED)[0]
-        logger.info(self._mem)
+        mems = self._helper.cf.mem.get_mems(MemoryElement.TYPE_DRIVER_LED)
+        if len(mems) > 0:
+            self._mem = mems[0]
+            logger.info(self._mem)
+
         if self._mem:
             for btn in self._btns:
                 btn.setEnabled(True)
@@ -158,4 +166,4 @@ class LEDTab(Tab, led_tab_class):
             btn.setStyleSheet("background-color: none")
             self._intensity_slider.setEnabled(False)
             self._intensity_spin.setEnabled(False)
-            self._intensity_slider.setValue(100)
\ No newline at end of file
+            self._intensity_slider.setValue(100)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LEDTab.pyc
deleted file mode 100755
index 6687928d80f5b2fa0155ed7409e097da94404bfe..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.py
old mode 100755
new mode 100644
index 7437823c..4a42a543
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.py
@@ -21,28 +21,27 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Shows all the parameters available in the Crazyflie and also gives the ability
 to edit them.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LogBlockTab']
+from PyQt5 import QtCore, QtWidgets, uic
+from PyQt5.QtCore import Qt, pyqtSignal
 
-import time
-import sys
+import cfclient
+from cfclient.ui.tab import Tab
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+__author__ = 'Bitcraze AB'
+__all__ = ['LogBlockDebugTab']
 
-from cfclient.ui.tab import Tab
+logblock_tab_class = uic.loadUiType(cfclient.module_path +
+                                    "/ui/tabs/logBlockDebugTab.ui")[0]
 
-logblock_tab_class = uic.loadUiType(sys.path[0] +
-                                 "/cfclient/ui/tabs/logBlockDebugTab.ui")[0]
 
 class LogBlockDebugTab(Tab, logblock_tab_class):
     """
@@ -64,10 +63,13 @@ class LogBlockDebugTab(Tab, logblock_tab_class):
 
         self._helper.cf.log.block_added_cb.add_callback(self._block_added)
         self._disconnected_signal.connect(self._disconnected)
-        self._helper.cf.disconnected.add_callback(self._disconnected_signal.emit)
+        self._helper.cf.disconnected.add_callback(
+            self._disconnected_signal.emit)
         self._blocks_updated_signal.connect(self._update_tree)
 
-        self._block_tree.setHeaderLabels(['Id', 'Name', 'Period (ms)', 'Added', 'Started', 'Error', 'Contents'])
+        self._block_tree.setHeaderLabels(
+            ['Id', 'Name', 'Period (ms)', 'Added', 'Started', 'Error',
+             'Contents'])
         self._block_tree.sortItems(0, QtCore.Qt.AscendingOrder)
 
     def _block_added(self, block):
@@ -79,7 +81,7 @@ class LogBlockDebugTab(Tab, logblock_tab_class):
         """Update the block tree"""
         self._block_tree.clear()
         for block in self._helper.cf.log.log_blocks:
-            item = QtGui.QTreeWidgetItem()
+            item = QtWidgets.QTreeWidgetItem()
             item.setFlags(Qt.ItemIsEnabled |
                           Qt.ItemIsSelectable)
             item.setData(0, Qt.DisplayRole, block.id)
@@ -89,15 +91,15 @@ class LogBlockDebugTab(Tab, logblock_tab_class):
             item.setData(4, Qt.EditRole, block.started)
             item.setData(5, Qt.EditRole, block.err_no)
             for var in block.variables:
-                subItem = QtGui.QTreeWidgetItem()
+                subItem = QtWidgets.QTreeWidgetItem()
                 subItem.setFlags(Qt.ItemIsEnabled |
-                              Qt.ItemIsSelectable)
+                                 Qt.ItemIsSelectable)
                 subItem.setData(6, Qt.EditRole, var.name)
-                item.addChild(subItem)                
+                item.addChild(subItem)
 
             self._block_tree.addTopLevelItem(item)
             self._block_tree.expandItem(item)
 
     def _disconnected(self, link_uri):
         """Callback when the Crazyflie is disconnected"""
-        self._block_tree.clear()
\ No newline at end of file
+        self._block_tree.clear()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockDebugTab.pyc
deleted file mode 100755
index 072ba320bb399515f2283559891157209c168abd..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3746
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
NH=K^!Mk;N%{{XvRS2zFw

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.py
old mode 100755
new mode 100644
index 98eb6ce9..b5a21c31
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.py
@@ -31,34 +31,33 @@ This tab shows all log blocks that are registered and can be used to start the
 logging and also to write the logging data to file.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LogBlockTab']
-
-import sys
-
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, pyqtSignal
 
+import cfclient
 from cfclient.ui.tab import Tab
 
-logblock_tab_class = uic.loadUiType(sys.path[0] +
-                                 "/cfclient/ui/tabs/logBlockTab.ui")[0]
-
 import logging
-logger = logging.getLogger(__name__)
 
-from PyQt4.QtGui import QApplication, QStyledItemDelegate, QAbstractItemView
-from PyQt4.QtGui import QStyleOptionButton, QStyle
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import pyqtSlot, pyqtSignal, QThread
-from PyQt4.QtCore import QAbstractItemModel, QModelIndex, QString, QVariant
+from PyQt5.QtWidgets import QApplication, QStyledItemDelegate
+from PyQt5.QtWidgets import QAbstractItemView, QStyleOptionButton, QStyle
+from PyQt5.QtCore import QAbstractItemModel, QModelIndex
 
 from cfclient.utils.logdatawriter import LogWriter
 
+__author__ = 'Bitcraze AB'
+__all__ = ['LogBlockTab']
+
+logblock_tab_class = uic.loadUiType(
+    cfclient.module_path + "/ui/tabs/logBlockTab.ui")[0]
+
+logger = logging.getLogger(__name__)
+
 
 class LogBlockChildItem(object):
     """Class that acts as a child in the tree and represents one variable in
     a log block"""
+
     def __init__(self, parent, name):
         """Initialize the node"""
         self.parent = parent
@@ -100,7 +99,9 @@ class LogBlockItem(object):
         self._doing_transaction = False
 
     def _log_error(self, logconfig, msg):
-        """Callback when there's an error starting the block in the Crazyflie"""
+        """
+        Callback when there's an error starting the block in the Crazyflie
+        """
         # Do nothing here, a pop-up will notify the user that the
         # starting failed
         self._doing_transaction = False
@@ -109,9 +110,9 @@ class LogBlockItem(object):
         """Callback when a block has been started in the Crazyflie"""
         logger.debug("%s started: %s", self.name, started)
         if started:
-             self._block_started = True
+            self._block_started = True
         else:
-             self._block_started = False
+            self._block_started = False
         self._doing_transaction = False
         self._model.refresh()
 
@@ -163,6 +164,7 @@ class LogBlockItem(object):
 
 
 class LogBlockModel(QAbstractItemModel):
+
     def __init__(self, view, parent=None):
         super(LogBlockModel, self).__init__(parent)
         self._nodes = []
@@ -180,7 +182,9 @@ class LogBlockModel(QAbstractItemModel):
         self.layoutChanged.emit()
 
     def clicked(self, index):
-        """Callback when a cell has been clicked (mouse down/up on same cell)"""
+        """
+        Callback when a cell has been clicked (mouse down/up on same cell)
+        """
         node = index.internalPointer()
         if not node.parent and index.column() == 3:
             if node.logging_started():
@@ -217,7 +221,7 @@ class LogBlockModel(QAbstractItemModel):
     def headerData(self, section, orientation, role):
         """Re-implemented method to get the headers"""
         if role == Qt.DisplayRole:
-            return QString(self._column_headers[section])
+            return self._column_headers[section]
 
     def rowCount(self, parent):
         """Re-implemented method to get the number of rows for a given index"""
@@ -261,7 +265,7 @@ class LogBlockModel(QAbstractItemModel):
                 (index.column() == 4 or index.column() == 3):
             return Qt.AlignHCenter | Qt.AlignVCenter
 
-        return QVariant()
+        return None
 
     def reset(self):
         """Reset the model"""
@@ -282,7 +286,7 @@ class CheckboxDelegate(QStyledItemDelegate):
         col = index.column()
         if not item.parent and (col == 3 or col == 4):
             s = QStyleOptionButton()
-            checkbox_rect = QApplication.style().\
+            checkbox_rect = QApplication.style(). \
                 subElementRect(QStyle.SE_CheckBoxIndicator, option)
             s.rect = option.rect
             center_offset = s.rect.width() / 2 - checkbox_rect.width() / 2
@@ -342,4 +346,6 @@ class LogBlockTab(Tab, logblock_tab_class):
 
     def _disconnected(self, link_uri):
         """Callback when the Crazyflie is disconnected"""
-        self._model.reset()
\ No newline at end of file
+        self._model.beginResetModel()
+        self._model.reset()
+        self._model.endResetModel()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogBlockTab.pyc
deleted file mode 100755
index c71e399d654417ad5df9fb3c9cbc87ec96f9b9b3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.py
old mode 100755
new mode 100644
index 629b452f..7db1f804
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.py
@@ -20,30 +20,26 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 Shows the Log TOC of available variables in the Crazyflie.
 """
 
+import cfclient
+from cfclient.ui.tab import Tab
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import Qt
+
 __author__ = 'Bitcraze AB'
 __all__ = ['LogTab']
 
-import time
-import sys
-
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
-
-from cflib.crazyflie import Crazyflie
-
-from cfclient.ui.tab import Tab
-
-param_tab_class = uic.loadUiType(sys.path[0] +
-                                 "/cfclient/ui/tabs/logTab.ui")[0]
+param_tab_class = uic.loadUiType(cfclient.module_path +
+                                 "/ui/tabs/logTab.ui")[0]
 
 
 class LogTab(Tab, param_tab_class):
@@ -82,11 +78,11 @@ class LogTab(Tab, param_tab_class):
 
         toc = self.cf.log.toc
 
-        for group in toc.toc.keys():
-            groupItem = QtGui.QTreeWidgetItem()
+        for group in list(toc.toc.keys()):
+            groupItem = QtWidgets.QTreeWidgetItem()
             groupItem.setData(0, Qt.DisplayRole, group)
-            for param in toc.toc[group].keys():
-                item = QtGui.QTreeWidgetItem()
+            for param in list(toc.toc[group].keys()):
+                item = QtWidgets.QTreeWidgetItem()
                 item.setData(0, Qt.DisplayRole, param)
                 item.setData(1, Qt.DisplayRole, toc.toc[group][param].ident)
                 item.setData(2, Qt.DisplayRole, toc.toc[group][param].pytype)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/LogTab.pyc
deleted file mode 100755
index e9ffc7219c6f8354eb9c3150ad53016588c9790b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2830
zcmcguUvC>l5TCpA|2T=0HYtG$EP;?8Xe=c9Rw3F%YNJLeIVV({gihzXjlJ%j&%Irj
z8YNHVkuSlQ;7h=_;RC>L<{T#oUW@G=@6OK7&Y$1Ro%iQ@>skE#yO@?A5C7j_m_I-g
zq5#yPz@fyY5hgAr9wik@Jqj=>=M@SnGOtovrL0Cljj}ogb;=qPG{|AO8l_FjS`@S>
zTcco&vNi>6%GN1Zr)-0QjZ&^o=_X|z3OePwLFpD{+Z1e*qZ%~1L#jfPyOcC(FKN-e
zcd!l9V24dq+oX2r0#>fk&qVKtz7KZU-a)U;UOfV74aWJ8rfbKldz_EDXD<%A`9(K+
z6X`S>rmFiUDl|__S5HOipoo52T%=m<x6B$8Jkd4=OLZSVu{Err<t!TNzwkNfaR7yT
zY7g>4*(%nj_UT+(-kIyT#~kYl+cxkwTfDY|G`F^Oz0jj+l-fFroQ(?=C8BU}^z`KM
zanAwUHbGWql`K}zX5f#^M<D(9B8JgZ+n?*cjfSS5ilO^3f`$0QW<0?#0}zFDJERar
zj}TSl^k!aVFd(AHtg164IP9*(7?KTUmZy+v4m_Am@&~;N^u}x&PuTOP80L2ni=RW6
zkacO|(xpeg5II;+JmES>zwC#=RynECB?O7W8eNv0I&&rsVG5lzY0_fLN@ylk8dcaD
zQ4I8~(WK4NlXaSGtTwRN6z<xJ1=-HE?AC2rEK1pq$R-4AF$zu$Cv1r*%kG{;nUX{w
z9ZCYvr?V)2C3zj#yog4sx6Ogzu$cKw6+R{;m<U5X)iw-8*eE-nooksRkD``=ld0)k
z7JU6!rO+V2fXqvsjFgqj;|n>+xi6Hmn~;UVXF!!Ij-#PUjU0;e=~Ts5C6)^%N|G>+
z(salM^O4o|paduTr!s9t_i|HCCfclIExUJ{Q63ghNQ8_^FZ>+{`FBBt6%`}X!-9mE
z7nt?Od8YcqW!3d(MLvP0rq4wvb@`ygxp^>K*l|AXr+WBr@RwD(KU?@6=zNG_J^&$S
z*I9R)PE$tPyYKEfcf37E96KG@LQh9AmkAH9y#oxh1;Qx852b(&fdOxy^jOfp2O^1$
zQxz2@ugg46T&kz9rU1u#_VZ(0^&G>nMdXSXj8Puq#X}hU4=;Fudh%#ep(~f(ZaZ9F
zXtz~%^6&@8x$?NXP3pY9s?a6&8eE>h5b6#^{LUli?Qc?+*!F1e`s}ZCRlRi<B@8{c
z&*Bc8U2@%PjdDNhxvWAL>hnehrj)n-Q>J}ert;r1>!l2=-(WkqLA)N*%VjW7-#1MI
zA?aMNUw=U_CDUB8C(>#)CtY)dwFlB;WJvb?PkFWrBAp-gC;v8&1?R8S!uWhl%IlPC
zvn<*pt1<x}s`N0jk<X=O`MGnb%`A-;ex8<(6`i2DOJ@P@7qgNX%ZyQm8a^27G?5Fi
zILl|p>Wxa}0)E!0x3g%P@Uq8{@Vg*ouK+&J{UiT#X0WTHBA?HsO~_0%Fn<;mQ6}za
z)&kCZEZaS3=XPN3^F8jmyXo#aZIthaLO*l(yXAJA9y_;eqg-Zaqs$4zEKlYsmOeL3
z$%e6o&(BK#6DHgkeD=%d(((Di8=qwMUiuNPp)WBETUmoMZMV6*Q|U<$;mm|#lE*7A
zqB)vev3xd!A-Xi?0uqhq4TI1ujHK<`#i{+uXMhUQeBP5LEgSpg8;ano^qRxs3ltbX
zW#7kp&v1X$X?=e2SZ<U}7jF~$c;NUFb0%pXCFlB#@yJHaB0H7?f|U@WVVp+B$g}Q$
gh_2w^QJML#Ijx3EvgX#%@j24>ou1p_ue0I(4VbN2DF6Tf

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.py
old mode 100755
new mode 100644
index 7ac7fada..a3c97891
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.py
@@ -21,35 +21,37 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Shows all the parameters available in the Crazyflie and also gives the ability
 to edit them.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['ParamTab']
+import logging
 
-import sys
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
-from PyQt4.QtCore import QAbstractItemModel, QModelIndex, QString, QVariant
-from PyQt4.QtGui import QApplication, QStyledItemDelegate, QAbstractItemView, QBrush, QColor
-from PyQt4.QtGui import QSortFilterProxyModel
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, pyqtSignal
+from PyQt5.QtCore import QAbstractItemModel, QModelIndex
+from PyQt5.QtGui import QBrush, QColor
 
+import cfclient
 from cfclient.ui.tab import Tab
 
-param_tab_class = uic.loadUiType(sys.path[0] +
-                                 "/cfclient/ui/tabs/paramTab.ui")[0]
+__author__ = 'Bitcraze AB'
+__all__ = ['ParamTab']
+
+param_tab_class = uic.loadUiType(
+    cfclient.module_path + "/ui/tabs/paramTab.ui")[0]
 
-import logging
 logger = logging.getLogger(__name__)
 
+
 class ParamChildItem(object):
     """Represents a leaf-node in the tree-view (one parameter)"""
+
     def __init__(self, parent, name, crazyflie):
         """Initialize the node"""
         self.parent = parent
@@ -81,6 +83,7 @@ class ParamChildItem(object):
 
 class ParamGroupItem(object):
     """Represents a parameter group in the tree-view"""
+
     def __init__(self, name, model):
         """Initialize the parent node"""
         super(ParamGroupItem, self).__init__()
@@ -93,8 +96,10 @@ class ParamGroupItem(object):
         """Return the number of children this node has"""
         return len(self.children)
 
+
 class ParamBlockModel(QAbstractItemModel):
     """Model for handling the parameters in the tree-view"""
+
     def __init__(self, parent):
         """Create the empty model"""
         super(ParamBlockModel, self).__init__(parent)
@@ -142,7 +147,7 @@ class ParamBlockModel(QAbstractItemModel):
     def headerData(self, section, orientation, role):
         """Re-implemented method to get the headers"""
         if role == Qt.DisplayRole:
-            return QString(self._column_headers[section])
+            return self._column_headers[section]
 
     def rowCount(self, parent):
         """Re-implemented method to get the number of rows for a given index"""
@@ -184,37 +189,36 @@ class ParamBlockModel(QAbstractItemModel):
                 return node.value
         elif role == Qt.EditRole and index.column() == 3:
             return node.value
-        elif (role == Qt.BackgroundRole and index.column() == 3
-                and node.is_updating):
+        elif (role == Qt.BackgroundRole and index.column() == 3 and
+              node.is_updating):
             return self._red_brush
 
-        return QVariant()
+        return None
 
     def setData(self, index, value, role):
         """Re-implemented function called when a value has been edited"""
         node = index.internalPointer()
         if role == Qt.EditRole:
-            new_val = str(value.toString())
+            new_val = str(value)
             # This will not update the value, only trigger a setting and
             # reading of the parameter from the Crazyflie
             node.set_value(new_val)
             return True
         return False
 
-
     def flags(self, index):
         """Re-implemented function for getting the flags for a certain index"""
         flag = super(ParamBlockModel, self).flags(index)
         node = index.internalPointer()
-        if index.column() == 3 and node.parent and node.access=="RW":
+        if index.column() == 3 and node.parent and node.access == "RW":
             flag |= Qt.ItemIsEditable
         return flag
 
-
     def reset(self):
         """Reset the model"""
+        super(ParamBlockModel, self).beginResetModel()
         self._nodes = []
-        super(ParamBlockModel, self).reset()
+        super(ParamBlockModel, self).endResetModel()
         self.layoutChanged.emit()
 
 
@@ -252,4 +256,6 @@ class ParamTab(Tab, param_tab_class):
         self.paramTree.expandAll()
 
     def _disconnected(self, link_uri):
+        self._model.beginResetModel()
         self._model.reset()
+        self._model.endResetModel()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ParamTab.pyc
deleted file mode 100755
index 68c20f7541dca74cae5f9e4f4c2fd3595f495658..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10768
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
Xj`J3-jT-(r>-5fR+iz^IZ$JG%ulRQ^

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.py
old mode 100755
new mode 100644
index b6cd3e19..42cbb02a
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.py
@@ -20,47 +20,39 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 This tab plots different logging data defined by configurations that has been
 pre-configured.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['PlotTab']
-
-import glob
-import json
 import logging
-import os
-import sys
-
-logger = logging.getLogger(__name__)
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import pyqtSlot, pyqtSignal, QThread, Qt
-from PyQt4.QtGui import QMessageBox
-from PyQt4.QtGui import QApplication, QStyledItemDelegate, QAbstractItemView
-from PyQt4.QtCore import QAbstractItemModel, QModelIndex, QString, QVariant
+from cfclient.ui.tab import Tab
+from cfclient.ui.widgets.plotwidget import PlotWidget
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import QAbstractItemModel
+from PyQt5.QtCore import QModelIndex
+from PyQt5.QtCore import Qt
+from PyQt5.QtWidgets import QMessageBox
 
-from pprint import pprint
-import datetime
+import cfclient
 
-from cfclient.ui.widgets.plotwidget import PlotWidget
+__author__ = 'Bitcraze AB'
+__all__ = ['PlotTab']
 
-from cflib.crazyflie.log import Log
+logger = logging.getLogger(__name__)
 
-from cfclient.ui.tab import Tab
+plot_tab_class = uic.loadUiType(cfclient.module_path +
+                                "/ui/tabs/plotTab.ui")[0]
 
-plot_tab_class = uic.loadUiType(sys.path[0] +
-                                "/cfclient/ui/tabs/plotTab.ui")[0]
 
 class LogConfigModel(QAbstractItemModel):
     """Model for log configurations in the ComboBox"""
+
     def __init__(self, parent=None):
         super(LogConfigModel, self).__init__(parent)
         self._nodes = []
@@ -85,7 +77,7 @@ class LogConfigModel(QAbstractItemModel):
         """Re-implemented method to get the number of rows for a given index"""
         parent_item = parent.internalPointer()
         if parent.isValid():
-            parent_item = parent.internalPointer()
+            parent_item = parent.internalPointer()  # noqa
             return 0
         else:
             return len(self._nodes)
@@ -104,12 +96,12 @@ class LogConfigModel(QAbstractItemModel):
 
     def data(self, index, role):
         """Re-implemented method to get the data for a given index and role"""
-        node = index.internalPointer()
-        if not index.isValid() or not 0 <= index.row() < len(self._nodes): 
-            return QVariant() 
+        node = index.internalPointer()  # noqa
+        if not index.isValid() or not 0 <= index.row() < len(self._nodes):
+            return None
         if role == Qt.DisplayRole:
             return self._nodes[index.row()].name
-        return QVariant()
+        return None
 
     def reset(self):
         """Reset the model"""
@@ -119,6 +111,7 @@ class LogConfigModel(QAbstractItemModel):
     def get_config(self, i):
         return self._nodes[i]
 
+
 class PlotTab(Tab, plot_tab_class):
     """Tab for plotting logging data"""
 
@@ -127,7 +120,17 @@ class PlotTab(Tab, plot_tab_class):
     _disconnected_signal = pyqtSignal(str)
     _connected_signal = pyqtSignal(str)
 
-    colors = ['g', 'b', 'm', 'r', 'y', 'c']
+    colors = [
+        (60, 200, 60),    # green
+        (40, 100, 255),   # blue
+        (255, 130, 240),  # magenta
+        (255, 26, 28),    # red
+        (255, 170, 0),    # orange
+        (40, 180, 240),   # cyan
+        (153, 153, 153),  # grey
+        (176, 96, 50),    # brown
+        (180, 60, 240),   # purple
+    ]
 
     def __init__(self, tabWidget, helper, *args):
         super(PlotTab, self).__init__(*args)
@@ -174,7 +177,9 @@ class PlotTab(Tab, plot_tab_class):
 
     def _disconnected(self, link_uri):
         """Callback for when the Crazyflie has been disconnected"""
+        self._model.beginResetModel()
         self._model.reset()
+        self._model.endResetModel()
         self.dataSelector.setCurrentIndex(-1)
         self._previous_config = None
         self._started_previous = False
@@ -204,7 +209,7 @@ class PlotTab(Tab, plot_tab_class):
         # First check if we need to stop the old block
         if self._started_previous and self._previous_config:
             logger.debug("Should stop config [%s], stopping!",
-                        self._previous_config.name)
+                         self._previous_config.name)
             self._previous_config.delete()
 
         # Remove our callback for the previous config
@@ -227,8 +232,8 @@ class PlotTab(Tab, plot_tab_class):
         self._plot.set_title(lg.name)
 
         for d in lg.variables:
-            self._plot.add_curve(d.name,
-                                self.colors[color_selector % len(self.colors)])
+            self._plot.add_curve(d.name, self.colors[
+                color_selector % len(self.colors)])
             color_selector += 1
         lg.data_received_cb.add_callback(self._log_data_signal_wrapper)
         lg.error_cb.add_callback(self._log_error_signal_wrapper)
@@ -242,8 +247,9 @@ class PlotTab(Tab, plot_tab_class):
 
     def _logging_error(self, log_conf, msg):
         """Callback from the log layer when an error occurs"""
-        QMessageBox.about(self, "Plot error", "Error when starting log config"
-                " [%s]: %s" % (log_conf.name, msg))
+        QMessageBox.about(
+            self, "Plot error", "Error when starting log config [%s]: %s" % (
+                log_conf.name, msg))
 
     def _log_data_received(self, timestamp, data, logconf):
         """Callback when the log layer receives new data"""
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/PlotTab.pyc
deleted file mode 100755
index 6177d2525e46ab08df538999f586baf6b8b331ad..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.py
old mode 100755
new mode 100644
index e9bfba63..d07aa572
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.py
@@ -7,7 +7,7 @@
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
 #
-#  Copyright (C) 2011-2013 Bitcraze AB
+#  Copyright (C) 2011-2017 Bitcraze AB
 #
 #  Crazyflie Nano Quadcopter Client
 #
@@ -20,38 +20,38 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 Find all the available tabs so they can be loaded.
 
 Dropping a new .py file into this directory will automatically list and load
 it into the UI when it is started.
 """
+from .ConsoleTab import ConsoleTab
+# from .ExampleTab import ExampleTab
+from .FlightTab import FlightTab
+# from .GpsTab import GpsTab
+from .LEDTab import LEDTab
+from .LogBlockTab import LogBlockTab
+from .LogTab import LogTab
+from .ParamTab import ParamTab
+from .PlotTab import PlotTab
+from .locopositioning_tab import LocoPositioningTab
 
 __author__ = 'Bitcraze AB'
 __all__ = []
 
-import os
-import glob
-import logging
-
-logger = logging.getLogger(__name__)
-
-found_tabs = [os.path.splitext(os.path.basename(f))[0] for
-             f in glob.glob(os.path.dirname(__file__) + "/[A-Za-z]*Tab.py")]
-if len(found_tabs) == 0:
-    found_tabs = [os.path.splitext(os.path.basename(f))[0] for
-                 f in glob.glob(os.path.dirname(__file__) +
-                                "/[A-Za-z]*Tab.pyc")]
-
-logger.debug("Found tabs: %s", found_tabs)
-
-available = []
-
-for tab in found_tabs:
-    tabModule = __import__(tab, globals(), locals(), [tab], -1)
-    available.append(getattr(tabModule, tab))
+available = [
+    ConsoleTab,
+    # ExampleTab,
+    FlightTab,
+    # GpsTab,
+    LEDTab,
+    LogBlockTab,
+    LogTab,
+    ParamTab,
+    PlotTab,
+    LocoPositioningTab,
+]
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/__init__.pyc
deleted file mode 100755
index 229ceb2b231e511d54ef38e37ed32371bd1adde2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1101
zcmb7CO>fgc5S_J?v`xQTN`ccB2`NHKeFg!dRjGvdkPt;6qhhV?NwUGQUGIiAz2?UM
z;HPlm?;vr7w{8L#IN-#yGjC>g-pttlzS<sr`+Snn>{-D17_WIJh*F{uQcx(U58a~_
zf1fg+LVvC|C~VC2CWTGnCJkG}3p7RIqD$lk4I9Kh4VP%xCSG=~v_ZQ#j!ruiuFRdQ
zb7hTq#YMTmCf)qt(HT>?PP{?9K0`lxRQ>q({jLAJ|Es${2irv&Zc@5X7xGBB&bR2|
ziL;MRA5yqYe2o}#ho%U>UdwIjgQ`bU%wU&zi-tFdZxTb_rYUei;%r;I#rR%#7Ttuu
zK(vo_o=TNv(hgXvPfBMh&RAL%8)*uMPGq8T8MDj^m2$e@ZXZ=eS?atmmCX5E?w1qU
z(@4^}bs5^oR9BqXqMFEajl0#@79(YKf<hCSX=9~AS$APu+j$<#H&5mHfOF|El((v~
zuAo^4(?e~ON?o!%IMhG!yfhm?gZBsBP<1a)@1Cd_L^Lomn}6{nW)0|ZF-Bq6-F<n-
zbZ!B%?vsn6v`C`Jwrd@H2So+*$_3WYJ-7;E8#ww|5!b$~==U)QyW~K&&tY<9-E^ZU
zS0hGR3x*2=?ovx-2X!h&<RWIlZhi>HH&4A9GG(SMU)b7+mEk(r(d)SuBG-cT-QAqq
zCeD=O@fDHZTde&EoOPu~Wl`B#SFQz>nHfDS#?(z9`bCkBGp-$~EIChWy68?>TXj&0
z{s{95W-us59K^Hz1Z7nWv3wJ_bxnGi=57L!ThlEkm}?$nIu4TF6&Q?l;Ccz7Naq^t
tu*ACO2cw$DqdinGw;@_yOSHTdfuFbT`Qn+_6290G_q+|S<*kZ6@e4O62crN0

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/consoleTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/consoleTab.ui
old mode 100755
new mode 100644
index 39f514a8..6011683b
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/consoleTab.ui
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/consoleTab.ui
@@ -13,12 +13,49 @@
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
+  <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
       <widget class="QTextEdit" name="console"/>
      </item>
+     <item>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <widget class="QPushButton" name="_clearButton">
+         <property name="text">
+          <string>Clear</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="_dumpSystemLoadButton">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
+         <property name="text">
+          <string>Task dump</string>
+         </property>
+         <property name="checkable">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
     </layout>
    </item>
   </layout>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/exampleTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/exampleTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/flightTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/flightTab.ui
old mode 100755
new mode 100644
index 5653fb73..28e4ae86
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/flightTab.ui
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/flightTab.ui
@@ -34,7 +34,7 @@
          </property>
          <property name="minimumSize">
           <size>
-           <width>320</width>
+           <width>160</width>
            <height>0</height>
           </size>
          </property>
@@ -54,16 +54,10 @@
              <widget class="QComboBox" name="flightModeCombo">
               <property name="minimumSize">
                <size>
-                <width>150</width>
+                <width>0</width>
                 <height>0</height>
                </size>
               </property>
-              <property name="maximumSize">
-               <size>
-                <width>150</width>
-                <height>16777215</height>
-               </size>
-              </property>
               <property name="toolTip">
                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select what flightmode to use:&lt;/p&gt;&lt;p&gt; * Safe prevents crashing&lt;/p&gt;&lt;p&gt; * Crazy does not prevent crashing :)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
               </property>
@@ -104,23 +98,23 @@
             <item row="2" column="0">
              <widget class="QLabel" name="label_5">
               <property name="text">
-               <string>Thrust mode</string>
+               <string>Assist mode</string>
               </property>
              </widget>
             </item>
             <item row="2" column="1">
-             <widget class="QComboBox" name="thrustModeCombo">
+             <widget class="QComboBox" name="_assist_mode_combo">
               <property name="enabled">
-               <bool>false</bool>
+               <bool>true</bool>
               </property>
               <item>
                <property name="text">
-                <string>Linear</string>
+                <string>Altitude hold</string>
                </property>
               </item>
               <item>
                <property name="text">
-                <string>Quadratic</string>
+                <string>Position hold</string>
                </property>
               </item>
              </widget>
@@ -236,7 +230,7 @@
          </property>
          <property name="minimumSize">
           <size>
-           <width>320</width>
+           <width>160</width>
            <height>0</height>
           </size>
          </property>
@@ -347,7 +341,7 @@
         <widget class="QGroupBox" name="groupBox_4">
          <property name="minimumSize">
           <size>
-           <width>320</width>
+           <width>160</width>
            <height>0</height>
           </size>
          </property>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/gpsTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/gpsTab.ui
old mode 100755
new mode 100644
index da2c503d..d9af9747
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/gpsTab.ui
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/gpsTab.ui
@@ -30,18 +30,29 @@
        <property name="sizeConstraint">
         <enum>QLayout::SetDefaultConstraint</enum>
        </property>
-       <item row="0" column="5">
-        <widget class="QLabel" name="label_6">
+       <item row="2" column="2">
+        <widget class="QLabel" name="label_7">
          <property name="text">
-          <string>Accuracy</string>
+          <string>Fix Type</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="0">
-        <widget class="QLineEdit" name="_lat">
-         <property name="enabled">
+       <item row="0" column="3">
+        <widget class="QLabel" name="label_4">
+         <property name="text">
+          <string>Ground speed</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="4">
+        <widget class="QLineEdit" name="_height">
+         <property name="readOnly">
           <bool>true</bool>
          </property>
+        </widget>
+       </item>
+       <item row="1" column="3">
+        <widget class="QLineEdit" name="_speed">
          <property name="readOnly">
           <bool>true</bool>
          </property>
@@ -54,46 +65,42 @@
          </property>
         </widget>
        </item>
-       <item row="0" column="1">
-        <widget class="QLabel" name="label_2">
-         <property name="text">
-          <string>Long</string>
+       <item row="1" column="0">
+        <widget class="QLineEdit" name="_lat">
+         <property name="enabled">
+          <bool>true</bool>
          </property>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QLineEdit" name="_speed_max">
          <property name="readOnly">
           <bool>true</bool>
          </property>
         </widget>
        </item>
-       <item row="1" column="5">
-        <widget class="QLineEdit" name="_accuracy"/>
-       </item>
-       <item row="2" column="2">
-        <widget class="QLineEdit" name="_fix_type">
-         <property name="readOnly">
-          <bool>true</bool>
+       <item row="0" column="1">
+        <widget class="QLabel" name="label_2">
+         <property name="text">
+          <string>Long</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="3">
-        <widget class="QLabel" name="label_4">
+       <item row="0" column="5">
+        <widget class="QLabel" name="label_6">
          <property name="text">
-          <string>Ground speed</string>
+          <string>Accuracy</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="4">
-        <widget class="QLineEdit" name="_height">
+       <item row="1" column="5">
+        <widget class="QLineEdit" name="_accuracy"/>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLineEdit" name="_speed_max">
          <property name="readOnly">
           <bool>true</bool>
          </property>
         </widget>
        </item>
-       <item row="1" column="3">
-        <widget class="QLineEdit" name="_speed">
+       <item row="3" column="2">
+        <widget class="QLineEdit" name="_fix_type">
          <property name="readOnly">
           <bool>true</bool>
          </property>
@@ -127,13 +134,30 @@
          </property>
         </widget>
        </item>
-       <item row="2" column="1">
+       <item row="3" column="1">
         <widget class="QPushButton" name="_reset_max_btn">
          <property name="text">
           <string>Reset all</string>
          </property>
         </widget>
        </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="label_8">
+         <property name="text">
+          <string>Max speed</string>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="3">
+        <widget class="QLabel" name="label_9">
+         <property name="text">
+          <string>Locked sats</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="3">
+        <widget class="QLineEdit" name="_nbr_locked_sats"/>
+       </item>
       </layout>
      </item>
      <item>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ledTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/ledTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.py
new file mode 100644
index 00000000..b5885f27
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.py
@@ -0,0 +1,671 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
+#  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
+#  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
+#   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
+#
+#  Copyright (C) 2011-2017 Bitcraze AB
+#
+#  Crazyflie Nano Quadcopter Client
+#
+#  This program 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 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, write to the Free Software
+#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+#  02110-1301, USA.
+
+"""
+Shows data for the Loco Positioning system
+"""
+
+import logging
+from enum import Enum
+from collections import namedtuple
+
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal, QTimer
+from PyQt5.QtGui import QFont
+from PyQt5.QtGui import QMessageBox
+
+import cfclient
+from cfclient.ui.tab import Tab
+
+from cflib.crazyflie.log import LogConfig
+from cflib.crazyflie.mem import MemoryElement
+from lpslib.lopoanchor import LoPoAnchor
+
+import copy
+import sys
+
+__author__ = 'Bitcraze AB'
+__all__ = ['LocoPositioningTab']
+
+logger = logging.getLogger(__name__)
+
+locopositioning_tab_class = uic.loadUiType(
+    cfclient.module_path + "/ui/tabs/locopositioning_tab.ui")[0]
+
+# Try the imports for PyQtGraph to see if it is installed
+try:
+    import pyqtgraph as pg
+    from pyqtgraph import ViewBox  # noqa
+    import pyqtgraph.console  # noqa
+    import numpy as np  # noqa
+
+    _pyqtgraph_found = True
+except Exception:
+    import traceback
+
+    logger.warning("PyQtGraph (or dependency) failed to import:\n%s",
+                   traceback.format_exc())
+    _pyqtgraph_found = False
+
+
+class Anchor:
+    def __init__(self, x=0.0, y=0.0, z=0.0, distance=0.0):
+        self.x = x
+        self.y = y
+        self.z = z
+        self.distance = distance
+
+    def set_position(self, position):
+        """Sets the position."""
+        self.x = position[0]
+        self.y = position[1]
+        self.z = position[2]
+
+    def get_position(self):
+        """Returns the position as a vector"""
+        return (self.x, self.y, self.z)
+
+
+class AxisScaleStep:
+    def __init__(self, from_view, from_axis, to_view, to_axis,
+                 center_only=False):
+        self.from_view = from_view.view
+        self.from_axis = from_axis
+        self.to_view = to_view.view
+        self.to_axis = to_axis
+        self.center_only = center_only
+
+
+class PlotWrapper:
+    XAxis = 0
+    YAxis = 1
+    _refs = []
+    _change_lock = False
+
+    axis_dict = {'x': 0, 'y': 1, 'z': 2}
+
+    ANCHOR_BRUSH = (60, 60, 60)
+    HIGHLIGHT_ANCHOR_BRUSH = (0, 255, 0)
+    POSITION_BRUSH = (0, 0, 255)
+
+    VICINITY_DISTANCE = 2.5
+    HIGHLIGHT_DISTANCE = 0.5
+
+    LABEL_SIZE = 15
+    LABEL_HIGHLIGHT_SIZE = 30
+
+    ANCHOR_SIZE = 10
+    HIGHLIGHT_SIZE = 20
+
+    def __init__(self, title, horizontal, vertical):
+        self._horizontal = horizontal
+        self._vertical = vertical
+        self._depth = self._find_missing_axis(horizontal, vertical)
+        self._title = title
+        self.widget = pg.PlotWidget(title=title, enableMenu=False)
+        self.widget.getPlotItem().hideButtons()
+        self._axis_scale_steps = []
+
+        self.widget.setLabel('left', self._vertical, units='m')
+        self.widget.setLabel('bottom', self._horizontal, units='m')
+
+        self.widget.setAspectLocked(True, 1)
+        self.widget.getViewBox().sigRangeChanged.connect(self._view_changed)
+        self.view = self.widget.getViewBox()
+
+    def update(self, anchors, pos, display_mode):
+        self.widget.clear()
+
+        # Sort anchors in depth order to add the one closes last
+        for (i, anchor) in sorted(
+                anchors.items(),
+                key=lambda item: getattr(item[1], self._depth), reverse=True):
+            anchor_v = getattr(anchor, self._horizontal)
+            anchor_h = getattr(anchor, self._vertical)
+            self._plot_anchor(anchor_v, anchor_h, i, anchor.distance,
+                              display_mode)
+
+        if display_mode is DisplayMode.estimated_position:
+            cf_h = pos[PlotWrapper.axis_dict[self._horizontal]]
+            cf_v = pos[PlotWrapper.axis_dict[self._vertical]]
+            self.widget.plot([cf_h], [cf_v], pen=None,
+                             symbolBrush=PlotWrapper.POSITION_BRUSH)
+
+    def _find_missing_axis(self, axis1, axis2):
+        all = set(self.axis_dict.keys())
+        all.remove(axis1)
+        all.remove(axis2)
+
+        return list(all)[0]
+
+    def _plot_anchor(self, x, y, anchor_id, distance, display_mode):
+        brush = PlotWrapper.ANCHOR_BRUSH
+        size = PlotWrapper.ANCHOR_SIZE
+        font_size = self.LABEL_SIZE
+        if display_mode is DisplayMode.identify_anchor:
+            if distance < PlotWrapper.VICINITY_DISTANCE:
+                brush = self._mix_brushes(
+                    brush,
+                    PlotWrapper.HIGHLIGHT_ANCHOR_BRUSH,
+                    distance / PlotWrapper.VICINITY_DISTANCE)
+
+            if distance < PlotWrapper.HIGHLIGHT_DISTANCE:
+                brush = PlotWrapper.HIGHLIGHT_ANCHOR_BRUSH
+                size = PlotWrapper.HIGHLIGHT_SIZE
+                font_size = self.LABEL_HIGHLIGHT_SIZE
+
+        self.widget.plot([x], [y], pen=None, symbolBrush=brush,
+                         symbolSize=size)
+
+        text = pg.TextItem(text="{}".format(anchor_id))
+        font = QFont("Helvetica", font_size)
+        text.setFont(font)
+        self.widget.addItem(text)
+        text.setPos(x, y)
+
+    def _mix_brushes(self, brush1, brush2, mix):
+        if mix < 0.0:
+            return brush1
+        if mix > 1.0:
+            return brush2
+
+        b1 = mix
+        b2 = 1.0 - mix
+        return (
+            brush1[0] * b1 + brush2[0] * b2,
+            brush1[1] * b1 + brush2[1] * b2,
+            brush1[2] * b1 + brush2[2] * b2,
+        )
+
+    def _view_changed(self, view, settings):
+        # Ignore all callbacks until this change is processed
+        if PlotWrapper._change_lock:
+            return
+        PlotWrapper._change_lock = True
+
+        for step in self._axis_scale_steps:
+            range = step.from_view.viewRange()[step.from_axis]
+            new_range = range
+
+            if step.center_only:
+                center = (range[0] + range[1]) / 2
+                current_range = step.to_view.viewRange()[step.to_axis]
+                current_center = (current_range[0] + current_range[1]) / 2
+                delta = center - current_center
+                new_range = [current_range[0] + delta,
+                             current_range[1] + delta]
+
+            if step.to_axis is PlotWrapper.XAxis:
+                step.to_view.setRange(xRange=new_range, padding=0.0,
+                                      update=True)
+            else:
+                step.to_view.setRange(yRange=new_range, padding=0.0,
+                                      update=True)
+
+        PlotWrapper._change_lock = False
+
+    def set_scale_steps(self, steps):
+        self._axis_scale_steps = steps
+
+
+class DisplayMode(Enum):
+    identify_anchor = 1
+    estimated_position = 2
+
+
+Range = namedtuple('Range', ['min', 'max'])
+
+
+class AnchorPosWrapper():
+    """Wraps the UI elements of one anchor position"""
+    def __init__(self, x, y, z):
+        self._x = x
+        self._y = y
+        self._z = z
+
+    def get_position(self):
+        """Get the position from the UI elements"""
+        return (self._x.value(), self._y.value(), self._z.value())
+
+    def set_position(self, position):
+        """Set the position in the UI elements"""
+        self._x.setValue(position[0])
+        self._y.setValue(position[1])
+        self._z.setValue(position[2])
+
+    def enable(self, enabled):
+        """Enable/disable all UI elements for the position"""
+        self._x.setEnabled(enabled)
+        self._y.setEnabled(enabled)
+        self._z.setEnabled(enabled)
+
+
+class LocoPositioningTab(Tab, locopositioning_tab_class):
+    """Tab for plotting Loco Positioning data"""
+
+    # Update period of log data in ms
+    UPDATE_PERIOD_LOG = 100
+
+    # Update period of anchor position data
+    UPDATE_PERIOD_ANCHOR_POS = 5000
+
+    # Frame rate (updates per second)
+    FPS = 2
+
+    _connected_signal = pyqtSignal(str)
+    _disconnected_signal = pyqtSignal(str)
+    _log_error_signal = pyqtSignal(object, str)
+    _anchor_range_signal = pyqtSignal(int, object, object)
+    _position_signal = pyqtSignal(int, object, object)
+    _anchor_position_signal = pyqtSignal(object)
+
+    def __init__(self, tabWidget, helper, *args):
+        super(LocoPositioningTab, self).__init__(*args)
+        self.setupUi(self)
+
+        self.tabName = "Loco Positioning"
+        self.menuName = "Loco Positioning Tab"
+        self.tabWidget = tabWidget
+
+        self._helper = helper
+
+        self._anchors = {}
+        self._position = []
+        self._clear_state()
+        self._refs = []
+
+        self._display_mode = DisplayMode.estimated_position
+
+        # Always wrap callbacks from Crazyflie API though QT Signal/Slots
+        # to avoid manipulating the UI when rendering it
+        self._connected_signal.connect(self._connected)
+        self._disconnected_signal.connect(self._disconnected)
+        self._anchor_range_signal.connect(self._anchor_range_received)
+        self._position_signal.connect(self._position_received)
+        self._anchor_position_signal.connect(self._anchor_positions_updated)
+
+        self._id_anchor_button.clicked.connect(
+            lambda enabled:
+            self._set_display_mode(DisplayMode.identify_anchor)
+        )
+
+        self._estimated_postion_button.clicked.connect(
+            lambda enabled:
+            self._set_display_mode(DisplayMode.estimated_position)
+        )
+
+        self._anchor_pos_ui = {}
+        for anchor_nr in range(0, 8):
+            self._register_anchor_pos_ui(anchor_nr)
+
+        self._write_pos_to_anhors_button.clicked.connect(
+            lambda enabled:
+            self._write_positions_to_anchors()
+        )
+
+        self._read_pos_from_anhors_button.clicked.connect(
+            lambda enabled:
+            self._read_positions_from_anchors()
+        )
+
+        self._show_all_button.clicked.connect(self._scale_and_center_graphs)
+
+        # Connect the Crazyflie API callbacks to the signals
+        self._helper.cf.connected.add_callback(
+            self._connected_signal.emit)
+
+        self._helper.cf.disconnected.add_callback(
+            self._disconnected_signal.emit)
+
+        self._set_up_plots()
+
+        self._graph_timer = QTimer()
+        self._graph_timer.setInterval(1000 / self.FPS)
+        self._graph_timer.timeout.connect(self._update_graphics)
+        self._graph_timer.start()
+
+        self._anchor_pos_timer = QTimer()
+        self._anchor_pos_timer.setInterval(self.UPDATE_PERIOD_ANCHOR_POS)
+        self._anchor_pos_timer.timeout.connect(self._poll_anchor_positions)
+
+    def _register_anchor_pos_ui(self, nr):
+        x_spin = getattr(self, 'spin_a{}x'.format(nr))
+        y_spin = getattr(self, 'spin_a{}y'.format(nr))
+        z_spin = getattr(self, 'spin_a{}z'.format(nr))
+        self._anchor_pos_ui[nr] = AnchorPosWrapper(x_spin, y_spin, z_spin)
+
+    def _write_positions_to_anchors(self):
+        lopo = LoPoAnchor(self._helper.cf)
+
+        for id, anchor_pos in self._anchor_pos_ui.items():
+            if id in self._anchors:
+                position = anchor_pos.get_position()
+                lopo.set_position(id, position)
+
+    def _read_positions_from_anchors(self):
+        for id, anchor_pos in self._anchor_pos_ui.items():
+            position = (0.0, 0.0, 0.0)
+            if id in self._anchors:
+                position = self._anchors[id].get_position()
+
+            anchor_pos.set_position(position)
+
+    def _enable_anchor_pos_ui(self):
+        for id, anchor_pos in self._anchor_pos_ui.items():
+            exists = id in self._anchors
+            anchor_pos.enable(exists)
+
+    def _set_up_plots(self):
+        self._plot_xy = PlotWrapper("Top view (X/Y)", "x", "y")
+        self._plot_top_left_layout.addWidget(self._plot_xy.widget)
+        self._plot_xz = PlotWrapper("Front view (X/Z)", "x", "z")
+        self._plot_bottom_left_layout.addWidget(self._plot_xz.widget)
+        self._plot_yz = PlotWrapper("Right view (Y/Z)", "y", "z")
+        self._plot_bottom_right_layout.addWidget(self._plot_yz.widget)
+        self._plot_xy.set_scale_steps([
+            AxisScaleStep(self._plot_xy, PlotWrapper.XAxis,
+                          self._plot_xz, PlotWrapper.XAxis),
+            AxisScaleStep(self._plot_xz, PlotWrapper.YAxis,
+                          self._plot_yz, PlotWrapper.YAxis),
+            AxisScaleStep(self._plot_xy, PlotWrapper.YAxis,
+                          self._plot_yz, PlotWrapper.XAxis, center_only=True)
+        ])
+        self._plot_xz.set_scale_steps([
+            AxisScaleStep(self._plot_xz, PlotWrapper.XAxis,
+                          self._plot_xy, PlotWrapper.XAxis),
+            AxisScaleStep(self._plot_xz, PlotWrapper.YAxis,
+                          self._plot_yz, PlotWrapper.YAxis),
+            AxisScaleStep(self._plot_xy, PlotWrapper.YAxis,
+                          self._plot_yz, PlotWrapper.XAxis, center_only=True)
+        ])
+        self._plot_yz.set_scale_steps([
+            AxisScaleStep(self._plot_yz, PlotWrapper.YAxis,
+                          self._plot_xz, PlotWrapper.YAxis),
+            AxisScaleStep(self._plot_xz, PlotWrapper.XAxis,
+                          self._plot_xy, PlotWrapper.XAxis),
+            AxisScaleStep(self._plot_yz, PlotWrapper.XAxis,
+                          self._plot_xy, PlotWrapper.YAxis, center_only=True)
+        ])
+
+        self._plot_xy.view.setRange(xRange=(0.0, 5.0))
+
+    def _set_display_mode(self, display_mode):
+        self._display_mode = display_mode
+
+    def _clear_state(self):
+        self._anchors = {}
+        self._position = [0.0, 0.0, 0.0]
+
+    def _scale_and_center_graphs(self):
+        start_bounds = Range(sys.float_info.max, -sys.float_info.max)
+        bounds = {"x": start_bounds, "y": start_bounds,
+                  "z": start_bounds}
+        for a in self._anchors.values():
+            bounds = self._find_min_max_data_range(bounds, [a.x, a.y, a.z])
+        bounds = self._find_min_max_data_range(bounds, self._position)
+
+        bounds = self._pad_bounds(bounds)
+        self._center_all_data_in_graphs(bounds)
+        self._rescale_to_fit_data(bounds)
+
+    def _rescale_to_fit_data(self, bounds):
+        [[xy_xmin, xy_xmax],
+            [xy_ymin, xy_ymax]] = self._plot_xy.view.viewRange()
+        [[yz_xmin, yz_xmax],
+            [yz_ymin, yz_ymax]] = self._plot_yz.view.viewRange()
+        if not self._is_data_visibile(bounds, self._position):
+            if self._will_new_range_zoom_in(Range(xy_xmin, xy_xmax),
+                                            bounds["x"]):
+                self._plot_xy.view.setRange(xRange=bounds["x"],
+                                            padding=0.0, update=True)
+
+        if not self._is_data_visibile(bounds, self._position):
+            if self._will_new_range_zoom_in(Range(xy_ymin, xy_ymax),
+                                            bounds["y"]):
+                self._plot_xy.view.setRange(yRange=bounds["y"],
+                                            padding=0.0, update=True)
+
+        if not self._is_data_visibile(bounds, self._position):
+            if self._will_new_range_zoom_in(Range(yz_xmin, yz_xmax),
+                                            bounds["y"]):
+                self._plot_yz.view.setRange(yRange=bounds["y"],
+                                            padding=0.0, update=True)
+
+        if not self._is_data_visibile(bounds, self._position):
+            if self._will_new_range_zoom_in(Range(yz_ymin, yz_ymax),
+                                            bounds["z"]):
+                self._plot_yz.view.setRange(yRange=bounds["z"], padding=0.0,
+                                            update=True)
+
+    def _pad_bounds(self, ranges):
+        new_ranges = ranges
+
+        new_ranges["x"] = Range(new_ranges["x"].min - 1.0,
+                                new_ranges["x"].max + 1.0)
+
+        new_ranges["y"] = Range(new_ranges["y"].min - 1.0,
+                                new_ranges["y"].max + 1.0)
+
+        new_ranges["z"] = Range(new_ranges["z"].min - 1.0,
+                                new_ranges["z"].max + 1.0)
+
+        return new_ranges
+
+    def _center_all_data_in_graphs(self, ranges):
+        # Will center data in graphs without taking care of scaling
+        self._plot_xy.view.setRange(xRange=ranges["x"], yRange=ranges["y"],
+                                    padding=0.0, update=True)
+        self._plot_yz.view.setRange(yRange=ranges["z"], padding=0.0,
+                                    update=True)
+
+    def _will_new_range_zoom_in(self, old_range, new_range):
+        return old_range.min > new_range.min
+
+    def _is_data_visibile(self, ranges, point):
+        [[xy_xmin, xy_xmax],
+            [xy_ymin, xy_ymax]] = self._plot_xy.view.viewRange()
+        [[yz_xmin, yz_xmax],
+            [yz_ymin, yz_ymax]] = self._plot_yz.view.viewRange()
+        [[xz_xmin, xz_xmax],
+            [xz_ymin, xz_ymax]] = self._plot_xz.view.viewRange()
+
+        allVisible = True
+
+        if ranges["x"].min < xy_xmin or ranges["x"].max > xy_xmax:
+            allVisible = False
+
+        if ranges["z"].min < yz_ymin or ranges["z"].max > yz_ymax:
+            allVisible = False
+
+        if ranges["y"].min < yz_xmin or ranges["y"].max > yz_xmax:
+            allVisible = False
+
+        if ranges["y"].min < xy_ymin or ranges["y"].max > xy_ymax:
+            allVisible = False
+
+        return allVisible
+
+    def _find_min_max_data_range(self, ranges, point):
+        result = ranges
+
+        result["x"] = Range(min(ranges["x"].min, point[0]),
+                            max(ranges["x"].max, point[0]))
+
+        result["y"] = Range(min(ranges["y"].min, point[1]),
+                            max(ranges["y"].max, point[1]))
+
+        result["z"] = Range(min(ranges["z"].min, point[2]),
+                            max(ranges["z"].max, point[2]))
+
+        return result
+
+    def _connected(self, link_uri):
+        """Callback when the Crazyflie has been connected"""
+        logger.debug("Crazyflie connected to {}".format(link_uri))
+
+        self._clear_state()
+
+        try:
+            self._register_logblock(
+                "LoPoTab0",
+                [
+                    ("ranging", "distance0", "float"),
+                    ("ranging", "distance1", "float"),
+                    ("ranging", "distance2", "float"),
+                    ("ranging", "distance3", "float"),
+                ],
+                self._anchor_range_signal.emit,
+                self._log_error_signal.emit)
+
+            self._register_logblock(
+                "LoPoTab1",
+                [
+                    ("ranging", "distance4", "float"),
+                    ("ranging", "distance5", "float"),
+                    ("ranging", "distance6", "float"),
+                    ("ranging", "distance7", "float"),
+                ],
+                self._anchor_range_signal.emit,
+                self._log_error_signal.emit),
+
+            self._register_logblock(
+                "LoPoTab2",
+                [
+                    ("kalman", "stateX", "float"),
+                    ("kalman", "stateY", "float"),
+                    ("kalman", "stateZ", "float"),
+                ],
+                self._position_signal.emit,
+                self._log_error_signal.emit),
+        except KeyError as e:
+            logger.warning(str(e))
+        except AttributeError as e:
+            logger.warning(str(e))
+
+        self._start_polling_anchor_pos(self._helper.cf)
+
+    def _disconnected(self, link_uri):
+        """Callback for when the Crazyflie has been disconnected"""
+        logger.debug("Crazyflie disconnected from {}".format(link_uri))
+        self._stop_polling_anchor_pos()
+
+    def _register_logblock(self, logblock_name, variables, data_cb, error_cb):
+        """Register log data to listen for. One logblock can contain a limited
+        number of parameters (6 for floats)."""
+        lg = LogConfig(logblock_name, self.UPDATE_PERIOD_LOG)
+        for variable in variables:
+            if self._is_in_toc(variable):
+                lg.add_variable('{}.{}'.format(variable[0], variable[1]),
+                                variable[2])
+
+        self._helper.cf.log.add_config(lg)
+        lg.data_received_cb.add_callback(data_cb)
+        lg.error_cb.add_callback(error_cb)
+        lg.start()
+        return lg
+
+    def _is_in_toc(self, variable):
+        toc = self._helper.cf.log.toc
+        group = variable[0]
+        param = variable[1]
+        return group in toc.toc and param in toc.toc[group]
+
+    def _anchor_range_received(self, timestamp, data, logconf):
+        """Callback from the logging system when a range is updated."""
+        for name, value in data.items():
+            valid, anchor_number = self._parse_range_param_name(name)
+            if valid:
+                self._get_anchor(anchor_number).distance = float(value)
+
+    def _position_received(self, timestamp, data, logconf):
+        """Callback from the logging system when the position is updated."""
+        for name, value in data.items():
+            valid, axis = self._parse_position_param_name(name)
+            if valid:
+                self._position[axis] = float(value)
+
+    def _logging_error(self, log_conf, msg):
+        """Callback from the log layer when an error occurs"""
+        QMessageBox.about(self, "LocoPositioningTab error",
+                          "Error when using log config",
+                          " [{0}]: {1}".format(log_conf.name, msg))
+
+    def _start_polling_anchor_pos(self, crazyflie):
+        """Set up a timer to poll anchor positions from the memory sub
+        system"""
+        self._anchor_pos_timer.start()
+
+    def _stop_polling_anchor_pos(self):
+        self._anchor_pos_timer.stop()
+
+    def _poll_anchor_positions(self):
+        mems = self._helper.cf.mem.get_mems(MemoryElement.TYPE_LOCO)
+        if len(mems) > 0:
+            mems[0].update(self._anchor_position_signal.emit)
+
+    def _anchor_positions_updated(self, mem):
+        """Callback from the memory sub system when the anchor positions
+         are updated"""
+        for anchor_number, anchor_data in enumerate(mem.anchor_data):
+            if anchor_data.is_valid:
+                anchor = self._get_anchor(anchor_number)
+                anchor.set_position(anchor_data.position)
+
+    def _parse_range_param_name(self, name):
+        """Parse a parameter name for a ranging distance and return the number
+           of the anchor. The name is on the format 'ranging.distance4' """
+        valid = False
+        anchor = 0
+        if name.startswith('ranging.distance'):
+            anchor = int(name[-1])
+            valid = True
+        return (valid, anchor)
+
+    def _parse_position_param_name(self, name):
+        """Parse a parameter name for a position and return the
+           axis (0=x, 1=y, 2=z).
+           The param name is on the format 'kalman.stateY' """
+        valid = False
+        axis = 0
+        if name.startswith('kalman.state'):
+            axis = {'X': 0, 'Y': 1, 'Z': 2}[name[-1]]
+            valid = True
+        return (valid, axis)
+
+    def _get_anchor(self, anchor_number):
+        if anchor_number not in self._anchors:
+            self._anchors[anchor_number] = Anchor()
+        return self._anchors[anchor_number]
+
+    def _update_graphics(self):
+        if self.is_visible():
+            anchors = copy.deepcopy(self._anchors)
+            self._plot_yz.update(anchors, self._position, self._display_mode)
+            self._plot_xy.update(anchors, self._position, self._display_mode)
+            self._plot_xz.update(anchors, self._position, self._display_mode)
+            self._enable_anchor_pos_ui()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.ui
new file mode 100644
index 00000000..9c9fe234
--- /dev/null
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/locopositioning_tab.ui
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>850</width>
+    <height>595</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Plot</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <layout class="QGridLayout" name="gridLayout" rowstretch="0,0" columnstretch="0,0">
+     <property name="leftMargin">
+      <number>0</number>
+     </property>
+     <item row="1" column="0">
+      <layout class="QVBoxLayout" name="_plot_bottom_left_layout"/>
+     </item>
+     <item row="0" column="0">
+      <layout class="QVBoxLayout" name="_plot_top_left_layout"/>
+     </item>
+     <item row="0" column="1">
+      <layout class="QVBoxLayout" name="_inputLayout">
+       <item>
+        <widget class="QGroupBox" name="groupBox_2">
+         <property name="title">
+          <string>Mode</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_2">
+          <item>
+           <widget class="QRadioButton" name="_estimated_postion_button">
+            <property name="text">
+             <string>Position estimate</string>
+            </property>
+            <property name="checked">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QRadioButton" name="_id_anchor_button">
+            <property name="text">
+             <string>Anchor identification</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="enabled">
+          <bool>true</bool>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>13</height>
+          </size>
+         </property>
+         <property name="title">
+          <string>Anchor Positions</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout">
+          <item>
+           <layout class="QHBoxLayout" name="anchor_block_0">
+            <item>
+             <layout class="QHBoxLayout" name="block_a0">
+              <item>
+               <widget class="QLabel" name="labela0">
+                <property name="text">
+                 <string>Anchor 0</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a0x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a0y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a0z"/>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <layout class="QHBoxLayout" name="block_a1">
+              <item>
+               <widget class="QLabel" name="labela1">
+                <property name="text">
+                 <string>Anchor 1</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a1x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a1y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a1z"/>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="anchor_block_1">
+            <item>
+             <layout class="QHBoxLayout" name="block_a2">
+              <item>
+               <widget class="QLabel" name="labela2">
+                <property name="text">
+                 <string>Anchor 2</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a2x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a2y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a2z"/>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <layout class="QHBoxLayout" name="block_a3">
+              <item>
+               <widget class="QLabel" name="labela3">
+                <property name="text">
+                 <string>Anchor 3</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a3x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a3y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a3z"/>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="anchor_block_2">
+            <item>
+             <layout class="QHBoxLayout" name="block_a4">
+              <item>
+               <widget class="QLabel" name="labela4">
+                <property name="text">
+                 <string>Anchor 4</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a4x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a4y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a4z"/>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <layout class="QHBoxLayout" name="block_a5">
+              <item>
+               <widget class="QLabel" name="labela5">
+                <property name="text">
+                 <string>Anchor 5</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a5x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a5y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a5z"/>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="anchor_block_3">
+            <item>
+             <layout class="QHBoxLayout" name="block_a6">
+              <item>
+               <widget class="QLabel" name="labela6">
+                <property name="text">
+                 <string>Anchor 6</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a6x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a6y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a6z"/>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <layout class="QHBoxLayout" name="block_a7">
+              <item>
+               <widget class="QLabel" name="labela7">
+                <property name="text">
+                 <string>Anchor 7</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a7x"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a7y"/>
+              </item>
+              <item>
+               <widget class="QDoubleSpinBox" name="spin_a7z"/>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </item>
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+            <item>
+             <widget class="QPushButton" name="_read_pos_from_anhors_button">
+              <property name="text">
+               <string>Get from anchors</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QPushButton" name="_write_pos_to_anhors_button">
+              <property name="text">
+               <string>Write to anchors</string>
+              </property>
+             </widget>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_3">
+         <property name="title">
+          <string>Graph settings</string>
+         </property>
+         <layout class="QHBoxLayout" name="horizontalLayout_5">
+          <item>
+           <layout class="QHBoxLayout" name="horizontalLayout_4">
+            <item>
+             <widget class="QPushButton" name="_show_all_button">
+              <property name="text">
+               <string>Show all</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </item>
+     <item row="1" column="1">
+      <layout class="QVBoxLayout" name="_plot_bottom_right_layout"/>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockDebugTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockDebugTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logBlockTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/logTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/paramTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/paramTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/plotTab.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/tabs/plotTab.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.py
old mode 100755
new mode 100644
index 79c8f010..7dae68fa
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#     ||          ____  _ __                           
-#  +------+      / __ )(_) /_______________ _____  ___ 
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
@@ -15,51 +15,55 @@
 #  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 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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 A detachable toolbox for showing console printouts from the Crazyflie
 """
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import Qt
+
+import cfclient
 
 __author__ = 'Bitcraze AB'
 __all__ = ['ConsoleToolbox']
 
-import sys, time
+console_class = uic.loadUiType(
+    cfclient.module_path + "/ui/toolboxes/consoleToolbox.ui")[0]
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal
-  
-console_class = uic.loadUiType(sys.path[0] + "/cfclient/ui/toolboxes/consoleToolbox.ui")[0]
 
-class ConsoleToolbox(QtGui.QWidget, console_class):
+class ConsoleToolbox(QtWidgets.QWidget, console_class):
     """Console toolbox for showing printouts from the Crazyflie"""
     update = pyqtSignal(str)
 
     def __init__(self, helper, *args):
         super(ConsoleToolbox, self).__init__(*args)
         self.setupUi(self)
-        
+
         self.update.connect(self.console.insertPlainText)
-        
+
         self.helper = helper
 
     def getName(self):
         return 'Console'
-    
+
+    def _console_updated(self, data):
+        self.update.emit(data)
+
     def enable(self):
-        self.helper.cf.console.receivedChar.add_callback(self.update.emit)
-    
+        self.helper.cf.console.receivedChar.add_callback(self._console_updated)
+
     def disable(self):
-        self.helper.cf.console.receivedChar.remove_callback(self.update.emit)
-    
+        self.helper.cf.console.receivedChar.remove_callback(
+            self._console_updated)
+
     def preferedDockArea(self):
         return Qt.BottomDockWidgetArea
-
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/ConsoleToolbox.pyc
deleted file mode 100755
index 0635198045bcde4805aa3c02761f9db148a5ce56..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2448
zcmc&#+m75s5G{M|v%A@F(T0d98i|)tr0l#P1X2X-4kB->tal@Xg=Bf`o|$%Rw{f>a
z2JKsTLi`1P!|(6`P^at-1OZQk^-PzmFRrdSr@FfL>%p}6<;Tl}x~IqQ&$-#3S)@cE
zOOHa2QlB=g_>}f2?Ni>Pkd;>NQ`i@MK>2`*A%#OKMih>y7*jYV59@}MPpFtuIHh8b
z!aXYXDcmPdjVU`I)uZedr6anVj_J-z-jCJr5ZkH|Ww%Kk(waA)&<{i}iM|fsf*Tj}
zDV%-GVtO)5m5Y;Yyvo(g8I!Nfi`m-LGrKk4>2fnmOlb|zRkbdiX`G#{Yg5eJR?U`m
z{QYj7Yc;idZ0l6Jgh$lu<ka2b{<8h@vNfuI<L7J+sN9gnxm%iAxq+yU8|^UD=%iiY
z%di{stJ;0*E^^}>oR*H>lyR=PM|RF)k*pJTqI8Q!FS-zvU389j+aI%Oe1QkXPq_&K
zis@qDSTblmQhj0^!vP3n(3lej6Uqo&K^X%=C=*HtqD(2cm?I|pF^ewjzXkK(Kuq8k
zKtKaG_DdFy{~ld2eLiJAUHSAAk;nb4C!=25=~Fg9KO0guLImEGd=;^`#Dsfn>TEuN
zK_G6MO4R`?BoIfDF13pyH^Q89P4!d@Nllf;PRTICS*pZc>&OXr$jfzURqdYSu`Vyw
z3n!m#RnGQXCi`MCUk6ADhhAK7gf{|tWWQmt*qTBuR$T%us@i0{7jt->VGmn|?Zay4
zwx(R<di4*qzn*o+)h<919b+db<Q;hj{*j*mk?Xd^EL>yKFXrIkOycZpiJt;tfQZ{J
zD{tO+@nWOgSzM@(upxXS@0IiDit`_^0{Z#yAx}6vvc8NAkP}FVKji^vZux+LWF74D
z%R$sCQTn+`m)p3OfjCX0B+m0yoIDF~0);|VXm>M!;Fzfr)#?-0{%bsfci5<)5xk37
zL3gbR^IW|SLU6<rHv<5;OSJ_8k68UH0!V4e2(07c!Rc^)`oVR8EO&_Qlq;$!zA(wN
zuXM^Oc2cYOW+J-H-c+?(t6HV-2cCS!V_j%-+$~+1D)}66nL-{$QDM?1M;D<+QEHMX
z3XmUil~`9xzRK|r-sa)p4#ZuE_gVaLj759%b%^(*2iz<w;m{j;`~GA+>ESmQ|L*g6
z7hBwLnX6yL#s`q~9zNb#Ie|_W?dADockVt6KzkqrW09O(nK*8*S)n~Z<!=E3fVqj&
zr}}bNDKS{ZZtD(soC`gQdz9p{wSw(=n;~*v{NJbv@sC=nKLtQ7dj8Ox`0x4mynFtA
F|95dnMO**?

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.py
old mode 100755
new mode 100644
index 37476512..718aa7bf
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#     ||          ____  _ __                           
-#  +------+      / __ )(_) /_______________ _____  ___ 
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
@@ -15,49 +15,53 @@
 #  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 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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
-Toolbox for showing packets that is sent via the communication link when debugging.
+Toolbox for showing packets that is sent via the communication link when
+debugging.
 """
+import os
+from time import time
+from binascii import hexlify
 
-__author__ = 'Bitcraze AB'
-__all__ = ['CrtpSharkBoolbox']
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import Qt
 
-import sys, time
-import os
+import cfclient
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
-from time import time
+__author__ = 'Bitcraze AB'
+__all__ = ['CrtpSharkToolbox']
+
+param_tab_class = uic.loadUiType(
+    cfclient.module_path + "/ui/toolboxes/crtpSharkToolbox.ui")[0]
 
-param_tab_class = uic.loadUiType(sys.path[0] +
-                                "/cfclient/ui/toolboxes/crtpSharkToolbox.ui")[0]
 
-class CrtpSharkToolbox(QtGui.QWidget, param_tab_class):
+class CrtpSharkToolbox(QtWidgets.QWidget, param_tab_class):
     """Show packets that is sent vie the communication link"""
     nameModified = pyqtSignal()
     _incoming_packet_signal = pyqtSignal(object)
     _outgoing_packet_signal = pyqtSignal(object)
-    
+
     def __init__(self, helper, *args):
         super(CrtpSharkToolbox, self).__init__(*args)
         self.setupUi(self)
 
         self.helper = helper
-        
-        #Init the tree widget
+
+        # Init the tree widget
         self.logTree.setHeaderLabels(['ms', 'Direction', 'Port/Chan', 'Data'])
-        
-        #Connect GUI signals
+
+        # Connect GUI signals
         self.clearButton.clicked.connect(self.clearLog)
         self.saveButton.clicked.connect(self._save_data)
 
@@ -68,50 +72,58 @@ class CrtpSharkToolbox(QtGui.QWidget, param_tab_class):
         self._data = []
 
     def _packet(self, dir, pk):
-        if self.masterCheck.isChecked():
-            line = QtGui.QTreeWidgetItem()
+        if self.masterCheck.isChecked() and \
+           not (pk.port == 15 and pk.channel == 3):
+            line = QtWidgets.QTreeWidgetItem()
 
-            ms_diff = int(round(time()*1000))-self._ms_offset
+            ms_diff = int(round(time() * 1000)) - self._ms_offset
             line.setData(0, Qt.DisplayRole, "%d" % ms_diff)
             line.setData(1, Qt.DisplayRole, "%s" % dir)
             line.setData(2, Qt.DisplayRole, "%d/%d" % (pk.port, pk.channel))
-            line.setData(3, Qt.DisplayRole, pk.datal.__str__())
+
+            line.setData(3, Qt.DisplayRole, hexlify(pk.data).decode('utf8'))
 
             s = "%d, %s, %d/%d, %s" % (ms_diff, dir, pk.port, pk.channel,
-                                      pk.datal.__str__())
+                                       hexlify(pk.data).decode('utf8'))
             self._data.append(s)
 
             self.logTree.addTopLevelItem(line)
             self.logTree.scrollToItem(line)
-    
+
     @pyqtSlot()
     def clearLog(self):
         self.logTree.clear()
         self._data = []
-    
+
     def getName(self):
         return 'Crtp sniffer'
-    
+
     def getTabName(self):
         return 'Crtp sniffer'
-    
+
+    def _incoming_packet(self, pk):
+        self._incoming_packet_signal.emit(pk)
+
+    def _outgoing_packet(self, pk):
+        self._outgoing_packet_signal.emit(pk)
+
     def enable(self):
         self.helper.cf.packet_received.add_callback(
-            self._incoming_packet_signal.emit)
+            self._incoming_packet)
         self.helper.cf.packet_sent.add_callback(
-            self._outgoing_packet_signal.emit)
+            self._outgoing_packet)
 
     def disable(self):
         self.helper.cf.packet_received.remove_callback(
-            self._incoming_packet_signal.emit)
+            self._incoming_packet)
         self.helper.cf.packet_sent.remove_callback(
-            self._outgoing_packet_signal.emit)
+            self._outgoing_packet)
 
     def preferedDockArea(self):
         return Qt.RightDockWidgetArea
 
     def _save_data(self):
-        dir = os.path.join(sys.path[1], "logdata")
+        dir = os.path.join(cfclient.config_path, "logdata")
         fname = os.path.join(dir, "shark_data.csv")
         if not os.path.exists(dir):
             os.makedirs(dir)
@@ -119,8 +131,3 @@ class CrtpSharkToolbox(QtGui.QWidget, param_tab_class):
         for s in self._data:
             f.write("%s\n" % s)
         f.close()
-
-
-
-
-
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/CrtpSharkToolbox.pyc
deleted file mode 100755
index 15e2f34b5bcbf4cd9cc2eb10b5e248280ac71b27..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 5286
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
W>ieisfkrDgq0!r3M^nMo%D({$oTxVd

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.py
old mode 100755
new mode 100644
index 402b9cbb..d69ddabf
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.py
@@ -20,34 +20,33 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 """
 Toolbox used to interact with the DebugDriver using a designated port. It's
 intended to be used for debugging.
 """
+import struct
 
-__author__ = 'Bitcraze AB'
-__all__ = ['DebugDriverToolbox']
-
-import time
-import sys
+from cflib.crtp.crtpstack import CRTPPacket
+from cflib.crtp.crtpstack import CRTPPort
+from PyQt5 import QtWidgets
+from PyQt5 import uic
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import Qt
 
-import struct
-from cflib.crtp.crtpstack import CRTPPacket, CRTPPort
+import cfclient
 
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, SIGNAL
+__author__ = 'Bitcraze AB'
+__all__ = ['DebugDriverToolbox']
 
 debugdriver_tab_class = uic.loadUiType(
-                           sys.path[0] +
-                           "/cfclient/ui/toolboxes/debugDriverToolbox.ui")[0]
+    cfclient.module_path +
+    "/ui/toolboxes/debugDriverToolbox.ui")[0]
 
 
-class DebugDriverToolbox(QtGui.QWidget, debugdriver_tab_class):
+class DebugDriverToolbox(QtWidgets.QWidget, debugdriver_tab_class):
     """Used to interact with the DebugDriver toolbox"""
     connectionDoneSignal = pyqtSignal(str)
     disconnectedSignal = pyqtSignal(str)
@@ -60,7 +59,7 @@ class DebugDriverToolbox(QtGui.QWidget, debugdriver_tab_class):
 
         # Connected / disconnected signals
         self.helper.cf.connected.add_callback(
-                                             self.connectionDoneSignal.emit)
+            self.connectionDoneSignal.emit)
         self.connectionDoneSignal.connect(self.connectionDone)
         self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit)
         self.disconnectedSignal.connect(self.disconnected)
@@ -69,14 +68,14 @@ class DebugDriverToolbox(QtGui.QWidget, debugdriver_tab_class):
         self.forceDisconnect.pressed.connect(self.forceDisconnecPressed)
 
     def forceDisconnecPressed(self):
-        if (self.helper.cf.link != None):
+        if (self.helper.cf.link is not None):
             p = CRTPPacket()
             p.set_header(CRTPPort.DEBUGDRIVER, 0)
             p.data = struct.pack('<B', 1)  # Force disconnect
             self.helper.cf.send_packet(p)
 
     def linkQualityChanged(self, value):
-        if (self.helper.cf.link != None):
+        if (self.helper.cf.link is not None):
             p = CRTPPacket()
             p.set_header(CRTPPort.DEBUGDRIVER, 0)
             p.data = struct.pack('<BB', 0, value)  # Set link quality
@@ -106,4 +105,3 @@ class DebugDriverToolbox(QtGui.QWidget, debugdriver_tab_class):
 
     def preferedDockArea(self):
         return Qt.RightDockWidgetArea
-
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/DebugDriverToolbox.pyc
deleted file mode 100755
index 8973d533d1112b1d954e0e5d7bcc9435755a2b54..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4458
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
GrTQCVMgn30

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.py
old mode 100755
new mode 100644
index 0ab24d41..5919562a
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 List all the available toolboxes so they can be used by the UI.
@@ -31,29 +31,15 @@ List all the available toolboxes so they can be used by the UI.
 Dropping a new .py file into this directory will automatically list and load
 it into the UI when it is started.
 """
+from .ConsoleToolbox import ConsoleToolbox
+from .CrtpSharkToolbox import CrtpSharkToolbox
+from .DebugDriverToolbox import DebugDriverToolbox
 
 __author__ = 'Bitcraze AB'
 __all__ = []
 
-import os
-import glob
-import logging
-
-logger = logging.getLogger(__name__)
-
-foundToolboxes = [os.path.splitext(os.path.basename(f))[0] for f in
-                  glob.glob(os.path.dirname(__file__) +
-                            "/[A-Za-z]*Toolbox.py")]
-if len(foundToolboxes) == 0:
-    foundToolboxes = [os.path.splitext(os.path.basename(f))[0] for f in
-                      glob.glob(os.path.dirname(__file__) +
-                                "/[A-Za-z]*Toolbox.pyc")]
-
-
-logger.debug("Found toolboxes: %s", foundToolboxes)
-
-toolboxes = []
-
-for tb in foundToolboxes:
-    tbModule = __import__(tb, globals(), locals(), [tb], -1)
-    toolboxes.append(getattr(tbModule, tb))
+toolboxes = [
+    ConsoleToolbox,
+    CrtpSharkToolbox,
+    DebugDriverToolbox
+]
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/__init__.pyc
deleted file mode 100755
index a2c0023e92b9b4013d7f43721d6c8aa271234f13..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1136
zcmb7D&2G~`5FXn}+Pc3qEv1~c5=aqJ>KhUW5UmPQrNV_4kWsPL_9WS`@w(m(ZF<d(
z$Kf5g@H$9bVRqw`Qx7=F?94ZR-^@C}uhnq$^V?|#^|L_dOZw@L9zYHdlk_0=pijCF
zIei0=0mQ*vZ$R9b>rIH8fK3>-02g3NiHkN78!&7D1~6QLVF<WvU3mj`=r}s>K)f<{
zuFjP;z!e*11Dmk>*@p{+cpY#9aJ@#q_)z`6y?*OI>;JIz3u3zn!#j{KxJEvBcJfWQ
zdS&gS^XCw^0k;52Zo`zq?>gCrK2h~yN;}vA+=Sshz+FJn+b|{E1Mi~keW3Nd>nz$0
ze<u;12yGabl9>TA{*?>KQ;EzdB~x{UnrUTS6PEFUrO3t_bCynA_}TG(7#>xsEJe|0
zoE3P<_R9(D3929pV>5+jxu`HRs+zD%L5=v>s1Y|JqplMsUH>9yQt><#W}b)a?3i5+
zuwWJ=8irQ}^ZigS6YWD`vWj0LJ2(`7=y|KR2#r1+bYtGVK7VvNqfcZ6;h?u~@n*VB
zp4Vzj1a3xt${y;@eZq}>8IvSeS(2F0=|p~@Dl%s-8i915TuPe;9et@%=aZ`6r>&SJ
z3!*t86Dwo)o+JeyA*Hp*uwjJT)RLQlOQn6;h&tFVlY;5r06hokQVN4t#u+Ks=z`a*
z-_B8wj@ksaJ{G1)XO8K3M&@QrN86<JU}99N%G86|DY(=%L%JyKnwj*C%EuBN&dU;u
z+!3bvxG`0S`oKS--;)^))Ci-rzOJaO)R5i<9ogHP^rXOUMxrpfTTW=RMI=QUWxW{~
zjYV`rH%byw2x3T=>exIRIWjNysEvL=qUE=|mcQcB$6xmYZ`*t9ZF=^65^VS_f7RRb
F{sJa%6}A8X

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/consoleToolbox.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/consoleToolbox.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/crtpSharkToolbox.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/crtpSharkToolbox.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/debugDriverToolbox.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/toolboxes/debugDriverToolbox.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.py
old mode 100755
new mode 100644
index 8de7dc26..97dc2b09
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.py
@@ -21,10 +21,13 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Custom widgets used by the user interface.
 """
+
+# This is required to show an hidden import to py2exe
+from .hexspinbox import HexSpinBox as _HexSpinBox  # noqa
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/__init__.pyc
deleted file mode 100755
index 8563898fea878cd9191ad2659176eee65bf93907..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 238
zcmYL@K?=e^3`M89Pzqi_X4!>pE+8VfcVky>hIS^kBb`p^q)0u2NAo&fz!VDx^78*D
zge*Us*u7u57IQ^BkK7?<7$L6ANL-S|l<gStX$a(<d{}cs3UUZ&WI0NzanilCEn#03
z8ngJEOy_9DP|A3%RKimH5puRrdxub3(tYtn=z4!gO#vo5R*l6}Gg=C1H&X3eXlx0(
f`h_r9m|p><Y->rWjQ7@jc<;O!8a!-S2X65Nq#{3r

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.py
old mode 100755
new mode 100644
index 39a975fe..926dd826
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.py
@@ -21,23 +21,26 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Attitude indicator widget.
 """
 
+import sys
+
+from PyQt5 import QtGui
+from PyQt5 import QtWidgets, QtCore
+
 __author__ = 'Bitcraze AB'
 __all__ = ['AttitudeIndicator']
 
-import sys
-from PyQt4 import QtGui, QtCore
-
 
-class AttitudeIndicator(QtGui.QWidget):
+class AttitudeIndicator(QtWidgets.QWidget):
     """Widget for showing attitude"""
+
     def __init__(self):
         super(AttitudeIndicator, self).__init__()
 
@@ -50,27 +53,32 @@ class AttitudeIndicator(QtGui.QWidget):
         self.setMinimumSize(30, 30)
         # self.setMaximumSize(240,240)
 
-    def setRoll(self, roll):
+    def setRoll(self, roll, repaint=True):
         self.roll = roll
-        self.repaint()
+        if repaint:
+            self.repaint()
 
-    def setPitch(self, pitch):
+    def setPitch(self, pitch, repaint=True):
         self.pitch = pitch
-        self.repaint()
-        
-    def setHover(self, target):        
+        if repaint:
+            self.repaint()
+
+    def setHover(self, target, repaint=True):
         self.hoverTargetASL = target
-        self.hover = target>0
-        self.repaint()
-        
-    def setBaro(self, asl):
-        self.hoverASL = asl;
-        self.repaint()
-
-    def setRollPitch(self, roll, pitch):
+        self.hover = target > 0
+        if repaint:
+            self.repaint()
+
+    def setBaro(self, asl, repaint=True):
+        self.hoverASL = asl
+        if repaint:
+            self.repaint()
+
+    def setRollPitch(self, roll, pitch, repaint=True):
         self.roll = roll
         self.pitch = pitch
-        self.repaint()
+        if repaint:
+            self.repaint()
 
     def paintEvent(self, e):
         qp = QtGui.QPainter()
@@ -103,7 +111,7 @@ class AttitudeIndicator(QtGui.QWidget):
         qp.drawRect(-w, h / 2, 3 * w, 3 * h)
 
         pen = QtGui.QPen(QtGui.QColor(255, 255, 255), 1.5,
-            QtCore.Qt.SolidLine)
+                         QtCore.Qt.SolidLine)
         qp.setPen(pen)
         qp.drawLine(-w, h / 2, 3 * w, h / 2)
 
@@ -135,57 +143,56 @@ class AttitudeIndicator(QtGui.QWidget):
         qp.setWorldMatrixEnabled(False)
 
         pen = QtGui.QPen(QtGui.QColor(0, 0, 0), 2,
-            QtCore.Qt.SolidLine)
+                         QtCore.Qt.SolidLine)
         qp.setBrush(QtGui.QColor(0, 0, 0))
         qp.setPen(pen)
         qp.drawLine(0, h / 2, w, h / 2)
-        
-        
-        
+
         # Draw Hover vs Target
-        
+
         qp.setWorldMatrixEnabled(False)
-        
+
         pen = QtGui.QPen(QtGui.QColor(255, 255, 255), 2,
                          QtCore.Qt.SolidLine)
         qp.setBrush(QtGui.QColor(255, 255, 255))
         qp.setPen(pen)
-        fh = max(7,h/50)
+        fh = max(7, h / 50)
         font = QtGui.QFont('Sans', fh, QtGui.QFont.Light)
         qp.setFont(font)
         qp.resetTransform()
-      
-        
-
-        
-        qp.translate(0,h/2)      
-        if not self.hover:  
-            qp.drawText(w-fh*10, fh/2, str(round(self.hoverASL,2)))  # asl
-               
-        
+
+        qp.translate(0, h / 2)
+        if not self.hover:
+            # asl
+            qp.drawText(w - fh * 10, fh / 2, str(round(self.hoverASL, 2)))
+
         if self.hover:
-            qp.drawText(w-fh*10, fh/2, str(round(self.hoverTargetASL,2)))  # target asl (center)    
-            diff = round(self.hoverASL-self.hoverTargetASL,2)
-            pos_y = -h/6*diff
-            
+            # target asl (center)
+            qp.drawText(
+                w - fh * 10, fh / 2, str(round(self.hoverTargetASL, 2)))
+            diff = round(self.hoverASL - self.hoverTargetASL, 2)
+            pos_y = -h / 6 * diff
+
             # cap to +- 2.8m
-            if diff<-2.8:
-                pos_y = -h/6*-2.8
-            elif diff>2.8:
-                pos_y= -h/6*2.8
+            if diff < -2.8:
+                pos_y = -h / 6 * -2.8
+            elif diff > 2.8:
+                pos_y = -h / 6 * 2.8
             else:
-                pos_y = -h/6*diff
-            qp.drawText(w-fh*3.8, pos_y+fh/2, str(diff)) # difference from target (moves up and down +- 2.8m)        
-            qp.drawLine(w-fh*4.5,0,w-fh*4.5,pos_y) # vertical line     
-            qp.drawLine(w-fh*4.7,0,w-fh*4.5,0) # left horizontal line
-            qp.drawLine(w-fh*4.2,pos_y,w-fh*4.5,pos_y) #right horizontal line
-        
-        
-        
+                pos_y = -h / 6 * diff
+
+            # difference from target (moves up and down +- 2.8m)
+            qp.drawText(w - fh * 3.8, pos_y + fh / 2, str(diff))
+            # vertical line
+            qp.drawLine(w - fh * 4.5, 0, w - fh * 4.5, pos_y)
+            # left horizontal line
+            qp.drawLine(w - fh * 4.7, 0, w - fh * 4.5, 0)
+            # right horizontal line
+            qp.drawLine(w - fh * 4.2, pos_y, w - fh * 4.5, pos_y)
 
 
 if __name__ == "__main__":
-    class Example(QtGui.QWidget):
+    class Example(QtWidgets.QWidget):
 
         def __init__(self):
             super(Example, self).__init__()
@@ -197,54 +204,51 @@ if __name__ == "__main__":
 
         def updateRoll(self, roll):
             self.wid.setRoll((roll / 10.0) - 180.0)
-        
+
         def updateTarget(self, target):
-            self.wid.setHover(500+target/10.)
+            self.wid.setHover(500 + target / 10.)
+
         def updateBaro(self, asl):
-            self.wid.setBaro(500+asl/10.)           
-        
-        
-        def initUI(self):
+            self.wid.setBaro(500 + asl / 10.)
 
-            vbox = QtGui.QVBoxLayout()
+        def initUI(self):
+            vbox = QtWidgets.QVBoxLayout()
 
-            sld = QtGui.QSlider(QtCore.Qt.Horizontal, self)
+            sld = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
             sld.setFocusPolicy(QtCore.Qt.NoFocus)
             sld.setRange(0, 3600)
             sld.setValue(1800)
             vbox.addWidget(sld)
-            
-            
+
             self.wid = AttitudeIndicator()
 
             sld.valueChanged[int].connect(self.updateRoll)
             vbox.addWidget(self.wid)
 
-            hbox = QtGui.QHBoxLayout()
+            hbox = QtWidgets.QHBoxLayout()
             hbox.addLayout(vbox)
 
-            sldPitch = QtGui.QSlider(QtCore.Qt.Vertical, self)
+            sldPitch = QtWidgets.QSlider(QtCore.Qt.Vertical, self)
             sldPitch.setFocusPolicy(QtCore.Qt.NoFocus)
             sldPitch.setRange(0, 180)
             sldPitch.setValue(90)
             sldPitch.valueChanged[int].connect(self.updatePitch)
             hbox.addWidget(sldPitch)
-            
-            sldASL = QtGui.QSlider(QtCore.Qt.Vertical, self)
+
+            sldASL = QtWidgets.QSlider(QtCore.Qt.Vertical, self)
             sldASL.setFocusPolicy(QtCore.Qt.NoFocus)
             sldASL.setRange(-200, 200)
             sldASL.setValue(0)
             sldASL.valueChanged[int].connect(self.updateBaro)
-            
-            sldT = QtGui.QSlider(QtCore.Qt.Vertical, self)
+
+            sldT = QtWidgets.QSlider(QtCore.Qt.Vertical, self)
             sldT.setFocusPolicy(QtCore.Qt.NoFocus)
             sldT.setRange(-200, 200)
             sldT.setValue(0)
             sldT.valueChanged[int].connect(self.updateTarget)
-            
-            hbox.addWidget(sldT)  
+
+            hbox.addWidget(sldT)
             hbox.addWidget(sldASL)
-                      
 
             self.setLayout(hbox)
 
@@ -253,16 +257,13 @@ if __name__ == "__main__":
             self.show()
 
         def changeValue(self, value):
-
             self.c.updateBW.emit(value)
             self.wid.repaint()
 
     def main():
-
-        app = QtGui.QApplication(sys.argv)
-        ex = Example()
+        app = QtWidgets.QApplication(sys.argv)
+        Example()
         sys.exit(app.exec_())
 
-
     if __name__ == '__main__':
         main()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/ai.pyc
deleted file mode 100755
index 7214cb8692aab93825ea2ad0850495e247bce2a7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8343
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
XqGTf{!fu`^%zt;pn!hpFKVtnCB?^+^

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.py
old mode 100755
new mode 100644
index 82eab2e9..446fa913
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.py
@@ -21,21 +21,24 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
-This class provides a spin box with hexadecimal numbers and arbitrarily length (i.e. not limited by 32 bit).
+This class provides a spin box with hexadecimal numbers and arbitrarily length
+(i.e. not limited by 32 bit).
 """
 
+from PyQt5 import QtGui, QtCore
+from PyQt5.QtWidgets import QAbstractSpinBox
+
 __author__ = 'Bitcraze AB'
 __all__ = ['HexSpinBox']
 
-from PyQt4 import QtGui, QtCore
-from PyQt4.QtGui import QAbstractSpinBox
 
 class HexSpinBox(QAbstractSpinBox):
+
     def __init__(self, *args):
         QAbstractSpinBox.__init__(self, *args)
         regexp = QtCore.QRegExp('^0x[0-9A-Fa-f]{1,10}$')
@@ -63,4 +66,5 @@ class HexSpinBox(QAbstractSpinBox):
         self.setValue(self._value + steps)
 
     def stepEnabled(self):
-        return QAbstractSpinBox.StepUpEnabled | QAbstractSpinBox.StepDownEnabled
+        return (QAbstractSpinBox.StepUpEnabled |
+                QAbstractSpinBox.StepDownEnabled)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/hexspinbox.pyc
deleted file mode 100755
index fe4095fa3bfd81eede39080a259b2554c64d7b83..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2777
zcmcguU2hvj6urCtNF6AR_y|Zy)jm*gB^;*|A%RduT+&uTikeLuff20MyAx-k^{%x$
zZfr=O$|L`l9{}gvb(~VfW9($E?|gXgoOAA-*~VWtH=iUw94E5;H1Pc$TJ;<z6&b>M
zGV~<%Wemrcv>|CzvW85WGHlAECBv3@9BoO~mdS<;H_-RRY{&_I*Oos-UWxoPydmj^
z9CdH-@j1-qvr}6INfuXCFfEH0HZ@fc2i4T(!Kj!A=hmGDr)D0fCb5$^3-Z}yWJ;{b
z(;zNK)|GK-vqg}Ze2k@CyJL2Oyl_EgC)SxX7%hVPUj$fqcW1MD3n2&AC1w1Z3HAnV
z6a6P<euQv?Vs8J&r|V<PwO|h2<C%4B^&S?b>3W>mVt;Q`A#mcBKU`7A6$7;DDU1Pi
z051ej(mZuQlCMsaG;*p%GU>F*ADxXQWi?$K=}1_!mM{brVtb5MJ%Di{XP#V$TzK-Q
zC!X`=41qj(<;hE5TvN_ka^bU!MG*q|>L8Fn4nFIk`T+LV-TBYEy|4FrkK*3RFTdaW
z{NC=%Pb?-xH4C}YQN1X#xph$#DqR~GISkEse?ASbSgHq(<IJY9D@xbFsu!ysiH*>m
z8I6xU0*uK{)QQV+rPP;ZZ06H0=0r_(46lD$OiUk|s*rso&Y4ME)n|8cl3CMBU~*UW
zrVDpk<o(Q!`pHQ>*q_<{xlP9gKR{+N)sSgB(?!S~e1=vLpm<x}E$>|~xg?w44>|iD
z3|Ks?IR~TQ)d!0NexT_Sk`JY63ActAk^qJ0%-lIXa9ULB!S*(S_0THnC0@d>%ciJ^
z83}^~+CEYc2Nn6)o!|Mf-XT}l2v{7oaB!|&7IzatNZ6yYm>e@-b}{fKj(@3xa&QU-
z`OYGsI^6z2oyl~SeVf-RpqOjjC{W0FYY|0}DUpQs3=r=l^#3Bei%H1C0<IGf$dH3t
z$*6Wr0WSVMt?4=&DPc%yH5)UVoBh-}$Na2}W5|#P+H2@<v5R*7x^i3Cgi87qeQs8~
zj+b!nY!ph9^A4Q4<Y+H(13lo951_|*V^xF-n{^t#PeVnO1+7s{;<Z2wN#-|bOK7*R
z>TZ><A7T1+Xpr&4H$>FR+g@SNt{x>U#LAiJdd?6%j~Q;T;GJ`sr~eV_9Zc3260I+T
z%cGH)>l=iE9N|gNr~7$4%1r9W6i2=<&hzEin#FQ_IUu}c_&s*XwRl~=CoHeMJf4^+
z(l>`FniT0QLszekkY}uxQ>dw@iV;^xjl+*&uCh+O>%7bmO+H1dSl?~0)9y6%ui0sK
z8V6m?A07iylorVfP&~tZS)yA{#aRZQY4&t+=)Tmuy}t2DmX7V{Ym&+uVr-2NRgiCM
T2_D===!!D6eSr11y)FMA2OEBA

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotter.ui b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotter.ui
old mode 100755
new mode 100644
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.py
old mode 100755
new mode 100644
index 459be6f6..19a5f46b
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Container for the simple plot with functionality for data legend, saving data
@@ -32,43 +32,38 @@ and manipulating the plot.
 For more advanced plotting save the data and use an external application.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['PlotWidget']
-
-from PyQt4 import QtCore, QtGui, uic
-from PyQt4.QtCore import Qt, pyqtSlot, pyqtSignal, QThread, QLine, QPoint, QPointF, QSize, QRectF
+from PyQt5 import QtWidgets, uic
 
 from time import time
-import math
 
 import logging
 
-logger = logging.getLogger(__name__)
+from PyQt5.QtWidgets import QButtonGroup
+from PyQt5.QtCore import *  # noqa
+from PyQt5.QtWidgets import *  # noqa
+from PyQt5.Qt import *  # noqa
 
-import sys
+import cfclient
 
-from PyQt4 import Qt, QtCore, QtGui, uic
-from PyQt4.QtGui import QButtonGroup
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4.Qt import *
-from time import time
+__author__ = 'Bitcraze AB'
+__all__ = ['PlotWidget']
+
+logger = logging.getLogger(__name__)
 
-(plot_widget_class,
-connect_widget_base_class) = (uic.loadUiType(
-                             sys.path[0] + '/cfclient/ui/widgets/plotter.ui'))
+(plot_widget_class, connect_widget_base_class) = (
+    uic.loadUiType(cfclient.module_path + '/ui/widgets/plotter.ui'))
 
 # Try the imports for PyQtGraph to see if it is installed
 try:
     import pyqtgraph as pg
     from pyqtgraph import ViewBox
-    from pyqtgraph.Qt import QtCore, QtGui
-    import pyqtgraph.console
-    import numpy as np
-    
+    import pyqtgraph.console  # noqa
+    import numpy as np  # noqa
+
     _pyqtgraph_found = True
 except Exception:
     import traceback
+
     logger.warning("PyQtGraph (or dependency) failed to import:\n%s",
                    traceback.format_exc())
     _pyqtgraph_found = False
@@ -77,14 +72,16 @@ except Exception:
 # Windows. But for Linux this is not required and might not be installed with
 # the PyQtGraph package.
 try:
-    from scipy.stats import futil
-    from scipy.sparse.csgraph import _validation
-    from scipy.special import _ufuncs_cxx
+    from scipy.stats import futil  # noqa
+    from scipy.sparse.csgraph import _validation  # noqa
+    from scipy.special import _ufuncs_cxx  # noqa
 except Exception:
     pass
 
+
 class PlotItemWrapper:
     """Wrapper for PlotDataItem to handle what data is shown"""
+
     def __init__(self, curve):
         """Initialize"""
         self.data = []
@@ -102,13 +99,16 @@ class PlotItemWrapper:
         self.ts.append(ts)
 
     def show_data(self, start, stop):
-        """Set what data should be shown from the curve. This is done to keep performance when many
-        points have been added."""
+        """
+        Set what data should be shown from the curve. This is done to keep
+        performance when many points have been added.
+        """
         limit = min(stop, len(self.data))
         self.curve.setData(y=self.data[start:limit], x=self.ts[start:limit])
-        return [self.ts[start], self.ts[limit-1]]
+        return [self.ts[start], self.ts[limit - 1]]
+
 
-class PlotWidget(QtGui.QWidget, plot_widget_class):
+class PlotWidget(QtWidgets.QWidget, plot_widget_class):
     """Wrapper widget for PyQtGraph adding some extra buttons"""
 
     def __init__(self, parent=None, fps=100, title="", *args):
@@ -129,9 +129,9 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         self._items = {}
         self._last_item = 0
 
-        self.setSizePolicy(QtGui.QSizePolicy(
-                                         QtGui.QSizePolicy.MinimumExpanding,
-                                         QtGui.QSizePolicy.MinimumExpanding))
+        self.setSizePolicy(QtWidgets.QSizePolicy(
+            QtWidgets.QSizePolicy.MinimumExpanding,
+            QtWidgets.QSizePolicy.MinimumExpanding))
 
         self.setMinimumSize(self.minimumSizeHint())
         self.parent = parent
@@ -143,13 +143,14 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         self._plot_widget.setLabel('bottom', "Time", "ms")
         self._plot_widget.addLegend()
         self._plot_widget.getViewBox().disableAutoRange(ViewBox.XAxis)
-        self._plot_widget.getViewBox().sigRangeChangedManually.connect(self._manual_range_change)
+        self._plot_widget.getViewBox().sigRangeChangedManually.connect(
+            self._manual_range_change)
         self._plot_widget.getViewBox().setMouseEnabled(x=False, y=True)
         self._plot_widget.getViewBox().setMouseMode(ViewBox.PanMode)
 
         self.plotLayout.addWidget(self._plot_widget)
 
-        #self.saveToFile.clicked.connect(self.saveToFileSignal)
+        # self.saveToFile.clicked.connect(self.saveToFileSignal)
         self._x_min = 0
         self._x_max = 500
         self._enable_auto_y.setChecked(True)
@@ -157,7 +158,8 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         self._last_ts = None
         self._dtime = None
 
-        self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text()))
+        self._x_range = (
+            float(self._range_x_min.text()), float(self._range_x_max.text()))
         self._nbr_samples = int(self._nbr_of_samples_x.text())
 
         self._nbr_of_samples_x.valueChanged.connect(self._nbr_samples_changed)
@@ -192,7 +194,9 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         """Callback when user changes the X-axis mode"""
         if box == self._enable_range_x:
             logger.info("Enable range x")
-            self._x_range = (float(self._range_x_min.text()), float(self._range_x_max.text()))
+            self._x_range = (
+                float(self._range_x_min.text()),
+                float(self._range_x_max.text()))
         else:
             self._range_x_min.setEnabled(False)
             self._range_x_max.setEnabled(False)
@@ -202,7 +206,9 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         if box == self._enable_range_y:
             self._range_y_min.setEnabled(True)
             self._range_y_max.setEnabled(True)
-            y_range = (float(self._range_y_min.value()), float(self._range_y_max.value()))
+            y_range = (
+                float(self._range_y_min.value()),
+                float(self._range_y_max.value()))
             self._plot_widget.getViewBox().setRange(yRange=y_range)
         else:
             self._range_y_min.setEnabled(False)
@@ -212,8 +218,12 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
             self._plot_widget.getViewBox().enableAutoRange(ViewBox.YAxis)
 
     def _manual_range_change(self, obj):
-        """Callback from pyqtplot when users changes the range of the plot using the mouse"""
-        [[x_min,x_max],[y_min,y_max]] = self._plot_widget.getViewBox().viewRange()
+        """
+        Callback from pyqtplot when users changes the range of the plot using
+        the mouse
+        """
+        [[x_min, x_max],
+         [y_min, y_max]] = self._plot_widget.getViewBox().viewRange()
         self._range_y_min.setValue(y_min)
         self._range_y_max.setValue(y_max)
         self._range_y_min.setEnabled(True)
@@ -222,7 +232,9 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
 
     def _y_range_changed(self, val):
         """Callback when user changes Y range manually"""
-        _y_range = (float(self._range_y_min.value()), float(self._range_y_max.value()))
+        _y_range = (
+            float(self._range_y_min.value()),
+            float(self._range_y_max.value()))
         self._plot_widget.getViewBox().setRange(yRange=_y_range, padding=0)
 
     def _nbr_samples_changed(self, val):
@@ -244,13 +256,15 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         title - the name of the data
         pen - color of curve (using r for red and so on..)
         """
-        self._items[title] = PlotItemWrapper(self._plot_widget.plot(name=title, pen=pen))
+        self._items[title] = PlotItemWrapper(
+            self._plot_widget.plot(name=title, pen=pen))
 
     def add_data(self, data, ts):
         """
         Add new data to the plot.
 
-        data - dictionary sent from logging layer containing variable/value pairs
+        data - dictionary sent from logging layer containing variable/value
+               pairs
         ts - timestamp of the data in ms
         """
         if not self._last_ts:
@@ -263,29 +277,41 @@ class PlotWidget(QtGui.QWidget, plot_widget_class):
         x_max_limit = 0
         # We are adding new datasets, calculate what we should show.
         if self._enable_samples_x.isChecked():
-            x_min_limit = max(0, self._last_item-self._nbr_samples)
+            x_min_limit = max(0, self._last_item - self._nbr_samples)
             x_max_limit = max(self._last_item, self._nbr_samples)
 
         for name in self._items:
             self._items[name].add_point(data[name], ts)
             if self._draw_graph and time() > self._ts + self._delay:
-                [self._x_min, self._x_max] = self._items[name].show_data(x_min_limit, x_max_limit)
+                [self._x_min, self._x_max] = self._items[name].show_data(
+                    x_min_limit, x_max_limit)
         if time() > self._ts + self._delay:
             self._ts = time()
-        if self._enable_samples_x.isChecked() and self._dtime and self._last_item < self._nbr_samples:
+        if (self._enable_samples_x.isChecked() and self._dtime and
+                self._last_item < self._nbr_samples):
             self._x_max = self._x_min + self._nbr_samples * self._dtime
 
         self._last_item = self._last_item + 1
-        self._plot_widget.getViewBox().setRange(xRange=(self._x_min, self._x_max))
+        self._plot_widget.getViewBox().setRange(
+            xRange=(self._x_min, self._x_max))
 
     def removeAllDatasets(self):
         """Reset the plot by removing all the datasets"""
         for item in self._items:
             self._plot_widget.removeItem(self._items[item])
-        self._plot_widget.plotItem.legend.items = []
+
+        self._clear_legend()
+
         self._items = {}
         self._last_item = 0
         self._last_ts = None
         self._dtime = None
         self._plot_widget.clear()
 
+    def _clear_legend(self):
+        legend = self._plot_widget.plotItem.legend
+
+        while legend.layout.count() > 0:
+            item = legend.items[0]
+            name = item[1].text
+            legend.removeItem(name)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/ui/widgets/plotwidget.pyc
deleted file mode 100755
index a6cc6be362d25fd29aa4af50696e22e375fe8247..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10686
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
IwWXE+1JLb)L;wH)

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.py
old mode 100755
new mode 100644
index 8a252d5b..cab62b7c
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.py
@@ -21,9 +21,9 @@
 #  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, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#  You should have received a copy of the GNU General Public License along with
+#  this program; if not, write to the Free Software Foundation, Inc.,
+#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 """
 Various utilities used by the user interface.
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/__init__.pyc
deleted file mode 100755
index 5859123c9c6fa6c4519f23a61276a26911af398d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 190
zcmYL>!3x4K42C;BC<R|Z>TMvjFCgL*coBBkC2Vbmfo_vFJM6i=c`^mT!2jh-2-&_5
z`g3j@uYOfYze%zd1f^PGr5^RB?3_S1U7~r(W?_oNgkl+k=~u%~ES?NajA`gRT79p}
yN8Skl!t4QRQT0bY$!M*M)H^@;NI0=8zq13Ni5S4XR^H3iWt_tj@p=@`67>agpez;u

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.py
old mode 100755
new mode 100644
index e7e09816..2bfe88af
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.py
@@ -29,24 +29,25 @@
 """
 Gives access for reading and writing application configuration parameters
 """
-
-__author__ = 'Bitcraze AB'
-__all__ = ['Config']
-
-import sys
 import json
 import logging
 from .singleton import Singleton
 
+import cfclient
+
+__author__ = 'Bitcraze AB'
+__all__ = ['Config']
+
 logger = logging.getLogger(__name__)
 
-class Config():
+
+class Config(metaclass=Singleton):
     """ Singleton class for accessing application configuration """
-    __metaclass__ = Singleton
+
     def __init__(self):
         """ Initializes the singleton and reads the config files """
-        self._dist_config = sys.path[0] + "/cfclient/configs/config.json"
-        self._config = sys.path[1] + "/config.json"
+        self._dist_config = cfclient.module_path + "/configs/config.json"
+        self._config = cfclient.config_path + "/config.json"
 
         [self._readonly, self._data] = self._read_distfile()
 
@@ -80,7 +81,7 @@ class Config():
         else:
             raise KeyError("Could not get the parameter [%s]" % key)
 
-        if (isinstance(value, unicode)):
+        if (isinstance(value, str)):
             value = str(value)
 
         return value
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config.pyc
deleted file mode 100755
index 484e51ab008a24f203c54cb006c29fea6489473f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3450
zcmcImYi}Dx6rEYWYNsV>D74|#<wKAKYW)QvAu3dwR;3gou|~8tpw(t~>}<N(wRXlS
zuG%kzf6NbnbME+&ikFZ`+PS{-*qOQK+{ZM2yVUzKefWK<7Jm)=-bS+(M5fdTQmc_x
zS)e9R0+lsX)>K79ji7kFsYcDE-cqBM%J9FfincoLs8L60(^5wll<BHdY|-Oh*#(t#
z)UQgND)nTv!7YdVE)RYP(Yv3Y7#k*OYOD>%RUOtQ$?|d%CS?{rt8*v%bXw$T;_|8t
z)2bZjlUeP1)1*$0jWf0F*$wP>CwFO`JU8JNcU&9&Jz1Uqj=%j}W1vsrc>WMO7sgfP
z3KCA;L9<^$7(fCrAOmH90qoW^gGL9Uw21^qIy8z3Ol^tMB`O^0sc6{maL-R6!qu5!
zS|kgDz3u;OX3DDtXk={<&E^nJsUuubs~z0v>I<dfU^&*nSksR+6lRW^#Q(>DdfXD(
zmhle9UuyM2tJ=s&n+&2026YLiXn`+6X+MDoAC#aZDe~uF%^jN1E>RT1NS+_}G=<~5
zz(QVD*>@oZ={PNNQ@Vj)U>CnPk8D*6LH4376W(NWU%bW9ayz%KiQj4B4jtFUS#DkI
zw{nDeslP^@w~-aRg>WuIRawkkOTJEA;`foIi+yP9Y?>v`^a;6~XiYJ8bg-E<_2Q5|
zx=Muo2HN1TIyQrYg#!+zb#-J?2Ls`c^D&IR;Vri}rgL{#m4hNbSi>=Md9eZm3oc;C
zIL?7~9N&a4u&CgQz7kvuF6y=xmmnx?dtC7?1YCk_i&vZmB-RD$2reLez6Aez;R_lN
z9KnUfCGf$U<okt0{SJScYG)FFdIDuXg9szQDV!7ZIzPabSMexBGd5j<J0pDQ8<`m=
zv%<k4=)SeR26-3XE@D_hJsj87aky(OLy|1q5PE1nqdz$)jKq(yP)$u4(E+4Kml36?
zl1vCqi^>{_`=XjmOf9o{Ij;HyDI$Mzm9b2K;p99yjOa)Vd)tFh!M5JiJ@A(<StGQ<
z92d<mE5J_jK%rK*9+mH_CT{z*r|OTD)*3oO9aCiL7p+RI9)rE1*k*UJML0B0fImr!
znF*_Lm@J`Q<;l>7Jhhq?Sy)ys1YYvVdchC7_NRUE{D>@wCq6Xudv#saXK<tuPmK>G
zIqy87^wDpeWM|$=1r2>!U()F^De^jk<p~tP;$7Xx!qc{@cNcL1{B|%`4u~YD1I6jP
z3w=4grEugcaKmN558Mo4Ro4n$hAx=kW?<}9BJTfpA|`)B1hbmB>wZ-lVI<;E#9(rC
ztQ;xWx};2vWWZUOr&VS=V(tuM(GEX*3*y|Ff-Mhlj@^b(K^uO*#TIM@n|d>l%thW-
z{y#+L&zTEcfE^fu;zg#U@S^0NYAv}6(`{BS4ZBgYkg+`7lF8O(>pg594wDlje$M>8
z3<_8Iv?V#=ndFVU%ut+i-p&%QJ*h)}nZ+JRfK})tgb6F!qM#j;f0(gMba~m$X2(<O
zDSMsku28%I;iF5^5qDuCi_be7N&TY<F{|NY9BX|bZR_huOF{~RXhq5sbmq6$ywKPG
zy`1=<T9lJV<u-CyM{?MA%wfz|kJqsh;)r!wIZKUH1zt3?^w_gBut@l-@mD+u`Vk#3
zdKGiA|K883nX+s}?_k9`n?+2Y(N&J2omWwhNOp{7={8JZ2nS$)4T-E3^u-^@NgS7W
z)W)%dcN`yA*{on!9yoDUrEwg|Gxm}!#``ys=Ol(XB6TNvn_5Wm0R@j<+a}uo|7wYF
zi24Xk3~b|-($?LLZnxX%ZgxBVcs|>r4<Q!TB{MvR>Xmg#QNRqwpN}Kj%wmo=h4<j)
sd($I8vyg4RmU18Q1RrHk&fi=qjki2KpI^s`-fSeiE}m%ohlCgW0a|wz5&!@I

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.py
old mode 100755
new mode 100644
index 8da823aa..e61daaae
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.py
@@ -7,7 +7,7 @@
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
 #
-#  Copyright (C) 2013 Bitcraze AB
+#  Copyright (C) 2013-2017 Bitcraze AB
 #  Copyright (C) 2013 Allyn Bauer
 #
 #  Crazyflie Nano Quadcopter Client
@@ -31,10 +31,6 @@
 Manager for loading/accesing input device mappings.
 """
 
-__author__ = 'Bitcraze AB/Allyn Bauer'
-__all__ = ['ConfigManager']
-
-import sys
 import json
 import logging
 import glob
@@ -44,15 +40,18 @@ import copy
 from .singleton import Singleton
 from cflib.utils.callbacks import Caller
 
+import cfclient
+
+__author__ = 'Bitcraze AB/Allyn Bauer'
+__all__ = ['ConfigManager']
+
 logger = logging.getLogger(__name__)
 
 
-class ConfigManager():
+class ConfigManager(metaclass=Singleton):
     """ Singleton class for managing input processing """
     conf_needs_reload = Caller()
-    configs_dir = sys.path[1] + "/input"
-
-    __metaclass__ = Singleton
+    configs_dir = cfclient.config_path + "/input"
 
     def __init__(self):
         """Initialize and create empty config list"""
@@ -65,7 +64,7 @@ class ConfigManager():
             return self._input_config[idx]
         except:
             return None
-    
+
     def get_settings(self, config_name):
         """Get the settings for an input device."""
         try:
@@ -87,16 +86,21 @@ class ConfigManager():
                 json_data = open(self.configs_dir + "/%s" % conf)
                 data = json.load(json_data)
                 new_input_device = {}
-                new_input_settings = {"updateperiod":10, "springythrottle":True}
+                new_input_settings = {"updateperiod": 10,
+                                      "springythrottle": True}
                 for s in data["inputconfig"]["inputdevice"]:
                     if s == "axis":
                         for a in data["inputconfig"]["inputdevice"]["axis"]:
                             axis = {}
                             axis["scale"] = a["scale"]
-                            axis["offset"] = a["offset"] if "offset" in a else 0.0
+                            axis["offset"] = a[
+                                "offset"] if "offset" in a else 0.0
                             axis["type"] = a["type"]
                             axis["key"] = a["key"]
                             axis["name"] = a["name"]
+
+                            self._translate_for_backwards_compatibility(axis)
+
                             try:
                                 ids = a["ids"]
                             except:
@@ -105,13 +109,15 @@ class ConfigManager():
                                 locaxis = copy.deepcopy(axis)
                                 if "ids" in a:
                                     if id == a["ids"][0]:
-                                        locaxis["scale"] = locaxis["scale"] * -1
+                                        locaxis["scale"] = locaxis[
+                                            "scale"] * -1
                                 locaxis["id"] = id
                                 # 'type'-'id' defines unique index for axis
                                 index = "%s-%d" % (a["type"], id)
                                 new_input_device[index] = locaxis
                     else:
-                        new_input_settings[s] = data["inputconfig"]["inputdevice"][s]
+                        new_input_settings[s] = data[
+                            "inputconfig"]["inputdevice"][s]
                 self._input_config.append(new_input_device)
                 self._input_settings.append(new_input_settings)
                 json_data.close()
@@ -119,3 +125,57 @@ class ConfigManager():
         except Exception as e:
             logger.warning("Exception while parsing inputconfig file: %s ", e)
         return self._list_of_configs
+
+    def save_config(self, input_map, config_name):
+        """Save a configuration to file"""
+        mapping = {'inputconfig': {'inputdevice': {'axis': []}}}
+
+        # Create intermediate structure for the configuration file
+        funcs = {}
+        for m in input_map:
+            key = input_map[m]["key"]
+            if key not in funcs:
+                funcs[key] = []
+            funcs[key].append(input_map[m])
+
+        # Create a mapping for each axis, take care to handle
+        # split axis configurations
+        for a in funcs:
+            func = funcs[a]
+            axis = {}
+            # Check for split axis
+            if len(func) > 1:
+                axis["ids"] = [func[0]["id"], func[1]["id"]]
+                axis["scale"] = func[1]["scale"]
+            else:
+                axis["id"] = func[0]["id"]
+                axis["scale"] = func[0]["scale"]
+            axis["key"] = func[0]["key"]
+            axis["name"] = func[0]["key"]  # Name isn't used...
+            axis["type"] = func[0]["type"]
+            mapping["inputconfig"]["inputdevice"]["axis"].append(axis)
+
+        mapping["inputconfig"]['inputdevice']['name'] = config_name
+        mapping["inputconfig"]['inputdevice']['updateperiod'] = 10
+
+        filename = ConfigManager().configs_dir + "/%s.json" % config_name
+        logger.info("Saving config to [%s]", filename)
+        json_data = open(filename, 'w')
+        json_data.write(json.dumps(mapping, indent=2))
+        json_data.close()
+
+        self.conf_needs_reload.call(config_name)
+
+    def _translate_for_backwards_compatibility(self, axis):
+        """Handle changes in the config file format"""
+
+        # The parameter that used to be called 'althold' has been renamed to
+        # 'assistedControl'
+        althold = 'althold'
+        assistedControl = 'assistedControl'
+
+        if axis['key'] == althold:
+            axis['key'] = assistedControl
+
+        if axis['name'] == althold:
+            axis['name'] = assistedControl
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/config_manager.pyc
deleted file mode 100755
index 51f6358a17701d6345bff2f8a43213c3bd918ffc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3562
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
D7pp8S

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/guiconfig.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/guiconfig.pyc
deleted file mode 100755
index c08a5488a3f3fbab088fa8501cfa241ea285020f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1832
zcmcgsO>fjl5G{MYnBgPCqDA6FABbd-5?{C=5L%L51ql=p&t7&AvW(p`ap<u}-R+=3
z;j-D&{xtp$KLB2pop4+2CCp6MbX9j(SG`x&y{|VXt1tilnN#=a;r}-bcLGrm%^?Gt
z2ULW##3ZDmM@64ZkLH-*Hz3oe)qv&$3RoYK8PaM*^AQEQM<>@vkLesoC+tHHXaQ#<
z`iJP8=&$*8_BM;I@tv<ACI{uIb}Gwr?VMWFR#}}DWwlgURj7})^fF(sO_^uDtSgn*
z)uLQBw$;{|%~slL>n83x{Oy%Kx7jDHUhMfX^n<3{mjmTDd=8@kHa~=Dt*t(Sel+tI
zS6w2*8}~5WLkJCIkOm|G2{;)>Ba}&>VPVUFl3CQ}BTpdI4Bm|P9I?r|+}bq%JENRA
zVK+SXG2By#vyeXb$jihBbRLp@Kt5zUz{XOAya0cn&afw-vmTxIz)%3NLw2$ap=R1E
zf2`GMW*V*Pg~~cO)g_MVFdAU1pFotZtenrPTqo=U{^7{mL_icpd&$^K+S)8+%Ll#j
z>_cu5uyF`V1RIHPZ!n9G>y?h*cZ9`jTc7CMyO{agEKI3)a)`>io%O~a*HvuF_i?^x
zjd9~k<Kksgw)L>P-XwhI4u<3EqHq{&;hS^h94n7~40j3v?mh!N;6!v1(1#(}?QRa^
zJ*-vn#d0Xizss_mk>x4F0eG?fE*SVbAb<cikU5iMxym|n;7oX%MS__yaqvHwaQ8Xn
zx-o^SYOj{v5upkduikFEcZU%dui$@JS6XmSi_B+I{V6w7U73w%NM7m9AJ*13;V?X(
zYbwB3=!EH$;1X_)gqIRNA!LcT62_!jkk(^d<$i%^Nt=SUX*dl*Uzl^PT@0b`1`Ny^
zdi!NTC~sbE8$00_Ky=CDs-tJrie|Nzu(-@9h!{TsJ54J*Olc~Ol%}h?Xbh{2ZJHK!
zo~BZ;$rcRB6yis?SBH3ld*~5{^vEz6hU3wAD`HHOI}ly8S%ZeNm(ga%baPWLmw3MX
zuh@Ihio4Q^yKNt~Zv*>#vpMpQcaQvjZM)}#-(#@-8a}j5Zu4~v7yE>c*-wE$*m>6S
W@tix%-GUh6xfq8xf+;F*EBp=}d#=s^

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input.pyc
deleted file mode 100755
index 3e22bf8fd4eddad80cf08030c3f123c337ac4114..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 11733
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
Df1&Vz

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.py
old mode 100755
new mode 100644
index 34d3c4d1..b3edf6ac
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.py
@@ -38,11 +38,6 @@ Windows drivers.
 The input device's axes and buttons are mapped to software inputs using a
 configuration file.
 """
-
-__author__ = 'Bitcraze AB'
-__all__ = ['JoystickReader']
-
-import sys
 import os
 import re
 import glob
@@ -50,24 +45,27 @@ import traceback
 import logging
 import shutil
 
-import inputreaders as readers
-import inputinterfaces as interfaces
-
-logger = logging.getLogger(__name__)
+from . import inputreaders as readers
+from . import inputinterfaces as interfaces
 
+import cfclient
 from cfclient.utils.config import Config
 from cfclient.utils.config_manager import ConfigManager
 
 from cfclient.utils.periodictimer import PeriodicTimer
 from cflib.utils.callbacks import Caller
-import mux
-from .mux import InputMux
 from .mux.nomux import NoMux
 from .mux.takeovermux import TakeOverMux
 from .mux.takeoverselectivemux import TakeOverSelectiveMux
 
+__author__ = 'Bitcraze AB'
+__all__ = ['JoystickReader']
+
+logger = logging.getLogger(__name__)
+
 MAX_THRUST = 65000
 
+
 class JoystickReader(object):
     """
     Thread that will read input from devices/joysticks and send control-set
@@ -75,9 +73,17 @@ class JoystickReader(object):
     """
     inputConfig = []
 
+    ASSISTED_CONTROL_ALTHOLD = 0
+    ASSISTED_CONTROL_POSHOLD = 1
+
     def __init__(self, do_device_discovery=True):
         self._input_device = None
 
+        self._mux = [NoMux(self), TakeOverSelectiveMux(self),
+                     TakeOverMux(self)]
+        # Set NoMux as default
+        self._selected_mux = self._mux[0]
+
         self.min_thrust = 0
         self.max_thrust = 0
         self._thrust_slew_rate = 0
@@ -87,10 +93,13 @@ class JoystickReader(object):
 
         self.max_rp_angle = 0
         self.max_yaw_rate = 0
+        try:
+            self.set_assisted_control(Config().get("assistedControl"))
+        except KeyError:
+            self.set_assisted_control(JoystickReader.ASSISTED_CONTROL_ALTHOLD)
 
         self._old_thrust = 0
         self._old_raw_thrust = 0
-        self._old_alt_hold = False
         self.springy_throttle = True
 
         self.trim_roll = Config().get("trim_roll")
@@ -98,10 +107,6 @@ class JoystickReader(object):
 
         self._input_map = None
 
-        self._mux = [NoMux(self), TakeOverSelectiveMux(self), TakeOverMux(self)]
-        # Set NoMux as default
-        self._selected_mux = self._mux[0]
-
         if Config().get("flightmode") is "Normal":
             self.max_yaw_rate = Config().get("normal_max_yaw")
             self.max_rp_angle = Config().get("normal_max_rp")
@@ -122,10 +127,9 @@ class JoystickReader(object):
         self._dev_blacklist = None
         if len(Config().get("input_device_blacklist")) > 0:
             self._dev_blacklist = re.compile(
-                            Config().get("input_device_blacklist"))
+                Config().get("input_device_blacklist"))
         logger.info("Using device blacklist [{}]".format(
-                            Config().get("input_device_blacklist")))
-
+            Config().get("input_device_blacklist")))
 
         self._available_devices = {}
 
@@ -133,8 +137,8 @@ class JoystickReader(object):
         self._read_timer = PeriodicTimer(0.01, self.read_input)
 
         if do_device_discovery:
-            self._discovery_timer = PeriodicTimer(1.0, 
-                            self._do_device_discovery)
+            self._discovery_timer = PeriodicTimer(1.0,
+                                                  self._do_device_discovery)
             self._discovery_timer.start()
 
         # Check if user config exists, otherwise copy files
@@ -142,8 +146,8 @@ class JoystickReader(object):
             logger.info("No user config found, copying dist files")
             os.makedirs(ConfigManager().configs_dir)
 
-        for f in glob.glob(sys.path[0] +
-                           "/cfclient/configs/input/[A-Za-z]*.json"):
+        for f in glob.glob(
+                cfclient.module_path + "/configs/input/[A-Za-z]*.json"):
             dest = os.path.join(ConfigManager().
                                 configs_dir, os.path.basename(f))
             if not os.path.isfile(dest):
@@ -153,11 +157,12 @@ class JoystickReader(object):
         ConfigManager().get_list_of_configs()
 
         self.input_updated = Caller()
+        self.assisted_input_updated = Caller()
         self.rp_trim_updated = Caller()
         self.emergency_stop_updated = Caller()
         self.device_discovery = Caller()
         self.device_error = Caller()
-        self.althold_updated = Caller()
+        self.assisted_control_updated = Caller()
         self.alt1_updated = Caller()
         self.alt2_updated = Caller()
 
@@ -175,10 +180,6 @@ class JoystickReader(object):
         """Set if altitude hold is available or not (depending on HW)"""
         self.has_pressure_sensor = available
 
-    def enable_alt_hold(self, althold):
-        """Enable or disable altitude hold"""
-        self._old_alt_hold = althold
-
     def _do_device_discovery(self):
         devs = self.available_devices()
 
@@ -207,6 +208,12 @@ class JoystickReader(object):
 
         logger.info("Selected MUX: {}".format(self._selected_mux.name))
 
+    def set_assisted_control(self, mode):
+        self._assisted_control = mode
+
+    def get_assisted_control(self):
+        return self._assisted_control
+
     def available_devices(self):
         """List all available and approved input devices.
         This function will filter available devices by using the
@@ -216,13 +223,13 @@ class JoystickReader(object):
         approved_devs = []
 
         for dev in devs:
-            if ((not self._dev_blacklist) or 
-                    (self._dev_blacklist and not
-                     self._dev_blacklist.match(dev.name))):
+            if ((not self._dev_blacklist) or
+                    (self._dev_blacklist and
+                     not self._dev_blacklist.match(dev.name))):
                 dev.input = self
                 approved_devs.append(dev)
 
-        return approved_devs 
+        return approved_devs
 
     def enableRawReading(self, device_name):
         """
@@ -246,7 +253,7 @@ class JoystickReader(object):
         """Return the saved mapping for a given device"""
         config = None
         device_config_mapping = Config().get("device_config_mapping")
-        if device_name in device_config_mapping.keys():
+        if device_name in list(device_config_mapping.keys()):
             config = device_config_mapping[device_name]
 
         logging.debug("For [{}] we recommend [{}]".format(device_name, config))
@@ -260,7 +267,8 @@ class JoystickReader(object):
 
     def read_raw_values(self):
         """ Read raw values from the input device."""
-        [axes, buttons, mapped_values] = self._input_device.read(include_raw=True)
+        [axes, buttons, mapped_values] = self._input_device.read(
+            include_raw=True)
         dict_axes = {}
         dict_buttons = {}
 
@@ -294,7 +302,7 @@ class JoystickReader(object):
         config_name. Returns True if device supports mapping, otherwise False
         """
         try:
-            #device_id = self._available_devices[device_name]
+            # device_id = self._available_devices[device_name]
             # Check if we supplied a new map, if not use the preferred one
             device = self._get_device_from_name(device_name)
             self._selected_mux.add_device(device, role)
@@ -306,19 +314,19 @@ class JoystickReader(object):
             return device.supports_mapping
         except Exception:
             self.device_error.call(
-                     "Error while opening/initializing  input device\n\n%s" %
-                     (traceback.format_exc()))
+                "Error while opening/initializing  input device\n\n%s" %
+                (traceback.format_exc()))
 
         if not self._input_device:
             self.device_error.call(
-                     "Could not find device {}".format(device_name))
+                "Could not find device {}".format(device_name))
         return False
 
     def resume_input(self):
         self._selected_mux.resume()
         self._read_timer.start()
 
-    def pause_input(self, device_name = None):
+    def pause_input(self, device_name=None):
         """Stop reading from the input device."""
         self._read_timer.stop()
         self._selected_mux.pause()
@@ -339,12 +347,24 @@ class JoystickReader(object):
             data = self._selected_mux.read()
 
             if data:
-                if data.toggled.althold:
+                if data.toggled.assistedControl:
+                    if self._assisted_control == \
+                            JoystickReader.ASSISTED_CONTROL_POSHOLD:
+                        if data.assistedControl:
+                            for d in self._selected_mux.devices():
+                                d.limit_thrust = False
+                                d.limit_rp = False
+                        else:
+                            for d in self._selected_mux.devices():
+                                d.limit_thrust = True
+                                d.limit_rp = True
                     try:
-                        self.althold_updated.call(str(data.althold))
+                        self.assisted_control_updated.call(
+                                            data.assistedControl)
                     except Exception as e:
-                        logger.warning("Exception while doing callback from"
-                                       "input-device for althold: {}".format(e))
+                        logger.warning(
+                            "Exception while doing callback from input-device "
+                            "for assited control: {}".format(e))
 
                 if data.toggled.estop:
                     try:
@@ -366,41 +386,53 @@ class JoystickReader(object):
                         logger.warning("Exception while doing callback from"
                                        "input-device for alt2: {}".format(e))
 
-                # Update the user roll/pitch trim from device
-                if data.toggled.pitchNeg and data.pitchNeg:
-                    self.trim_pitch -= 1
-                if data.toggled.pitchPos and data.pitchPos:
-                    self.trim_pitch += 1
-                if data.toggled.rollNeg and data.rollNeg:
-                    self.trim_roll -= 1
-                if data.toggled.rollPos and data.rollPos:
-                    self.trim_roll += 1
-
-                if data.toggled.pitchNeg or data.toggled.pitchPos or \
-                        data.toggled.rollNeg or data.toggled.rollPos:
-                    self.rp_trim_updated.call(self.trim_roll, self.trim_pitch)
-
-                # Thrust might be <0 here, make sure it's not otherwise we'll
-                # get an error.
-                if data.thrust < 0:
-                    data.thrust = 0
-                if data.thrust > 0xFFFF:
-                    data.thrust = 0xFFFF
-
-                # If we are using alt hold the data is not in a percentage
-                if not data.althold:
-                    data.thrust = JoystickReader.p2t(data.thrust)
-
-                self.input_updated.call(data.roll + self.trim_roll,
-                                        data.pitch + self.trim_pitch,
-                                        data.yaw, data.thrust)
+                if self._assisted_control == \
+                        JoystickReader.ASSISTED_CONTROL_POSHOLD \
+                        and data.assistedControl:
+                    vx = data.roll
+                    vy = data.pitch
+                    vz = data.thrust
+                    yawrate = data.yaw
+                    # The odd use of vx and vy is to map forward on the
+                    # physical joystick to positiv X-axis
+                    self.assisted_input_updated.call(vy, -vx, vz, yawrate)
+                else:
+                    # Update the user roll/pitch trim from device
+                    if data.toggled.pitchNeg and data.pitchNeg:
+                        self.trim_pitch -= 1
+                    if data.toggled.pitchPos and data.pitchPos:
+                        self.trim_pitch += 1
+                    if data.toggled.rollNeg and data.rollNeg:
+                        self.trim_roll -= 1
+                    if data.toggled.rollPos and data.rollPos:
+                        self.trim_roll += 1
+
+                    if data.toggled.pitchNeg or data.toggled.pitchPos or \
+                            data.toggled.rollNeg or data.toggled.rollPos:
+                        self.rp_trim_updated.call(self.trim_roll,
+                                                  self.trim_pitch)
+
+                    # If we are using alt hold the data is not in a percentage
+                    if not data.assistedControl:
+                        data.thrust = JoystickReader.p2t(data.thrust)
+
+                    # Thrust might be <0 here, make sure it's not otherwise
+                    # we'll get an error.
+                    if data.thrust < 0:
+                        data.thrust = 0
+                    if data.thrust > 0xFFFF:
+                        data.thrust = 0xFFFF
+
+                    self.input_updated.call(data.roll + self.trim_roll,
+                                            data.pitch + self.trim_pitch,
+                                            data.yaw, data.thrust)
             else:
                 self.input_updated.call(0, 0, 0, 0)
         except Exception:
             logger.warning("Exception while reading inputdevice: %s",
                            traceback.format_exc())
             self.device_error.call("Error reading from input device\n\n%s" %
-                                     traceback.format_exc())
+                                   traceback.format_exc())
             self.input_updated.call(0, 0, 0, 0)
             self._read_timer.stop()
 
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/__init__.pyc
deleted file mode 100755
index 9b26a5bbbc2cbee07572abccdebf8393c0943072..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 13812
zcmcgz+ix7#dH-gXq_`_myi=rZ9^Yd6A~IGkavV9fEcup5j5?G|c^!E=+?geJxx2HP
znKenr%8Qf$MbVeGK#QVipPD|j2-+a%V;@}fALwh)hoC6X#{xxwKBP#0zwgY<4rLh)
zQiv4i@SJbXoXdB9-{pMgsPbQvwRaoedA}jqPX&M9z>{3EL;{gIQcLQV1h#A=V@ptx
zU_?3<sUu_ZBT^s9^P^H9&GTbYAItN{q<$>Vk4t?#&sU{h&GR*>AJ6j>QlFG?T-qlj
zoRa(KdRkwNN@qs8vr?ZGi`|b&XHL5FQlB^FW71iW?xNHeO?g~8C#Ab2^(9lr(3hpY
zECG70G2cBU^;39<@^R^$mhKs;pE2bL>714BIjNsB<w@y0Azer64$3E_{v^2)J|#`C
zXG$K3+!y(v{xtcsu`*3A{wugxyB-CDPUxhO6Ni4_w0iwP>IC7(twxwQelKv65J@BI
zrE%0rSTEfPohz~b$w9Nz3Ri2jn>($<>6&KPMv^tsjH9m8jt-Kv)!0p(D0U)z8h=3-
zN!~{-3DfiasMSj!(VO#L>NNbGvlX&>v$Z{lLk?O8b?ZHh=6yeIMT5i%;?~Duj8;wU
zL4taZnxqr>slV!68N_keOFIV+CWFf8dnc^jIM}#)?LyYpOU@Qpll9dcr0Ck|`6;?_
zl0m;8#i_H`>U21^ejI(=3eaN{v%c2q4fe^(+GeX4M0>^9ly~7Femn=B?`MohZ)wy6
z0sVCSe&0+WiJIviNxD)TYpb{I__drJ7*N!6nyn6&COM8}ezTP}uv(#W`OWkM%HPgb
z#KlsDaqHLkSziGXBppL?MY(FqlSTQu-}AS_cu2m1FQcH<xY_FFWc}Ljbnu3)nY!c1
zy+=r0AM6{-C@AYuQRE13`n%zGu~-FhzC_#zJ7I%N#@p6^{Ex^XZSW>)CjX5jgf;-s
zkwO(9tw;!|x8wn26C!U@0F1md17ROg3M740GZ3&b&D10~slUhMfi3k33C5K^NulJo
zCn%cCOi?D8f$UFcW=4WZ&CCiUkgw(_du(u8Tbq|)M(GPmoYmniN-(EHRGZh#k^~Ey
zS(fmW1dGg5$()w(jD$-Po|O9-+gWipR+h+tE|QvqpPM@>#p#Zpfw3giDvz0DuMOq$
zVHrOU`O~((KnC?)!$yxIc(|Nb@Ff2Z<s687D&k=sEX_b4n+#N;$&5%ks;{7W4dqx)
z!BQ9smcnGP6ea_`Ycdmg<w*gS+1He$)6{Hj@ZKhqNSrMZD>)HMVTLy^=>n^va=Msj
zPG*_ying%Cw2gJJWSK24ms%X*mw?UgxWof%*!@`EQ>|3_SWc{#h~qiYE)lCau~H(|
zaw6DN%=36oJSDv!l;{&Vy*z-)oLC;fiJVv-fEqGRwmblIYIs^6z)VgAI1NuvOM0d>
zl37+Dmn_*Gk@%Z-dRE%!9#Mhaot7Sy&lA#iC<yH*A5jfWSuNAkQ<B1l&FlI+Lor|z
z&&sEk#6PzAO4qjirTo=%TJt$+uMj2{yLw*QFG%}ENncXroaacBU)b3Y7Fo1dY4uPI
ze!Bla(lu$XN&02BL3BX4PvV2CcXs3+xM|vcdH7{Uxgeh^JTc&V;IFCn75P-*nfyvS
z|EdJQ9je*r|7+6zIt#-=f_nE?HhwoV+C`mF`U?M$3*V4o{?$_co2C4vQvS74{#&K|
z>!th~rTk^C_QuLG#C;vB0Zvw##I3Fe-=LG$@=_lrXGe>05w>?yI0vCxm-Q&_`W-bx
zJ<WPuf8RUs_fp!L5-IMdGbKu^=cPOGAW08V@#*KONhjR%I<0Oig}@YTDmC`gFg*rh
z-YHEM^XQFZ?+&}s;;?-dOAT|{!xk4&Qe*5H<?3y9{Kjslm88jOyt<_Z+Prd#SI&pu
zzjtT*`}03}=NF$mcpVmtKmYl9vVuSB5j~JN^Kjrp40^#!DD@9$>H{>a_B~0ygvx7;
zW&?g$FI_VpK(eM|S^Mzv`MQ7plRGc0wi9>}oWYf>g=do$+Rb!C`|5?te6KtOcLA?l
zPD~k|vDq8WnQH%SzXMY-$4a_3=5^Tfw>n{<-<9cRNmzTwPrQB{CJ7uU58h=0&uId5
zvl5=)+wOz~0od?#-RLNIQ76ckd@3);sFA^dAksR(n74z<I>npuAXF?Q{TK{9VC^VP
zJE5yy5A2p~hpEd&b;%~hLdFjGT`p1L(vfkA9c|L<4)zV#5_M0)Kq&-VdCod;`dmcD
z5Ed!B>|n`gL}LTVM%3-YXHzNZMB8w-w4+w987U2pWY<sASvKZ>?6*4Pat64>WrI3w
zntL<!R2in_lulYor^*YW9Hf9zBZAX)psewVqGxJzfs@paQypZK=xF+Wx}&2B_la(o
z<JW#N=%JN3C8xUZ=#V#GZFizAopOS$05R95bI)p9K9=9_npw9JI<0UI;75d8gKh07
z*%_p*juMIg3ko-^79>1Ly{PGBJ-cjISH!@0(1%+O6cQzI-%}lx(+KMj9N7+gjRP-9
zqrR8F;sRzuTrfnTm=VJ`23XlB5JrF%UlPEez5FoYLP22LDg?k_PF&GpGXaj8I=M%!
z5OLa6)&*gbQbmX+$t~p8cA{>$wv~DLYuI|U;V>s_bozCRcHZcR<b3}CWA3eWT3bV<
zLH6b<!vk_!spqYtB9|vGuOpxQ0Et*tyJ{8xn9s}hg0)~*?Pu(1d&y!R5B@DF-Q@A!
zI%kbpr>zNVu~Mxp*kdS7S<{szYtmY@=d2UfEWVkwrmeH~q&<OprGFLmIf-;WSMVgO
zNcNwT6p(_uAuz(rG{Uf&ZKUu$Y>6jX+_*a_o3Pd!D}-!v4#_)Vs+&frk8Hc^sDtcd
zPuC6C&B{>VDMHvts^Ks&Feqj<_Y^9ua6InsAW>P!prW|u!UadNUR2l~1taU8bMZKa
zzs8G%t0`dclr?TC8_5Pf%0{Y9aEmSkhFfsyRggEprB>4cvRmmO2pwXcJLEzIaa-Su
zQfDOy`v?@!Kw<m&?&kAmPw6^nM44_FL?v5%dnAmZw8Kn!xk(sm&!6xOnIQIW%#$Zj
z`z^I_oH%p@)$n2VWD|cDHA@pGk}{ofB-5sjGN!ng`A<R0=SyG`wtN%=?;`^Mv^7k0
z&ysy?i0IW$sX*bK&3)b7IoX6kz#F){v8!KHq&<>REVeKzZR~`Ms~yl^WMAtmYCGxE
z70aJnFV*g<wp|Le`yC{z>>7wBxUb|TD(aG`QE39}iHjhh(T2*`$EOnAi|FVd@Fdjr
zVoi)pT2xZgR)aIlALS+|Yq*(DpRe5)kSIG;7>)!7l<gtM;kJARf<b}R;Of)f@~@8j
z9x`U!*rZ^U<IA#tSt-QAlX4F$JyKGx%Pisp=#9I}{N3!$5-RZqQ}d#SCV>%bbigF6
zD*yr=1B{rCps9f+{8|bY%Hw)MTWJD62zp(=b^BH4`}Y(<?u&S%d~|OkXB>l0l!Wff
zd~t!vSCFi5TFPZpk29pt#)YBTW}ZvZJ(5LWuhc>4^`Dug7YADk>o*ORJcqv%cFk58
z5!S_W9H3AbHwYzG1kz`0-9?nQh0?iygD<Y$d6zp&GPNQT$?Yr`Kc8hNq*#VgvU<W$
zQTDJ5Xz^IK5w-3<FZkUA%>Xy~dko<kcN~z#lGbO?2q8&?Ik7-0yO|M9Ry96kVo@*@
z%|Q>*JD3Cwjl#oAv9T!tnSbPL9b|z_MqT+ae}<bS<K+$DPqQg@9`z8ah3`CwQO*aF
zndjA&ag5rfN^>{KLVERZIm5W=BdYD5CyfAsN8Q*_fVe(s^z<2M?FDN74SoPi<5}k2
zP;Vvb&?0jb_;G(1L--dw34M4Oq0SkzC#@PFw1{Wk*e}ASfX-bMjDW>YWf_AT3&K|j
z<~|}Bs=x2kd4haHXaNU==#2BUHWcH#Yl2@oQKnfUN9_f`gRj|a=3V_0x-Ql*GnVwS
z=t!x5&{W5(j2fUL-Emq$hKKipRYWp@9utcXiq;UohmYg1wU7PI0D*D_*dbae8y@tX
zsQC~Yo%c;WM$9>YqAB(mA)cSb&mBhC(Z~?K>jp*K!n;i-^!0|IGJ1vnjM;JEdo@}S
z;4?H+?g#wns7#b@<&4#L{XN(4``<7ERj4vng`Yj4Zs2rf!Z?D|H+-(J)=eZqg(!e>
z#G*nsV_Bgvj5R3K`0kj*7pXD;lV#L~iq8}~zyn+WBO1k`R##QR9uigEMq+t{l=##g
z8QXOoeP<hS{$2(G1Zma6;~*;A<sn$4Ym{&$-p0Z+hT`mTVX=Mg@|=nk<7=4ZQnO1L
z)wS6Tu>++t<_;T+?OsLR*b9!($U9d|HGxq&Zi4brNO{UgK0SD4Ozy{LQ~o918NUOY
zrdj-(w3ml|N8!mcAoPDr{ZLe&LH(<l6Z?>emc?^*-5~m~EF7^XL!Ur5>lmn)>5^ZQ
zMy)N_TTU8=P$apUis&CAlc_0<M#FsG7wdb#I6$qT*cNQ)h%g<M{b#5S0bc<3>YYXT
z9%_uqJy=Kl!hVj)rMnkpGpnYKOR3tpe2QP_PFDK}MigJ5R1ushWUBEw49B5d9#UaE
zC#6IjV!7@mTfIgH+b%@F_KZd13MiDx0GG?HG1#y-KtKZ#j}^{dajdm?mZ*Tw&Js03
zLP#NCWfZ7>j)OdGkXV<lt(Ni+C_pWBm3&RNjzknRY=aqc;@Ln)F%qN3Yz7g=fd3Qv
ze17kC24l{o0P*y~U|G~tL+qbKEpBgdK3rxzHPX7-xGCKGs5ackxmpD2u?Jvg&<A}+
za-gs<b7TU+EtRTq-&v^OQM5Bg1Amd4+o)ipxhoRCMjT@9dYA?EZYlxm3SuzJ8zFbd
zHFfBX3ji@N4kGF56p#X0Knpm-0ug6*rUgqb1%x@rlYAA)wFoFTXN!;Iu`&6Cy;1ra
zFX6gpQQ9I%OZ~gPLKn`&8wpWWlg8>NE`>^6JW?~I{XDCG$b<`~2Mz@jH7ugBUzcDm
zxq51>e~%xGBgxzf4aq<D<>o$(%Uz6enM-{FRIz7)_eqOkwOLCo(^b8m(IBts#`4ki
z|2t$3KFF|d)EIYc3I|5SkjHA_9El{eZ`b`8UeIhKg)dhzuW`8rCz5dNNUq7oX75EA
zfl}J7N&F+RENx?gZ~?5KS8x>uwHImfdzRd04^xu-t@duJ!8e%Bl&jVPn`eNS3I?70
z7)jxpZ7}X!xQj+OH8w}I7$4uDhnUF-x~Q2mXE0DSXNp>370Q=ehQ#5afP=_Z)?9Xh
z1NT^ri}8}VtFqThLPyUziq;bDG2dbw*xB1bz}lh12VVlmF0HiXcUqs&6+NU<YPDyR
zgx38^G(h-_;j$)fg5-T;Ys(Fxfh(OP1+yOnnGfLJ;M*;}AS^Y8%p)tRdQ;#58pXnt
z%n5}1br9TdATehj=7vg=`%wDzTl<Z$&n=aEjrG`I8e@yJh4U*NggJHa!u^J;%8*-Y
z_bigq{#yMdLJ?<xVd*qL8Ln_OJU$Y`aUA2&V+$ilPg95-&}6hy!A{$rf+*D>Ovmw5
zt%^0P@$0#vD}@h?EHOq*5UcR093Te>n>a==3~X`g8kW$x;#>=+c*y)Cc9Mt!GX%qc
z*9wC{_lSNXpWk$n#g^`Ae6)f1TOpK%I2!3RD-1VLnW4yQ;1k0Zs;9n>6U~wtC1{Qe
z5Zbxn$K`?_*gqHiDE#MD49hqSh-e`L)wYZK3%HV?UWA9O4z5vXlm&SO0lzh;;b!t@
zP*%sxC4!8wu+GpaQ$G!q$8J;fOn^q^;WNp%$pz{X2BC1oVnR<uMS%?Nk_`M0MKC$L
zBZhQwvhnaNu5%V-tr+p8At_8DW19!Rw967~0%-BiZ7i&j<hU;fXLXut1|h(FrB^a&
zp*HXKVe*ct$?J%P{elGzOrHm}YMJlEil}#+-jiwfxWu2yfnF$T!}6)$)YdyYXz{b6
z#eY21A~egP7C$SuI4SYGm9=;xZ&5Gypv8GBALF!D9wY4gp%&+@(io>CZssjc=Pl|5
zAhg&lTHHF+qB;V`W7JtU%Pr1G{09~}U^3W)wQ&n>R9>-h9c##(If;L!)l8<ScJXkv
zd5M3n)l7!faAi(gTPU@*D6y@}X);AMv{tS*Bgut))#pn2`BEM&tSekjDm$R;%|#+y
zWx~2=6TpSAG1-NRZQ00Rw%$@c8oUBhpe!EP$Q*iAk>s!JbXnS`6e3I9UJfgur_=cg
zoKY|?$VoENAam9f&gGwuU@!=~=U-tM#qWK*+w5%@2>Yl4H!VZ#cy`0;K0N=-0eq6Z
z;!>lz_k<VfynSKIeDRdDpH`=kE*`EyZmg)mr6$*1ZDtK{qt+azYMdv#A(6Q|$?K?G
zI3Ae~72rm|Hm>S+I&?ksTW#um=AJRimz|#RC?I+5w`>DD+^DZDT>33rz$jk+|2A-e
z4d^A=7Dgesf(u2)UChI5;U=GqQC=8Uyz0Q0e42ID1<h-yJucf~`kd=4&!D0?GWi5K
zjRd3!ec^tN`w?GVXR^gtP?vC=V)qY8d6^Vi09-VtZ>u3PjhHI~-EZ?fO+C5cu9r#|
z-0!kP+oG4i*28Ucr>3CXz+DnH%^PEUt4?Q5z)SZ%Ho%xp=EovuhS$H4y6>{Up7p|+
zdKP-ujKhZ)?EVq{x_``s9<6c18psVJvidded}}x(By=CQA$GrpK5o!jL5;uzt5{Qr
z;!VK)Jd5L>32O$Yh!yMP=kr=8qgS~5D?PYov1FYY;rDnD4p_1m;p5HOXVtYupcmIE
zN-;t*?Ft?}e8T?Ucr>tN3-eG%S$yg#R*HJK7KA;!(+}eYZYkmBx89sb(A_M_HfrJL
zgE!QnQ|RDyMK=uBFW>fVzU$uFxT#)((uU0(3A6tOL;I7$HK?qw&<|5Ydb%a?JROzi
zng6nYBGKpJYE%Px>NAxiumS(Qz<6@EKs4L4JIuj16g>@gL+12c0Q&^da~d~hZjZ@6
zlLt(G$mI8#{3(+^WAf)r{({M0G9gBE6Nl{!{=)<=MeRg^%gGpNim}g((*yS<P=<We
z++#fRMrZO4p5)6&#zq)-oA{u5tU7{!6V=MpWOb%GTdh^csweQ&rcPByCPwkTQhjG?
z)TkdGnP(jL2bfe`a2)F1^V~P^-hGwH8WWlaBgO;f-a?{m(M6%U!(ALbh0$wRN-Z7j
z?Xo&m3SvRm^ctP}Gd80dZ2`Ibw&bc_d|EZJ0do<M``Smo#-3UK`-6!;o%wt<tc?C|
z2)#OIF5{WLaMddBD6?&e-c)lbLN3*p4i@LatGx)R-Zj*Tk(A;V9k1x|1u?281mzdz
z@*&PlSYw<`{*=|IJfkh%0&|f&I<zQIFB!4=7LlnJw8o(8s)sLgv1Cu#)7CT}Xey>G
HjoJSTv2EBl

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.py
old mode 100755
new mode 100644
index c27e0157..907ba867
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.py
@@ -31,49 +31,55 @@ Find all the available input interfaces and try to initialize them.
 
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['InputInterface']
-
-import os
-import glob
 import logging
 from ..inputreaderinterface import InputReaderInterface
 
+__author__ = 'Bitcraze AB'
+__all__ = ['InputInterface']
+
 logger = logging.getLogger(__name__)
 
-found_interfaces = [os.path.splitext(os.path.basename(f))[0] for
-             f in glob.glob(os.path.dirname(__file__) + "/[A-Za-z]*.py")]
-if len(found_interfaces) == 0:
-    found_interfaces = [os.path.splitext(os.path.basename(f))[0] for
-                 f in glob.glob(os.path.dirname(__file__) +
-                                "/[A-Za-z]*.pyc")]
+# Force py2exe to include interfaces module in the build
+try:
+    from . import leapmotion  # noqa
+    from . import wiimote  # noqa
+    from . import zmqpull  # noqa
+except Exception:
+    pass
+
+# Statically listing input interfaces
+input_interface = ["leapmotion",
+                   "wiimote",
+                   "zmqpull"]
 
-logger.info("Found interfaces: {}".format(found_interfaces))
+logger.info("Found interfaces: {}".format(input_interface))
 
 initialized_interfaces = []
 available_interfaces = []
 
-for interface in found_interfaces:
+for interface in input_interface:
     try:
-        module = __import__(interface, globals(), locals(), [interface], -1)
+        module = __import__(interface, globals(), locals(), [interface], 1)
         main_name = getattr(module, "MODULE_MAIN")
         initialized_interfaces.append(getattr(module, main_name)())
         logger.info("Successfully initialized [{}]".format(interface))
     except Exception as e:
         logger.info("Could not initialize [{}]: {}".format(interface, e))
 
+
 def devices():
     # Todo: Support rescanning and adding/removing devices
     if len(available_interfaces) == 0:
         for reader in initialized_interfaces:
             devs = reader.devices()
             for dev in devs:
-                available_interfaces.append(InputInterface(dev["name"],
-                                                           dev["id"],
-                                                           reader))
+                available_interfaces.append(InputInterface(
+                    dev["name"], dev["id"], reader))
     return available_interfaces
 
+
 class InputInterface(InputReaderInterface):
+
     def __init__(self, dev_name, dev_id, dev_reader):
         super(InputInterface, self).__init__(dev_name, dev_id, dev_reader)
 
@@ -95,7 +101,7 @@ class InputInterface(InputReaderInterface):
     def read(self, include_raw=False):
         mydata = self._reader.read(self.id)
         # Merge interface returned data into InputReader Data Item
-        for key in mydata.keys():
+        for key in list(mydata.keys()):
             self.data.set(key, mydata[key])
 
-        return self.data
\ No newline at end of file
+        return self.data
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/__init__.pyc
deleted file mode 100755
index 0b8ff01cd5178a884db66a9b124ccbe1efb1dace..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3290
zcmd5;-EJFI5T3Jk?AmdD`je(^8gR=67AUoZxB($V+BBlHO{I+>bW2!mc8{HP*SpT{
zacj59Rr(NI@;bZ$uYq^~_-1zP1R*ZqqQUYR&zUo4{%4L$zc19k_8)!cQ}L<d_baUI
zH$@Z>Ie>~BMS(><AQlBB3d$6f$N`e$Wpc_>e2$zs3h=E^RG~qYoGK|jNBv8rYjg?`
zb?Oo6GWE-(OVppIeuMM^9|cuf#n0A$o1Dez;nEaYCcVg9%y@~KKU#D&Cg(EgE2J+M
z)E5?|HT943YyVRIuPi@?wRP%Wr2z0+p$kT^8fS%_ajw(&XFk~4|B0Mcn)sw|kX|L-
zq*L6!DR7koh=`pcL~EpPkzS)<o=z=t)=95W|Gk2!*O`cmtfWxg5Y?-N|7!2(6IIsl
z(~CN#zbNIjW{e93qi%^1NC4~iSbM=Dy@jo}IhDFfT^O^(6exP;+~K6|wwF2e+W__L
zFb-N?6t&EuZh0@gF!Bx}-3sI3$N(Chc0FHbEe~uaowQ5>YG^_)3SVo!G`L%@XY&ws
zFEoDYfw+0kEMotVMLe8J2>-xmC$w<TM#+)6Hf6E37wB}xm@VL-^L%r|@it!Xe{^>^
z2|=KYMgE2CXDnhn8NsqMLqBi5IWcU`lc!tXK7Qan*?hQ@tz*AC^5I9;9YxXPoC`tg
z`J0n{;kciSqM#Kg?Dxz=K4qEGIVH%cV%^8e4gn0ld8I1inha?Cl#GP}*`gDoW1>C^
zf#^ihxI@QW^B>ZQ#h1_)W{!^0Xcjg3r-UD53H*{w+B<5}9*PpYyX`WR?MNUDqp>&8
zP(u_3?F!q$mPI<2sLrzJo`uC+XXcq(!TBThD9|rMgvYQjZ#dL(U<0Ez%N1fOSrX;o
z%|s!Pws0}XG(hJt8R*VIQ3;)4n)J1AvJMx<q#K2L!v}~>wlSQT!zAuR;X%jm=ETm(
zgi+R!(#zqQ{T&w;hsJeL5B4Q!+GLen#$;Vl3#x&&tg327`Ap*vhvyzv)&YQVJlsfH
z1Ho2;V60h!U_@b*mFO+zR)y?5-abcqy6&^2CjfcMIa3z(EzT*DcZ{r+NFgdXaLc^!
zBe}o<fmZ|v1YQ-q%Es(UE9|t{Aru2NjD|Xu$Q!0jotCq0FUqu$&K(VhNoq28fK-KX
zPk5tnfcT_C)4;`iV-C|%W=w5Hn0T+Gk|d3pj=FLaX>_HaIQhH@15+>1Jna{fWo~#5
zc*eGnx>c%`8_2WI(}Nf1SF*AS1flNZi(~*|sG^0=#aF7B%iKLz#tEw2=JZMuY#t^T
z;%5_zpJ8R}5dCNW>>Ic(h2lp^rvDF~-GoIyU`;(^2RYze>5{o`fc!mkn2+O+xvTQo
zxwXGeC(>9LncP*trQ@3DKy`G7_E-eJYFrgNG7s}$ur5xx#6oKRg`Q;j4D*a9GYl;y
zEg|`rha-&rXcTBS^<K&38%%;JGp=7qiLAj97c1kTKx)Ohs@AMF7j!WuxP4t$y4H0E
zNid4AwYh_AE-#xiVJ|UYQD;5~_6{dEl+$A@aipSZjasQzYJUKVk@j?h#Gm=$jqpUI
z*ycz0lLDM;D9Ll!i;@F5i;`ZC#~`<`ydHU%&t4Ck3q!_WPn*YJ#*DqgBp!HtS*KDI
zL(d$Fz#vRzAab}}w;OUa@eC8?12Y>&q0wU_!9VaaEzCTbyZmqD+}mn%sf+9|?k1wI
zo1_EJ*zA)nPdAU}nW;qz!vPQY!gcl&v%j#`pQ3r1#a_7O8Iy{O122qaoZBo|NDs!o
z9-1(T#Ro0#Xa2l{<6JeoyF!r2eUW?cWeY}Rp8`}Yl!V1YzM+<_C99+!sVl04NBuMF
VI?gKA0(Q66l4`1(fVZvM{GX*Q`(*$C

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.py
old mode 100755
new mode 100644
index 80c76d07..b21e7097
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#     ||          ____  _ __                           
-#  +------+      / __ )(_) /_______________ _____  ___ 
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
@@ -15,7 +15,7 @@
 #  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 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
@@ -28,27 +28,27 @@
 
 """
 Leap Motion reader for controlling the Crazyflie. Note that this reader needs
-the Leap Motion SDK to be manually copied. See lib/leapsdk/__init__.py for
+the Leap Motion SDK to be manually copied. See src/leapsdk/__init__.py for
 more info.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LeapmotionReader']
-
 try:
     import leapsdk.Leap as Leap
-    from leapsdk.Leap import CircleGesture, KeyTapGesture, ScreenTapGesture, SwipeGesture
 except Exception as e:
-    raise Exception("Leap Motion library probably not installed ({})".format(e))
+    raise Exception(
+        "Leap Motion library probably not installed ({})".format(e))
 
 import logging
-import time
+
+__author__ = 'Bitcraze AB'
+__all__ = ['LeapmotionReader']
 
 logger = logging.getLogger(__name__)
 
 MODULE_MAIN = "LeapmotionReader"
 MODULE_NAME = "Leap Motion"
 
+
 class LeapListener(Leap.Listener):
 
     def set_data_callback(self, callback):
@@ -75,8 +75,6 @@ class LeapListener(Leap.Listener):
         # Get the most recent frame and report some basic information
         frame = controller.frame()
         data = {"roll": 0, "pitch": 0, "yaw": 0, "thrust": 0}
-        #logger.info("Frame id: %d, timestamp: %d, hands: %d, fingers: %d, tools: %d, gestures: %d" % (
-        #                              frame.id, frame.timestamp, len(frame.hands), len(frame.fingers), len(frame.tools), len(frame.gestures())))
         if not frame.hands.is_empty:
             # Get the first hand
             hand = frame.hands[0]
@@ -89,7 +87,8 @@ class LeapListener(Leap.Listener):
                 data["roll"] = -direction.pitch * Leap.RAD_TO_DEG / 30.0
                 data["pitch"] = -normal.roll * Leap.RAD_TO_DEG / 30.0
                 data["yaw"] = direction.yaw * Leap.RAD_TO_DEG / 70.0
-                data["thrust"] = (hand.palm_position[1] - 80)/150.0 # Use the elevation of the hand for thrust
+                # Use the elevation of the hand for thrust
+                data["thrust"] = (hand.palm_position[1] - 80) / 150.0
 
             if data["thrust"] < 0.0:
                 data["thrust"] = 0.0
@@ -98,10 +97,12 @@ class LeapListener(Leap.Listener):
 
         self._dcb(data)
 
+
 class LeapmotionReader:
     """Used for reading data from input devices using the PyGame API."""
+
     def __init__(self):
-        #pygame.init()
+        # pygame.init()
         self._ts = 0
         self._listener = LeapListener()
         self._listener.set_data_callback(self.leap_callback)
@@ -115,18 +116,20 @@ class LeapmotionReader:
 
         self.data = {"roll": 0.0, "pitch": 0.0, "yaw": 0.0,
                      "thrust": -1.0, "estop": False, "exit": False,
-                     "althold": False, "alt1": False, "alt2": False,
+                     "assistedControl": False, "alt1": False, "alt2": False,
                      "pitchNeg": False, "rollNeg": False,
                      "pitchPos": False, "rollPos": False}
         logger.info("Initialized Leap")
 
     def open(self, deviceId):
-        """Initialize the reading and open the device with deviceId and set the mapping for axis/buttons using the
-        inputMap"""
+        """
+        Initialize the reading and open the device with deviceId and set the
+        mapping for axis/buttons using the inputMap
+        """
         return
 
     def leap_callback(self, data):
-        for k in data.keys():
+        for k in list(data.keys()):
             self.data[k] = data[k]
 
     def read(self, id):
@@ -141,9 +144,8 @@ class LeapmotionReader:
         dev = []
 
         # According to API doc only 0 or 1 devices is supported
-        #logger.info("Devs: {}".format(self._controller.is_connected))
+        # logger.info("Devs: {}".format(self._controller.is_connected))
         if self._controller.is_connected:
             dev.append({"id": 0, "name": "Leapmotion"})
-        
-        return dev
 
+        return dev
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/leapmotion.pyc
deleted file mode 100755
index 7715c47e3d587d68a8815f5c15244d4fe9273e17..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 6071
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
SdpK6Hjp){{qOVn3ee>Tc@~4yl

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.py
old mode 100755
new mode 100644
index 290e9628..693ea836
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 import logging
 from threading import Thread
 import time
@@ -12,6 +13,7 @@ logger = logging.getLogger(__name__)
 MODULE_MAIN = "WiimoteReader"
 MODULE_NAME = "WII"
 
+
 class _Reader(object):
     # needs attributes:
     # - name
@@ -19,15 +21,21 @@ class _Reader(object):
     # - limit_thrust
     # - limit_yaw
     # - open
+
     def devices(self):
         """List all the available connections"""
         raise NotImplemented()
+
     def open(self, device_id):
-        """Initialize the reading and open the device with deviceId and set the mapping for axis/buttons using the
-        inputMap"""
+        """
+        Initialize the reading and open the device with deviceId and set the
+        mapping for axis/buttons using the inputMap
+        """
         return
+
     def close(self, device_id):
         return
+
     def read(self, device_id):
         """Read input from the selected device."""
         raise NotImplemented()
@@ -47,6 +55,7 @@ PLUS = 4096
 
 
 class HandleWiimote(Thread):
+
     def __init__(self, reader, wii, *args):
         super(HandleWiimote, self).__init__(*args)
         self.reader = reader
@@ -90,9 +99,9 @@ class HandleWiimote(Thread):
                 self.reader.data['thrust'] = -1
 
             if button:
-                sample = max(max_sample, sample/3)
+                sample = max(max_sample, sample / 3)
             else:
-                sample = min(min_sample, sample*3)
+                sample = min(min_sample, sample * 3)
                 self.adjust()
             time.sleep(sample)
 
@@ -112,6 +121,7 @@ class HandleWiimote(Thread):
         else:
             self.reader.data['roll'] = 0
 
+
 class WiimoteReader(_Reader):
     name = MODULE_NAME
 
@@ -120,14 +130,14 @@ class WiimoteReader(_Reader):
         self.limit_thrust = False
         self.limit_yaw = False
 
-        print "Press 1 + 2 to connect wii"
+        print("Press 1 + 2 to connect wii")
         time.sleep(1)
         self.wm = cwiid.Wiimote()
         self.wm.rpt_mode = cwiid.RPT_BTN
         logger.info("FOUND WIIMOTE")
         self.data = {"roll": 0.0, "pitch": 0.0, "yaw": 0.0,
                      "thrust": -1.0, "estop": False, "exit": False,
-                     "althold": False, "alt1": False, "alt2": False,
+                     "assistedControl": False, "alt1": False, "alt2": False,
                      "pitchNeg": False, "rollNeg": False,
                      "pitchPos": False, "rollPos": False}
         self.wii_thread = HandleWiimote(self, self.wm)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/wiimote.pyc
deleted file mode 100755
index a7367d572ff1f96996c426106d5de2b58bd85b78..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.py
old mode 100755
new mode 100644
index f12f702d..0ff0e6bc
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#     ||          ____  _ __                           
-#  +------+      / __ )(_) /_______________ _____  ___ 
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
@@ -15,7 +15,7 @@
 #  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 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
@@ -30,22 +30,21 @@
 Input interface that supports receiving commands via ZMQ.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['ZMQReader']
+import logging
+from threading import Thread
+
+from cfclient.utils.config import Config
 
 try:
     import zmq
 except Exception as e:
     raise Exception("ZMQ library probably not installed ({})".format(e))
 
-from cfclient.utils.config import Config
 if not Config().get("enable_zmq_input"):
     raise Exception("ZMQ input disabled in config file")
 
-import logging
-import time
-import pprint
-from threading import Thread
+__author__ = 'Bitcraze AB'
+__all__ = ['ZMQReader']
 
 ZMQ_PULL_PORT = 1024 + 188
 
@@ -54,6 +53,7 @@ logger = logging.getLogger(__name__)
 MODULE_MAIN = "ZMQReader"
 MODULE_NAME = "ZMQ"
 
+
 class _PullReader(Thread):
 
     def __init__(self, receiver, callback, *args):
@@ -66,8 +66,10 @@ class _PullReader(Thread):
         while True:
             self._cb(self._receiver.recv_json())
 
+
 class ZMQReader:
     """Used for reading data from input devices using the PyGame API."""
+
     def __init__(self):
         context = zmq.Context()
         receiver = context.socket(zmq.PULL)
@@ -85,7 +87,7 @@ class ZMQReader:
 
         self.data = {"roll": 0.0, "pitch": 0.0, "yaw": 0.0,
                      "thrust": -1.0, "estop": False, "exit": False,
-                     "althold": False, "alt1": False, "alt2": False,
+                     "assistedControl": False, "alt1": False, "alt2": False,
                      "pitchNeg": False, "rollNeg": False,
                      "pitchPos": False, "rollPos": False}
 
@@ -95,12 +97,14 @@ class ZMQReader:
         self._receiver_thread.start()
 
     def _cmd_callback(self, cmd):
-        for k in cmd["ctrl"].keys():
+        for k in list(cmd["ctrl"].keys()):
             self.data[k] = cmd["ctrl"][k]
 
     def open(self, device_id):
-        """Initialize the reading and open the device with deviceId and set the mapping for axis/buttons using the
-        inputMap"""
+        """
+        Initialize the reading and open the device with deviceId and set the
+        mapping for axis/buttons using the inputMap
+        """
         return
 
     def read(self, device_id):
@@ -116,4 +120,3 @@ class ZMQReader:
         # As a temporary workaround we always say we have ZMQ
         # connected. If it's not connected, there's just no data.
         return [{"id": 0, "name": "ZMQ@{}".format(self._bind_addr)}]
-
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputinterfaces/zmqpull.pyc
deleted file mode 100755
index e1193a55587204f671f4fe287d21eeaa117ab9f1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4432
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
G_J0AuhZ}DI

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.py
old mode 100755
new mode 100644
index 7e41cd73..d6bb14c1
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.py
@@ -37,6 +37,7 @@ logger = logging.getLogger(__name__)
 
 
 class _ToggleState(dict):
+
     def __getattr__(self, attr):
         return self.get(attr)
 
@@ -45,11 +46,12 @@ class _ToggleState(dict):
 
 
 class InputData:
+
     def __init__(self):
-        #self._toggled = {}
+        # self._toggled = {}
         self._axes = ("roll", "pitch", "yaw", "thrust")
         self._buttons = ("alt1", "alt2", "estop", "exit", "pitchNeg",
-                         "pitchPos", "rollNeg", "rollPos", "althold",
+                         "pitchPos", "rollNeg", "rollPos", "assistedControl",
                          "muxswitch")
         for axis in self._axes:
             self.__dict__[axis] = 0.0
@@ -64,7 +66,7 @@ class InputData:
         return self._axes + self._buttons
 
     def _check_toggle(self, key, data):
-        if not key in self._prev_btn_values:
+        if key not in self._prev_btn_values:
             self._prev_btn_values[key] = data
         elif self._prev_btn_values[key] != data:
             self._prev_btn_values[key] = data
@@ -95,6 +97,7 @@ class InputData:
 
 
 class InputReaderInterface(object):
+
     def __init__(self, dev_name, dev_id, dev_reader):
         """Initialize the reader"""
         # Set if the device supports mapping and can be configured
@@ -122,7 +125,6 @@ class InputReaderInterface(object):
         # Stateful things
         self._old_thrust = 0
         self._old_raw_thrust = 0
-        self._old_alt_hold = False
 
         self._prev_thrust = 0
         self._last_time = 0
@@ -159,14 +161,16 @@ class InputReaderInterface(object):
         return [self._cap_rp(roll), self._cap_rp(pitch)]
 
     def _scale_and_deadband_yaw(self, yaw):
-        return InputReaderInterface.deadband(yaw, 0.2) * self.input.max_yaw_rate
+        return (InputReaderInterface.deadband(yaw, 0.2) *
+                self.input.max_yaw_rate)
 
-    def _limit_thrust(self, thrust, althold, emergency_stop):
+    def _limit_thrust(self, thrust, assisted_control, emergency_stop):
         # Thust limiting (slew, minimum and emergency stop)
         if self.input.springy_throttle:
-            if althold and self.input.has_pressure_sensor:
-                thrust = int(round(InputReaderInterface.deadband(thrust, 0.2)
-                                   * 32767 + 32767))  # Convert to uint16
+            if assisted_control and self.input.get_assisted_control() == \
+                    self.input.ASSISTED_CONTROL_ALTHOLD:
+                thrust = int(round(InputReaderInterface.deadband(thrust, 0.2) *
+                                   32767 + 32767))  # Convert to uint16
             else:
                 # Scale the thrust to percent (it's between 0 and 1)
                 thrust *= 100
@@ -190,8 +194,8 @@ class InputReaderInterface(object):
                         else:
                             # If we are "inside" the limit, then lower
                             # according to the rate we have set each iteration
-                            lowering = (time() - self._last_time) * \
-                                self.input.thrust_slew_rate
+                            lowering = ((time() - self._last_time) *
+                                        self.input.thrust_slew_rate)
                             limited_thrust = self._prev_thrust - lowering
                 elif emergency_stop or thrust < self.thrust_stop_limit:
                     # If the thrust have been pulled down or the
@@ -214,7 +218,8 @@ class InputReaderInterface(object):
                 thrust = limited_thrust
         else:
             thrust = thrust / 2 + 0.5
-            if althold and self.input.has_pressure_sensor:
+            if assisted_control and self.input.get_assisted_control() == \
+                    self.input.ASSISTED_CONTROL_ALTHOLD:
                 thrust = 32767
             else:
                 if thrust < -0.90 or emergency_stop:
@@ -224,14 +229,14 @@ class InputReaderInterface(object):
                         self.input.max_thrust -
                         self.input.min_thrust)
                 if (self.input.thrust_slew_enabled and
-                            self.input.thrust_slew_limit > thrust and not
-                emergency_stop):
+                    self.input.thrust_slew_limit > thrust and not
+                        emergency_stop):
                     if self._old_thrust > self.input.thrust_slew_limit:
                         self._old_thrust = self.input.thrust_slew_limit
                     if thrust < (self._old_thrust -
-                                     (self.input.thrust_slew_rate / 100)):
-                        thrust = self._old_thrust - \
-                                 self.input.thrust_slew_rate / 100
+                                 self.input.thrust_slew_rate / 100):
+                        thrust = (self._old_thrust -
+                                  self.input.thrust_slew_rate / 100)
                     if thrust < -1 or thrust < self.input.min_thrust:
                         thrust = 0
 
@@ -239,14 +244,6 @@ class InputReaderInterface(object):
         self._old_raw_thrust = thrust
         return thrust
 
-    def set_alt_hold_available(self, available):
-        """Set if altitude hold is available or not (depending on HW)"""
-        self.input._has_pressure_sensor = available
-
-    def enable_alt_hold(self, althold):
-        """Enable or disable altitude hold"""
-        self._old_alt_hold = althold
-
     @staticmethod
     def deadband(value, threshold):
         if abs(value) < threshold:
@@ -255,4 +252,4 @@ class InputReaderInterface(object):
             value -= threshold
         elif value < 0:
             value += threshold
-        return value / (1 - threshold)
\ No newline at end of file
+        return value / (1 - threshold)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaderinterface.pyc
deleted file mode 100755
index b768cf698b267463801adcd5ac995978e6ad369c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8721
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
N0_wbfZ2IV>{{p8c|JMKj

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.py
old mode 100755
new mode 100644
index 11d1a8fe..978132fb
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.py
@@ -33,37 +33,41 @@ To create a new input device reader drop a .py file into this
 directory and it will be picked up automatically.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['InputDevice']
-
-import os
-import glob
 import logging
 from ..inputreaderinterface import InputReaderInterface
 
+__author__ = 'Bitcraze AB'
+__all__ = ['InputDevice']
+
 logger = logging.getLogger(__name__)
 
-found_readers = [os.path.splitext(os.path.basename(f))[0] for
-                 f in glob.glob(os.path.dirname(__file__) + "/[A-Za-z]*.py")]
-if len(found_readers) == 0:
-    found_readers = [os.path.splitext(os.path.basename(f))[0] for
-                     f in glob.glob(os.path.dirname(__file__) +
-                                    "/[A-Za-z]*.pyc")]
 
-logger.info("Found readers: {}".format(found_readers))
+# Forces py2exe to include the input readers in the windows build
+try:
+    from . import pysdl2  # noqa
+    from . import linuxjsdev  # noqa
+except Exception:
+    pass
+
+# Statically listing the available input readers
+input_readers = ["linuxjsdev",
+                 "pysdl2"]
+
+logger.info("Input readers: {}".format(input_readers))
 
 initialized_readers = []
 available_devices = []
 
-for reader in found_readers:
+for reader in input_readers:
     try:
-        module = __import__(reader, globals(), locals(), [reader], -1)
+        module = __import__(reader, globals(), locals(), [reader], 1)
         main_name = getattr(module, "MODULE_MAIN")
         initialized_readers.append(getattr(module, main_name)())
         logger.info("Successfully initialized [{}]".format(reader))
     except Exception as e:
         logger.info("Could not initialize [{}]: {}".format(reader, e))
 
+
 def devices():
     # Todo: Support rescanning and adding/removing devices
     if len(available_devices) == 0:
@@ -77,6 +81,7 @@ def devices():
 
 
 class InputDevice(InputReaderInterface):
+
     def __init__(self, dev_name, dev_id, dev_reader):
         super(InputDevice, self).__init__(dev_name, dev_id, dev_reader)
 
@@ -135,7 +140,7 @@ class InputDevice(InputReaderInterface):
                                                                self.data.pitch)
         if self.limit_thrust:
             self.data.thrust = self._limit_thrust(self.data.thrust,
-                                                  self.data.althold,
+                                                  self.data.assistedControl,
                                                   self.data.estop)
         if self.limit_yaw:
             self.data.yaw = self._scale_and_deadband_yaw(self.data.yaw)
@@ -143,4 +148,4 @@ class InputDevice(InputReaderInterface):
         if include_raw:
             return [axis, buttons, self.data]
         else:
-            return self.data
\ No newline at end of file
+            return self.data
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/__init__.pyc
deleted file mode 100755
index fbb91527005546476a12468b4d18d99d6b80b392..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4311
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
GrT+qP1<Mrx

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.py
old mode 100755
new mode 100644
index a0fee1ba..aaedd429
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.py
@@ -1,4 +1,4 @@
-# -*- coding: utf8 -*-
+# -*- coding: utf-8 -*-
 #     ||
 #  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
@@ -22,30 +22,32 @@
 #  You should have received a copy of the GNU General Public License
 #  along with this program; if not, write to the Free Software Foundation,
 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
 """
 Linux joystick driver using the Linux input_joystick subsystem. Requires sysfs
 to be mounted on /sys and /dev/input/js* to be readable.
 
 This module is very linux specific but should work on any CPU platform
 """
-
+import ctypes
+import glob
+import logging
+import os
+import struct
 import sys
+
 if not sys.platform.startswith('linux'):
     raise Exception("Only supported on Linux")
 
-import struct
-import glob
-import os
-import ctypes
-import fcntl
-import logging
-
-logger = logging.getLogger(__name__)
+try:
+    import fcntl
+except ImportError as e:
+    raise Exception("fcntl library probably not installed ({})".format(e))
 
 __author__ = 'Bitcraze AB'
 __all__ = ['Joystick']
 
+logger = logging.getLogger(__name__)
+
 JS_EVENT_FMT = "@IhBB"
 JE_TIME = 0
 JE_VALUE = 1
@@ -56,31 +58,36 @@ JS_EVENT_BUTTON = 0x001
 JS_EVENT_AXIS = 0x002
 JS_EVENT_INIT = 0x080
 
-#ioctls
+# ioctls
 JSIOCGAXES = 0x80016a11
 JSIOCGBUTTONS = 0x80016a12
 
 MODULE_MAIN = "Joystick"
 MODULE_NAME = "linuxjsdev"
 
+
 class JEvent(object):
     """
     Joystick event class. Encapsulate single joystick event.
     """
+
     def __init__(self, evt_type, number, value):
         self.type = evt_type
         self.number = number
         self.value = value
 
     def __repr__(self):
-        return "JEvent(type={}, number={}, value={})".format(self.type,
-                   self.number, self.value)
+        return "JEvent(type={}, number={}, value={})".format(
+            self.type, self.number, self.value)
+
 
-#Constants
+# Constants
 TYPE_BUTTON = 1
 TYPE_AXIS = 2
 
+
 class _JS():
+
     def __init__(self, num, name):
         self.num = num
         self.name = name
@@ -97,10 +104,10 @@ class _JS():
             raise Exception("{} at {} is already "
                             "opened".format(self.name, self._f_name))
 
-        self._f = open("/dev/input/js{}".format(self.num), "r")
+        self._f = open("/dev/input/js{}".format(self.num), "rb")
         fcntl.fcntl(self._f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
 
-        #Get number of axis and button
+        # Get number of axis and button
         val = ctypes.c_int()
         if fcntl.ioctl(self._f.fileno(), JSIOCGAXES, val) != 0:
             self._f.close()
@@ -142,7 +149,7 @@ class _JS():
 
     def __decode_event(self, jsdata):
         """ Decode a jsdev event into a dict """
-        #TODO: Add timestamp?
+        # TODO: Add timestamp?
         if jsdata[JE_TYPE] & JS_EVENT_AXIS != 0:
             return JEvent(evt_type=TYPE_AXIS,
                           number=jsdata[JE_NUMBER],
@@ -165,6 +172,8 @@ class _JS():
                 self._f.close()
                 self._f = None
                 raise IOError("Device has been disconnected")
+        except TypeError:
+            pass
         except ValueError:
             # This will happen if I/O operations are done on a closed device,
             # which is the case when you first close and then open the device
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/linuxjsdev.pyc
deleted file mode 100755
index 4816fdfea45669fd14e80ae7cff76c50a9c7465c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 9030
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
ZZMFt45~cjJEqn>BvsF8OkoD2c{{o;!B+vi=

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.py
old mode 100755
new mode 100644
index f998ad8e..5039f3a9
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.py
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-#     ||          ____  _ __                           
-#  +------+      / __ )(_) /_______________ _____  ___ 
+#     ||          ____  _ __
+#  +------+      / __ )(_) /_______________ _____  ___
 #  | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 #  +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 #   ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
@@ -15,45 +15,49 @@
 #  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 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, write to the Free Software
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 #  USA.
-
 """
 Driver for reading data from the PySDL2 API. Used from Inpyt.py for reading
 input data.
 """
-
+import logging
 import sys
+import time
+from threading import Thread
+
+from queue import Queue
+
 if sys.platform.startswith('linux'):
     raise Exception("No SDL2 support on Linux")
 
+try:
+    import sdl2
+    import sdl2.ext
+    import sdl2.hints
+except ImportError as e:
+    raise Exception("sdl2 library probably not installed ({})".format(e))
+
 __author__ = 'Bitcraze AB'
 __all__ = ['PySDL2Reader']
 
-import sdl2
-import sdl2.ext
-import sdl2.hints
-from threading import Thread
-from Queue import Queue
-import time
-import logging
-
 logger = logging.getLogger(__name__)
 
 MODULE_MAIN = "PySDL2Reader"
 MODULE_NAME = "PySDL2"
 
+
 class _SDLEventDispatcher(Thread):
     """Wrapper to read all SDL2 events from the global queue and distribute
     them to the different devices"""
+
     def __init__(self, callback):
         Thread.__init__(self)
         self._callback = callback
@@ -77,12 +81,12 @@ class _SDLEventDispatcher(Thread):
 
 class _JS():
     """Wrapper for one input device"""
+
     def __init__(self, sdl_index, sdl_id, name):
         self.axes = []
         self.buttons = []
         self.name = MODULE_NAME
         self._j = None
-        self._btn_count = 0
         self._id = sdl_id
         self._index = sdl_index
         self._name = name
@@ -90,25 +94,40 @@ class _JS():
 
     def open(self):
         self._j = sdl2.SDL_JoystickOpen(self._index)
-        self._btn_count = sdl2.SDL_JoystickNumButtons(self._j)
+        btn_count = sdl2.SDL_JoystickNumButtons(self._j)
 
         self.axes = list(0 for i in range(sdl2.SDL_JoystickNumAxes(self._j)))
-        self.buttons = list(0 for i in range(sdl2.SDL_JoystickNumButtons(
-            self._j) + 4))
+        self.buttons = list(0 for i in range(btn_count + 4))
 
     def close(self):
         if self._j:
             sdl2.joystick.SDL_JoystickClose(self._j)
         self._j = None
 
-    def _set_fake_hat_button(self, btn=None):
-        self.buttons[self._btn_count] = 0
-        self.buttons[self._btn_count+1] = 0
-        self.buttons[self._btn_count+2] = 0
-        self.buttons[self._btn_count+3] = 0
-
-        if btn:
-            self.buttons[self._btn_count+btn] = 1
+    def _set_virtual_dpad(self, position):
+        self.buttons[-4:] = [0, 0, 0, 0]
+
+        # -4 UP -3 DOWN -2 LEFT -1 RIGHT
+        if position == sdl2.SDL_HAT_UP:
+            self.buttons[-4] = 1
+        elif position == sdl2.SDL_HAT_RIGHTUP:
+            self.buttons[-4] = 1
+            self.buttons[-1] = 1
+        elif position == sdl2.SDL_HAT_RIGHT:
+            self.buttons[-1] = 1
+        elif position == sdl2.SDL_HAT_RIGHTDOWN:
+            self.buttons[-1] = 1
+            self.buttons[-3] = 1
+        elif position == sdl2.SDL_HAT_DOWN:
+            self.buttons[-3] = 1
+        elif position == sdl2.SDL_HAT_LEFTDOWN:
+            self.buttons[-3] = 1
+            self.buttons[-2] = 1
+        elif position == sdl2.SDL_HAT_LEFT:
+            self.buttons[-2] = 1
+        elif position == sdl2.SDL_HAT_LEFTUP:
+            self.buttons[-2] = 1
+            self.buttons[-4] = 1
 
     def add_event(self, event):
         self._event_queue.put(event)
@@ -126,25 +145,18 @@ class _JS():
                 self.buttons[e.jbutton.button] = 0
 
             if e.type == sdl2.SDL_JOYHATMOTION:
-                if e.jhat.value == sdl2.SDL_HAT_CENTERED:
-                    self._set_fake_hat_button()
-                elif e.jhat.value == sdl2.SDL_HAT_UP:
-                    self._set_fake_hat_button(0)
-                elif e.jhat.value == sdl2.SDL_HAT_DOWN:
-                    self._set_fake_hat_button(1)
-                elif e.jhat.value == sdl2.SDL_HAT_LEFT:
-                    self._set_fake_hat_button(2)
-                elif e.jhat.value == sdl2.SDL_HAT_RIGHT:
-                    self._set_fake_hat_button(3)
+                self._set_virtual_dpad(e.jhat.value)
+
         return [self.axes, self.buttons]
 
+
 class PySDL2Reader():
     """Used for reading data from input devices using the PySDL2 API."""
+
     def __init__(self):
-        sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO | sdl2.SDL_INIT_JOYSTICK)
+        sdl2.SDL_Init(sdl2.SDL_INIT_JOYSTICK)
         sdl2.SDL_SetHint(sdl2.hints.SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
-                         "1")
-        sdl2.ext.init()
+                         b"1")
         self._js = {}
         self.name = MODULE_NAME
         self._event_dispatcher = _SDLEventDispatcher(self._dispatch_events)
@@ -178,7 +190,7 @@ class PySDL2Reader():
             logger.info("Found {} devices".format(nbrOfInputs))
             for sdl_index in range(0, nbrOfInputs):
                 j = sdl2.joystick.SDL_JoystickOpen(sdl_index)
-                name = sdl2.joystick.SDL_JoystickName(j)
+                name = sdl2.joystick.SDL_JoystickName(j).decode("UTF-8")
                 if names.count(name) > 0:
                     name = "{0} #{1}".format(name, names.count(name) + 1)
                 sdl_id = sdl2.joystick.SDL_JoystickInstanceID(j)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/inputreaders/pysdl2.pyc
deleted file mode 100755
index 141afec89ad6dd1d4462cddb511db7cfad27c97d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 8270
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
BNXY;I

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.py
old mode 100755
new mode 100644
index 402c4d87..63a300e1
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.py
@@ -20,7 +20,6 @@
 #  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, write to the Free Software
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
@@ -29,16 +28,16 @@
 The mux is used to open one or more devices and mix the inputs from all
 of them into one "input" for the Crazyflie and UI.
 """
+import logging
 
 __author__ = 'Bitcraze AB'
 __all__ = ['InputMux']
 
-import logging
-
 logger = logging.getLogger(__name__)
 
 
 class InputMux(object):
+
     def __init__(self, input_layer):
         self._devs = {"Device": None}
         self.name = "N/A"
@@ -49,34 +48,46 @@ class InputMux(object):
         for r in self._devs:
             if self._devs[r]:
                 if self._devs[r] == dev:
-                    self._devs[r].close()
                     self._devs[r] = None
+                    dev.close()
+
+        # First set role to None to stop reading
+        old_dev = self._devs[role]
+        self._devs[role] = None
+        if old_dev:
+            old_dev.close()
 
-        if self._devs[role]:
-            self._devs[role].close()
+        # Open the new device before attaching it to a role
+        dev.open()
         self._devs[role] = dev
-        self._devs[role].open()
 
     def supported_roles(self):
-        return self._devs.keys()
+        return list(self._devs.keys())
 
     def add_device(self, dev, role):
         logger.info("Adding device {} to MUX {}".format(dev.name, self.name))
         self._open_new_device(dev, role)
 
     def pause(self):
-        for d in [key for key in self._devs.keys() if self._devs[key]]:
+        for d in [key for key in list(self._devs.keys()) if self._devs[key]]:
             self._devs[d].close()
 
+    def devices(self):
+        devs = ()
+        for d in self._devs:
+            if self._devs[d]:
+                devs += (self._devs[d], )
+        return devs
+
     def resume(self):
-        for d in [key for key in self._devs.keys() if self._devs[key]]:
+        for d in [key for key in list(self._devs.keys()) if self._devs[key]]:
             self._devs[d].open()
 
     def close(self):
         """Close down the MUX and close all it's devices"""
-        for d in [key for key in self._devs.keys() if self._devs[key]]:
+        for d in [key for key in list(self._devs.keys()) if self._devs[key]]:
             self._devs[d].close()
             self._devs[d] = None
 
     def read(self):
-        return None
\ No newline at end of file
+        return None
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/__init__.pyc
deleted file mode 100755
index ac147b6b3038f7b89e9ebfa6ad78bc2bf1f8f8e2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3102
zcmc&$TW{P{5I(jyo9xoiloUdEsa2t}MM{l?l&2MtrV_o-1)PM^h}PQJXE)w@?Tyb_
znn3at{slji9{}Gs-b*SF5)W*XoXO0b+sro?AMcOV=EL~O53!p3c=-PnhItH<D0K+x
zs6$63uIhtvRpP0nrZP_*dP;k0P*ZwIU1F-vHF{a~uy{%RrqrcU&kt9)daqUIndczQ
z{bTJ9$ESX3{ISuAZwtQ|>D(`J?H8p#EK2Ps`sXy(#_#5dKTJ=3i#=&R8e8M{%3|nu
zv#eS4s2)Pk6R`QVthnv>a0)l<mfc^@dReOFn1e_6n&urCa6h#%X0*R^->yJ@#B-mH
zPt!l~)0qL`a4ClQ4nzY8c%|qSA#j8N5Uwyag2JgKI!gvv2n2`ADyfSGI4ld(P~l#S
z7soCL2QlBpFn2&wxd%6F1FcAKC*!JfN0Gs$3V3o)#}d^C6;`4Mc3L&4EJ+8L*d;I#
z&@`gTyTeK)NVRyk=#9>Lme`0s%DQK|Y(Z2)%yV$TaWT}v(FD6-R2BmrTN4mU0eLG1
z(z!KTqceM4<Uy7m1#z!Z24kCMCXmwu#6F0kG*4|5-NRx+F_k|BZ|IbA)|`eD(<%DG
zAqf2r=JbF-4B+{T$LhkH2<M*KESpyZ;PuK?<^C1bz+p~0iJI%$C;RH8$-igSq315n
zIh!tkFxix2lSBX)V@-R$df-h@-D@#xIue7BwhR7oRu~=5z-F>nE9j`@G6YECP!^fC
zJYsR^ui>_cCPle^%}hbv1<;xIK$N@YtUBw?4QIn$b#8)>Y29>4L{_1wu&98VVnBZ@
z3>dsu`pgJ8A)Q`WZe7P^W;_}drPWD9cukus8mFrCBL1`V`W%8qZlUZPHISM^bm<;q
z?6S)_6l#(RkX=cpJ*lLQ`3Sprk|fRhlLqGhdcpSg^x#KuE!Lt`Y*zI9x|E2gd9M&1
zn%1yuLs}BP3nB$BV1+Eq@EUa(3n|Ga?&&7UBptqlWN4UjZdD2J24>%4;`E{FznKOP
zUTmt1S-m)@sda+((p4wxDBKNo0d%E`S#W^*633r>rk*A2ZdDoa8cCs$aSR(Eb6BKs
zkXBMJ$-<yv5Jz2nxOTxzP}zQ)s4!M@RKoWmh96Lev5;h8L6_Q$hx%)9{{qQRm`3mZ
zZ;A5pKPC#QbCx`9$r=Y)!>Tr0AiM0iep0;7<srcO<4ZysG2ae;YCkd4N5++QJ<l^~
z*KZS6$@V97NIr+|Hk$C?n=h;KO2M#fD$9jiXse|urS2x*)8?wbwwRlf?>nC!QDmu!
zqG6GYGl<~|L}_;+zeC|ok`0m%Nm%gVCdfROh5LUWBq1(TcQFiYsymIP#%jZB)a19`
zqEU7kB#M$Ep1IT=<JD6_tfr7;6Q0c;Uj)m2eQm#y-XHQ)5#HcY3{r8#$CO;WP*){3
W?J62y+=3y7@u|CT+P&sp_x=LI*0}fp

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.py
old mode 100755
new mode 100644
index d32965a1..ba4d51f0
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.py
@@ -20,7 +20,6 @@
 #  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, write to the Free Software
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
@@ -28,16 +27,18 @@
 """
 This mux will only use one device and not mix it with any other input.
 """
+import logging
+
+from . import InputMux
 
 __author__ = 'Bitcraze AB'
 __all__ = ['NoMux']
 
-from . import InputMux
-import logging
 logger = logging.getLogger(__name__)
 
 
 class NoMux(InputMux):
+
     def __init__(self, *args):
         super(NoMux, self).__init__(*args)
         self.name = "Normal"
@@ -49,4 +50,4 @@ class NoMux(InputMux):
 
             return data
         else:
-            return None
\ No newline at end of file
+            return None
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/nomux.pyc
deleted file mode 100755
index 295adbfe806ffd6abffdc7e855a0a8fdd5e6bced..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1267
zcmchW&2G~`5XWcjd^DjINJvO<Kt6CV60HwNoGJtbi6S5e7gZvcmFwLk8?EigyM_jp
zQ#tasJOKP>69O+lt?YPac6L4Un@RlhV0>D>J1=Sb#CX5Ja#ILJgqIRD6{I4XLy1Vm
zq<Umys(Li-kx+e71G0UZ_DT0?IUqfxYlQCc8Qr594iD)&(KXSh>4>Ax(mnphDa82W
z!nmaBE|V|D+N7!NI_aE-q7$V*n^Gr5t&+O&No6h*;}Pc<@U4@^FLaxjde!-(vAc!K
zPK+<x;;T+xp7=iON%Nt*Gy+=6!t+<(ay+|#;hF3T=lv5b_W(kpaAZxKHJ2=c5>tMb
zM%XSnm=&h=2FpE#@c0S3LY)yUBf1jwgMcTvWK2i{7XryMgh)UmVBiZTe!#M6tHK8L
zbtpS!Z>Yj`E8XU>HU&s&YU8E!J$UM((m|O3ScsOO=0cjm@3fr-rD*3a<x7Ha=g_i6
zQ|att3oTo<%~F@%Wz29rvqm455Vd!QtF>P=b!N>)R?argtn<dYEa1=3zpQQ`k5=oP
z$v?(&TmgxDVkCCNnA$7edjbIv%P?Q}+eiNxOTnY^4d4WwF{XfuPfl_M7O3Ui%TQRW
z3zZMq&msBfk6#tOxS4`^^p3C`=S1Q_+>Lrs%IyggCna|Y4I9HFW!0$8!VH{pKKnPz
zp#9I@;A`P?j<XwxQ9tFRJmZs6HRUeLqC>}9n47J_TIh(PJp7Z`Yn%Dp)N{|o=i0xA
mi8(!h6~>siw{v@Q1qR^98^q5aA{Dm}F^EuVbVuxq+wpIm)glrA

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.py
old mode 100755
new mode 100644
index d4cccf3e..8295e202
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.py
@@ -20,7 +20,6 @@
 #  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, write to the Free Software
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
@@ -30,21 +29,22 @@ Mux for giving control to one device (slave/student) for all axis (roll/pitch/
 yaw/thrust) with the ability to take over all of them from a second device
 (master/teacher).
 """
-
-__author__ = 'Bitcraze AB'
-__all__ = ['SelectiveMux']
-
 import logging
 
 from .takeoverselectivemux import TakeOverSelectiveMux
 
+__author__ = 'Bitcraze AB'
+__all__ = ['TakeOverMux']
+
 logger = logging.getLogger(__name__)
 
 
 class TakeOverMux(TakeOverSelectiveMux):
+
     def __init__(self, *args):
         super(TakeOverMux, self).__init__(*args)
         self.name = "Teacher (RPYT)"
-        self._muxing = {self._master: ("estop", "alt1", "alt2", "althold",
-                                       "exit"),
-                        self._slave: ("roll", "pitch", "yaw", "thrust")}
\ No newline at end of file
+        self._muxing = {
+            self._master: ("estop", "alt1", "alt2", "assistedControl", "exit"),
+            self._slave: ("roll", "pitch", "yaw", "thrust")
+        }
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeovermux.pyc
deleted file mode 100755
index 02296e8241ecfc48e3669cb25e0c5d3c2052fd54..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1396
zcmcgs&2G~`5FXn}+N3Q%65_l^SE9A(ffGWd7m$F0k_xF2lI7YPd&AmmdB<sjdMig>
zg{R{IU}o)<K0%|*cy>Jh->ic_2b1^dhp#F0zkr^nM0QRr1E5Fd!Q6w)hnxf-vH-FH
z=m6#<3?UnV9zZ#S`4BuAz;Xm~2X4u97qT6YLs*dWF8l<z1-P7#*?Sg_Imd5elTYnh
zEKDPEwNh0sQd41Lv_K<FB}FDzDwQI%I$6ocVw=ed51m7zwMf>=ijeGeR4Yu2XtGJJ
zBP^QMlGU}sLSP|9a;3Dw4F|>KyA)<68^Qi&!S744XiO;*VI`%{`lOSvOf1SKLYbt6
zYz~hnc8@APqeM;eLyEU&xKHPq)G|f2lGKU%OTTmFkve3C&xl=6%FmSXz9Dj??F(|e
z1Ax8Gi0o5hk^rFT0Z)%cKb^UtDckr&BcgXi_LLaX--8<(vkyxjZanw};1PJFiUUxD
z+#buz0ldogoiv13{Bpz@X5j$^Ik%69Uvv$NaQfx);t+?Vk`_&k1CkPrFSo)8?sS^M
z=*%hQTA>pd6X)r0LEbBZ2D#)8o{+=ZyV!Ocdn=sSd$FC8V~1?!PMpBGy9BmRVDBYh
ze^-KSYuQYBVz^5zj#Z^Fj$NHqQcBlF+@b9%jNQ8RYC^TjL+9<1OTFm&Z*m(_IB?8<
zBPl9ODWj`?L87`bOIi&Z@xE*pTFIl7ScUee-e6&>NUN(TU3AK*MWt<|s=CFfY}XO5
zDsL*u$Mt5)_#6@02{G`Vdt)!~CSJ&$_kD3Q)E67XacQzv)6qHpFZ6+`<$1jzvTjkm
zkZbA&8fPZGD>7+m4h<a{tT?7S*~{AGInCW&pzR>+_NLK9rtW(2XC#;Sk&FppzHAOZ
hcJ2{>=*Arque;g55mb=nZ^XzSd1HUyf8sw5{sE<!VW<EA

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.py
old mode 100755
new mode 100644
index cde7af02..40207d53
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.py
@@ -31,17 +31,18 @@ from a second device (master/teacher) with the possibility to take over
 roll/pitch as well.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['TakeOverSelectiveMux']
-
 import logging
 
 from . import InputMux
 
+__author__ = 'Bitcraze AB'
+__all__ = ['TakeOverSelectiveMux']
+
 logger = logging.getLogger(__name__)
 
 
 class TakeOverSelectiveMux(InputMux):
+
     def __init__(self, *args):
         super(TakeOverSelectiveMux, self).__init__(*args)
         self._master = "Teacher"
@@ -49,9 +50,11 @@ class TakeOverSelectiveMux(InputMux):
         self.name = "Teacher (RP)"
         self._devs = {self._master: None, self._slave: None}
 
-        self._muxing = {self._master: ("thrust", "yaw", "estop", "alt1", "alt2",
-                                       "althold", "exit"),
-                        self._slave: ("roll", "pitch")}
+        self._muxing = {
+            self._master: ("thrust", "yaw", "estop", "alt1", "alt2",
+                           "assistedControl", "exit"),
+            self._slave: ("roll", "pitch")
+        }
 
     def read(self):
         try:
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/input/mux/takeoverselectivemux.pyc
deleted file mode 100755
index e24f03584f76f52794220b9cdbf47b64a85ffe4d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2001
zcmc&!UvJ|?5TCW3q)D&W)A8p3fmnEQrR!Oo(1{0xpnw1Y1v#fXh=eTH-Xu;PJ9sy3
zg4(C@h{OXgd<8xOFMKCH0Q_d0rYAlC=VWJRXXnrE%x~8JdvEZ0_T`g|HlL6ALkv3t
z$%!!KibjfZk0xL|%6-ZMDt#J(=}_LKGN5^fMjcYdr&*UwkFKD)!#1WvV;J}7XQC^j
z??-*M9)>#{;}4L**UOb2*Nx8V$~ARa7S%-a94!i$P4&2`=en+p&dpho86Da(Ju{JY
z%iL7%K&Mr%-PGvDST_*mR9gdQ`PO2dT4$QbnKYZ4=0KkpZYnm5+S=lzC=0jNuGTI+
zHM%}C&ET2%snzGEEFTQ)E>3%dGd1Z?Mt^kVUc~w_Oum7|(3B=~#hJlvihuAO7Yf@U
z6UTS`qFO8+Hn)l9og)nU8i+xnktO0Raf+2NKE=b(!*<5X%&@1=Fl-It@K<z!ym~bA
z=t9viL<+VLC8!NVU;-`}GaV}6nV6sX^k~Bc^oTcmvbne2ye-^j6NMy{Y#%X?T@Une
zn@Qn^Z6WNf8@UeSZx39Tk2r0X);R{%Iz4wC%qUa6Z~?fqbnjd<55*TG)4I$>XjX+2
zhHD{~f`^df+Z*3@<J)e1+iTy~%tOmI8{Z;i-;!8aaR4!I1N5OR@$7P8ni#9Lf=N<T
zg-a4SY0_d!E|~}-<*ZdYH^LkPvEn2FZ0*Jb(5NO7S9Gi?$HJt|#D*M4hy@rZn$~j@
zoovt+Et+};eA$S>w;q>;Im|#RXAc)^<gALy;v~w(tuR`;qO?)Lkc;NaRm8w%Tq9zO
zQV1U`*70pbI>fMdKuEo;`tp0j^VL8J=s2r9KE|+rfvkTQWVA3+^lJ0lGi&cZYwQDR
zS45Wr%2{g#t&LPbI}6DEN~?FpPe&*;KKbEIx&&|)KPVSqfbkwPcv*mV^<zO#EBI41
zWN<#M-lD+u>2yHNpQJ7WQf@%AUAhR^Lb1+wOr#@^Lq==-0ux4c%=ed4G$zgAh6ow5
zcqg)H%xx|Rwx&h$#JKn_3t8{eRc02hz}v-`EbGa{G*a&Kw5hn<oW1xZR_6xJ=j~+0
z<EdGrgV7VurTX^}`8^E#3J57*X&`_xa8GG3@OHd?wWmVvCV9b<gwYNB4<JdBd7Upy
zECoa{`?|Tr|BYh=r~4Sv&Rx~t4f%|1*ClzKZ4aF;(Jak%4<~6^Zg?&ns)Z*N)sjb>
qi;GHsB^8a|X8G$(FrME{r4aA8ssBLZB=YQbJ>1#5<=yf2{eJ-?TiO@^

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/__init__.pyc
deleted file mode 100755
index f98770b26655e6ba6ee2e856607abb6defe8a526..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 245
zcmYL@K?=e^3`Iv>C<U(|UDk!>0wSKkjUwV^Xs0PntsR-9i+Tai;5og3859iU<^N9z
znY`!8bNM<t^Q)20oi-<m(wK{KWDeOlW}rw;c_80&+6%QLgsK?Jv=~yUG3t;~Cm5>S
z;X2u8@uEx>)|TE`o2fK^@L4U?{)SMHxR5^(?!h<cgdy6YY6(|P(Fw2agVer*mI`py
iH-z{JL*oY)a#ygHIudKwx;xY3o0~8D7Pkx4tZhDNA3`z!

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/linuxjsdev.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/joystick/linuxjsdev.pyc
deleted file mode 100755
index 45bc0a261684b6e4666f9b7509e4b3d94ebc7c92..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 9305
zcmc&)OK;rP6~5$*Mw-#XmMzJa?bbvZH*#uADbUzx>!yB4PUP6*gpwao<FFJ-NgPq+
zh?iqajtvxXfEGo8B4{_+6xkGAbX8>0MFVu#ZJTXZU3Fa`KOp_Sb2%f)d2~@k(U^z#
z{W|A-=iEbAJ{fNO{Pg>afhzwhcwfY$KLrVuS^~9HXsg6hOGucst(NR=x}ugU-E>tg
zRlDgvwba*5*VIz2o9<Uj{VM8LtpOF))e{WcP*GL22GtYHRZ;5|mH$#jLn^GY_8m*5
zD932SD#SP=D#Qo}R5+lP4yv%OmPV!Ikdz!&VM8sAsc=v&jjM1-ElsF!SVc$F3RXU%
z-c_9CjisZ~XHxncQz3@KC<lAh$GPK$sY5)7k3kyO<FvEow6bko#KF1~=JEX~cRD&w
zSDj)la!h@kwmXH_Yo$BO8XcmIX~&H=J8>Rq2L&s-QDn|?<ZNV}w1`3{OPv{%JAN8E
zGhuXpM#h<G>E|8OFpvDuUrwUwMq_a;*60{^lE^^{tJroDS)6W1LA(+N&T^-4^jg+Q
zLgzu2uXA`m-FB|LcFSoeezB6}8;$r={56X{>`j)gPa-8_ms?{`&8}u=S(<EXw!S#O
zcKLFQgo-T^n}k9W{|qEyYP4l5$P1H)Bw5suyf$|~N{av~`D5qHc(el&LC(M)P?0Jy
zi6Ui_9grt?VTxmEHg7oiyVhkx#37v^@wJ|I=F-4#>kf7pIphltsK*IuI4zxnDu&_1
zm0!UlTYqG!M@o50J+dW%Y()}Skb)#|xlLI{!M??IJCa?cosH!vmvg-DC!J_YYDsjI
ztP}%CME47i?OkrdWz`fOLp0P&&8%e`(adsO1iAk(nrY`*D+&rd!|e7-5=UnPkhIWe
z+uOxjmd+&c@=UN|3THY+oamYEPEiLzZD~l+G+J|h&x_Nz@VtviYjQ$ab^HQui4RvK
z=WqfE=ywZ;pj1l^1ngtFqMlT62t2W-eiqa)bBf#g(c6#DIOZ56DaU}+X>$~ukP_z?
zF1znK1kUYJr1twb@~EAA-W+Du+`F=dtSPReJgwB<h&-=opv3cxrXkxe*)R({&t=-J
zgY2waQeQDQU7pwlJi^6VrDoOpWX)ZD2v8?~Y)Ea<4?(_Mxd6EDLd$^ERY?G*`y|m%
zv}M%*p^}L@(UOS<VV8+PqAe2u>p@8XqlY9hLbV;{8h!vGnrDziWYdW^+DWtlq4tXy
zAd{^Kigq_*RNAO3_rj;Au9Ve6WYn|Ns!7=01YpCIi0Ogsdf1RD=~sX)mS96vX_02Z
z!71`mboi>DXrtI!J4&Na*bY1`vQ&%W`&*GoG_%w+Z0VIai3$z@rHg~ei$mdxfcOo+
zUGNmVb{^d)(K-qRP4-vxjm%;pdIZEE08yZa1e9s&svyCykif}4ws_FM1E2yd@nc(U
zwF!{3_tw<oiYicT6C7Gqq9s}YvQM&Mm8Xd!2-gwhe?6%lBj2Z5HCo?RKk4I|x)WB_
z>vsXYa0OsU9>I0!Q|BImV>NXS{jALs>JF+GrnowdwHQI74RE8Plc%tmP8bJ;^B^wP
zoZk66zIN85Z84~((4khdSm25B<|l~=7zd*T52FI83u|mTXk#r{tH&@g4fKpynjPyb
z#!nBi)^wWTEKM8=%wZ_<!U7{+RTQo!*>X`~ZCXgH%m`E4FV;k6mVF(ui}a-kN`mHJ
z#8Ve}+!njzw^13&xriW%pq49_k+58js@)Tq&gBlIn1fSZ-J>Ykfv>L^xr)P>Z8a(`
z-S^{!j?AoRiv9_T^+6ETSF;b;!`2DwuyxcrX$L$co*17ic=U(BfEWlQLUxX?ijr3q
zFDN@ChK2p+HK5KxT7XjWYM9p`WDA;TsTlH!+96XsY+fVgb-*-&G#W=hyZ{Jz{)GPF
zLg^>;DR2QUBSaZPw)#Z)52+`n&wv6PwCYkdpjr)zJ4*&tF{E0<G^SQDqFM(;51>e>
zJGi&?sAv>4=&<<1M=ef+u`ma;7v~v{aZckL7w~t-iMqu&yR{}*HH!!TxZ@+AH^b4r
zGd%pCGfaHR43o0@V`g#3Wl|_J&THxjnRf@Ir))PNxuS7hpQY5eX=hQ?u*6V$x2y27
zQ)d~9+!Y+Jl=0qZfGP85G$l(C(Udm4sWnlxZT~^p=0ATG)hX8UjxIzSq*dT2qCGkK
zGEG+iAfL5m#Aqunq#8AASz@4F`Zc4~UO%P>&`&B}gH{u;I3UtZeE^v~e*N2zft_do
zgM`!h2FO(?2CxV2K9#-nrv#>8aDuM=Bd};b;~?Pdy+LAhsMKw16S6|26zoAQyj4=k
z3)D=%Aaln1ru3R7@xm(1=vF&_31X`>7gtmN?{?hpVHo#CkgsVkzu4K!)CsPIHdUl0
z^b6meU=cawlJSDQ?l+klAR!crjI9J|k%&YRkkd?L=Bl?aw|Mosdz`K4g5LC+H=CEQ
z-@NjwG!5u-Yv~`ruP-DOX8}fH>uU@1H?O>W>F(TuX_91cXUK=StsrXC)skf<F%*Du
zp8M%)BzF>b6j^aq%ovw%EiT?{F1SQzzzR^L>ztYUgxFDIy%zKG-XoUC?3X=6{m^dT
zxKs>cR$cgcfuq4qJYiO5ufAf9T4Pq-u3Obg-TtQaOl8P=)*7}BSkKtqcf%IR>?)g>
zo#!wFp%(+ewS|H)1Bb;nP-pIl;vgB-)3mE!gm6u{5*ewW7`Q(sq40bi9w8@x509o;
zDxM4su$;gi!@G{kt&j#2_`%&{>u~%`TD(5Gc(eB|5{g)lP>z^K*hXL?>hKS)Bg7Xb
z5hXCJu#@l~*|;HAh_2qZ;0|^HO#cv*x&%UcW~Kiv-W>gJhxggoPmC|8os~S>Fa|}J
zrldJVNpLTNh!8@(M7~9uMFZWFtfRvVpQ;lWa{%-Ybo?-am8L3rbGPT3i{8~6i_)-@
zw*6qepmy)lg-#nf4~+yd+?AUoWyo{Sfl620c>oOirw3gBZZ&-$`I612t>e}qD<Bf{
z>G@YbMF!3d*gOf|UIZ%`hkHTFY&8kbew_RQ*U+e{CNHFCdhPpq?ceOSXWQCNTWAOa
z2%JsxRBp+s3DW>#QJ#XE{<6-J4udy5OxnJu887CtH0J-h*c9(qQ1jZHxA?|ub0vJ0
ze7kgaenE^fYHwe<erwJ^9MKRZ&09Av&$$H=y2ojQc_JiYHw~WMM3envom>{ZT~hS{
zrZ0In2LE_$hj-Ll0jc{)e3p0L=j{x9g9hO6OSa+0#Z(_S+NZ{!s0uw=VS25{#Jt-P
zA%HLG2$#FOm_38}o!KbJ!pQL*bHO*EIWRXvkzCP)doEROCkV8QncR*0I*Cg{4HC;m
z#(LzXyU6kdl3T2#ic6(o+t<c1;<pFCl-u`Y+kZfbxz<$15L{}&%9wXg?YKK(9W`PH
z_NI}WOL;*OH;}<)s6p;O=tA8T@3|S`yBoLwqWbhMFVEZqd5p$Ko)7m=YUw55;);d4
z{sRIx*7hOF#N$&tcJ&MPO=CD4YqN3emOd~>C^yGWvbp`+51paVENEv#e|~C1737Kb
z!pH!L?N`;-EVU`07vm;=0@M#C5gJ!oLZ}-`Y7!xVZG<J1OCxWRVp*+C1V-+pqpAw<
zT5qWQEoE6&YN@+Ba`IiyijY)?F^wb<92Lpa&Sod-;3Cm!!%9l|wS}HhB=os+B;tM0
z1iJGi*GOI^xlVEeL~wQf=3Jg<xx~E<7!thQ{Y6B|mPd*3uvMdA`Y$Lmku1A{7#2<1
zIJ~)lqSBA2XV%_92EYT?gjB+WrRO0Zf-IaVqE%a`N`B4WJ649O0E>u6U0_VgR_D=X
z^NctsJFOW9Lu*($`~wg7wqBCR70OrnA&H{W#0sz&F3}w5TS)D=CA(rd)L|&SC&9*U
zX1PEJlIUp|E%zU}(fLA`_fI)!qR0<u#%+G{(0@aLJ_e$!npLxFcEhe&2Z4Jdy|-|N
zTj35wVg3#GgI)r<9;G`8PC!FUK!fGR!^Ytow*!{w!cGQf&0rAh8v=%WG5muU!#{W-
z{KFR`M0g=W1dm06L3lA3gjX31f^8h4bZq@m=IH}ZKcJl8n;|4%0<yB5OAUBjfzcen
zb3m=zDj%1CNm+bQO+qlhZ4>7#y&rZMRg*_PQ+P;Cj<FEign_Lp*o8@iN6%L-q)Hjx
zhyMlLKMmCv-N#}O3ObLKZvGZ>Xx98YSwcV7{2L2$h>%dZW`<A^IKnE=*xP@4di~>4
zGiL8vWx0MiC3gEzM#kaP)#OmgfV#S{iB58aZ1Z=E&b({^huW<hl)*pg_8;8oKWN&Z
zLwRTuI5fE<a1cbx`ju>d^JBXTdEoY^Y-}I-yXo)M_IsbdkB>foA7&le2CvICVt$-1
zGkfOmO+K0L845fy9jVymC}xqHAK6c_=^tDtA$k{^Ua{_&{$&h|pFws-t$776!_ZHC
zrsT)VAQJ4xhfRFmB*Ke&b#LG$pgV{eIOaP==|=%ip2sxqcSycX@*D}F!97iKhU6>>
zT@3*w+-sGZ=XH6SUe?)Dp?s**jXlM3jY3FW5GY$&L0CZo2pX%41k)tSWyUcM8Ag)W
z`0g?jcIMFL7JQK@!9g)BBh1qFn(zsc-`J}Oq^1ZT#tOa2)G~;yAx^_+%Z-?=gZNvq
zmgs~_o4n6~Zf;F%l>{LEiJay-dA&XWSRA&7`(7zQv0@!TP@-m!<9Ey&wyQn39I{N^
z5Mtp&08+dw3||b}{V;dzg;IMI2Ja|xrstHzn&f2V?#nBn`RH?ssh3H3<9BCC#KJQ)
zyXz*q+k<r(nRnkL5$=RcwLo^PjHJHe?*=YqlWP_6#}`k#UaybVPt^zN{rC;ltN0Dp
z$IPluaFMd_d8Q^wB#uVG>Hg0LS3(QtQ6e5rlC7@7(-gtM2a4;+M!Cyl6iH__KJU|L
z;e!hPCx_fR<~Q0|UWjWXUQ_Q5I)7u%Tu|g5Bli_vRpdsq_i{SloL_WbVjYd4(W+&B
z_Lqx~dzUqgn#&37@1e_``GWcI{Stjd{Q^kM9)i^Me)w8*2oeo*Z+<3)PtrAeVubX+
DWOf+p

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.py
old mode 100755
new mode 100644
index 1e948b48..c548dcf4
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.py
@@ -35,22 +35,19 @@ Currently it can just use the PySdl2 driver but in the future there will be a
 Linux and Windows driver that can bypass PySdl2.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LogVariable', 'LogConfigReader', 'LogConfigRemoveThis']
-
 import glob
 import json
 import logging
 import os
 import shutil
-import sys
 
-logger = logging.getLogger(__name__)
+import cfclient
+from cflib.crazyflie.log import LogVariable, LogConfig
 
-#from PyQt4 import QtCore, QtGui, uic
-#from PyQt4.QtCore import pyqtSlot, pyqtSignal
+__author__ = 'Bitcraze AB'
+__all__ = ['LogVariable', 'LogConfigReader']
 
-from cflib.crazyflie.log import LogVariable, LogConfig
+logger = logging.getLogger(__name__)
 
 
 class LogConfigReader():
@@ -59,24 +56,25 @@ class LogConfigReader():
     def __init__(self, crazyflie):
         self.dsList = []
         # Check if user config exists, otherwise copy files
-        if (not os.path.exists(sys.path[1] + "/log")):
+        if (not os.path.exists(cfclient.config_path + "/log")):
             logger.info("No user config found, copying dist files")
-            os.makedirs(sys.path[1] + "/log")
-            for f in glob.glob(sys.path[0] +
-                               "/cfclient/configs/log/[A-Za-z]*.json"):
-                shutil.copy2(f, sys.path[1] + "/log")
+            os.makedirs(cfclient.config_path + "/log")
+            for f in glob.glob(
+                    cfclient.module_path + "/configs/log/[A-Za-z]*.json"):
+                shutil.copy2(f, cfclient.config_path + "/log")
         self._cf = crazyflie
         self._cf.connected.add_callback(self._connected)
 
     def _read_config_files(self):
         """Read and parse log configurations"""
         configsfound = [os.path.basename(f) for f in
-                        glob.glob(sys.path[1] + "/log/[A-Za-z_-]*.json")]
+                        glob.glob(cfclient.config_path +
+                                  "/log/[A-Za-z_-]*.json")]
         new_dsList = []
         for conf in configsfound:
             try:
                 logger.info("Parsing [%s]", conf)
-                json_data = open(sys.path[1] + "/log/%s" % conf)
+                json_data = open(cfclient.config_path + "/log/%s" % conf)
                 self.data = json.load(json_data)
                 infoNode = self.data["logconfig"]["logblock"]
 
@@ -115,7 +113,7 @@ class LogConfigReader():
 
     def saveLogConfigFile(self, logconfig):
         """Save a log configuration to file"""
-        filename = sys.path[1] + "/log/" + logconfig.name + ".json"
+        filename = cfclient.config_path + "/log/" + logconfig.name + ".json"
         logger.info("Saving config for [%s]", filename)
 
         # Build tree for JSON
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logconfigreader.pyc
deleted file mode 100755
index 5bc212757895ae145bd54f853d5f53b9df89c06d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4251
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
OEt|{V+S<ac`hNjTB%X!<

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.py
old mode 100755
new mode 100644
index d9c551c6..0f305fa1
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.py
@@ -30,20 +30,17 @@
 Used to write log data to files.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['LogWriter']
-
 import os
-import sys
 import datetime
 
 import logging
 
-logger = logging.getLogger(__name__)
+import cfclient
 
-from cflib.crazyflie.log import LogConfig
+__author__ = 'Bitcraze AB'
+__all__ = ['LogWriter']
 
-import traceback
+logger = logging.getLogger(__name__)
 
 
 class LogWriter():
@@ -55,7 +52,7 @@ class LogWriter():
         self._dir = directory
         self._connected_ts = connected_ts
 
-        self._dir = os.path.join(sys.path[1], "logdata",
+        self._dir = os.path.join(cfclient.config_path, "logdata",
                                  connected_ts.strftime("%Y%m%dT%H-%M-%S"))
         self._file = None
         self._header_written = False
@@ -116,4 +113,4 @@ class LogWriter():
             self._write_header()
             self._block.data_received_cb.add_callback(self._new_data)
             logger.info("Started logging of block [%s] to file [%s]",
-                        self._block.name, self._filename)
\ No newline at end of file
+                        self._block.name, self._filename)
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/logdatawriter.pyc
deleted file mode 100755
index d41df77b73f2fa48831abd2082f3b08482223575..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3823
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
BTeJWG

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.py
old mode 100755
new mode 100644
index cfdff4ee..7ba3063d
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.py
@@ -30,14 +30,14 @@ Implementation of a periodic timer that will call a callback every time
 the timer expires once started.
 """
 
-__author__ = 'Bitcraze AB'
-__all__ = ['PeriodicTimer']
-
 import logging
 from threading import Thread
 from cflib.utils.callbacks import Caller
 import time
 
+__author__ = 'Bitcraze AB'
+__all__ = ['PeriodicTimer']
+
 logger = logging.getLogger(__name__)
 
 
@@ -68,6 +68,7 @@ class PeriodicTimer:
 
 
 class _PeriodicTimerThread(Thread):
+
     def __init__(self, period, caller):
         super(_PeriodicTimerThread, self).__init__()
         self._period = period
@@ -82,4 +83,4 @@ class _PeriodicTimerThread(Thread):
             time.sleep(self._period)
             if self._stop:
                 break
-            self._callbacks.call()
\ No newline at end of file
+            self._callbacks.call()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/periodictimer.pyc
deleted file mode 100755
index 04a5eb1373f92282b172bf825bba163593671ac3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2914
zcmcgu-*4kY5FXq4(d1gLy7Kdozyg7C(p@9*079SxT6BPbs&Xn2d9hr3+dAji!MowE
zsBgU&{$Bn7_`b1|_7L#aI@!tYdUj{`o0)GC{JAy!HvRsmRN5!N@0V!y4~R@;3hBwz
zlgyV>bbQGI$vRR5GDQd9t`r@acV*fYkK>*cJ(>4q+Hc0t-H_>qm_TL&F+;h;Hg~vR
zHk7O{FGMayewl7c2Bof?z}8?ryG3J@(H$NshZuf0Ule9;N|(62D#Pj|Ou~h!^D4{J
z(B*SehwdzK;j_Fb!Zd+M^yfH9pN8f)Q=hBW(4Co9-8^69wXtDUrY5v5sh!Dohn6Py
za+lW0?<V|e&uw9R*cv*bo%}C62O|&jt_N{+R+}Wd8t=onsZ+eshkAQx_5p+evbZNC
zVDNZbqUmd=Ls&V}m1r{RaLHqceeCYc|J`;41MHsv^Xh4UE!cc+g=Rm4aEkqfNbCvZ
z%#)cf7d~C&xqwq~M=tbT+~sjO(`RR*_dFPFV3&w{x*<eNz=^bVn;0fpww`faOgu>n
zYaG|aEzqvdL347)yB<`fX(nBRCl9S}tSL?u=vJHCtn7`@7Zvshz42K!H{;{hd*el2
z%}na-n9e*uDRT2Dg(#hUv^aNXRXHy5<8gY@Opcc>FYI`QrpDAR^z_(qUgj>2$1q}f
zWAQe<ZEt{2N(Zy?z>4q$9il2y-xsIY!q>zWo}M)L&VVmex^fBNfy8RXtS3N$y3G!=
z4Q7ch9MOQi3o&7^BHY_ZwjW?lLo-YY#^U)ZoF9f|<w68G7v$yX!Ds;0h(Zx9s?$?b
zE9}pbx`c*%74PE1>+#;icSMIpJc8qLxby48%&SsebW|^mI$8~Bh(tu`7Tgo<z|O}!
z5hG9hfw$##yf@*TwPV(y{~;7w$Gq2e5c-O56YC<S^4?^`HTD&ViK`Y@P#>rh8UQsz
z@it<B-0q#}q%U|v@=tT;5xZ@ymdV`2ag&+xyvmjZhnjJ5R;6(qk<=8qh+AE`NqaYz
zN)c?yLo`dsdS1^T^aq1z8-o;0pEX^+kKvjwU;GDSf+!i1YnJ0+AI*LQ;qX<zBFDgQ
zm&l`*(?D@e+I0kB%lzwICpRM1g!2+?pyz84TjxMTR#O!aTD54Rf)O9Fd}wZwqD*}S
z?aiS|XMTgGsEW7qGA*s6pK5@Fx78A~qH-!k_bA?ixcxx>5mqe^A^(!HtboryX_M7{
z+R`bLIJm}=^#eIX=5o5Dq>8<M4dmx*1&isS7gWL`xi=mzj9FacHYPPacdIa<B%oF-
z%R~IUR9!mWh=CTpM)5j@CN6U}dI#bvx^6genW9h7lyG|9pf?B_+oZ_o4TzR)k|pYD
zy=EIA+4fm#SYNdEXobfpVzxWpE=6@d-qi}cyDIKh|6oLKQ-{k=jr&0hR)dF{#<XaH
i-WC)}v7a}j`uJT~w@jU$4^VvmCD`^h{ky@={l5VW|CKTT

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/pysdl2reader.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/pysdl2reader.pyc
deleted file mode 100755
index 371ba770c345e6c3e06779065a005f1d301ca081..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.py
old mode 100755
new mode 100644
index 3a0dab0e..832d2cee
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.py
@@ -33,12 +33,14 @@ Singleton class.
 __author__ = 'Bitcraze AB'
 __all__ = ['Singleton']
 
+
 class Singleton(type):
     """Class for making singletons"""
     _instances = {}
-    
+
     def __call__(cls, *args, **kwargs):
         """Called when creating new class"""
         if cls not in cls._instances:
-            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
+            cls._instances[cls] = super(Singleton, cls).__call__(
+                *args, **kwargs)
         return cls._instances[cls]
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/singleton.pyc
deleted file mode 100755
index ec89e13b651a261d597761710075f458596fbfb2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 899
zcmcIiO>fgc5FM{WN`nv*H&j7=0LhnjFB~gA+B+bJ3%RVe>rLWhy|%m)MM1fh6NmmV
z{!afuXV$6dA84F;o}G;6y?IW0_i|GI`}@<t;giz+3q_CwCBTd@fms5jfCVLj6Pv=E
zDk=N{xB>Vz8$mgOY5t5Kd`&Q!R(|0uHa;^>hj2a#FQ|N3q3QH*n|-~+V>%CA1AW3>
z6yYs_C3>PE6i^YSEQKhEu9)V6+fE3sm?4`tT~_Ng@n+$HJQ$wGD{*|M2%ib|@w)<8
zA3^sKFaZ=?yb-WUVV}TW!0kg1)i3;`!<%W&L&H0QEA5;uv+dH-o}Jam?A~tsrSlQB
z;DkU`KA`r-28<SMTH6&=2Yk-IDnoOW%2^~b7#ENq*4-lDn3DCD)0{Gh5Pnc5mrZTu
z^}$owcFoEf43aJ0&0S^B41vdR*6wiGc<HKZY36-VZm@De4pyDFyMn2Cd|*ltuaXZ*
ze5D7KUe{Ksej!yi<;L;xh+35@8>3Xg#tc(>rB5iAMZTwqa>of>;#<^P@PF%|Q*UVX
hZqONxj^5&~wecPNclGJCMh7o?&pw?Fn#DLd7WW5?)2ILd

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.py
old mode 100755
new mode 100644
index 8232b6c3..e639b092
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.py
@@ -30,25 +30,27 @@
 Give access to the LED driver memory via ZMQ.
 """
 
-import cflib
-import cflib.crazyflie
 from cflib.crazyflie.mem import MemoryElement
 
 import logging
 from threading import Thread, Lock
+
 ZMQ_PULL_PORT = 1024 + 190
 logger = logging.getLogger(__name__)
 
 enabled = False
 try:
     import zmq
+
     enabled = True
 except Exception as e:
     logger.warning("Not enabling ZMQ LED driver access,"
                    "import failed ({})".format(e))
 
+
 class _PullReader(Thread):
     """Blocking thread for reading from ZMQ socket"""
+
     def __init__(self, receiver, callback, *args):
         """Initialize"""
         super(_PullReader, self).__init__(*args)
@@ -59,12 +61,13 @@ class _PullReader(Thread):
 
     def run(self):
         while True:
-            #self.lock.acquire()
+            # self.lock.acquire()
             self._cb(self._receiver.recv_json())
 
 
 class ZMQLEDDriver:
     """Used for reading data from input devices using the PyGame API."""
+
     def __init__(self, crazyflie):
 
         if enabled:
@@ -96,4 +99,4 @@ class ZMQLEDDriver:
             memory.write_data(self._write_cb)
 
     def _write_cb(self, mem, addr):
-        return
\ No newline at end of file
+        return
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_led_driver.pyc
deleted file mode 100755
index 9d11f15fe5930ef3137ec1223755222a21c76613..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

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

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.py b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.py
old mode 100755
new mode 100644
index e2ea3fc0..da221b6b
--- a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.py
+++ b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.py
@@ -32,15 +32,18 @@ Give access to the parameter framework via ZMQ.
 
 import logging
 from threading import Thread, Lock
+
 ZMQ_PULL_PORT = 1024 + 189
 logger = logging.getLogger(__name__)
 
 enabled = False
 try:
     import zmq
+
     enabled = True
 except Exception as e:
-    logger.warning("Not enabling ZMQ param access, import failed ({})".format(e))
+    logger.warning(
+        "Not enabling ZMQ param access, import failed ({})".format(e))
 
 
 class _PullReader(Thread):
@@ -60,6 +63,7 @@ class _PullReader(Thread):
 
 class ZMQParamAccess:
     """Used for reading data from input devices using the PyGame API."""
+
     def __init__(self, crazyflie):
 
         if enabled:
@@ -70,21 +74,23 @@ class ZMQParamAccess:
             # If the port is already bound an exception will be thrown
             # and caught in the initialization of the readers and handled.
             self._receiver.bind(self._bind_addr)
-            logger.info("Biding ZMQ for parameters at {}".format(self._bind_addr))
-            self._receiver_thread = _PullReader(self._receiver, self._cmd_callback)
+            logger.info(
+                "Biding ZMQ for parameters at {}".format(self._bind_addr))
+            self._receiver_thread = _PullReader(self._receiver,
+                                                self._cmd_callback)
 
     def start(self):
         if enabled:
             self._receiver_thread.start()
 
     def _cmd_callback(self, data):
-        #logger.info(data)
+        # logger.info(data)
         if data["cmd"] == "toc":
-            response = {"version":1, "toc": []}
+            response = {"version": 1, "toc": []}
             self._receiver.send_json(response)
             self._receiver_thread.lock.release()
         if data["cmd"] == "set":
-            resp = {"version": 1}
+            resp = {"version": 1}  # noqa
             group = data["name"].split(".")[0]
             name = data["name"].split(".")[1]
             self._cf.param.add_update_callback(group=group, name=name,
@@ -98,6 +104,6 @@ class ZMQParamAccess:
         self._cf.param.remove_update_callback(group=group, name=name_short,
                                               cb=self._param_callback)
 
-        response = {"version":1, "cmd": "set", "name": name, "value": value}
+        response = {"version": 1, "cmd": "set", "name": name, "value": value}
         self._receiver.send_json(response)
         self._receiver_thread.lock.release()
diff --git a/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.pyc b/pps_ws/src/d_fall_pps/crazyradio/cfclient/utils/zmq_param.pyc
deleted file mode 100755
index 168cdd01bcb4d437b887c1e9a61e7e9a3cf25da2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 3797
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
P0F|_7cFgO+?#}-J<hdv%

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/__init__.pyc
index f5e936ccbb0fd4da975be38c2a121c3f618e5b17..a5ca6d4071705a3ae3b59a286df950bbcbb51bb7 100644
GIT binary patch
delta 40
vcmbQoxsa2c`7<w9YUSmP>;^2t0SpWb`WgATsrt!9iB*+pIhm=G-C4o`^TG^k

delta 37
tcmZ3;IggW_`7<w<!`#~&*$r3(d>I%R^fU5vQ}t7H(-L!XCVR1j0|3i)3f2Gs

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/__init__.pyc
index b09a12f550842caeaa953ba1c7a810c6c4aaaf89..1d052e26d093f2d2af461e4f7305e6843adeba19 100644
GIT binary patch
delta 951
zcmX?AxweX(`7<w9YUSmP?2#<OQ49<W`WgATsrt!9iB*+pIhm=G7xMaS-oxUJOVWFC
z5@#C@jRBKAxF+J1v*hl>DW}fUf>Vy07pr}n7xFeS;n3tgxlZ6X4mqFA3k9_qaY%Y^
zRu_)IDLMI;$S+(PC+my7#UbajxkCIlZbR2e-ov5M8)zuo=C@LXxHS80-X$}G8JF(O
zYZV%C>GYo5sdNyl#z5nM$*YtXW0eD?jg=}=I1Sw_r*;WfocL_^(G<kx)_}=-b$W4F
z8L)YkE<08$Hy_js#VP?##6<>)xFz+Cgs@6(4m6&LRRV0Jn`s_yNdfZ>xcu%tS=y=&
ThxdFof3>p0Wvch&E*l2`A6Go?

delta 852
zcmZ2mb*hq``7<w<!`#~&*&|s5!WkGC^fU5vQ}t7H(-L!XCNpyRY~Ih}ja9~bat3D`
zHZ2da2?k7d<?h2SVaC&fT|$-@tN8(&+4zi@uxat0JWb#@HVL22djz!^vB`LEb`_4m
zE;ISJ$S<r~CI^eX#U|midA|5<9A@2+yoXJT_hu34a;#c>HouaY!Hiwc1BFJcdb}s^
zS2~DIi_hfy%F8h&0!;%pzf=*!Zr0{lwM$q-*=KW~rXW_A1x#kr?Zvc)kt<;HCtY@|
z*7$6W(C5S<bHE@GhfIT!5DuA-#=e*`n*&XEVTyuNcb54Ete*6qTwzs*%_}~eL#?f_
L8s<Iut&IZ!0DJb9

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/commander.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/commander.pyc
index 1a4551165f13f85143fbb07424587f5960cf074a..8c878db97973dab1c6de56c815a53f19287b7151 100644
GIT binary patch
delta 154
zcmew>&?Css{F#?4wes>t_CzM(Xa)ub{fzwFRQ=?l#Hz})oXph8f*gUHPcktw;*j*+
atj?l?OQ-MT4Qv%SH2O?#VXws@mjeJwMK7oT

delta 135
zcmeAX{42oD{F#@_VeajX?1@YQ5ey6r`WgATsro6pX^A;GlNC4uH=ki*WW<o!{D8R<
di~0x5zLR&dRbVKe{D9eK@&xu;ObG>!901*~DQW-!

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/console.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/console.pyc
index 7eda3dbedd01ce70ec7b102c900beb60cab58b61..1a8c8c2f279ac0c46bc4c8048ae830c7e0bbfcd1 100644
GIT binary patch
delta 125
zcmeC<oyE(}{F#?4wes>t_R~zlkqitB`WgATsrt!9iB*+pIhm=G4OzW5>o8j|;*j*7
Syq_frhulLP;$D+;*pvW_ZYNs+

delta 113
zcmbQm+sDh!{F#@_VeajX?5CLo!WbAB^fU5vQ}t7H(-L!XChM{JZ#H2zX2d4rHTeij
NGIog;*6G+JasW^uAp!sZ

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/log.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/log.pyc
index d210b97174cb49fbd0506298c0ccae2dd1f3d8e8..5fd1124b09b2bf380993fdf3f869e6755d087817 100644
GIT binary patch
delta 910
zcmcaLn{oRbMt0`Uyj-c3mp8Is=N1lSU|`VC$j?pHPcBNVs!YqtOr1PY#(lCW&j*}x
zHN0za$~Evk!6~<!zZR?9MGN=M{Q@D(I3&F{+lgc_VU?UH<Gq<tTmzS+`{V}61voT<
z<X9$GOGV?AH<X@%L*8eys!R+vxy=)0R$})GFkClJRN%+y+RfjUE;3>>5)>nw<y9}^
zmh@CN#%b*2%bMG;nhFZ{2U`2FYXnJt)8)W!B}g(<p9Qz%1_N%~l0rtmaY=e_&M+~+
zCF#ETz3C;auHAgm!k7)KA3<rkL6T#0vi)T2#)1_1IxfYfd9$a}Dt4@rpfK?AV#RJM
QNOGC?1niO^D|>x?0qUVM00000

delta 802
zcmdl!hw;{IMt0`Uyj%`*Z*OG3&Mgqcz`&rNk)NBYpQ4+Vn3J>lBeyvthUnyv-0qW`
zc-LZ==;V8XUE(-@Ej9_a&2t4pnX$`wi{vt4lX2fHB(8%+CQ$M@rt&~Z@5$4oqOnW(
zOV7ZR0Qt{RCK0Q|=07q?n6BMis1Sz5JwSstD=J^a9)z2HR4-$ZDOB*@T&u2+-L%PU
zTHCNW%Wbo$_5rL~+&1g!abmINBe&b;3Hq!!WZoI@;E)M6`h!Deg^4K+88frXINX+G
z`IZ&aKY^0|n>X4|#%h}T<av%uF|~j~dalzdc5E_kn-_SoVKvNc^MCJ&SY^B?zw`A3
E08J|Y8vp<R

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/mem.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/mem.pyc
index 81bb975962c1dd992cb3a97871cedbca6f3738ce..c4343391b200d15a226cc52046ce297a6e8b47e6 100644
GIT binary patch
delta 1673
zcmaKs%`3xk9LM)#4;W(e5E;pogRF#!6&ByGg@{>F9@Y$No7K3Gqtgx!K8Zq<+MQ3S
zm4$MU+sI|}bnpi(4&o$Sy`5j*_xt^M`u(nw%3Dg&WxnO*c$aUFbn#5%s7j@>%!h(r
zizn<}S)L8}ywueo=s>ICDs`CxAFOLmAv@4ML3XE$04Dh)%Z36aIdW1!C}>4L0+?iT
z?o<YZ$$Sk=<dy=c6trKW;k3bp)Pi=4?m_I2n9>FvC5uD<yqN?{va>Xdf+d^EQfRM|
z22C;G`m=NLR1N|zIlIb;C%IVN3QMBtCN*hm_K-7u)+|7FX2!eq)fU25IZ^k4%dM_2
zKoFgo<VDLn5=p*j?1cm1=_Wgb^wE3`yDzr}AbYURA;vqcuQ>3fZ3_wMrX78sf{$%}
z-2YO?CQAH0t(h(#N@cU%3Z3b=8(&Ve=Ny{G#RfFxsAC(ID`~UO4P6KNi`5XuhJwgd
z(CTmk2n8LEJVW;VFMf39LSyc9r4W=H9>a~YdwdOzNO1eaiT<ymSn*xryb6B=!QVSj
Gg7OPS93<fY

delta 1473
zcmZ{j%`3xk9LM*w&14Tv^N{k8nFC?9WMtS@_AA>6vtmiV@@zjVIVlHn;X*z{;@}@p
zd~-mGBHD?QY(+V^xsc>$-}Cpq^Q-s6=kxh~zthq~N-}7_&H3KL^oik0Ywg!)G|s7n
zI_?~6m{8(zQq&-`>q;d=WZKbRA`qnG+!O*by&Kj<@Z^%&U7iPoWC+Fb)1pLCW!g0M
zi-3E1OrtrN{8;ojg+;7LlZjzw+c41Z0yl+Onwf1zl8O^z2d+vMkBETRUM`sjL7aq3
z)8ICIIV<JoqM4$GXuqOI1l-GCX@koNGFH`u^T}6z1kK3fn8U!^qNBW;UI^JqO#vQ<
zmDT>iaxzQQTQQ-R#%&yP@B9@d?8&u(r(_pReoQFZoP-gy=#FFHZJC6CNv&U5Lc(pk
zP(mG^brJBFX>Xqq2PA&vkIo&ClKIT^;+q!Dxa7d^#%9#ebqFQo2wX$JI^-?v#p=5E
zKr#N3%R&k^dkz)pFbVXjz>NPf^T4Ah;lLevLm<c&22I$DrJ^Z7_{uCpS%x`{t%CXa
Z$zDg!jA8+9_Bp+jCFXW^9S}v``Uh`s*p2`I

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/param.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/param.pyc
index 300adf07e0912abb81c395eab49e516c272d5c0f..f804a69a9f074702fb526631e73d0d01aa742de1 100644
GIT binary patch
delta 643
zcmZpQIugas{F#?4wes>t_VaAQ;S3B6`WgATsrt!9iB*+pIhm=G6{I{S>#@(oCAV3g
zqlyuSr03>OoX?qXN*eKM;nL}`c?+L4Zb^3mK4zT8t`knjtut5j6>iD(;=VW~Cx=Mx
z!Di)V1t|?&nmjizlorC}P>;#n^0-3PbMs&MLYx6N`MA;%Y)%12mFMIq%Kvf6ZMIQO
i!0ptpYQeZA7iu`+lJuBtt(Az=%CB05xHaz6aRC50o6La#

delta 569
zcmX>S)fC0f{F#@_VeajX?C048LKqkr^fU5vQ}t7H(-L!XCJPF9PBvnnfmLF&8b>7~
zri`PM=jPv>&zZ2x*zsy%(F3$*^ASEPOqtDs0%6S9O*$-`j;S8x;LUBKFLB767Wcs}
zGr3rDH-<Hv9i=p|D4(d|yZNLv9~NhULd#elOK5?@L|vf}dzeiAqI3kq?#VzclSNei
rW0lyPubP0xVIW(y)q^o*Hc!;(#uNodZiQ9?b}LM@3vp;+)O7{`4DF?Z

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/platformservice.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/platformservice.pyc
index c983623f14c9112fa7340dc67dae8cf239564dad..8e52e53c5ddb19fd7b056fbfd10099ba065fafb7 100644
GIT binary patch
delta 125
zcmZ3(vxA47`7<w9YUSmP>`Y9;i3|)3`WgATsrt!9iB*+pIhm=G|1bw{&S7d`#36Ya
Shj`FrP1Z&na>0{%+2jEY^(n#t

delta 113
zcmdnNvxbMA`7<w<!`#~&*_oIG;ushh^fU5vQ}t7H(-L!XCO=>a+MLJK$cR;DatKQ$
PHi^sF1cN3^uqglltwJLh

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/toc.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/toc.pyc
index 4f1b78dbfca9968abd4baa1f92115eb83a5a37ac..c4aeffa7a142105eb313e0067d3be5011c1398f6 100644
GIT binary patch
delta 468
zcmbPle%_p&`7<w9YUSmP>`$14Lm3zt^fU5vQ}vUJ600iHaxzmVC$hOsc4YpBL(YA2
zA4?%lxiHq>*yJ`RvQ;r+lK@)gzS)SQ5tpRfWKOQvI5fI#_TtvTt?>*`JWh>`yuWd3
x+<b}u2rfzY&2I&{a7+3L^ReKxbCdW4Tsqw*&yWnorE#*e)Fm8p?vrz*jR6~ymy-Yh

delta 417
zcmX?aKHr?3`7<w<!`#~&*`F{81Tio$=x5~Trs}8YrX}X&Z2re&!-yd|`5%+p<jE{W
z*d^jv|6rBayqV1eyIGqZIGV7^xKEbhdWFp}_st31+E}#A<5`Mb`CQ&#Sd{-`a^L)s
u|1ee=x6Qml+&E+kh51>q+jC32AFCes$%iFFuxgoHD0LB=gxloV(k1|6w1t8I

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/toccache.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crazyflie/toccache.pyc
index b8a5da1d4d2221ea5b2848d45378c56f3f277164..e5b628ed00701329883b82d40698b14eb32a18cd 100644
GIT binary patch
delta 212
zcmaDT`%RXe`7<w9YUSmP?2*jEQ49<W`WgATsrt!9iB*+pIhm=GA9DC?-oxzAgi|t|
pEeosU=7$`w7;)(G-mJ!*gi~_zW1ccx8YgezU4cW+XYvj{O#s7kNY(%V

delta 187
zcmew+`%sph`7<w<!`#~&*&~?+!WkGC^fU5vQ}t7H(-L!XCO7g0Y(C8F&4eMdS&?lU
rrs!lvHlNLAobwnl)B|O_Hyd#$VV9ZwiKh&!mdVF>S71ss@|6MrZCy9B

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/__init__.pyc
index d51361206bc0697d66635adddef42367f3445640..47b409e54ba811525f2e198f5b5c5b337b68ad59 100644
GIT binary patch
delta 156
zcmew_+$X}${F#?4wes>t_5)19p$rTR`WgATsrt!9iB*+pIhm=OuQRP-#3nKMI+Oe6
YTP)nTC2iQ2<Ce7Iu*4}j`4p!q0OG<l6#xJL

delta 141
zcmeAZ`7g}Q{F#@_VeajX><5?xf*2SW^fU5vQ}t7H(-L!XCjV!5->k@-%7{(Id-D?(
bcC0e)n_bzKW6Es)&)$G33bJGJO-@q)ND3_G

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/crtpdriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/crtpdriver.pyc
index ccd50c1a2b57d9278b134e4e69ca71755eafaea9..5db88fa87e5e1b8d9a5c3613c0b188a8e6a7cbf5 100644
GIT binary patch
delta 338
zcmcaA^HYYM`7<w9YUSmP>_$w&;S3B6`WgATsrt!9iB*+pIhm=GKl1u+p2oD05vyb)
zo9E;SEIGL3Hixpx;L>;>m!`=(*{5NZ1G;4L8jhn_<r+DEVHXEF@Cw%^ta2dp9&^WG
Xl?&v#f>pec&0}&cZwgkqkGv@W2c2@`

delta 311
zcmew<b5(|&`7<w<!`#~&*^QV4LKqkr^fU5vQ}t7H(-L!XCKqz}Zl1}skP(}V=j3TD
zIann&$Fa)b&~lA!8dfcnPq1T3Y%b&w!eP#R&W+g3dBe2{Q(`0cYD~dG4$sLuc)GDk
Rcubzhn}SWkcXAS+H~`M7UsC`8

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/crtpstack.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/crtpstack.pyc
index 442e4dafa5e3fe75cdaf89fafdabe6efc3fad89e..ec186b246738c1e481340ff0969dcfadfc5fe543 100644
GIT binary patch
delta 466
zcmdm?@j`>0`7<w9YUSmP?CMOyVGIlm`WgATsrt!9iB*+pIhm=GFABSFZe?18OVVd@
zGix;tjUJQ3*p}mz3uQ0EDW}Xa0jC@{XDv>-2b`zy$gxaj<GzSP-hHwjPc{xYkIf%>
u4l?49bf3)0zZi#{$7B|P9XRCNCkqSi#v$i1Sxsmc4mtP9=E7Y#<kA69a-IeN

delta 422
zcmaE%u|tEM`7<w<!`#~&+0~f@f*BYX^fU5vQ}t7H(-L!XHajxC#1x&(DB?4@leHQ{
zIZ(o5ay;8|ToSC4)7T5KOY-w_PPXP~$0f-+S&6d(yX05SQ`jY>xUXVLI5K%m_TtIH
zlmI$?Ge7S^Mobxy7H$4Tm=Yl0Y6$GWlmO|l7Tkp?0n!m5ghc|RBUQK)n~rn<WaW5F

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/debugdriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/debugdriver.pyc
index 6b2576f59196bc4b770a3d5df22a1ff1427fd798..f97e1180c96b4e355311a8106d298493719a4c42 100644
GIT binary patch
delta 1043
zcmca~lX2fIMt0`Uyj-c3mp8Ikvk6BqFfiz6<maa9Cl@7FRi@=+rcT~y<Td$&0?XtF
zY}GjBx3U*ul{=W?wYibwg%D23!_pDVSS3NWmda=0l(STb#U;1-gF-GVPRZ?RwT!qV
zC--U0$0^sYc^jwP9<6+=av=Y=YVTsgB{_MfUN0`W%?<jBSi@%XMk9ah{sUPTWs!na
z*JO~Sgw1E{o(D;$+Ua69cB7H!=GV?;SaohLbQNd8>4it0&p2>ODg}SXY9z>|lZ!)h
zacZ;*yNcV&%xFQ}re2BJip$i=k7E;X$oXwv821);9KJ{_z@gD=^QI(A+^%s=$-$;^
j^TCw;xTEk^1_y2vZL<8anFx;ir&)H`HNrA@V@@Cd#;|dV

delta 931
zcmdmYi}BJ;Mt0`Uyj%`*Z*OF;W)lcyU|`VC$j?pHPti?F%*mNt$nG`yK3hFDi9MKt
zj5c1IyEtA5VU?MDK#yhfW$6%ROj(dEE%I5I5{wGVF$ICDH?u0{vSODxuU5;5Rc7)^
zjrrImmTKO{CgC^vp;k7g1jv&swRbULl>vIP7puhPRr-q9eZE=4m=%j(z+q{Tf~jXS
zqm3=5<(mWT%CVSI$nLpW#ia~;h;07udKT0C$sn5*y`FJk_eV<bcPyp>^-SIonu}da
zQ`l7&tTNyvu_Kxnhk;75Td`|1iA%tgP)zmP{59?^X3&5<G}%6>08<Odr##7)IIIVz
q*U8ILGBC7lR!rTGBiL*+IdB-ZD9aziAaF?gW!quV0?H9Db3y?h;2Pin

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/exceptions.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/exceptions.pyc
index 60f4731de97ab8939d73b92c20b3cf87f32cdbfe..eaceba555ada6016b0e18416fa742354f22f4dc5 100644
GIT binary patch
delta 96
zcmZ3>v5kYB`7<w9YUSmP?2Jsp;S3B6`WgATsrt!9iB*+pIhm=G`I$W@Co;{$A-4jD
KxW{CE7C8Wdz8xX}

delta 87
zcmdnSv6h3K`7<w<!`#~&*%_GxLKqkr^fU5vQ}t7H(-L!XCSPFon4HWsAG<^>a{@Mr
FGyr@K8r}c^

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/radiodriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/radiodriver.pyc
index ba8b4dd57c47ce72b0371ab0982658814c939458..ec96f252e92283b12ef806a1e36b4866a655a017 100644
GIT binary patch
delta 717
zcmdm+(3;53{F#?4wes>tc77J&2nGfQ{fzwFRQ=?l#Hz})oXph83x&Kk7qDz+!y)Op
zxq(}P376#L_X@0=zwyR1;#9DXzYC|_M1j3H<r=tIC$ABFicNm=LLoz(7H-xSVPnRs
z%Tb&WR|t4co-JLAO%o_|COgQoOfHitz$1^#ix9mUa`??=md7uDPksjuyFE9*SJ;6w
zC?+YF;L<nwtnx%0a$cKvs3_oyaIeV)EG(1F)YstDY@_i9cPLNPU5iuW3_T&7KAFsH
GU<ClDC+$@L

delta 608
zcmZoo+?&A8{F#@_VeajX?EEYOp$rTR`WgATsro6pX^A;GlNsf_HW#yOXTy})$m_Ma
zom-p<LuT_v-nEPvqLT~xFJlS<4Vk=9U=MbQU4kz$C4df^B>Wsx9ON7q5mshQ8ITv2
ziEqau1G0UWbPYBwev_xm6kwOgkZr>zaT=ST-(+3+TI>?s3Og_*HuCyyR#DuHCHO#Y
zHBm0crp0SAi^>E{36Q@(swiMa5GYb7=c#YN(6ZT3!;KX~bTY{5E4phiB|tXZ)f2+u
IS|0;T08$FJ+yDRo

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/serialdriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/serialdriver.pyc
index a750b4443eac55cb030929271f9cd05899348aec..7dccc6413750c3c141518887764df6ca7856b3e1 100644
GIT binary patch
delta 181
zcmX@jcbAWy`7<w9YUSmP>^~TVBN-SN^fU5vQ}vUJ600iHaxzmVGqQPYj$}&3DLGk!
cB?Xtp$=6uoaLV<uCgYGhheO<JvL?F{04g&$KL7v#

delta 163
zcmcc1cbbo#`7<w<!`#~&*?%w!gfTEM=x5~Trs}8YrX}X&O#aB`zd4a90jrGnWO<fk
ctXd{NVTr^h;XQdaYZ5jIugOttE!ZS-0JiKjh5!Hn

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/udpdriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/udpdriver.pyc
index d1bd738f1d44c57b3967c315484bead65cc82ee4..981031d8fb3899920cd996450f5043489367bd4a 100644
GIT binary patch
delta 295
zcmaDL{ZE>m`7<w9YUSmP>@G~gVGIlm`WgATsrt!9iB*+pIhm=G9k@I;FJ{`$h(pqS
z^G=q3xFkI`^Rvg{l60SZgrg0IsUDLTarWVmn}<W(W3m}{EKa%C+=V#g+$V45S%X8)
JWAb)hO#m>_U*G@$

delta 265
zcmew-{Xm+X`7<w<!`#~&*<F|ff*BYX^fU5vQ}t7H(-L!XCSPFl*u0EsKO;67_s#oR
z{$a{&zQDE&Qxs^D`{WB8ZP*O*n7om*54*%Ht}yHp-rTX+Bzz{b^W<WaaG!jRXAL$9
JkI7egH33j1RYm{+

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/usbdriver.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/crtp/usbdriver.pyc
index ce85a2d9158d09302e4287d02ca52494a49aea28..00e521d81c13456e1fffd28d828eb77c36f42175 100644
GIT binary patch
delta 463
zcmeCO+GWMg{F#?4wes>t_7BX$VGIlm`WgATsrt!9iB*+pIhm=G9Yx$X`>}Mh;E?p#
zY{>bB5vOD+_e5Nh?vrDAn{jEJY{9n?m)vGYekYuUZoVaO5SOIK<j+DKxJ;dVSvU@d
w+&LWL?wiv@H{i0&eR8h&T3i|z7fLW;m1~q*id7sG3$@ZrxGeLTd|O5z04p+;kN^Mx

delta 420
zcmdmG)n&!b{F#@_VeajX>>ro~f*BYX^fU5vQ}t7H(-L!XCI?D*Yz|`SV!<ZkzS)fP
zEhBcBTJA|$WjrQl@it-AGTDu96IO}MLHy3x&D#7y-~d(`_sLwsomdT<{8l&~yTme)
zc5D(Jn>$3;W3|L%@+9#!7+N+5O1Lv&hyugWeex%%IBXIgn^#LSVzt42GMlUk0Os6%
ArvLx|

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/__init__.pyc
index 3a1be3d44723ddc6e2148aa5d17d34b9b6948f6e..439cbca53e07ce314914a57bf924c6c86fc1d6f9 100644
GIT binary patch
delta 38
tcmeyz*vQ1r{F#?4wes>r_733)1_lQGjQreG{p6y=s>-yS%+!hV;{otc4Ke@#

delta 35
rcmZo<`p3x5{F#@_VeajT>>UE33=9nV8Tq-X`YF0;i8(nF7sUer$4m>I

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/cfusb.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/cfusb.pyc
index 8c8e137aa5f0c8add477e9fb323ae6583c6f6e8d..7b7678b9858a809ce8fbb7a05aa8ac7012a9eab4 100644
GIT binary patch
delta 354
zcmaE*+o#9Q{F#?4wes>t_N&aop$rTR`WgATsrt!9iB*+pIhm=GH}bh}HfEWQQ*yE*
z$7x&|Cp&X~z$w?oH3O$yCHEOza+~Myurgtj+`N&G1*-(e3zK;SXJgX@lylqsS1^bX
Xr{q#$K3tOSo4G`ta7s>IEanaXpX_xp

delta 319
zcmeCvd!@_H{F#@_VeajX>{pouf*2SW^fU5vQ}t7H(-L!XCOdMwZ#H9@j$LN5I>%|O
zS|<B&e!wm<jcW#m#AZisVMYv5u+{5$SedZP@bd4)u4l4};B0JK+%`)H1!2|Vw)wCy
TA66On&Dx?)*kvXk7jp*yKT})Z

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/crazyradio.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/drivers/crazyradio.pyc
index fc0771ba3cc7a0596f8cb15beeb6f4c3ad6c6b0c..d1e265c341b2a469db40734587773f7e90c769e3 100644
GIT binary patch
delta 579
zcmbQ{eaV}h`7<w9YUSmP>|89uQ49<W`WgATsrt!9iB*+pIhm=O6<LfKu}Mr;Wbxj-
zo>hbmhosMDc^-9KI(;TD;(dZcqxa^Ad|J3PdQVOhID$*#<W|95IOS#uUBV@|`M9t$
zE(?7oyNNEvrE#*G*kPP<DdNF6<a{;@OUPlhaI>T28>|wO9VJ6IPm&g8#$lxQWG4Bq
fxa2kmDdb@{6%>ckN_@B_Ta*)VN%~B7R1F0HSLU=E

delta 530
zcmccQJ<Xe)`7<w<!`#~&*|}H*!WkGC^fU5vQ}t7H(-L!XCL5~yOfFz~j!nXQ^Hx?7
zHf%Bhn{{}U8L`RuOkT(P1e=8S<_~;YShaXht`InaRm<dAg1fLwY!bSJRbulaVO;J?
z5nYN^%j9&i!`LM{#DlR(_-wY4ki+T|P)M?D-Yq!?kL)gKDQ0Y@dQUcz|B6*&bE`rg
URs+2^2P*O5klCx8h*f4G06HX{jsO4v

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/utils/__init__.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/utils/__init__.pyc
index 9a836124b1252f7c20851b151691a737f68a4bde..7c1192880b3f121662f5fcb0f624294c7bba6b2c 100644
GIT binary patch
delta 38
ucmey!_=S<3`7<w9YUSmL?6tyS3=9nV8Tq-X`pHF!Rh4NunW+<}!~y{Q9}Rr~

delta 35
rcmeyu_>qyF`7<w<!`#~w*=q%Y85kJ!GxBp&^;2}y5_57UPLBlu)Da8l

diff --git a/pps_ws/src/d_fall_pps/crazyradio/cflib/utils/callbacks.pyc b/pps_ws/src/d_fall_pps/crazyradio/cflib/utils/callbacks.pyc
index 74e35185cd8928cfd392adc026a7e4c35c1703a1..79876aa959683ac1070d0dc0f785b469ba986413 100644
GIT binary patch
delta 180
zcmX@fdz+V?`7<w9YUSmP?0t;F;S3B6`WgATsrt!9iB*+pIhm=GZ!>vLe#dwhhum8n
e;+~TgS&rhAvu91iA?GpqFKYx2InT-K*rWmb(msd)

delta 163
zcmcc3dy<!(`7<w<!`#~&+4~p;LKqkr^fU5vQ}t7H(-L!XCO>5IoP2<dW%5_Xo7g1Z
fVhC=2$jpbs9B<Y%4CO!zJSOw7MPQQv*(?nJ*H<&~

-- 
GitLab