From 13da1e38f019ef8989df1423164bd080768a7e04 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 14:53:11 +0300
Subject: [PATCH 01/28] Switched from NULL to nullptr

---
 src/displayapp/screens/Brightness.cpp         |  6 ++---
 src/displayapp/screens/Clock.cpp              | 22 +++++++++----------
 src/displayapp/screens/DropDownDemo.cpp       |  4 ++--
 src/displayapp/screens/FirmwareUpdate.cpp     | 10 ++++-----
 src/displayapp/screens/FirmwareValidation.cpp | 20 ++++++++---------
 src/displayapp/screens/Gauge.cpp              |  4 ++--
 src/displayapp/screens/Label.cpp              |  2 +-
 src/displayapp/screens/Meter.cpp              |  4 ++--
 src/displayapp/screens/Modal.cpp              |  6 ++---
 src/displayapp/screens/Tile.cpp               |  2 +-
 10 files changed, 40 insertions(+), 40 deletions(-)

diff --git a/src/displayapp/screens/Brightness.cpp b/src/displayapp/screens/Brightness.cpp
index 9e3416c0..8ea9a771 100644
--- a/src/displayapp/screens/Brightness.cpp
+++ b/src/displayapp/screens/Brightness.cpp
@@ -11,15 +11,15 @@ void slider_event_cb(lv_obj_t * slider, lv_event_t event) {
 }
 
 Brightness::Brightness(Pinetime::Applications::DisplayApp *app, Controllers::BrightnessController& brightness) : Screen(app), brightness{brightness} {
-  slider = lv_slider_create(lv_scr_act(), NULL);
+  slider = lv_slider_create(lv_scr_act(), nullptr);
   lv_obj_set_user_data(slider, this);
   lv_obj_set_width(slider, LV_DPI * 2);
-  lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_align(slider, nullptr, LV_ALIGN_CENTER, 0, 0);
   lv_obj_set_event_cb(slider, slider_event_cb);
   lv_slider_set_range(slider, 0, 2);
   lv_slider_set_value(slider, LevelToInt(brightness.Level()), LV_ANIM_OFF);
 
-  slider_label = lv_label_create(lv_scr_act(), NULL);
+  slider_label = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(slider_label, LevelToString(brightness.Level()));
   lv_obj_set_auto_realign(slider_label, true);
   lv_obj_align(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp
index 243d4c04..bb14d520 100644
--- a/src/displayapp/screens/Clock.cpp
+++ b/src/displayapp/screens/Clock.cpp
@@ -29,28 +29,28 @@ Clock::Clock(DisplayApp* app,
   displayedChar[3] = 0;
   displayedChar[4] = 0;
 
-  batteryIcon = lv_label_create(lv_scr_act(), NULL);
+  batteryIcon = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(batteryIcon, Symbols::batteryFull);
   lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 2);
 
-  batteryPlug = lv_label_create(lv_scr_act(), NULL);
+  batteryPlug = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(batteryPlug, Symbols::plug);
   lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0);
 
-  bleIcon = lv_label_create(lv_scr_act(), NULL);
+  bleIcon = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(bleIcon, Symbols::bluetooth);
   lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 0);
 
 
-  label_date = lv_label_create(lv_scr_act(), NULL);
+  label_date = lv_label_create(lv_scr_act(), nullptr);
 
   lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 60);
 
-  label_time = lv_label_create(lv_scr_act(), NULL);
+  label_time = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_style(label_time, LV_LABEL_STYLE_MAIN, LabelBigStyle);
   lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0);
 
-  backgroundLabel = lv_label_create(lv_scr_act(), NULL);
+  backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
   backgroundLabel->user_data = this;
   lv_obj_set_click(backgroundLabel, true);
   lv_obj_set_event_cb(backgroundLabel, event_handler);
@@ -60,23 +60,23 @@ Clock::Clock(DisplayApp* app,
   lv_label_set_text(backgroundLabel, "");
 
 
-  heartbeatIcon = lv_label_create(lv_scr_act(), NULL);
+  heartbeatIcon = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(heartbeatIcon, Symbols::heartBeat);
   lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
 
-  heartbeatValue = lv_label_create(lv_scr_act(), NULL);
+  heartbeatValue = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(heartbeatValue, "0");
   lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
 
-  heartbeatBpm = lv_label_create(lv_scr_act(), NULL);
+  heartbeatBpm = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(heartbeatBpm, "BPM");
   lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
 
-  stepValue = lv_label_create(lv_scr_act(), NULL);
+  stepValue = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(stepValue, "0");
   lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
 
-  stepIcon = lv_label_create(lv_scr_act(), NULL);
+  stepIcon = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(stepIcon, Symbols::shoe);
   lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
 }
diff --git a/src/displayapp/screens/DropDownDemo.cpp b/src/displayapp/screens/DropDownDemo.cpp
index 735a0cce..ce3acd53 100644
--- a/src/displayapp/screens/DropDownDemo.cpp
+++ b/src/displayapp/screens/DropDownDemo.cpp
@@ -9,7 +9,7 @@ extern lv_font_t jetbrains_mono_bold_20;
 
 DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp *app) : Screen(app) {
   // Create the dropdown object, with many item, and fix its height
-  ddlist = lv_ddlist_create(lv_scr_act(), NULL);
+  ddlist = lv_ddlist_create(lv_scr_act(), nullptr);
   lv_ddlist_set_options(ddlist, "Apple\n"
                                 "Banana\n"
                                 "Orange\n"
@@ -24,7 +24,7 @@ DropDownDemo::DropDownDemo(Pinetime::Applications::DisplayApp *app) : Screen(app
   lv_ddlist_set_fix_width(ddlist, 150);
   lv_ddlist_set_draw_arrow(ddlist, true);
   lv_ddlist_set_fix_height(ddlist, 150);
-  lv_obj_align(ddlist, NULL, LV_ALIGN_IN_TOP_MID, 0, 20);
+  lv_obj_align(ddlist, nullptr, LV_ALIGN_IN_TOP_MID, 0, 20);
 }
 
 DropDownDemo::~DropDownDemo() {
diff --git a/src/displayapp/screens/FirmwareUpdate.cpp b/src/displayapp/screens/FirmwareUpdate.cpp
index e831114d..778409eb 100644
--- a/src/displayapp/screens/FirmwareUpdate.cpp
+++ b/src/displayapp/screens/FirmwareUpdate.cpp
@@ -10,19 +10,19 @@ extern lv_font_t jetbrains_mono_bold_20;
 FirmwareUpdate::FirmwareUpdate(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Ble& bleController) :
       Screen(app), bleController{bleController} {
 
-  titleLabel = lv_label_create(lv_scr_act(), NULL);
+  titleLabel = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(titleLabel, "Firmware update");
   lv_obj_set_auto_realign(titleLabel, true);
-  lv_obj_align(titleLabel, NULL, LV_ALIGN_IN_TOP_MID, 0, 50);
+  lv_obj_align(titleLabel, nullptr, LV_ALIGN_IN_TOP_MID, 0, 50);
 
-  bar1 = lv_bar_create(lv_scr_act(), NULL);
+  bar1 = lv_bar_create(lv_scr_act(), nullptr);
   lv_obj_set_size(bar1, 200, 30);
-  lv_obj_align(bar1, NULL, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_align(bar1, nullptr, LV_ALIGN_CENTER, 0, 0);
   lv_bar_set_anim_time(bar1, 10);
   lv_bar_set_range(bar1, 0, 100);
   lv_bar_set_value(bar1, 0, LV_ANIM_OFF);
 
-  percentLabel = lv_label_create(lv_scr_act(), NULL);
+  percentLabel = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_text(percentLabel, "");
   lv_obj_set_auto_realign(percentLabel, true);
   lv_obj_align(percentLabel, bar1, LV_ALIGN_OUT_TOP_MID, 0, 60);
diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp
index 2300b41d..4ac399ff 100644
--- a/src/displayapp/screens/FirmwareValidation.cpp
+++ b/src/displayapp/screens/FirmwareValidation.cpp
@@ -20,20 +20,20 @@ namespace {
 FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
                                        Pinetime::Controllers::FirmwareValidator &validator)
                                        : Screen{app}, validator{validator} {
-  labelVersionInfo = lv_label_create(lv_scr_act(), NULL);
-  lv_obj_align(labelVersionInfo, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
+  labelVersionInfo = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_align(labelVersionInfo, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
   lv_label_set_text(labelVersionInfo, "Version : ");
   lv_label_set_align(labelVersionInfo, LV_LABEL_ALIGN_LEFT);
 
 
-  labelVersionValue = lv_label_create(lv_scr_act(), NULL);
+  labelVersionValue = lv_label_create(lv_scr_act(), nullptr);
   lv_obj_align(labelVersionValue, labelVersionInfo, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
   lv_label_set_recolor(labelVersionValue, true);
   sprintf(version, "%ld.%ld.%ld", Version::Major(), Version::Minor(), Version::Patch());
   lv_label_set_text(labelVersionValue, version);
 
-  labelIsValidated = lv_label_create(lv_scr_act(), NULL);
-  lv_obj_align(labelIsValidated, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50);
+  labelIsValidated = lv_label_create(lv_scr_act(), nullptr);
+  lv_obj_align(labelIsValidated, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 50);
   lv_label_set_recolor(labelIsValidated, true);
   lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK);
   lv_obj_set_width(labelIsValidated, 240);
@@ -44,21 +44,21 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp *app,
     lv_label_set_text(labelIsValidated,
                       "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version.");
 
-    buttonValidate = lv_btn_create(lv_scr_act(), NULL);
+    buttonValidate = lv_btn_create(lv_scr_act(), nullptr);
     lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
     buttonValidate->user_data = this;
     lv_obj_set_event_cb(buttonValidate, ButtonEventHandler);
 
-    labelButtonValidate = lv_label_create(buttonValidate, NULL);
+    labelButtonValidate = lv_label_create(buttonValidate, nullptr);
     lv_label_set_recolor(labelButtonValidate, true);
     lv_label_set_text(labelButtonValidate, "#00ff00 Validate#");
 
-    buttonReset = lv_btn_create(lv_scr_act(), NULL);
+    buttonReset = lv_btn_create(lv_scr_act(), nullptr);
     buttonReset->user_data = this;
-    lv_obj_align(buttonReset, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
+    lv_obj_align(buttonReset, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
     lv_obj_set_event_cb(buttonReset, ButtonEventHandler);
 
-    labelButtonReset = lv_label_create(buttonReset, NULL);
+    labelButtonReset = lv_label_create(buttonReset, nullptr);
     lv_label_set_recolor(labelButtonReset, true);
     lv_label_set_text(labelButtonReset, "#ff0000 Reset#");
   }
diff --git a/src/displayapp/screens/Gauge.cpp b/src/displayapp/screens/Gauge.cpp
index fd905231..81c283ca 100644
--- a/src/displayapp/screens/Gauge.cpp
+++ b/src/displayapp/screens/Gauge.cpp
@@ -25,11 +25,11 @@ Gauge::Gauge(Pinetime::Applications::DisplayApp *app) : Screen(app) {
   needle_colors[0] = LV_COLOR_ORANGE;
 
   /*Create a gauge*/
-  gauge1 = lv_gauge_create(lv_scr_act(), NULL);
+  gauge1 = lv_gauge_create(lv_scr_act(), nullptr);
   lv_gauge_set_style(gauge1, LV_GAUGE_STYLE_MAIN, &style);
   lv_gauge_set_needle_count(gauge1, 1, needle_colors);
   lv_obj_set_size(gauge1, 180, 180);
-  lv_obj_align(gauge1, NULL, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_align(gauge1, nullptr, LV_ALIGN_CENTER, 0, 0);
   lv_gauge_set_scale(gauge1, 360, 60, 0);
   lv_gauge_set_range(gauge1, 0, 59);
 
diff --git a/src/displayapp/screens/Label.cpp b/src/displayapp/screens/Label.cpp
index 780ee88e..540776cc 100644
--- a/src/displayapp/screens/Label.cpp
+++ b/src/displayapp/screens/Label.cpp
@@ -4,7 +4,7 @@
 using namespace Pinetime::Applications::Screens;
 
 Label::Label(Pinetime::Applications::DisplayApp *app, const char *text)  : Screen(app), text{text} {
-  label = lv_label_create(lv_scr_act(), NULL);
+  label = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_align(label, LV_LABEL_ALIGN_LEFT);
   lv_obj_set_size(label, 240, 240);
   lv_label_set_text(label, text);
diff --git a/src/displayapp/screens/Meter.cpp b/src/displayapp/screens/Meter.cpp
index c74b8bdf..273e111d 100644
--- a/src/displayapp/screens/Meter.cpp
+++ b/src/displayapp/screens/Meter.cpp
@@ -17,14 +17,14 @@ Meter::Meter(Pinetime::Applications::DisplayApp *app) : Screen(app) {
   style_lmeter.body.padding.left = 16;                           /*Line length*/
 
   /*Create a line meter */
-  lmeter = lv_lmeter_create(lv_scr_act(), NULL);
+  lmeter = lv_lmeter_create(lv_scr_act(), nullptr);
   lv_lmeter_set_range(lmeter, 0, 60);                   /*Set the range*/
   lv_lmeter_set_value(lmeter, value);                       /*Set the current value*/
   lv_lmeter_set_angle_offset(lmeter, 180);
   lv_lmeter_set_scale(lmeter, 360, 60);                  /*Set the angle and number of lines*/
   lv_lmeter_set_style(lmeter, LV_LMETER_STYLE_MAIN, &style_lmeter);           /*Apply the new style*/
   lv_obj_set_size(lmeter, 150, 150);
-  lv_obj_align(lmeter, NULL, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_align(lmeter, nullptr, LV_ALIGN_CENTER, 0, 0);
 
 }
 
diff --git a/src/displayapp/screens/Modal.cpp b/src/displayapp/screens/Modal.cpp
index 63ae70c0..29f7bfa7 100644
--- a/src/displayapp/screens/Modal.cpp
+++ b/src/displayapp/screens/Modal.cpp
@@ -54,7 +54,7 @@ void Modal::Show(const char* msg) {
   modal_style.body.main_color = modal_style.body.grad_color = LV_COLOR_BLACK;
   modal_style.body.opa = LV_OPA_50;
 
-  obj = lv_obj_create(lv_scr_act(), NULL);
+  obj = lv_obj_create(lv_scr_act(), nullptr);
   lv_obj_set_style(obj, &modal_style);
   lv_obj_set_pos(obj, 0, 0);
   lv_obj_set_size(obj, LV_HOR_RES, LV_VER_RES);
@@ -63,10 +63,10 @@ void Modal::Show(const char* msg) {
   static const char * btns2[] = {"Ok", ""};
 
   /* Create the message box as a child of the modal background */
-  mbox = lv_mbox_create(obj, NULL);
+  mbox = lv_mbox_create(obj, nullptr);
   lv_mbox_add_btns(mbox, btns2);
   lv_mbox_set_text(mbox, msg);
-  lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
+  lv_obj_align(mbox, nullptr, LV_ALIGN_CENTER, 0, 0);
   lv_obj_set_event_cb(mbox, Modal::mbox_event_cb);
 
   mbox->user_data = this;
diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp
index deb88472..75fa6ef5 100644
--- a/src/displayapp/screens/Tile.cpp
+++ b/src/displayapp/screens/Tile.cpp
@@ -30,7 +30,7 @@ Tile::Tile(DisplayApp* app, std::array<Applications, 6>& applications) : Screen(
   }
   modal.reset(new Modal(app));
 
-  btnm1 = lv_btnm_create(lv_scr_act(), NULL);
+  btnm1 = lv_btnm_create(lv_scr_act(), nullptr);
   lv_btnm_set_map(btnm1, btnm_map1);
   lv_obj_set_size(btnm1, LV_HOR_RES, LV_VER_RES);
 

From e85d1ffc625c73dcbb30c783707bfb6110af6a41 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 15:09:17 +0300
Subject: [PATCH 02/28] Replaced NULL with nullptr

---
 src/systemtask/SystemMonitor.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/systemtask/SystemMonitor.h b/src/systemtask/SystemMonitor.h
index ec1fd817..029a1364 100644
--- a/src/systemtask/SystemMonitor.h
+++ b/src/systemtask/SystemMonitor.h
@@ -27,7 +27,7 @@ namespace Pinetime {
         void Process() const {
           if(xTaskGetTickCount() - lastTick > 10000) {
             NRF_LOG_INFO("---------------------------------------\nFree heap : %d", xPortGetFreeHeapSize());
-            auto nb = uxTaskGetSystemState(tasksStatus, 10, NULL);
+            auto nb = uxTaskGetSystemState(tasksStatus, 10, nullptr);
             for (uint32_t i = 0; i < nb; i++) {
               NRF_LOG_INFO("Task [%s] - %d", tasksStatus[i].pcTaskName, tasksStatus[i].usStackHighWaterMark);
               if (tasksStatus[i].usStackHighWaterMark < 20)

From 1d96758acd4e3bf03c3e733a3a95d0deb74f6042 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 15:11:21 +0300
Subject: [PATCH 03/28] Minor #include improvements

---
 src/displayapp/screens/Tab.cpp |  4 ++--
 src/systemtask/SystemTask.cpp  | 10 ++++++----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/displayapp/screens/Tab.cpp b/src/displayapp/screens/Tab.cpp
index adc32578..44b806c0 100644
--- a/src/displayapp/screens/Tab.cpp
+++ b/src/displayapp/screens/Tab.cpp
@@ -1,13 +1,13 @@
 #include <cstdio>
 #include <libs/date/includes/date/date.h>
-#include <Components/DateTime/DateTimeController.h>
+#include "components/datetime/DateTimeController.h"
 #include <Version.h>
 #include <libs/lvgl/src/lv_core/lv_obj.h>
 #include <libs/lvgl/src/lv_font/lv_font.h>
 #include <libs/lvgl/lvgl.h>
 #include <libraries/log/nrf_log.h>
 #include "Tab.h"
-#include <DisplayApp/DisplayApp.h>
+#include "displayapp/DisplayApp.h"
 
 
 using namespace Pinetime::Applications::Screens;
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 68f8ab53..0ed99f86 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -11,7 +11,7 @@
 #include <host/ble_gap.h>
 #include <host/util/util.h>
 #include <drivers/InternalFlash.h>
-#include "../main.h"
+#include "main.h"
 #include "components/ble/NimbleController.h"
 
 using namespace Pinetime::System;
@@ -36,7 +36,7 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd,
                        bleController{bleController}, dateTimeController{dateTimeController},
                        watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager},
                        nimbleController(*this, bleController,dateTimeController, notificationManager, batteryController, spiNorFlash) {
-  systemTaksMsgQueue = xQueueCreate(10, 1);
+  systemTasksMsgQueue = xQueueCreate(10, 1);
 }
 
 void SystemTask::Start() {
@@ -102,7 +102,7 @@ void SystemTask::Work() {
 
   while(true) {
     uint8_t msg;
-    if (xQueueReceive(systemTaksMsgQueue, &msg, isSleeping?2500 : 1000)) {
+    if (xQueueReceive(systemTasksMsgQueue, &msg, isSleeping ? 2500 : 1000)) {
       Messages message = static_cast<Messages >(msg);
       switch(message) {
         case Messages::GoToRunning:
@@ -191,6 +191,8 @@ void SystemTask::Work() {
     if(!nrf_gpio_pin_read(pinButton))
       watchdog.Kick();
   }
+  // Clear diagnostic suppression
+  #pragma clang diagnostic pop
 }
 
 void SystemTask::OnButtonPushed() {
@@ -228,7 +230,7 @@ void SystemTask::PushMessage(SystemTask::Messages msg) {
   }
   BaseType_t xHigherPriorityTaskWoken;
   xHigherPriorityTaskWoken = pdFALSE;
-  xQueueSendFromISR(systemTaksMsgQueue, &msg, &xHigherPriorityTaskWoken);
+  xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken);
   if (xHigherPriorityTaskWoken) {
     /* Actual macro used here is port specific. */
     // TODO : should I do something here?

From 9b7ba7b5b84072e5abbb0c77c7ea5c52cbbb1098 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 15:13:01 +0300
Subject: [PATCH 04/28] Fixed a typo in SystemTask

---
 src/systemtask/SystemTask.cpp | 6 +++---
 src/systemtask/SystemTask.h   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 68f8ab53..bb3a7728 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -36,7 +36,7 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd,
                        bleController{bleController}, dateTimeController{dateTimeController},
                        watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager},
                        nimbleController(*this, bleController,dateTimeController, notificationManager, batteryController, spiNorFlash) {
-  systemTaksMsgQueue = xQueueCreate(10, 1);
+  systemTasksMsgQueue = xQueueCreate(10, 1);
 }
 
 void SystemTask::Start() {
@@ -102,7 +102,7 @@ void SystemTask::Work() {
 
   while(true) {
     uint8_t msg;
-    if (xQueueReceive(systemTaksMsgQueue, &msg, isSleeping?2500 : 1000)) {
+    if (xQueueReceive(systemTasksMsgQueue, &msg, isSleeping?2500 : 1000)) {
       Messages message = static_cast<Messages >(msg);
       switch(message) {
         case Messages::GoToRunning:
@@ -228,7 +228,7 @@ void SystemTask::PushMessage(SystemTask::Messages msg) {
   }
   BaseType_t xHigherPriorityTaskWoken;
   xHigherPriorityTaskWoken = pdFALSE;
-  xQueueSendFromISR(systemTaksMsgQueue, &msg, &xHigherPriorityTaskWoken);
+  xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken);
   if (xHigherPriorityTaskWoken) {
     /* Actual macro used here is port specific. */
     // TODO : should I do something here?
diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h
index 1be28e3f..6ef0cfbf 100644
--- a/src/systemtask/SystemTask.h
+++ b/src/systemtask/SystemTask.h
@@ -54,7 +54,7 @@ namespace Pinetime {
         std::unique_ptr<Pinetime::Applications::DisplayApp> displayApp;
         Pinetime::Controllers::Ble& bleController;
         Pinetime::Controllers::DateTime& dateTimeController;
-        QueueHandle_t systemTaksMsgQueue;
+        QueueHandle_t systemTasksMsgQueue;
         std::atomic<bool> isSleeping{false};
         std::atomic<bool> isGoingToSleep{false};
         std::atomic<bool> isWakingUp{false};

From 77f4d5448bb05287a3802ce3511817fc27a825ab Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 15:14:09 +0300
Subject: [PATCH 05/28] Fixed a small warning with Screen's constructor

---
 src/displayapp/screens/Screen.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h
index dbf81a44..0a17b4da 100644
--- a/src/displayapp/screens/Screen.h
+++ b/src/displayapp/screens/Screen.h
@@ -9,7 +9,7 @@ namespace Pinetime {
     namespace Screens {
       class Screen {
         public:
-          Screen(DisplayApp* app) : app{app} {}
+          explicit Screen(DisplayApp* app) : app{app} {}
           virtual ~Screen() = default;
 
           // Return false if the app can be closed, true if it must continue to run

From cc3a9f3c793b943eb633f7c914e654ae19b77b9b Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 18:46:34 +0300
Subject: [PATCH 06/28] Removed an incomplete message() call from
 CMakeLists.txt

---
 src/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2f38ec58..961dedb4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -747,7 +747,6 @@ elseif (USE_OPENOCD)
                 COMMENT "flashing ${EXECUTABLE_NAME}.hex"
                 )
     else ()
-        message()
         add_custom_target(FLASH_ERASE
                 COMMAND ${OPENOCD_BIN_PATH} -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c init -c halt -c 'nrf5 mass_erase' -c reset -c shutdown
                 COMMENT "erasing flashing"

From c4599dbf90d10cf140579388a400b2d5ffd9ff58 Mon Sep 17 00:00:00 2001
From: Maarten de Jong <35239587+arteeh@users.noreply.github.com>
Date: Tue, 6 Oct 2020 21:10:51 +0200
Subject: [PATCH 07/28] Fix typo

GCC output file is .out instead of .bin
---
 doc/filesInReleaseNotes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/filesInReleaseNotes.md b/doc/filesInReleaseNotes.md
index d2930513..2fdfadf4 100644
--- a/doc/filesInReleaseNotes.md
+++ b/doc/filesInReleaseNotes.md
@@ -42,7 +42,7 @@ This firmware is intended to be used with our [MCUBoot-based bootloader](../boot
 
 The following files are not directly usable by the bootloader:
 
- - **pinetime-mcuboot-app.bin** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB.
+ - **pinetime-mcuboot-app.out** : Output file of GCC containing debug symbols, useful is you want to debug the firmware using GDB.
  - **pinetime-mcuboot-app.hex** : Firmware in Intel HEX file format. 
  - **pinetime-mcuboot-app.bin** : Firmware in binary format. 
  - **pinetime-mcuboot-app.map** : Map file containing all the symbols, addresses in memory,...

From f68c7b65b31f0bb7ff729740a29d5796b2c04f01 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 15:08:48 +0300
Subject: [PATCH 08/28] Minor formatting, diagnostic and documentation changes

---
 src/CMakeLists.txt                     |  2 +-
 src/displayapp/screens/InfiniPaint.cpp | 12 ++++++------
 src/displayapp/screens/Screen.h        | 18 +++++++++++++++---
 src/logging/NrfLogger.cpp              |  5 +++++
 src/systemtask/SystemTask.cpp          |  5 ++++-
 5 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 961dedb4..cd37810f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -552,7 +552,7 @@ link_directories(
 )
 
 
-set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type)
+set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wno-unknown-pragmas -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type)
 add_definitions(-DCONFIG_GPIO_AS_PINRESET)
 add_definitions(-DDEBUG)
 add_definitions(-DNIMBLE_CFG_CONTROLLER)
diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp
index b340f5d8..312bb93a 100644
--- a/src/displayapp/screens/InfiniPaint.cpp
+++ b/src/displayapp/screens/InfiniPaint.cpp
@@ -7,9 +7,9 @@ using namespace Pinetime::Applications::Screens;
 extern lv_font_t jetbrains_mono_extrabold_compressed;
 extern lv_font_t jetbrains_mono_bold_20;
 
-InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp *app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} {
+InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp *app, Pinetime::Components::LittleVgl &lvgl) : Screen(app), lvgl{lvgl} {
   app->SetTouchMode(DisplayApp::TouchModes::Polling);
-  std::fill(b, b+bufferSize, LV_COLOR_WHITE);
+  std::fill(b, b + bufferSize, LV_COLOR_WHITE);
 }
 
 InfiniPaint::~InfiniPaint() {
@@ -33,10 +33,10 @@ bool InfiniPaint::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
 
 bool InfiniPaint::OnTouchEvent(uint16_t x, uint16_t y) {
   lv_area_t area;
-  area.x1 = x-(width/2);
-  area.y1 = y-(height/2);
-  area.x2 = x+(width/2)-1;
-  area.y2 = y+(height/2)-1;
+  area.x1 = x - (width / 2);
+  area.y1 = y - (height / 2);
+  area.x2 = x + (width / 2) - 1;
+  area.y2 = y + (height / 2) - 1;
   lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
   lvgl.FlushDisplay(&area, b);
   return true;
diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h
index 0a17b4da..6b1d0eec 100644
--- a/src/displayapp/screens/Screen.h
+++ b/src/displayapp/screens/Screen.h
@@ -12,13 +12,25 @@ namespace Pinetime {
           explicit Screen(DisplayApp* app) : app{app} {}
           virtual ~Screen() = default;
 
-          // Return false if the app can be closed, true if it must continue to run
+          /**
+           * Most of the time, apps only react to events (touch events, for example).
+           * In this case you don't need to do anything in this method.
+           *
+           * For example, InfiniPaint does nothing in Refresh().
+           * But, if you want to update your display periodically, draw an animation...
+           * you cannot do it in a touch event handler because these handlers are not
+           * called if the user does not touch the screen.
+           *
+           * That's why Refresh() is there: update the display periodically.
+           *
+           * @return false if the app can be closed, true if it must continue to run
+           **/
           virtual bool Refresh() = 0;
 
-          // Return false if the button hasn't been handled by the app, true if it has been handled
+          /** @return false if the button hasn't been handled by the app, true if it has been handled */
           virtual bool OnButtonPushed() { return false; }
 
-          // Return false if the event hasn't been handled by the app, true if it has been handled
+          /** @return false if the event hasn't been handled by the app, true if it has been handled */
           virtual bool OnTouchEvent(TouchEvents event) { return false; }
           virtual bool OnTouchEvent(uint16_t x, uint16_t y) { return false; }
 
diff --git a/src/logging/NrfLogger.cpp b/src/logging/NrfLogger.cpp
index 7ccacc82..0d95c06a 100644
--- a/src/logging/NrfLogger.cpp
+++ b/src/logging/NrfLogger.cpp
@@ -19,10 +19,15 @@ void NrfLogger::Init() {
 
 void NrfLogger::Process(void*) {
   NRF_LOG_INFO("Logger task started!");
+  // Suppress endless loop diagnostic
+  #pragma clang diagnostic push
+  #pragma ide diagnostic ignored "EndlessLoop"
   while (1) {
     NRF_LOG_FLUSH();
     vTaskDelay(100); // Not good for power consumption, it will wake up every 100ms...
   }
+  // Clear diagnostic suppression
+  #pragma clang diagnostic pop
 }
 
 void NrfLogger::Resume() {
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index c0552d53..01942daf 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -100,6 +100,9 @@ void SystemTask::Work() {
   idleTimer = xTimerCreate ("idleTimer", idleTime, pdFALSE, this, IdleTimerCallback);
   xTimerStart(idleTimer, 0);
 
+  // Suppress endless loop diagnostic
+  #pragma clang diagnostic push
+  #pragma ide diagnostic ignored "EndlessLoop"
   while(true) {
     uint8_t msg;
     if (xQueueReceive(systemTasksMsgQueue, &msg, isSleeping ? 2500 : 1000)) {
@@ -231,7 +234,7 @@ void SystemTask::PushMessage(SystemTask::Messages msg) {
   xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken);
   if (xHigherPriorityTaskWoken) {
     /* Actual macro used here is port specific. */
-    // TODO : should I do something here?
+    // TODO: should I do something here?
   }
 }
 

From 189c5a83b2599dd843b06d2cccdc1f28a89d404f Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 4 Oct 2020 16:24:52 +0300
Subject: [PATCH 09/28] Made sure to unsuppress the diagnostic check after the
 infinite loop declaration

---
 src/systemtask/SystemTask.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 01942daf..3efe21b8 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -194,6 +194,8 @@ void SystemTask::Work() {
     if(!nrf_gpio_pin_read(pinButton))
       watchdog.Kick();
   }
+  // Clear diagnostic suppression
+  #pragma clang diagnostic pop
 }
 
 void SystemTask::OnButtonPushed() {

From 1c645b776a7c13ea03caba5d0547e073ed0faeae Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Fri, 9 Oct 2020 11:34:28 +0300
Subject: [PATCH 10/28] Improved code formatting rules

---
 .idea/codeStyles/Project.xml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index b3b93deb..7bdfbcb1 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -7,6 +7,10 @@
       <option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
       <option name="INDENT_DIRECTIVE_AS_CODE" value="true" />
       <option name="SPACE_BEFORE_TEMPLATE_DECLARATION_LT" value="true" />
+      <option name="SPACE_BEFORE_POINTER_IN_DECLARATION" value="false" />
+      <option name="SPACE_AFTER_POINTER_IN_DECLARATION" value="true" />
+      <option name="SPACE_BEFORE_REFERENCE_IN_DECLARATION" value="false" />
+      <option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
     </Objective-C>
     <codeStyleSettings language="ObjectiveC">
       <option name="RIGHT_MARGIN" value="140" />

From fd110dabe82f100550a7538c0e3eb3a439c9a7d2 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Fri, 9 Oct 2020 11:35:32 +0300
Subject: [PATCH 11/28] Reformatted InfiniPaint again

---
 src/displayapp/screens/InfiniPaint.cpp |  2 +-
 src/displayapp/screens/InfiniPaint.h   | 40 ++++++++++++++------------
 2 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/src/displayapp/screens/InfiniPaint.cpp b/src/displayapp/screens/InfiniPaint.cpp
index 312bb93a..3ea75e9e 100644
--- a/src/displayapp/screens/InfiniPaint.cpp
+++ b/src/displayapp/screens/InfiniPaint.cpp
@@ -7,7 +7,7 @@ using namespace Pinetime::Applications::Screens;
 extern lv_font_t jetbrains_mono_extrabold_compressed;
 extern lv_font_t jetbrains_mono_bold_20;
 
-InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp *app, Pinetime::Components::LittleVgl &lvgl) : Screen(app), lvgl{lvgl} {
+InfiniPaint::InfiniPaint(Pinetime::Applications::DisplayApp* app, Pinetime::Components::LittleVgl& lvgl) : Screen(app), lvgl{lvgl} {
   app->SetTouchMode(DisplayApp::TouchModes::Polling);
   std::fill(b, b + bufferSize, LV_COLOR_WHITE);
 }
diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h
index fb4f979b..f29135d5 100644
--- a/src/displayapp/screens/InfiniPaint.h
+++ b/src/displayapp/screens/InfiniPaint.h
@@ -11,24 +11,28 @@
 namespace Pinetime {
   namespace Applications {
     namespace Screens {
-
-      class InfiniPaint : public Screen{
-        public:
-          InfiniPaint(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl);
-          ~InfiniPaint() override;
-
-          bool Refresh() override;
-          bool OnButtonPushed() override;
-          bool OnTouchEvent(TouchEvents event) override;
-          bool OnTouchEvent(uint16_t x, uint16_t y) override;
-
-        private:
-          Pinetime::Components::LittleVgl& lvgl;
-          static constexpr uint16_t width = 10;
-          static constexpr uint16_t height = 10;
-          static constexpr uint16_t bufferSize = width*height;
-          lv_color_t b[bufferSize];
-          bool running = true;
+      
+      class InfiniPaint : public Screen {
+      public:
+        InfiniPaint(DisplayApp* app, Pinetime::Components::LittleVgl& lvgl);
+        
+        ~InfiniPaint() override;
+        
+        bool Refresh() override;
+        
+        bool OnButtonPushed() override;
+        
+        bool OnTouchEvent(TouchEvents event) override;
+        
+        bool OnTouchEvent(uint16_t x, uint16_t y) override;
+      
+      private:
+        Pinetime::Components::LittleVgl& lvgl;
+        static constexpr uint16_t width = 10;
+        static constexpr uint16_t height = 10;
+        static constexpr uint16_t bufferSize = width * height;
+        lv_color_t b[bufferSize];
+        bool running = true;
       };
     }
   }

From efb7a973a1f243bebb2628173d45d22cefc07143 Mon Sep 17 00:00:00 2001
From: Rafa Couto <rafacouto@users.noreply.github.com>
Date: Mon, 12 Oct 2020 05:12:31 +0200
Subject: [PATCH 12/28] Update SystemInfo.cpp

Show MAC bytes with left-zeroes
---
 src/displayapp/screens/SystemInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index 8a3b8dbb..6ab3df8b 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -105,7 +105,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() {
 
 std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
   auto& bleAddr = bleController.Address();
-  sprintf(t2, "BLE MAC: \n  %2x:%2x:%2x:%2x:%2x:%2x",
+  sprintf(t2, "BLE MAC: \n  %02x:%02x:%02x:%02x:%02x:%02x",
           bleAddr[5], bleAddr[4], bleAddr[3], bleAddr[2], bleAddr[1], bleAddr[0]);
   return std::unique_ptr<Screen>(new Screens::Label(app, t2));
 }

From 2d5ddb88a74bf9a58788054631179c2aac79f902 Mon Sep 17 00:00:00 2001
From: Robert Curtin <robertecurtin@gmail.com>
Date: Mon, 12 Oct 2020 08:45:41 -0400
Subject: [PATCH 13/28] Noticed this typo when booting my PineTime

---
 src/displayapp/screens/SystemInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp
index 8a3b8dbb..3e00f7de 100644
--- a/src/displayapp/screens/SystemInfo.cpp
+++ b/src/displayapp/screens/SystemInfo.cpp
@@ -111,6 +111,6 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
 }
 
 std::unique_ptr<Screen> SystemInfo::CreateScreen3() {
-  strncpy(t3, "Hello from\nthe developper!", 27);
+  strncpy(t3, "Hello from\nthe developer!", 27);
   return std::unique_ptr<Screen>(new Screens::Label(app, t3));
 }

From 2b9906184bcff68d2c4d35a350bdb2b787a761fb Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Sun, 11 Oct 2020 03:11:55 +0300
Subject: [PATCH 14/28] Refactored and improved the Music watchapp

---
 src/components/ble/MusicService.cpp     | 290 +++++++++++++-------
 src/components/ble/MusicService.h       | 216 ++++++++++-----
 src/displayapp/icons/music/disc.cpp     | 110 ++++++++
 src/displayapp/icons/music/disc.png     | Bin 0 -> 516 bytes
 src/displayapp/icons/music/disc_f_1.cpp |  79 ++++++
 src/displayapp/icons/music/disc_f_1.png | Bin 0 -> 200 bytes
 src/displayapp/icons/music/disc_f_2.cpp |  79 ++++++
 src/displayapp/icons/music/disc_f_2.png | Bin 0 -> 197 bytes
 src/displayapp/screens/Music.cpp        | 350 +++++++++++++++++-------
 src/displayapp/screens/Music.h          | 100 +++++--
 10 files changed, 932 insertions(+), 292 deletions(-)
 create mode 100644 src/displayapp/icons/music/disc.cpp
 create mode 100644 src/displayapp/icons/music/disc.png
 create mode 100644 src/displayapp/icons/music/disc_f_1.cpp
 create mode 100644 src/displayapp/icons/music/disc_f_1.png
 create mode 100644 src/displayapp/icons/music/disc_f_2.cpp
 create mode 100644 src/displayapp/icons/music/disc_f_2.png

diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp
index 9105a8e6..84f2972b 100644
--- a/src/components/ble/MusicService.cpp
+++ b/src/components/ble/MusicService.cpp
@@ -1,129 +1,225 @@
+/*  Copyright (C) 2020 JF, Adam Pigg, Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
 #include <systemtask/SystemTask.h>
 #include "MusicService.h"
 
 int MSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
-  auto musicService = static_cast<Pinetime::Controllers::MusicService*>(arg);
+  auto musicService = static_cast<Pinetime::Controllers::MusicService *>(arg);
   return musicService->OnCommand(conn_handle, attr_handle, ctxt);
 }
 
-Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system)
-{
-    msUuid.value[11] = msId[0];
-    msUuid.value[12] = msId[1];
-    msEventCharUuid.value[11] = msEventCharId[0];
-    msEventCharUuid.value[12] = msEventCharId[1];
-    msStatusCharUuid.value[11] = msStatusCharId[0];
-    msStatusCharUuid.value[12] = msStatusCharId[1];
-    msTrackCharUuid.value[11] = msTrackCharId[0];
-    msTrackCharUuid.value[12] = msTrackCharId[1];
-    msArtistCharUuid.value[11] = msArtistCharId[0];
-    msArtistCharUuid.value[12] = msArtistCharId[1];
-    msAlbumCharUuid.value[11] = msAlbumCharId[0];
-    msAlbumCharUuid.value[12] = msAlbumCharId[1];
-
-    characteristicDefinition[0] = { .uuid = (ble_uuid_t*)(&msEventCharUuid),
-                                    .access_cb = MSCallback,
-                                    .arg = this,
-                                    .flags =  BLE_GATT_CHR_F_NOTIFY,
-                                    .val_handle = &m_eventHandle
-    };
-    characteristicDefinition[1] = { .uuid = (ble_uuid_t*)(&msStatusCharUuid),
-                                    .access_cb = MSCallback,
-                                    .arg = this,
-                                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
-    };
-    characteristicDefinition[2] = { .uuid = (ble_uuid_t*)(&msTrackCharUuid),
-                                    .access_cb = MSCallback,
-                                    .arg = this,
-                                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
-    };
-    characteristicDefinition[3] = { .uuid = (ble_uuid_t*)(&msArtistCharUuid),
-                                    .access_cb = MSCallback,
-                                    .arg = this,
-                                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
-    };
-    characteristicDefinition[4] = { .uuid = (ble_uuid_t*)(&msAlbumCharUuid),
-                                    .access_cb = MSCallback,
-                                    .arg = this,
-                                    .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
-    };
-    characteristicDefinition[5] = {0};
-
-    serviceDefinition[0] = {
-                        .type = BLE_GATT_SVC_TYPE_PRIMARY,
-                        .uuid = (ble_uuid_t *) &msUuid,
-                        .characteristics = characteristicDefinition
-    };
-    serviceDefinition[1] = {0};
-
-    m_artist = "Waiting for";
-    m_album = "";
-    m_track = "track information...";
+Pinetime::Controllers::MusicService::MusicService(Pinetime::System::SystemTask &system) : m_system(system) {
+  msUuid.value[11] = msId[0];
+  msUuid.value[12] = msId[1];
+  msEventCharUuid.value[11] = msEventCharId[0];
+  msEventCharUuid.value[12] = msEventCharId[1];
+  msStatusCharUuid.value[11] = msStatusCharId[0];
+  msStatusCharUuid.value[12] = msStatusCharId[1];
+  msTrackCharUuid.value[11] = msTrackCharId[0];
+  msTrackCharUuid.value[12] = msTrackCharId[1];
+  msArtistCharUuid.value[11] = msArtistCharId[0];
+  msArtistCharUuid.value[12] = msArtistCharId[1];
+  msAlbumCharUuid.value[11] = msAlbumCharId[0];
+  msAlbumCharUuid.value[12] = msAlbumCharId[1];
+  msPositionCharUuid.value[11] = msPositionCharId[0];
+  msPositionCharUuid.value[12] = msPositionCharId[1];
+  msTotalLengthCharUuid.value[11] = msTotalLengthCharId[0];
+  msTotalLengthCharUuid.value[12] = msTotalLengthCharId[1];
+  msTrackNumberCharUuid.value[11] = msTrackNumberCharId[0];
+  msTrackNumberCharUuid.value[12] = msTrackNumberCharId[1];
+  msTrackTotalCharUuid.value[11] = msTrackTotalCharId[0];
+  msTrackTotalCharUuid.value[12] = msTrackTotalCharId[1];
+  msPlaybackSpeedCharUuid.value[11] = msPlaybackSpeedCharId[0];
+  msPlaybackSpeedCharUuid.value[12] = msPlaybackSpeedCharId[1];
+  msRepeatCharUuid.value[11] = msRepeatCharId[0];
+  msRepeatCharUuid.value[12] = msRepeatCharId[1];
+  msShuffleCharUuid.value[11] = msShuffleCharId[0];
+  msShuffleCharUuid.value[12] = msShuffleCharId[1];
+  
+  characteristicDefinition[0] = {.uuid = (ble_uuid_t *) (&msEventCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags =  BLE_GATT_CHR_F_NOTIFY,
+      .val_handle = &eventHandle
+  };
+  characteristicDefinition[1] = {.uuid = (ble_uuid_t *) (&msStatusCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[2] = {.uuid = (ble_uuid_t *) (&msTrackCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[3] = {.uuid = (ble_uuid_t *) (&msArtistCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[4] = {.uuid = (ble_uuid_t *) (&msAlbumCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[5] = {.uuid = (ble_uuid_t *) (&msPositionCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[6] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[7] = {.uuid = (ble_uuid_t *) (&msTotalLengthCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[8] = {.uuid = (ble_uuid_t *) (&msTrackNumberCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[9] = {.uuid = (ble_uuid_t *) (&msTrackTotalCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[10] = {.uuid = (ble_uuid_t *) (&msPlaybackSpeedCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[11] = {.uuid = (ble_uuid_t *) (&msRepeatCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[12] = {.uuid = (ble_uuid_t *) (&msShuffleCharUuid),
+      .access_cb = MSCallback,
+      .arg = this,
+      .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ
+  };
+  characteristicDefinition[13] = {0};
+  
+  serviceDefinition[0] = {
+      .type = BLE_GATT_SVC_TYPE_PRIMARY,
+      .uuid = (ble_uuid_t *) &msUuid,
+      .characteristics = characteristicDefinition
+  };
+  serviceDefinition[1] = {0};
+  
+  artistName = "Waiting for";
+  albumName = "";
+  trackName = "track information...";
+  playing = false;
+  repeat = false;
+  shuffle = false;
+  playbackSpeed = 1.0f;
+  trackProgress = 0;
+  trackLength = 0;
 }
 
-void Pinetime::Controllers::MusicService::Init()
-{
+void Pinetime::Controllers::MusicService::Init() {
   int res = 0;
   res = ble_gatts_count_cfg(serviceDefinition);
   ASSERT(res == 0);
-
+  
   res = ble_gatts_add_svcs(serviceDefinition);
   ASSERT(res == 0);
 }
 
 int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle,
-                                                    struct ble_gatt_access_ctxt *ctxt) {
-
+                                                   struct ble_gatt_access_ctxt *ctxt) {
+  
   if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
-        size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
-        uint8_t data[notifSize + 1];
-        data[notifSize] = '\0';
-        os_mbuf_copydata(ctxt->om, 0, notifSize, data);
-        char *s = (char *) &data[0];
-        NRF_LOG_INFO("DATA : %s", s);
-        if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *)&msArtistCharUuid) == 0) {
-            m_artist = s;
-        } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *)&msTrackCharUuid) == 0) {
-            m_track = s;
-        } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *)&msAlbumCharUuid) == 0) {
-            m_album = s;
-        } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *)&msStatusCharUuid) == 0) {
-            m_status = s[0];
-        }
+    size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
+    uint8_t data[notifSize + 1];
+    data[notifSize] = '\0';
+    os_mbuf_copydata(ctxt->om, 0, notifSize, data);
+    char *s = (char *) &data[0];
+    NRF_LOG_INFO("DATA : %s", s);
+    if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msArtistCharUuid) == 0) {
+      artistName = s;
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackCharUuid) == 0) {
+      trackName = s;
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msAlbumCharUuid) == 0) {
+      albumName = s;
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msStatusCharUuid) == 0) {
+      playing = s[0];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msRepeatCharUuid) == 0) {
+      repeat = s[0];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msShuffleCharUuid) == 0) {
+      shuffle = s[0];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPositionCharUuid) == 0) {
+      trackProgress = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTotalLengthCharUuid) == 0) {
+      trackLength = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackNumberCharUuid) == 0) {
+      trackNumber = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msTrackTotalCharUuid) == 0) {
+      tracksTotal = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+    } else if (ble_uuid_cmp(ctxt->chr->uuid, (ble_uuid_t *) &msPlaybackSpeedCharUuid) == 0) {
+      playbackSpeed = static_cast<float>(((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])) / 100.0f;
+    }
   }
   return 0;
 }
 
-std::string Pinetime::Controllers::MusicService::album()
-{
-    return m_album;
+std::string Pinetime::Controllers::MusicService::getAlbum() {
+  return albumName;
 }
 
-std::string Pinetime::Controllers::MusicService::artist()
-{
-    return m_artist;
+std::string Pinetime::Controllers::MusicService::getArtist() {
+  return artistName;
 }
 
-std::string Pinetime::Controllers::MusicService::track()
-{
-    return m_track;
+std::string Pinetime::Controllers::MusicService::getTrack() {
+  return trackName;
 }
 
-unsigned char Pinetime::Controllers::MusicService::status()
-{
-    return m_status;
+bool Pinetime::Controllers::MusicService::isPlaying() {
+  return playing;
 }
 
-void Pinetime::Controllers::MusicService::event(char event)
-{
-    auto *om = ble_hs_mbuf_from_flat(&event, 1);
-
-    uint16_t connectionHandle = m_system.nimble().connHandle();
-
-    if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
-        return;
-    }
-
-    ble_gattc_notify_custom(connectionHandle, m_eventHandle, om);
+float Pinetime::Controllers::MusicService::getPlaybackSpeed() {
+  return playbackSpeed;
+}
+
+void Pinetime::Controllers::MusicService::event(char event) {
+  auto *om = ble_hs_mbuf_from_flat(&event, 1);
+  
+  uint16_t connectionHandle = m_system.nimble().connHandle();
+  
+  if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
+    return;
+  }
+  
+  ble_gattc_notify_custom(connectionHandle, eventHandle, om);
+}
+
+int Pinetime::Controllers::MusicService::getProgress() {
+  return trackProgress;
+}
+
+int Pinetime::Controllers::MusicService::getTrackLength() {
+  return trackLength;
 }
 
diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h
index ab6db572..00cffb27 100644
--- a/src/components/ble/MusicService.h
+++ b/src/components/ble/MusicService.h
@@ -1,3 +1,20 @@
+/*  Copyright (C) 2020 JF, Adam Pigg, Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
 #pragma once
 
 #include <cstdint>
@@ -14,78 +31,135 @@ namespace Pinetime {
     class SystemTask;
   }
   namespace Controllers {
-
+    
     class MusicService {
-      public:
-        MusicService(Pinetime::System::SystemTask &system);
-        void Init();
-        int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
-                                    struct ble_gatt_access_ctxt *ctxt);
-
-        std::string artist();
-        std::string track();
-        std::string album();
-        unsigned char status();
-
-        void event(char event);
-
-        static const char EVENT_MUSIC_OPEN = 0xe0;
-        static const char EVENT_MUSIC_PLAY = 0x00;
-        static const char EVENT_MUSIC_PAUSE = 0x01;
-        static const char EVENT_MUSIC_NEXT = 0x03;
-        static const char EVENT_MUSIC_PREV = 0x04;
-        static const char EVENT_MUSIC_VOLUP = 0x05;
-        static const char EVENT_MUSIC_VOLDOWN = 0x06;
-        static const char STATUS_MUSIC_PAUSED = 0x00;
-        static const char STATUS_MUSIC_PLAYING = 0x01;
-
-      private:
-        static constexpr uint8_t msId[2] = {0x00, 0x01};
-        static constexpr uint8_t msEventCharId[2] = {0x00, 0x02};
-        static constexpr uint8_t msStatusCharId[2] = {0x00, 0x03};
-        static constexpr uint8_t msArtistCharId[2] = {0x00, 0x04};
-        static constexpr uint8_t msTrackCharId[2] = {0x00, 0x05};
-        static constexpr uint8_t msAlbumCharId[2] = {0x00, 0x06};
-
-        ble_uuid128_t msUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-
-        ble_uuid128_t msEventCharUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-        ble_uuid128_t msStatusCharUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-        ble_uuid128_t msArtistCharUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-        ble_uuid128_t msTrackCharUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-        ble_uuid128_t msAlbumCharUuid {
-                .u = { .type = BLE_UUID_TYPE_128 },
-                .value = MUSIC_SERVICE_UUID_BASE
-        };
-
-        struct ble_gatt_chr_def characteristicDefinition[6];
-        struct ble_gatt_svc_def serviceDefinition[2];
-
-        uint16_t m_eventHandle;
-
-        std::string m_artist;
-        std::string m_album;
-        std::string m_track;
-
-        unsigned char m_status;
-
-        Pinetime::System::SystemTask& m_system;
-
+    public:
+      explicit MusicService(Pinetime::System::SystemTask &system);
+      
+      void Init();
+      
+      int OnCommand(uint16_t conn_handle, uint16_t attr_handle,
+                    struct ble_gatt_access_ctxt *ctxt);
+      
+      void event(char event);
+      
+      std::string getArtist();
+      
+      std::string getTrack();
+      
+      std::string getAlbum();
+      
+      int getProgress();
+      
+      int getTrackLength();
+      
+      float getPlaybackSpeed();
+      
+      bool isPlaying();
+      
+      static const char EVENT_MUSIC_OPEN = 0xe0;
+      static const char EVENT_MUSIC_PLAY = 0x00;
+      static const char EVENT_MUSIC_PAUSE = 0x01;
+      static const char EVENT_MUSIC_NEXT = 0x03;
+      static const char EVENT_MUSIC_PREV = 0x04;
+      static const char EVENT_MUSIC_VOLUP = 0x05;
+      static const char EVENT_MUSIC_VOLDOWN = 0x06;
+      
+      enum MusicStatus {
+        NOT_PLAYING = 0x00,
+        PLAYING = 0x01
+      };
+    private:
+      static constexpr uint8_t msId[2] = {0x00, 0x01};
+      static constexpr uint8_t msEventCharId[2] = {0x00, 0x02};
+      static constexpr uint8_t msStatusCharId[2] = {0x00, 0x03};
+      static constexpr uint8_t msArtistCharId[2] = {0x00, 0x04};
+      static constexpr uint8_t msTrackCharId[2] = {0x00, 0x05};
+      static constexpr uint8_t msAlbumCharId[2] = {0x00, 0x06};
+      static constexpr uint8_t msPositionCharId[2] = {0x00, 0x07};
+      static constexpr uint8_t msTotalLengthCharId[2] = {0x00, 0x08};
+      static constexpr uint8_t msTrackNumberCharId[2] = {0x00, 0x09};
+      static constexpr uint8_t msTrackTotalCharId[2] = {0x00, 0x0a};
+      static constexpr uint8_t msPlaybackSpeedCharId[2] = {0x00, 0x0b};
+      static constexpr uint8_t msRepeatCharId[2] = {0x00, 0x0c};
+      static constexpr uint8_t msShuffleCharId[2] = {0x00, 0x0d};
+      
+      ble_uuid128_t msUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      
+      ble_uuid128_t msEventCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msStatusCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msArtistCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msTrackCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msAlbumCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msPositionCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msTotalLengthCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msTrackNumberCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msTrackTotalCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msPlaybackSpeedCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msRepeatCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      ble_uuid128_t msShuffleCharUuid{
+          .u = {.type = BLE_UUID_TYPE_128},
+          .value = MUSIC_SERVICE_UUID_BASE
+      };
+      
+      struct ble_gatt_chr_def characteristicDefinition[14];
+      struct ble_gatt_svc_def serviceDefinition[2];
+      
+      uint16_t eventHandle;
+      
+      std::string artistName;
+      std::string albumName;
+      std::string trackName;
+      
+      bool playing;
+      
+      int trackProgress;
+      int trackLength;
+      int trackNumber;
+      int tracksTotal;
+      
+      float playbackSpeed;
+      
+      bool repeat;
+      bool shuffle;
+      
+      Pinetime::System::SystemTask &m_system;
     };
   }
 }
diff --git a/src/displayapp/icons/music/disc.cpp b/src/displayapp/icons/music/disc.cpp
new file mode 100644
index 00000000..0957873f
--- /dev/null
+++ b/src/displayapp/icons/music/disc.cpp
@@ -0,0 +1,110 @@
+/*  Copyright (C) 2020 Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "lvgl/lvgl.h"
+
+#ifndef LV_ATTRIBUTE_MEM_ALIGN
+#define LV_ATTRIBUTE_MEM_ALIGN
+#endif
+
+#ifndef LV_ATTRIBUTE_IMG_DISC
+#define LV_ATTRIBUTE_IMG_DISC
+#endif
+
+const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC uint8_t disc_map[] = {
+    0xbd, 0xc1, 0xbe, 0xff,  /* Color of index 0: foreground */
+    0x00, 0x00, 0x00, 0x00,  /* Color of index 1: background */
+    
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff,
+    0xff, 0xff, 0xf0, 0x0f, 0xf8, 0x07, 0xff, 0xff,
+    0xff, 0xff, 0xc0, 0xff, 0xff, 0x81, 0xff, 0xff,
+    0xff, 0xff, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff,
+    0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff,
+    0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xff,
+    0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff,
+    0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff,
+    0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff,
+    0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff,
+    0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f,
+    0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f,
+    0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+    0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+    0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f,
+    0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf,
+    0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
+    0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7,
+    0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3,
+    0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3,
+    0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1,
+    0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1,
+    0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9,
+    0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9,
+    0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
+    0x8f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf8,
+    0x9f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe3, 0xe3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe7, 0xf3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xe3, 0xe3, 0xff, 0xff, 0xfc,
+    0x9f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfc,
+    0x8f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf8,
+    0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
+    0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9,
+    0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9,
+    0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1,
+    0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1,
+    0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3,
+    0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3,
+    0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7,
+    0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
+    0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf,
+    0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f,
+    0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+    0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f,
+    0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f,
+    0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f,
+    0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff,
+    0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff,
+    0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff,
+    0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff,
+    0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xff,
+    0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff,
+    0xff, 0xff, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff,
+    0xff, 0xff, 0xc0, 0xff, 0xff, 0x81, 0xff, 0xff,
+    0xff, 0xff, 0xf0, 0x0f, 0xf8, 0x07, 0xff, 0xff,
+    0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff,
+};
+
+const lv_img_dsc_t disc = {
+    {
+        LV_IMG_CF_INDEXED_1BIT,
+        0,
+        0,
+        64,
+        64
+    },
+    520,
+    disc_map
+};
\ No newline at end of file
diff --git a/src/displayapp/icons/music/disc.png b/src/displayapp/icons/music/disc.png
new file mode 100644
index 0000000000000000000000000000000000000000..699734fb9c7f8b8069857730bce2860cfb672460
GIT binary patch
literal 516
zcmV+f0{i`mP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00009a7bBm0013_
z0013_0gvVJWdHyHwn;=mRCwC$TTu?eFbGw$V|k3lLl{qHJjRY?qF*L+b}e)*P+-5t
z!F#*`-QawG-QFk1*TiLLUasW-JTH&#ew}+Mpa!r6A<YRW0mp!7aSwI^_MC3vY|nci
zCLrZp&u6!_y=nruf%mdsMZnfLC-Bz3z{ucJ_Nmo}q=5C!rGdBd53GRS`h`^jSOH&4
z0$2iHLjqU>PbC2?f~SxGC+8PfjXqWdAblQ}XqK`B^f<?BZI-eMuoC?e9`F?X6i)CE
z{Twdv7X2;W=mWgSe-B?Mz~l43&I6N_VJ-a!a2qeFjYExVoRd`KQ)GXCpO-6}5=4^V
z9yo~#6jdMy2m*otHGP0YL&jPLpO?o^sngI5vA+;0f#Yt*L|S1@Cr<Ei1kME_s(^+}
zELnj<0U8q%XCelSOsvZPj{q+!SmOi=Th^kVBp_ak8&m;#M5bokYy|MxZ-dbZ8dL#h
z)CWBxGa3olIj7<yFd_+*Aum)87>NYxgc~{ujzB`qcprITLfgK;QJ=_V@aTeqCh%1X
z$N_h=GbBlbnyoQxziobRka~bJyE)2nk{n`pxFsPRN%aHbSs=<6z5CMu0000<MNUMn
GLSTXfUeibb

literal 0
HcmV?d00001

diff --git a/src/displayapp/icons/music/disc_f_1.cpp b/src/displayapp/icons/music/disc_f_1.cpp
new file mode 100644
index 00000000..9b6b7417
--- /dev/null
+++ b/src/displayapp/icons/music/disc_f_1.cpp
@@ -0,0 +1,79 @@
+/*  Copyright (C) 2020 Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "lvgl/lvgl.h"
+
+#ifndef LV_ATTRIBUTE_MEM_ALIGN
+#define LV_ATTRIBUTE_MEM_ALIGN
+#endif
+
+#ifndef LV_ATTRIBUTE_IMG_DISC_F_1
+#define LV_ATTRIBUTE_IMG_DISC_F_1
+#endif
+
+const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC_F_1 uint8_t disc_f_1_map[] = {
+    0xbd, 0xc1, 0xbe, 0xff,  /* Color of index 0: foreground */
+    0x00, 0x00, 0x00, 0x00,  /* Color of index 1: background */
+    
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xc0,
+    0xff, 0xff, 0xfc, 0x00,
+    0xff, 0xff, 0xf0, 0x0f,
+    0xff, 0xff, 0xc0, 0xff,
+    0xff, 0xff, 0x07, 0xff,
+    0xff, 0xfc, 0x1f, 0xff,
+    0xff, 0xf8, 0x7f, 0xff,
+    0xff, 0xf0, 0xff, 0xff,
+    0xff, 0xe3, 0xff, 0xff,
+    0xff, 0xc7, 0xf3, 0xff,
+    0xff, 0x8f, 0xc3, 0xff,
+    0xff, 0x1f, 0x87, 0xff,
+    0xfe, 0x3f, 0x0f, 0xff,
+    0xfc, 0x7e, 0x1f, 0xff,
+    0xfc, 0x7c, 0x3f, 0xff,
+    0xf8, 0xfc, 0x7f, 0xff,
+    0xf9, 0xfc, 0xff, 0xff,
+    0xf1, 0xff, 0xff, 0xff,
+    0xf3, 0xff, 0xff, 0xff,
+    0xe3, 0xff, 0xff, 0xff,
+    0xe7, 0xff, 0xff, 0xff,
+    0xc7, 0xff, 0xff, 0xff,
+    0xc7, 0xff, 0xff, 0xff,
+    0xcf, 0xff, 0xff, 0xff,
+    0xcf, 0xff, 0xff, 0xff,
+    0x8f, 0xff, 0xff, 0xff,
+    0x8f, 0xff, 0xff, 0xf8,
+    0x9f, 0xff, 0xff, 0xf0,
+    0x9f, 0xff, 0xff, 0xe3,
+    0x9f, 0xff, 0xff, 0xe7,
+    0x9f, 0xff, 0xff, 0xe7,
+};
+
+const lv_img_dsc_t disc_f_1 = {
+    {
+        LV_IMG_CF_INDEXED_1BIT,
+        0,
+        0,
+        32,
+        32
+    },
+    136,
+    disc_f_1_map
+};
+
diff --git a/src/displayapp/icons/music/disc_f_1.png b/src/displayapp/icons/music/disc_f_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..946577344afa6d87ed4be12d174b4f779acdc287
GIT binary patch
literal 200
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)Tn`*Lkn<<2zGSN?P=vF<
zBeIx*LAD))8T+4pOa%&Nc)B=-a9p=NyOFm+L7?^FYaPkPz=$&$nI}2cIVCy16cE`W
zA?2g@sQQ>gQGDUgVvpm(J`7q5Bm{QMZiu=N7H~sVNc#i(hUn?XXX@=*aQS9wX4j9f
t5^??TNgis21$=+}C(G`i?DFY2xBcJz`0X3|P6F*@@O1TaS?83{1OQm8N4Ed~

literal 0
HcmV?d00001

diff --git a/src/displayapp/icons/music/disc_f_2.cpp b/src/displayapp/icons/music/disc_f_2.cpp
new file mode 100644
index 00000000..3d2331d1
--- /dev/null
+++ b/src/displayapp/icons/music/disc_f_2.cpp
@@ -0,0 +1,79 @@
+/*  Copyright (C) 2020 Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include "lvgl/lvgl.h"
+
+#ifndef LV_ATTRIBUTE_MEM_ALIGN
+#define LV_ATTRIBUTE_MEM_ALIGN
+#endif
+
+#ifndef LV_ATTRIBUTE_IMG_DISC_F_2
+#define LV_ATTRIBUTE_IMG_DISC_F_2
+#endif
+
+const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_DISC_F_2 uint8_t disc_f_2_map[] = {
+    0xbd, 0xc1, 0xbe, 0xff,  /* Color of index 0: foreground */
+    0x00, 0x00, 0x00, 0x00,  /* Color of index 1: background */
+    
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xc0,
+    0xff, 0xff, 0xfc, 0x00,
+    0xff, 0xff, 0xf0, 0x0f,
+    0xff, 0xff, 0xc0, 0xff,
+    0xff, 0xff, 0x07, 0xff,
+    0xff, 0xfc, 0x1f, 0xff,
+    0xff, 0xf8, 0x7f, 0xf1,
+    0xff, 0xf0, 0xff, 0x00,
+    0xff, 0xe3, 0xfc, 0x03,
+    0xff, 0xc7, 0xf0, 0x3f,
+    0xff, 0x8f, 0xf0, 0xff,
+    0xff, 0x1f, 0xf3, 0xff,
+    0xfe, 0x3f, 0xff, 0xff,
+    0xfc, 0x7f, 0xff, 0xff,
+    0xfc, 0x7f, 0xff, 0xff,
+    0xf8, 0xff, 0xff, 0xff,
+    0xf9, 0xff, 0xff, 0xff,
+    0xf1, 0xff, 0xff, 0xff,
+    0xf3, 0xff, 0xff, 0xff,
+    0xe3, 0xff, 0xff, 0xff,
+    0xe7, 0xff, 0xff, 0xff,
+    0xc7, 0xff, 0xff, 0xff,
+    0xc7, 0xff, 0xff, 0xff,
+    0xcf, 0xff, 0xff, 0xff,
+    0xcf, 0xff, 0xff, 0xff,
+    0x8f, 0xff, 0xff, 0xff,
+    0x8f, 0xff, 0xff, 0xf8,
+    0x9f, 0xff, 0xff, 0xf0,
+    0x9f, 0xff, 0xff, 0xe3,
+    0x9f, 0xff, 0xff, 0xe7,
+    0x9f, 0xff, 0xff, 0xe7,
+};
+
+const lv_img_dsc_t disc_f_2 = {
+    {
+        LV_IMG_CF_INDEXED_1BIT,
+        0,
+        0,
+        32,
+        32
+    },
+    136,
+    disc_f_2_map
+};
+
diff --git a/src/displayapp/icons/music/disc_f_2.png b/src/displayapp/icons/music/disc_f_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d9a4a388a00c95eac16b501a7c4dac326d029cb
GIT binary patch
literal 197
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)Tn`*Lkn<<2zGSN?P=vF<
zBeIx*LAD))8T+4pOa%(2db&7<a9p=Ndyw;h0uSp22Y%Z!7Wcv}eGfQdkIp{M_weBA
zM@OA9e${94K5-QKA?VC$#UvVFF0eDY(aPYPS{U#3HQf=b;&c+suKVWoGu*9b`>c1#
pLw%;mB(>)%H9VFd=B5P2$$6bCa1OI**blUj!PC{xWt~$(696G%LhAqk

literal 0
HcmV?d00001

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 9b7d198b..fc87a9e7 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -1,72 +1,120 @@
+/*  Copyright (C) 2020 JF, Adam Pigg, Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
 #include <libs/lvgl/lvgl.h>
+
 #include "Music.h"
 
 using namespace Pinetime::Applications::Screens;
+
 extern lv_font_t jetbrains_mono_extrabold_compressed;
 extern lv_font_t jetbrains_mono_bold_20;
 
-static void event_handler(lv_obj_t * obj, lv_event_t event)
-{
-  Music* screen = static_cast<Music *>(obj->user_data);
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+  Music *screen = static_cast<Music *>(obj->user_data);
   screen->OnObjectEvent(obj, event);
 }
 
+/**
+ * Music control watchapp
+ *
+ * TODO: Investigate Apple Media Service and AVRCPv1.6 support for seamless integration
+ */
 Music::Music(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::MusicService &music) : Screen(app), musicService(music) {
-    lv_obj_t * label;
-
-    btnVolDown = lv_btn_create(lv_scr_act(), NULL);
-    btnVolDown->user_data = this;
-    lv_obj_set_event_cb(btnVolDown, event_handler);
-    lv_obj_align(btnVolDown, NULL, LV_ALIGN_IN_TOP_LEFT, 10, 10);
-    label = lv_label_create(btnVolDown, NULL);
-    lv_label_set_text(label, "v-");
-
-    btnVolUp = lv_btn_create(lv_scr_act(), NULL);
-    btnVolUp->user_data = this;
-    lv_obj_set_event_cb(btnVolUp, event_handler);
-    lv_obj_align(btnVolUp, NULL, LV_ALIGN_IN_TOP_RIGHT, -10, 10);
-    label = lv_label_create(btnVolUp, NULL);
-    lv_label_set_text(label, "v+");
-
-    btnPrev = lv_btn_create(lv_scr_act(), NULL);
-    btnPrev->user_data = this;
-    lv_obj_set_event_cb(btnPrev, event_handler);
-    lv_obj_set_size(btnPrev, LV_HOR_RES / 4, LV_VER_RES / 4);
-    lv_obj_align(btnPrev, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 10,-10);
-    label = lv_label_create(btnPrev, NULL);
-    lv_label_set_text(label, "<<");
-
-    btnPlayPause = lv_btn_create(lv_scr_act(), NULL);
-    btnPlayPause->user_data = this;
-    lv_obj_set_event_cb(btnPlayPause, event_handler);
-    lv_obj_set_size(btnPlayPause, LV_HOR_RES / 4, LV_VER_RES / 4);
-    lv_obj_align(btnPlayPause, NULL, LV_ALIGN_IN_BOTTOM_MID, 0,-10);
-    txtPlayPause = lv_label_create(btnPlayPause, NULL);
-    lv_label_set_text(txtPlayPause, ">");
-
-    btnNext = lv_btn_create(lv_scr_act(), NULL);
-    btnNext->user_data = this;
-    lv_obj_set_event_cb(btnNext, event_handler);
-    lv_obj_set_size(btnNext, LV_HOR_RES / 4, LV_VER_RES / 4);
-    lv_obj_align(btnNext, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, -10,-10);
-    label = lv_label_create(btnNext, NULL);
-    lv_label_set_text(label, ">>");
-
-    txtArtist = lv_label_create(lv_scr_act(), NULL);
-    lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL);
-    lv_obj_align(txtArtist, NULL, LV_ALIGN_IN_LEFT_MID, 0,-20);
-    lv_label_set_text(txtArtist, "Artist Name");
-    lv_label_set_align(txtArtist, LV_LABEL_ALIGN_CENTER);
-    lv_obj_set_width(txtArtist, LV_HOR_RES);
-
-    txtTrack = lv_label_create(lv_scr_act(), NULL);
-    lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_DOT);
-    lv_obj_align(txtTrack, NULL, LV_ALIGN_IN_LEFT_MID, 0,20);
-    lv_label_set_text(txtTrack, "This is a very long track name");
-    lv_label_set_align(txtTrack, LV_LABEL_ALIGN_CENTER);
-    lv_obj_set_width(txtTrack, LV_HOR_RES);
-
-    musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN);
+  lv_obj_t *label;
+  
+  btnVolDown = lv_btn_create(lv_scr_act(), nullptr);
+  btnVolDown->user_data = this;
+  lv_obj_set_event_cb(btnVolDown, event_handler);
+  lv_obj_set_size(btnVolDown, LV_HOR_RES / 3, 80);
+  lv_obj_align(btnVolDown, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+  label = lv_label_create(btnVolDown, nullptr);
+  lv_label_set_text(label, "V-");
+  lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
+  
+  btnVolUp = lv_btn_create(lv_scr_act(), nullptr);
+  btnVolUp->user_data = this;
+  lv_obj_set_event_cb(btnVolUp, event_handler);
+  lv_obj_set_size(btnVolUp, LV_HOR_RES / 3, 80);
+  lv_obj_align(btnVolUp, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
+  label = lv_label_create(btnVolUp, nullptr);
+  lv_label_set_text(label, "V+");
+  lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
+  
+  btnPrev = lv_btn_create(lv_scr_act(), nullptr);
+  btnPrev->user_data = this;
+  lv_obj_set_event_cb(btnPrev, event_handler);
+  lv_obj_set_size(btnPrev, LV_HOR_RES / 3, 80);
+  lv_obj_align(btnPrev, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
+  label = lv_label_create(btnPrev, nullptr);
+  lv_label_set_text(label, "<<");
+  
+  btnNext = lv_btn_create(lv_scr_act(), nullptr);
+  btnNext->user_data = this;
+  lv_obj_set_event_cb(btnNext, event_handler);
+  lv_obj_set_size(btnNext, LV_HOR_RES / 3, 80);
+  lv_obj_align(btnNext, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
+  label = lv_label_create(btnNext, nullptr);
+  lv_label_set_text(label, ">>");
+  
+  btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
+  btnPlayPause->user_data = this;
+  lv_obj_set_event_cb(btnPlayPause, event_handler);
+  lv_obj_set_size(btnPlayPause, LV_HOR_RES / 3, 80);
+  lv_obj_align(btnPlayPause, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+  txtPlayPause = lv_label_create(btnPlayPause, nullptr);
+  lv_label_set_text(txtPlayPause, ">");
+  
+  txtTrackDuration = lv_label_create(lv_scr_act(), nullptr);
+  lv_label_set_long_mode(txtTrackDuration, LV_LABEL_LONG_SROLL);
+  lv_obj_align(txtTrackDuration, nullptr, LV_ALIGN_IN_TOP_LEFT, 12, 20);
+  lv_label_set_text(txtTrackDuration, "--:--/--:--");
+  lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_LEFT_MID);
+  lv_obj_set_width(txtTrackDuration, LV_HOR_RES);
+  
+  #define FONT_HEIGHT (12)
+  #define MIDDLE_OFFSET (-25)
+  #define LINE_PAD (15)
+  txtArtist = lv_label_create(lv_scr_act(), nullptr);
+  lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL);
+  lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);
+  lv_label_set_text(txtArtist, "Artist Name");
+  lv_label_set_align(txtArtist, LV_ALIGN_IN_LEFT_MID);
+  lv_obj_set_width(txtArtist, LV_HOR_RES);
+  
+  txtTrack = lv_label_create(lv_scr_act(), nullptr);
+  lv_label_set_long_mode(txtTrack, LV_LABEL_LONG_SROLL);
+  lv_obj_align(txtTrack, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 2 * FONT_HEIGHT + LINE_PAD);
+  lv_label_set_text(txtTrack, "This is a very long getTrack name");
+  lv_label_set_align(txtTrack, LV_ALIGN_IN_LEFT_MID);
+  lv_obj_set_width(txtTrack, LV_HOR_RES);
+  
+  /** Init animation */
+  imgDisc = lv_img_create(lv_scr_act(), nullptr);
+  lv_img_set_src_arr(imgDisc, &disc);
+  lv_obj_align(imgDisc, nullptr, LV_ALIGN_IN_TOP_RIGHT, -15, 15);
+  
+  imgDiscAnim = lv_img_create(lv_scr_act(), nullptr);
+  lv_img_set_src_arr(imgDiscAnim, &disc_f_1);
+  lv_obj_align(imgDiscAnim, nullptr, LV_ALIGN_IN_TOP_RIGHT, -15 - 32, 15);
+  
+  frameB = false;
+  
+  musicService.event(Controllers::MusicService::EVENT_MUSIC_OPEN);
 }
 
 Music::~Music() {
@@ -79,47 +127,155 @@ bool Music::OnButtonPushed() {
 }
 
 bool Music::Refresh() {
-
-    if (m_artist != musicService.artist()) {
-        m_artist = musicService.artist();
-        lv_label_set_text(txtArtist, m_artist.data());
+  if (artist != musicService.getArtist()) {
+    artist = musicService.getArtist();
+    currentLength = 0;
+    lv_label_set_text(txtArtist, artist.data());
+  }
+  
+  if (track != musicService.getTrack()) {
+    track = musicService.getTrack();
+    currentLength = 0;
+    lv_label_set_text(txtTrack, track.data());
+  }
+  
+  if (album != musicService.getAlbum()) {
+    album = musicService.getAlbum();
+    currentLength = 0;
+  }
+  
+  if (playing != musicService.isPlaying()) {
+    playing = musicService.isPlaying();
+  }
+  
+  // Because we increment this ourselves,
+  // we can't compare with the old data directly
+  // have to update it when there's actually new data
+  // just to avoid unnecessary draws that make UI choppy
+  if (lastLength != musicService.getProgress()) {
+    currentLength = musicService.getProgress();
+    lastLength = currentLength;
+    UpdateLength();
+  }
+  
+  if (totalLength != musicService.getTrackLength()) {
+    totalLength = musicService.getTrackLength();
+    UpdateLength();
+  }
+  
+  if (playing == Pinetime::Controllers::MusicService::MusicStatus::PLAYING) {
+    lv_label_set_text(txtPlayPause, "||");
+    if (xTaskGetTickCount() - 1024 >= lastIncrement) {
+      
+      if (frameB) {
+        lv_img_set_src(imgDiscAnim, &disc_f_1);
+      } else {
+        lv_img_set_src(imgDiscAnim, &disc_f_2);
+      }
+      frameB = !frameB;
+      
+      if (currentLength < totalLength) {
+        currentLength += static_cast<int>((static_cast<float>(xTaskGetTickCount() - lastIncrement) / 1024.0f) *
+                                          musicService.getPlaybackSpeed());
+      } else {
+        // Let's assume the getTrack finished, paused when the timer ends
+        //  and there's no new getTrack being sent to us
+        // TODO: ideally this would be configurable
+        playing = false;
+      }
+      lastIncrement = xTaskGetTickCount();
+      
+      UpdateLength();
     }
-    if (m_track != musicService.track()) {
-        m_track = musicService.track();
-        lv_label_set_text(txtTrack, m_track.data());
-    }
-    if (m_album != musicService.album()) {
-        m_album = musicService.album();
-    }
-    if (m_status != musicService.status()) {
-        m_status = musicService.status();
-    }
-    if (m_status == Pinetime::Controllers::MusicService::STATUS_MUSIC_PLAYING) {
-        lv_label_set_text(txtPlayPause, "||");
-    } else {
-        lv_label_set_text(txtPlayPause, ">");
-    }
-
+  } else {
+    lv_label_set_text(txtPlayPause, ">");
+  }
+  
   return running;
 }
 
-void Music::OnObjectEvent(lv_obj_t* obj, lv_event_t event)
-{
-    if (event == LV_EVENT_CLICKED) {
-        if (obj == btnVolDown) {
-            musicService.event(Controllers::MusicService::EVENT_MUSIC_VOLDOWN);
-        } else if (obj == btnVolUp) {
-            musicService.event(Controllers::MusicService::EVENT_MUSIC_VOLUP);
-        } else if (obj == btnPrev) {
-            musicService.event(Controllers::MusicService::EVENT_MUSIC_PREV);
-        } else if (obj == btnPlayPause) {
-            if (m_status == Pinetime::Controllers::MusicService::STATUS_MUSIC_PLAYING) {
-                musicService.event(Controllers::MusicService::EVENT_MUSIC_PAUSE);
-            } else {
-                musicService.event(Controllers::MusicService::EVENT_MUSIC_PLAY);
-            }
-        } else if (obj == btnNext) {
-            musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT);
-        }
-    }
+void Music::UpdateLength() {
+  if (totalLength > (99 * 60 * 60)) {
+    lv_label_set_text(txtTrackDuration, "Inf/Inf");
+  } else if (totalLength > (99 * 60)) {
+    char timer[12];
+    sprintf(timer, "%02d:%02d/%02d:%02d",
+            (currentLength / (60 * 60)) % 100,
+            ((currentLength % (60 * 60)) / 60) % 100,
+            (totalLength / (60 * 60)) % 100,
+            ((totalLength % (60 * 60)) / 60) % 100
+    );
+    lv_label_set_text(txtTrackDuration, timer);
+  } else {
+    char timer[12];
+    sprintf(timer, "%02d:%02d/%02d:%02d",
+            (currentLength / 60) % 100,
+            (currentLength % 60) % 100,
+            (totalLength / 60) % 100,
+            (totalLength % 60) % 100
+    );
+    lv_label_set_text(txtTrackDuration, timer);
+  }
 }
+
+void Music::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
+  if (event == LV_EVENT_CLICKED) {
+    if (obj == btnVolDown) {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_VOLDOWN);
+    } else if (obj == btnVolUp) {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_VOLUP);
+    } else if (obj == btnPrev) {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_PREV);
+    } else if (obj == btnPlayPause) {
+      if (playing == Pinetime::Controllers::MusicService::MusicStatus::PLAYING) {
+        musicService.event(Controllers::MusicService::EVENT_MUSIC_PAUSE);
+        
+        // Let's assume it stops playing instantly
+        playing = Controllers::MusicService::NOT_PLAYING;
+      } else {
+        musicService.event(Controllers::MusicService::EVENT_MUSIC_PLAY);
+        
+        // Let's assume it starts playing instantly
+        // TODO: In the future should check for BT connection for better UX
+        playing = Controllers::MusicService::PLAYING;
+      }
+    } else if (obj == btnNext) {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT);
+    }
+  }
+}
+
+
+bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
+  switch (event) {
+    case TouchEvents::SwipeUp: {
+      displayVolumeButtons = true;
+      lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
+      lv_obj_set_hidden(btnVolUp, !displayVolumeButtons);
+      
+      lv_obj_set_hidden(btnNext, displayVolumeButtons);
+      lv_obj_set_hidden(btnPrev, displayVolumeButtons);
+      return true;
+    }
+    case TouchEvents::SwipeDown: {
+      displayVolumeButtons = false;
+      lv_obj_set_hidden(btnNext, displayVolumeButtons);
+      lv_obj_set_hidden(btnPrev, displayVolumeButtons);
+      
+      lv_obj_set_hidden(btnVolDown, !displayVolumeButtons);
+      lv_obj_set_hidden(btnVolUp, !displayVolumeButtons);
+      return true;
+    }
+    case TouchEvents::SwipeLeft: {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT);
+      return true;
+    }
+    case TouchEvents::SwipeRight: {
+      musicService.event(Controllers::MusicService::EVENT_MUSIC_PREV);
+      return true;
+    }
+    default: {
+      return true;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/displayapp/screens/Music.h b/src/displayapp/screens/Music.h
index d43d31cc..81ba7935 100644
--- a/src/displayapp/screens/Music.h
+++ b/src/displayapp/screens/Music.h
@@ -1,3 +1,20 @@
+/*  Copyright (C) 2020 JF, Adam Pigg, Avamander
+
+    This file is part of InfiniTime.
+
+    InfiniTime is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    InfiniTime is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
 #pragma once
 
 #include <cstdint>
@@ -13,37 +30,66 @@
 #include <libs/lvgl/src/lv_core/lv_style.h>
 #include <libs/lvgl/src/lv_core/lv_obj.h>
 #include "../../Version.h"
+#include "displayapp/icons/music/disc.cpp"
+#include "displayapp/icons/music/disc_f_1.cpp"
+#include "displayapp/icons/music/disc_f_2.cpp"
 
 namespace Pinetime {
   namespace Applications {
     namespace Screens {
-
-      class Music : public Screen{
-        public:
-          Music(DisplayApp* app, Pinetime::Controllers::MusicService &music);
-          ~Music() override;
-
-          bool Refresh() override;
-          bool OnButtonPushed() override;
-
-          void OnObjectEvent(lv_obj_t* obj, lv_event_t event);
-
-        private:
-          lv_obj_t * btnPrev;
-          lv_obj_t * btnPlayPause;
-          lv_obj_t * btnNext;
-          lv_obj_t * btnVolDown;
-          lv_obj_t * btnVolUp;
-          lv_obj_t * txtArtist;
-          lv_obj_t * txtTrack;
-          lv_obj_t * txtPlayPause;
-
-          bool running = true;
-          Pinetime::Controllers::MusicService &musicService;
-          std::string m_artist;
-          std::string m_album;
-          std::string m_track;
-          unsigned char m_status;
+      class Music : public Screen {
+      public:
+        Music(DisplayApp *app, Pinetime::Controllers::MusicService &music);
+        
+        ~Music() override;
+        
+        bool Refresh() override;
+        
+        bool OnButtonPushed() override;
+        
+        void OnObjectEvent(lv_obj_t *obj, lv_event_t event);
+      
+      private:
+        bool OnTouchEvent(TouchEvents event);
+        
+        void UpdateLength();
+        
+        lv_obj_t *btnPrev;
+        lv_obj_t *btnPlayPause;
+        lv_obj_t *btnNext;
+        lv_obj_t *btnVolDown;
+        lv_obj_t *btnVolUp;
+        lv_obj_t *txtArtist;
+        lv_obj_t *txtTrack;
+        lv_obj_t *txtPlayPause;
+        
+        lv_obj_t *imgDisc;
+        lv_obj_t *imgDiscAnim;
+        lv_obj_t *txtTrackDuration;
+        
+        /** For the spinning disc animation */
+        bool frameB;
+        
+        bool displayVolumeButtons = false;
+        Pinetime::Controllers::MusicService &musicService;
+        
+        std::string artist;
+        std::string album;
+        std::string track;
+        
+        /** Total length in seconds */
+        int totalLength;
+        /** Current length in seconds */
+        int currentLength;
+        /** Last length */
+        int lastLength;
+        /** Last time an animation update or timer was incremented */
+        TickType_t lastIncrement;
+        
+        bool playing;
+        
+        /** Watchapp */
+        bool running = true;
       };
     }
   }

From 82126edf887c5d2dc4829cbe7e0e70e91d1494cf Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Wed, 14 Oct 2020 22:47:56 +0300
Subject: [PATCH 15/28] Added lv_img_set_src_arr that does better type checking
 when drawing images from arrays

---
 src/displayapp/screens/Music.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index fc87a9e7..82355e21 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -278,4 +278,15 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
       return true;
     }
   }
+}
+
+/**
+ * Set the pixel array to display by the image
+ * This just calls lv_img_set_src but adds type safety
+ *
+ * @param img pointer to an image object
+ * @param data the image array
+ */
+inline void lv_img_set_src_arr(lv_obj_t *img, const lv_img_dsc_t *src_img) {
+  lv_img_set_src(img, src_img);
 }
\ No newline at end of file

From d4531d7bf393af56bf295fee399893802dfcac40 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Thu, 15 Oct 2020 22:16:01 +0300
Subject: [PATCH 16/28] Reordered the functions in Music.cpp correctly

---
 src/displayapp/screens/Music.cpp | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 82355e21..63e2e276 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -29,6 +29,17 @@ static void event_handler(lv_obj_t *obj, lv_event_t event) {
   screen->OnObjectEvent(obj, event);
 }
 
+/**
+ * Set the pixel array to display by the image
+ * This just calls lv_img_set_src but adds type safety
+ *
+ * @param img pointer to an image object
+ * @param data the image array
+ */
+inline void lv_img_set_src_arr(lv_obj_t *img, const lv_img_dsc_t *src_img) {
+  lv_img_set_src(img, src_img);
+}
+
 /**
  * Music control watchapp
  *
@@ -278,15 +289,4 @@ bool Music::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
       return true;
     }
   }
-}
-
-/**
- * Set the pixel array to display by the image
- * This just calls lv_img_set_src but adds type safety
- *
- * @param img pointer to an image object
- * @param data the image array
- */
-inline void lv_img_set_src_arr(lv_obj_t *img, const lv_img_dsc_t *src_img) {
-  lv_img_set_src(img, src_img);
 }
\ No newline at end of file

From 6f45c0f669effacb535b8985396fe3b21a9a08f7 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Thu, 15 Oct 2020 22:45:53 +0300
Subject: [PATCH 17/28] Unified MusicStatus enum constant capitalization with
 others

---
 src/components/ble/MusicService.h |  4 ++--
 src/displayapp/screens/Music.cpp  | 14 +++++++-------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h
index 00cffb27..b365909b 100644
--- a/src/components/ble/MusicService.h
+++ b/src/components/ble/MusicService.h
@@ -66,8 +66,8 @@ namespace Pinetime {
       static const char EVENT_MUSIC_VOLDOWN = 0x06;
       
       enum MusicStatus {
-        NOT_PLAYING = 0x00,
-        PLAYING = 0x01
+        NotPlaying = 0x00,
+        Playing = 0x01
       };
     private:
       static constexpr uint8_t msId[2] = {0x00, 0x01};
diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 63e2e276..12c7e5ad 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -174,10 +174,10 @@ bool Music::Refresh() {
     UpdateLength();
   }
   
-  if (playing == Pinetime::Controllers::MusicService::MusicStatus::PLAYING) {
+  if (playing == Pinetime::Controllers::MusicService::MusicStatus::Playing) {
     lv_label_set_text(txtPlayPause, "||");
     if (xTaskGetTickCount() - 1024 >= lastIncrement) {
-      
+    
       if (frameB) {
         lv_img_set_src(imgDiscAnim, &disc_f_1);
       } else {
@@ -238,17 +238,17 @@ void Music::OnObjectEvent(lv_obj_t *obj, lv_event_t event) {
     } else if (obj == btnPrev) {
       musicService.event(Controllers::MusicService::EVENT_MUSIC_PREV);
     } else if (obj == btnPlayPause) {
-      if (playing == Pinetime::Controllers::MusicService::MusicStatus::PLAYING) {
+      if (playing == Pinetime::Controllers::MusicService::MusicStatus::Playing) {
         musicService.event(Controllers::MusicService::EVENT_MUSIC_PAUSE);
-        
+    
         // Let's assume it stops playing instantly
-        playing = Controllers::MusicService::NOT_PLAYING;
+        playing = Controllers::MusicService::NotPlaying;
       } else {
         musicService.event(Controllers::MusicService::EVENT_MUSIC_PLAY);
-        
+    
         // Let's assume it starts playing instantly
         // TODO: In the future should check for BT connection for better UX
-        playing = Controllers::MusicService::PLAYING;
+        playing = Controllers::MusicService::Playing;
       }
     } else if (obj == btnNext) {
       musicService.event(Controllers::MusicService::EVENT_MUSIC_NEXT);

From 128a2ea226dc3bf2833a595bccdb82686d9ada31 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Thu, 15 Oct 2020 22:50:28 +0300
Subject: [PATCH 18/28] Changed #define to constexpr in Music.cpp

---
 src/displayapp/screens/Music.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 12c7e5ad..6fa65bc7 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -97,9 +97,9 @@ Music::Music(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Mus
   lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_LEFT_MID);
   lv_obj_set_width(txtTrackDuration, LV_HOR_RES);
   
-  #define FONT_HEIGHT (12)
-  #define MIDDLE_OFFSET (-25)
-  #define LINE_PAD (15)
+  constexpr uint8_t FONT_HEIGHT(12);
+  constexpr uint8_t MIDDLE_OFFSET(-25);
+  constexpr uint8_t LINE_PAD(15);
   txtArtist = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL);
   lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);

From 174e5ccfe43554b208bd54da71d21376c99deb48 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Thu, 15 Oct 2020 22:51:43 +0300
Subject: [PATCH 19/28] Removed weird parentheses from constexpr

---
 src/displayapp/screens/Music.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index 6fa65bc7..e73d4c91 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -97,9 +97,9 @@ Music::Music(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Mus
   lv_label_set_align(txtTrackDuration, LV_ALIGN_IN_LEFT_MID);
   lv_obj_set_width(txtTrackDuration, LV_HOR_RES);
   
-  constexpr uint8_t FONT_HEIGHT(12);
-  constexpr uint8_t MIDDLE_OFFSET(-25);
-  constexpr uint8_t LINE_PAD(15);
+  constexpr uint8_t FONT_HEIGHT = 12;
+  constexpr uint8_t MIDDLE_OFFSET = -25;
+  constexpr uint8_t LINE_PAD = 15;
   txtArtist = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL);
   lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);

From 4b0a8520535af4229b7e77ba1acb78f59018e2f9 Mon Sep 17 00:00:00 2001
From: Avamander <avamander@gmail.com>
Date: Thu, 15 Oct 2020 22:52:53 +0300
Subject: [PATCH 20/28] Made sure to use right data type for a negative number

---
 src/displayapp/screens/Music.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/displayapp/screens/Music.cpp b/src/displayapp/screens/Music.cpp
index e73d4c91..225a15a4 100644
--- a/src/displayapp/screens/Music.cpp
+++ b/src/displayapp/screens/Music.cpp
@@ -98,8 +98,8 @@ Music::Music(Pinetime::Applications::DisplayApp *app, Pinetime::Controllers::Mus
   lv_obj_set_width(txtTrackDuration, LV_HOR_RES);
   
   constexpr uint8_t FONT_HEIGHT = 12;
-  constexpr uint8_t MIDDLE_OFFSET = -25;
   constexpr uint8_t LINE_PAD = 15;
+  constexpr int8_t MIDDLE_OFFSET = -25;
   txtArtist = lv_label_create(lv_scr_act(), nullptr);
   lv_label_set_long_mode(txtArtist, LV_LABEL_LONG_SROLL);
   lv_obj_align(txtArtist, nullptr, LV_ALIGN_IN_LEFT_MID, 12, MIDDLE_OFFSET + 1 * FONT_HEIGHT);

From e5efd0514a25192464726da112cc8a352866efa6 Mon Sep 17 00:00:00 2001
From: Enno Boland <g@s01.de>
Date: Mon, 19 Oct 2020 21:26:13 +0200
Subject: [PATCH 21/28] Update MemoryAnalysis.md

typo fix: aray -> array
---
 doc/MemoryAnalysis.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/MemoryAnalysis.md b/doc/MemoryAnalysis.md
index 1bf6e24d..95bd611c 100644
--- a/doc/MemoryAnalysis.md
+++ b/doc/MemoryAnalysis.md
@@ -1,6 +1,6 @@
 # Memory analysis
 ## FreeRTOS heap and task stack
-FreeRTOS statically allocate its own heap buffer in a global variable named `ucHeap`. This is an aray of *uint8_t*. Its size is specified by the definition `configTOTAL_HEAP_SIZE` in *FreeRTOSConfig.h*
+FreeRTOS statically allocate its own heap buffer in a global variable named `ucHeap`. This is an array of *uint8_t*. Its size is specified by the definition `configTOTAL_HEAP_SIZE` in *FreeRTOSConfig.h*
 FreeRTOS uses this buffer to allocate memory for tasks stack and all the RTOS object created during runtime (timers, mutexes,...).
 
 The function `xPortGetFreeHeapSize()` returns the amount of memory available in this *ucHeap* buffer. If this value reaches 0, FreeRTOS runs out of memory.
@@ -75,4 +75,4 @@ add_definitions(-D__STACK_SIZE=8192)
 *TODO*
 
 #Tools
- - https://github.com/eliotstock/memory : display the memory usage (FLASH/RAM) using the .map file from GCC.
\ No newline at end of file
+ - https://github.com/eliotstock/memory : display the memory usage (FLASH/RAM) using the .map file from GCC.

From 8842259c7c1680ae2dd3b2f0b77f2d4a483ff681 Mon Sep 17 00:00:00 2001
From: Enno Boland <g@s01.de>
Date: Tue, 20 Oct 2020 09:14:16 +0200
Subject: [PATCH 22/28] fix build on linux

This commit fixes upper/lowercase issues in directory names that cause
the build to fail on case sensitive file systems like Linux uses.
---
 src/graphics.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/graphics.cpp b/src/graphics.cpp
index 9373a9b6..288b5e9a 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -11,15 +11,15 @@
 #include <libraries/gpiote/app_gpiote.h>
 #include <hal/nrf_wdt.h>
 #include <cstring>
-#include <Components/Gfx/Gfx.h>
+#include <components/gfx/Gfx.h>
 #include <drivers/St7789.h>
-#include <Components/Brightness/BrightnessController.h>
+#include <components/brightness/BrightnessController.h>
 
 #if NRF_LOG_ENABLED
-#include "Logging/NrfLogger.h"
+#include "logging/NrfLogger.h"
 Pinetime::Logging::NrfLogger logger;
 #else
-#include "Logging/DummyLogger.h"
+#include "logging/DummyLogger.h"
 Pinetime::Logging::DummyLogger logger;
 #endif
 

From ab36c6cd249ef5e1fcf85f573add0eb38d045b45 Mon Sep 17 00:00:00 2001
From: Anton Fosselius <anton.fosselius@gmail.com>
Date: Fri, 23 Oct 2020 11:25:46 +0200
Subject: [PATCH 23/28] Update main.cpp

changed "include Logging" to "include logging", now compiles with RTT ;)
---
 src/main.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main.cpp b/src/main.cpp
index e3243362..45aac6de 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -29,7 +29,7 @@
 
 
 #if NRF_LOG_ENABLED
-#include "Logging/NrfLogger.h"
+#include "logging/NrfLogger.h"
 Pinetime::Logging::NrfLogger logger;
 #else
 #include "logging/DummyLogger.h"

From 2f710d06f37b9ee964ad24dc1832d18ac321c664 Mon Sep 17 00:00:00 2001
From: JF <jf@codingfield.com>
Date: Fri, 23 Oct 2020 22:25:37 +0200
Subject: [PATCH 24/28] Workaround for bug
 https://github.com/JF002/Pinetime/issues/79 until a better fix is found. When
 the driver is stuck in an infinite loop for more than ~2.5ms, the TWI device
 is re-init and the transaction is retried.

Read() and Write() return an error code.
---
 src/drivers/TwiMaster.cpp | 95 ++++++++++++++++++++++++++++++++++-----
 src/drivers/TwiMaster.h   | 16 ++++---
 2 files changed, 96 insertions(+), 15 deletions(-)

diff --git a/src/drivers/TwiMaster.cpp b/src/drivers/TwiMaster.cpp
index a9eb5d0c..3ff8a952 100644
--- a/src/drivers/TwiMaster.cpp
+++ b/src/drivers/TwiMaster.cpp
@@ -60,24 +60,53 @@ void TwiMaster::Init() {
 
 }
 
-void TwiMaster::Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
+TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
   xSemaphoreTake(mutex, portMAX_DELAY);
-  Write(deviceAddress, &registerAddress, 1, false);
-  Read(deviceAddress, data, size, true);
+  auto ret = ReadWithRetry(deviceAddress, registerAddress, data, size);
   xSemaphoreGive(mutex);
+
+  return ret;
 }
 
-void TwiMaster::Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
+TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
   ASSERT(size <= maxDataSize);
   xSemaphoreTake(mutex, portMAX_DELAY);
+
+  auto ret = WriteWithRetry(deviceAddress, registerAddress, data, size);
+  xSemaphoreGive(mutex);
+  return ret;
+}
+
+/* Execute a read transaction (composed of a write and a read operation). If one of these opeartion fails,
+ * it's retried once. If it fails again, an error is returned */
+TwiMaster::ErrorCodes TwiMaster::ReadWithRetry(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
+  TwiMaster::ErrorCodes ret;
+  ret = Write(deviceAddress, &registerAddress, 1, false);
+  if(ret != ErrorCodes::NoError)
+    ret = Write(deviceAddress, &registerAddress, 1, false);
+
+  if(ret != ErrorCodes::NoError) return ret;
+
+  ret = Read(deviceAddress, data, size, true);
+  if(ret != ErrorCodes::NoError)
+    ret = Read(deviceAddress, data, size, true);
+
+  return ret;
+}
+
+/* Execute a write transaction. If it fails, it is retried once. If it fails again, an error is returned. */
+TwiMaster::ErrorCodes TwiMaster::WriteWithRetry(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
   internalBuffer[0] = registerAddress;
   std::memcpy(internalBuffer+1, data, size);
-  Write(deviceAddress, internalBuffer, size+1, true);
-  xSemaphoreGive(mutex);
+  auto ret = Write(deviceAddress, internalBuffer, size+1, true);
+  if(ret != ErrorCodes::NoError)
+    ret = Write(deviceAddress, internalBuffer, size+1, true);
+
+  return ret;
 }
 
 
-void TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool stop) {
+TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool stop) {
   twiBaseAddress->ADDRESS = deviceAddress;
   twiBaseAddress->TASKS_RESUME = 0x1UL;
   twiBaseAddress->RXD.PTR = (uint32_t)buffer;
@@ -88,7 +117,15 @@ void TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool s
   while(!twiBaseAddress->EVENTS_RXSTARTED && !twiBaseAddress->EVENTS_ERROR);
   twiBaseAddress->EVENTS_RXSTARTED = 0x0UL;
 
-  while(!twiBaseAddress->EVENTS_LASTRX && !twiBaseAddress->EVENTS_ERROR);
+  txStartedCycleCount = DWT->CYCCNT;
+  uint32_t currentCycleCount;
+  while(!twiBaseAddress->EVENTS_LASTRX && !twiBaseAddress->EVENTS_ERROR) {
+    currentCycleCount = DWT->CYCCNT;
+    if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
+      FixHwFreezed();
+      return ErrorCodes::TransactionFailed;
+    }
+  }
   twiBaseAddress->EVENTS_LASTRX = 0x0UL;
 
   if (stop || twiBaseAddress->EVENTS_ERROR) {
@@ -105,9 +142,10 @@ void TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool s
   if (twiBaseAddress->EVENTS_ERROR) {
     twiBaseAddress->EVENTS_ERROR = 0x0UL;
   }
+  return ErrorCodes::NoError;
 }
 
-void TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, bool stop) {
+TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, bool stop) {
   twiBaseAddress->ADDRESS = deviceAddress;
   twiBaseAddress->TASKS_RESUME = 0x1UL;
   twiBaseAddress->TXD.PTR = (uint32_t)data;
@@ -118,7 +156,15 @@ void TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, b
   while(!twiBaseAddress->EVENTS_TXSTARTED && !twiBaseAddress->EVENTS_ERROR);
   twiBaseAddress->EVENTS_TXSTARTED = 0x0UL;
 
-  while(!twiBaseAddress->EVENTS_LASTTX && !twiBaseAddress->EVENTS_ERROR);
+  txStartedCycleCount = DWT->CYCCNT;
+  uint32_t currentCycleCount;
+  while(!twiBaseAddress->EVENTS_LASTTX && !twiBaseAddress->EVENTS_ERROR) {
+    currentCycleCount = DWT->CYCCNT;
+    if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
+      FixHwFreezed();
+      return ErrorCodes::TransactionFailed;
+    }
+  }
   twiBaseAddress->EVENTS_LASTTX = 0x0UL;
 
   if (stop || twiBaseAddress->EVENTS_ERROR) {
@@ -137,6 +183,8 @@ void TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, b
     uint32_t error = twiBaseAddress->ERRORSRC;
     twiBaseAddress->ERRORSRC = error;
   }
+
+  return ErrorCodes::NoError;
 }
 
 void TwiMaster::Sleep() {
@@ -152,3 +200,30 @@ void TwiMaster::Wakeup() {
   Init();
   NRF_LOG_INFO("[TWIMASTER] Wakeup");
 }
+
+/* Sometimes, the TWIM device just freeze and never set the event EVENTS_LASTTX.
+ * This method disable and re-enable the peripheral so that it works again.
+ * This is just a workaround, and it would be better if we could find a way to prevent
+ * this issue from happening.
+ * */
+void TwiMaster::FixHwFreezed() {
+  NRF_LOG_INFO("I2C device frozen, reinitializing it!");
+  // Disable I²C
+  uint32_t twi_state = NRF_TWI1->ENABLE;
+  twiBaseAddress->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+
+  NRF_GPIO->PIN_CNF[params.pinScl] = ((uint32_t)GPIO_PIN_CNF_DIR_Input      << GPIO_PIN_CNF_DIR_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup      << GPIO_PIN_CNF_PULL_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
+
+  NRF_GPIO->PIN_CNF[params.pinSda] = ((uint32_t)GPIO_PIN_CNF_DIR_Input        << GPIO_PIN_CNF_DIR_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect    << GPIO_PIN_CNF_INPUT_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup      << GPIO_PIN_CNF_PULL_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1       << GPIO_PIN_CNF_DRIVE_Pos)
+                         | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled   << GPIO_PIN_CNF_SENSE_Pos);
+
+  // Re-enable I²C
+  twiBaseAddress->ENABLE = twi_state;
+}
diff --git a/src/drivers/TwiMaster.h b/src/drivers/TwiMaster.h
index 9b6b5070..52e39098 100644
--- a/src/drivers/TwiMaster.h
+++ b/src/drivers/TwiMaster.h
@@ -10,6 +10,7 @@ namespace Pinetime {
       public:
         enum class Modules { TWIM1 };
         enum class Frequencies {Khz100, Khz250, Khz400};
+        enum class ErrorCodes {NoError, TransactionFailed};
         struct Parameters {
           uint32_t frequency;
           uint8_t pinSda;
@@ -19,15 +20,19 @@ namespace Pinetime {
         TwiMaster(const Modules module, const Parameters& params);
 
         void Init();
-        void Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, size_t size);
-        void Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t* data, size_t size);
+        ErrorCodes Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, size_t size);
+        ErrorCodes Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t* data, size_t size);
 
         void Sleep();
         void Wakeup();
 
       private:
-        void Read(uint8_t deviceAddress, uint8_t* buffer, size_t size, bool stop);
-        void Write(uint8_t deviceAddress, const uint8_t* data, size_t size, bool stop);
+        ErrorCodes ReadWithRetry(uint8_t deviceAddress, uint8_t registerAddress, uint8_t* buffer, size_t size);
+        ErrorCodes WriteWithRetry(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t* data, size_t size);
+
+        ErrorCodes Read(uint8_t deviceAddress, uint8_t* buffer, size_t size, bool stop);
+        ErrorCodes Write(uint8_t deviceAddress, const uint8_t* data, size_t size, bool stop);
+        void FixHwFreezed();
         NRF_TWIM_Type* twiBaseAddress;
         SemaphoreHandle_t mutex;
         const Modules module;
@@ -35,7 +40,8 @@ namespace Pinetime {
         static constexpr uint8_t maxDataSize{8};
         static constexpr uint8_t registerSize{1};
         uint8_t internalBuffer[maxDataSize + registerSize];
-
+        uint32_t txStartedCycleCount = 0;
+        static constexpr uint32_t HwFreezedDelay{161000};
     };
   }
 }
\ No newline at end of file

From cc7ba747908b8d23265c687d7a5cfef5f037e446 Mon Sep 17 00:00:00 2001
From: Steveis <SteveAmor@users.noreply.github.com>
Date: Sat, 24 Oct 2020 09:42:13 +0100
Subject: [PATCH 25/28] Update arm-gcc toolchain in example

The difference in the example caused some confusion for at least one person.
---
 doc/buildAndProgram.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md
index 26f3665e..72870e3d 100644
--- a/doc/buildAndProgram.md
+++ b/doc/buildAndProgram.md
@@ -18,7 +18,7 @@ CMake configures the project according to variables you specify the command line
 
  Variable | Description | Example|
 ----------|-------------|--------|
-**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2019-q4-major/`|
+**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2020-q2-update/`|
 **NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
 **USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1`
 **CMAKE_BUILD_TYPE**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`

From 1bb2eb9dcd59fbb198be157e34b7ff25367adea0 Mon Sep 17 00:00:00 2001
From: JF <jf@codingfield.com>
Date: Tue, 27 Oct 2020 19:38:45 +0100
Subject: [PATCH 26/28] Disable sleep mode on the SPI NOR Flash when the
 version is unknown. This is because the current bootloader (which does not
 exposes its version) cannot initialize the chip when it's in sleep mode. This
 feature will be re-enabled when the bootloader expses it's version.

---
 src/BootloaderVersion.cpp     | 26 ++++++++++++++++++++++++++
 src/BootloaderVersion.h       | 12 ++++++++++++
 src/CMakeLists.txt            |  2 ++
 src/drivers/SpiNorFlash.cpp   |  6 +++---
 src/systemtask/SystemTask.cpp |  7 ++++++-
 5 files changed, 49 insertions(+), 4 deletions(-)
 create mode 100644 src/BootloaderVersion.cpp
 create mode 100644 src/BootloaderVersion.h

diff --git a/src/BootloaderVersion.cpp b/src/BootloaderVersion.cpp
new file mode 100644
index 00000000..8555593f
--- /dev/null
+++ b/src/BootloaderVersion.cpp
@@ -0,0 +1,26 @@
+#include <cstdint>
+#include "BootloaderVersion.h"
+
+using namespace Pinetime;
+
+// NOTE : current bootloader does not export its version to the application firmware.
+
+uint32_t BootloaderVersion::Major() {
+  return 0;
+}
+
+uint32_t BootloaderVersion::Minor() {
+  return 0;
+}
+
+uint32_t BootloaderVersion::Patch() {
+  return 0;
+}
+
+const char *BootloaderVersion::VersionString() {
+  return "0.0.0";
+}
+
+bool BootloaderVersion::IsValid() {
+  return false;
+}
diff --git a/src/BootloaderVersion.h b/src/BootloaderVersion.h
new file mode 100644
index 00000000..c7fcbd98
--- /dev/null
+++ b/src/BootloaderVersion.h
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace Pinetime {
+  class BootloaderVersion {
+    public:
+      static uint32_t Major();
+      static uint32_t Minor();
+      static uint32_t Patch();
+      static const char* VersionString();
+      static bool IsValid();
+  };
+}
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cd37810f..af0b110e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -322,6 +322,7 @@ list(APPEND IMAGE_FILES
         )
 
 list(APPEND SOURCE_FILES
+        BootloaderVersion.cpp
         logging/NrfLogger.cpp
         displayapp/DisplayApp.cpp
         displayapp/screens/Screen.cpp
@@ -397,6 +398,7 @@ list(APPEND GRAPHICS_SOURCE_FILES
         )
 
 set(INCLUDE_FILES
+        BootloaderVersion.h
         logging/Logger.h
         logging/NrfLogger.h
         displayapp/DisplayApp.h
diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp
index 351a9dfc..bd24834e 100644
--- a/src/drivers/SpiNorFlash.cpp
+++ b/src/drivers/SpiNorFlash.cpp
@@ -12,7 +12,7 @@ SpiNorFlash::SpiNorFlash(Spi& spi) : spi{spi} {
 
 void SpiNorFlash::Init() {
   device_id = ReadIdentificaion();
-  NRF_LOG_INFO("[SPI FLASH] Manufacturer : %d, Memory type : %d, memory density : %d", device_id.manufacturer, device_id.type, device_id.density);
+  NRF_LOG_INFO("[SpiNorFlash] Manufacturer : %d, Memory type : %d, memory density : %d", device_id.manufacturer, device_id.type, device_id.density);
 }
 
 void SpiNorFlash::Uninit() {
@@ -22,7 +22,7 @@ void SpiNorFlash::Uninit() {
 void SpiNorFlash::Sleep() {
   auto cmd = static_cast<uint8_t>(Commands::DeepPowerDown);
   spi.Write(&cmd, sizeof(uint8_t));
-  NRF_LOG_INFO("[FLASH] Sleep")
+  NRF_LOG_INFO("[SpiNorFlash] Sleep")
 }
 
 void SpiNorFlash::Wakeup() {
@@ -38,7 +38,7 @@ void SpiNorFlash::Wakeup() {
   else {
     NRF_LOG_INFO("[SpiNorFlash] ID on Wakeup: %d", id);
   }
-  NRF_LOG_INFO("[FLASH] Wakeup")
+  NRF_LOG_INFO("[SpiNorFlash] Wakeup")
 }
 
 SpiNorFlash::Identification SpiNorFlash::ReadIdentificaion() {
diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp
index 3efe21b8..dac4ce29 100644
--- a/src/systemtask/SystemTask.cpp
+++ b/src/systemtask/SystemTask.cpp
@@ -13,6 +13,7 @@
 #include <drivers/InternalFlash.h>
 #include "main.h"
 #include "components/ble/NimbleController.h"
+#include "../BootloaderVersion.h"
 
 using namespace Pinetime::System;
 
@@ -161,7 +162,11 @@ void SystemTask::Work() {
           ReloadIdleTimer();
           break;
         case Messages::OnDisplayTaskSleeping:
-          spiNorFlash.Sleep();
+          if(BootloaderVersion::IsValid()) {
+            // First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH
+            // if it's in sleep mode. Avoid bricked device by disabling sleep mode on these versions.
+            spiNorFlash.Sleep();
+          }
           lcd.Sleep();
           touchPanel.Sleep();
 

From 8a8c8aa86312840a84533318bff92fdb6c42b8de Mon Sep 17 00:00:00 2001
From: JF <jf@codingfield.com>
Date: Tue, 27 Oct 2020 19:46:51 +0100
Subject: [PATCH 27/28] Handle error code when calling TwiMaster::Read().

---
 src/drivers/Cst816s.cpp |  4 +++-
 src/drivers/Cst816s.h   | 14 +++++++-------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp
index f6816545..94db3b34 100644
--- a/src/drivers/Cst816s.cpp
+++ b/src/drivers/Cst816s.cpp
@@ -37,7 +37,9 @@ void Cst816S::Init() {
 Cst816S::TouchInfos Cst816S::GetTouchInfo() {
   Cst816S::TouchInfos info;
 
-  twiMaster.Read(twiAddress, 0, touchData, 63);
+  auto ret = twiMaster.Read(twiAddress, 0, touchData, 63);
+  if(ret != TwiMaster::ErrorCodes::NoError) return {};
+
   auto nbTouchPoints = touchData[2] & 0x0f;
 
 //  uint8_t i = 0;
diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h
index b115a688..4569e82f 100644
--- a/src/drivers/Cst816s.h
+++ b/src/drivers/Cst816s.h
@@ -18,13 +18,13 @@ namespace Pinetime {
             LongPress = 0x0C
         };
         struct TouchInfos {
-          uint16_t x;
-          uint16_t y;
-          uint8_t action;
-          uint8_t finger;
-          uint8_t pressure;
-          uint8_t area;
-          Gestures gesture;
+          uint16_t x = 0;
+          uint16_t y = 0;
+          uint8_t action = 0;
+          uint8_t finger = 0;
+          uint8_t pressure = 0;
+          uint8_t area = 0;
+          Gestures gesture = Gestures::None;
           bool isTouch = false;
         };
 

From c5bf09d21b2ed8e2435ec625e351594f58713924 Mon Sep 17 00:00:00 2001
From: JF <jf@codingfield.com>
Date: Tue, 27 Oct 2020 20:00:06 +0100
Subject: [PATCH 28/28] Set version to 0.9.0

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5346ccfb..1e340f74 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.10)
-project(pinetime VERSION 0.8.2 LANGUAGES C CXX ASM)
+project(pinetime VERSION 0.9.0 LANGUAGES C CXX ASM)
 
 set(NRF_TARGET "nrf52")