InfiniTime.git

commit 4f51d429a57342a16cd3d250a2b8387a8101c6ba

Author: JF002 <JF002@users.noreply.github.com>

Merge branch 'develop' into patch-2

 .github/workflows/c-cpp.yml | 202 +++++++++++++++++++++++++++
 CMakeLists.txt | 2 
 README.md | 20 +-
 doc/SPI-LCD-driver.md | 6 
 src/CMakeLists.txt | 2 
 src/Components/Ble/MusicService.cpp | 130 +++++++++++++++++
 src/Components/Ble/MusicService.h | 92 ++++++++++++
 src/Components/Ble/NimbleController.cpp | 9 
 src/Components/Ble/NimbleController.h | 10 +
 src/DisplayApp/DisplayApp.cpp | 2 
 src/DisplayApp/DisplayApp.h | 2 
 src/DisplayApp/Screens/Gauge.cpp | 1 
 src/DisplayApp/Screens/Music.cpp | 125 ++++++++++++++++
 src/DisplayApp/Screens/Music.h | 49 ++++++
 src/DisplayApp/Screens/Tile.cpp | 2 
 src/SystemTask/SystemTask.cpp | 1 
 src/SystemTask/SystemTask.h | 7 
 src/drivers/TwiMaster.cpp | 4 


diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0647089a0ff53826381a8bfece0ebd320077a558
--- /dev/null
+++ b/.github/workflows/c-cpp.yml
@@ -0,0 +1,202 @@
+# GitHub Action to build FreeRTOS Firmware for PineTime Smart Watch
+# Based on https://github.com/lupyuen/pinetime-lab/blob/master/doc/buildAndProgram.md
+
+name: C/C++ CI
+
+# Run this workflow on every push and pull request on "master" branch
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+# Steps to be run for the workflow
+jobs:
+  build:
+
+    # Run these steps on Ubuntu
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Install cmake
+      uses: lukka/get-cmake@v3.18.0
+
+    - name: Check cache for Embedded Arm Toolchain arm-none-eabi-gcc
+      id:   cache-toolchain
+      uses: actions/cache@v2
+      env:
+        cache-name: cache-toolchain
+      with:
+        path: ${{ runner.temp }}/arm-none-eabi
+        key:  ${{ runner.os }}-build-${{ env.cache-name }}
+        restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}
+
+    - name: Install Embedded Arm Toolchain arm-none-eabi-gcc
+      if:   steps.cache-toolchain.outputs.cache-hit != 'true'  # Install toolchain if not found in cache
+      uses: fiam/arm-none-eabi-gcc@v1.0.2
+      with:
+        # GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4")
+        release: 8-2019-q3
+        # Directory to unpack GCC to. Defaults to a temporary directory.
+        directory: ${{ runner.temp }}/arm-none-eabi
+
+    - name: Check cache for nRF5 SDK
+      id:   cache-nrf5sdk
+      uses: actions/cache@v2
+      env:
+        cache-name: cache-nrf5sdk
+      with:
+        path: ${{ runner.temp }}/nrf5_sdk
+        key:  ${{ runner.os }}-build-${{ env.cache-name }}
+        restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}
+          
+    - name: Install nRF5 SDK
+      if:   steps.cache-nrf5sdk.outputs.cache-hit != 'true'  # Install SDK if not found in cache
+      run:  cd ${{ runner.temp }} && curl https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip -o nrf5_sdk.zip && unzip nrf5_sdk.zip && mv nRF5_SDK_15.3.0_59ac345 nrf5_sdk
+
+    - name: Checkout source files
+      uses: actions/checkout@v2
+
+    - name: Show files
+      run:  set ; pwd ; ls -l
+
+    - name: CMake
+      run:  mkdir -p build && cd build && cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=${{ runner.temp }}/arm-none-eabi -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 ../
+      
+    - name: Make
+      # For debugging builds, remove option "-j" for clearer output. Add "--trace" to see details.
+      run:  cd build && make -j pinetime-app
+      
+    - name: Find output
+      run:  find . -name pinetime-app.out
+
+    - name: Upload built firmware
+      uses: actions/upload-artifact@v2
+      with:
+        # Artifact name (optional)
+        name: pinetime-app.out
+        # A file, directory or wildcard pattern that describes what to upload
+        path: build/src/pinetime-app.out
+      
+# Embedded Arm Toolchain and nRF5 SDK will only be cached if the build succeeds.
+# So make sure that the first build always succeeds, e.g. comment out the "Make" step.
+
+# Sample compile command:
+# [100%] Building CXX object src/CMakeFiles/pinetime-app.dir/drivers/TwiMaster.cpp.o
+# cd /home/runner/work/pinetime-lab/pinetime-lab/build/src && /home/runner/work/_temp/arm-none-eabi/bin/arm-none-eabi-c++ --sysroot=/home/runner/work/_temp/arm-none-eabi/bin \
+# -DBOARD_PCA10040 \
+# -DCONFIG_GPIO_AS_PINRESET \
+# -DDEBUG \
+# -DDEBUG_NRF_USER \
+# -DFREERTOS \
+# -DNIMBLE_CFG_CONTROLLER \
+# -DNRF52 \
+# -DNRF52832 \
+# -DNRF52832_XXAA \
+# -DNRF52_PAN_12 \
+# -DNRF52_PAN_15 \
+# -DNRF52_PAN_20 \
+# -DNRF52_PAN_31 \
+# -DNRF52_PAN_36 \
+# -DNRF52_PAN_51 \
+# -DNRF52_PAN_54 \
+# -DNRF52_PAN_55 \
+# -DNRF52_PAN_58 \
+# -DNRF52_PAN_64 \
+# -DNRF52_PAN_74 \
+# -DOS_CPUTIME_FREQ \
+# -D__HEAP_SIZE=8192 \
+# -D__STACK_SIZE=8192 \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/. \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/.. \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/FreeRTOS \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/date/includes \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/porting/npl/freertos/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/porting/nimble/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/host/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/controller/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/transport/ram/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/drivers/nrf52/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/ext/tinycrypt/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/host/services/gap/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/host/services/gatt/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/host/util/include \
+# -I/home/runner/work/pinetime-lab/pinetime-lab/src/libs/mynewt-nimble/nimble/host/store/ram/include \
+# -I/home/runner/work/_temp/nrf5_sdk/components/drivers_nrf/nrf_soc_nosd \
+# -I/home/runner/work/_temp/nrf5_sdk/components \
+# -I/home/runner/work/_temp/nrf5_sdk/components/boards \
+# -I/home/runner/work/_temp/nrf5_sdk/components/softdevice/common \
+# -I/home/runner/work/_temp/nrf5_sdk/integration/nrfx \
+# -I/home/runner/work/_temp/nrf5_sdk/integration/nrfx/legacy \
+# -I/home/runner/work/_temp/nrf5_sdk/modules/nrfx \
+# -I/home/runner/work/_temp/nrf5_sdk/modules/nrfx/drivers/include \
+# -I/home/runner/work/_temp/nrf5_sdk/modules/nrfx/hal \
+# -I/home/runner/work/_temp/nrf5_sdk/modules/nrfx/mdk \
+# -I/home/runner/work/_temp/nrf5_sdk/external/freertos/source/include \
+# -I/home/runner/work/_temp/nrf5_sdk/components/toolchain/cmsis/include \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/atomic \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/atomic_fifo \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/atomic_flags \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/balloc \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/bootloader/ble_dfu \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/cli \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/crc16 \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/crc32 \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/crypto \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/csense \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/csense_drv \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/delay \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/ecc \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/experimental_section_vars \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/experimental_task_manager \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/fds \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/fstorage \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/gfx \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/gpiote \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/hardfault \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/hci \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/led_softblink \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/log \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/log/src \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/low_power_pwm \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/mem_manager \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/memobj \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/mpu \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/mutex \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/pwm \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/pwr_mgmt \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/queue \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/ringbuf \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/scheduler \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/sdcard \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/slip \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/sortlist \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/spi_mngr \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/stack_guard \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/strerror \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/svc \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/timer \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/audio \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/cdc \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/cdc/acm \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/hid \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/hid/generic \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/hid/kbd \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/hid/mouse \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/usbd/class/msc \
+# -I/home/runner/work/_temp/nrf5_sdk/components/libraries/util \
+# -I/home/runner/work/_temp/nrf5_sdk/external/segger_rtt \
+# -I/home/runner/work/_temp/nrf5_sdk/external/fprintf \
+# -I/home/runner/work/_temp/nrf5_sdk/external/thedotfactory_fonts -O3 \
+# -DNDEBUG -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 -O3 -std=gnu++11 \
+# -o CMakeFiles/pinetime-app.dir/drivers/TwiMaster.cpp.o \
+# -c /home/runner/work/pinetime-lab/pinetime-lab/src/drivers/TwiMaster.cpp
+
+# /home/runner/work/pinetime-lab/pinetime-lab/src/drivers/TwiMaster.cpp:1:10: fatal error: sdk/integration/nrfx/nrfx_log.h: No such file or directory
+# #include <sdk/integration/nrfx/nrfx_log.h>




diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed8abfc905ffd1e8878d299c5ea87e025d1f63e6..e33040c392db19ef516febbb8851e14a075867f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.10)
-project(pinetime VERSION 0.7.1 LANGUAGES C CXX ASM)
+project(pinetime VERSION 0.8.0 LANGUAGES C CXX ASM)
 
 set(NRF_TARGET "nrf52")
 




diff --git a/README.md b/README.md
index 95e98eedb409992c756434a728776e859742c788..b045df4674c5e4c19b8e3f8f0a8641c14b8fc734 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ > We envision the PineTime as a companion for not only your PinePhone but also for your favorite devices — any phone, tablet, or even PC.
 
 *https://www.pine64.org/pinetime/*
 
-The **Pinetime** smartwatch is built around the NRF52832 MCU (512KB Flash, 64KB RAM), a 240*240 LCD display driven by the ST7789 controller, an accelerometer, a heartrate sensor and a vibrator.
+The **Pinetime** smartwatch is built around the NRF52832 MCU (512KB Flash, 64KB RAM), a 240*240 LCD display driven by the ST7789 controller, an accelerometer, a heart rate sensor, and a vibration motor.
 
 The goal of this project is to design an open-source firmware for the Pinetime smartwatch : 
 
@@ -15,7 +15,7 @@  - Based on **[FreeRTOS 10.0.0](https://freertos.org)** real-time OS.
  - Using **[LittleVGL/LVGL 6.1.2](https://lvgl.io/)** as UI library...
  - ... and **[NimBLE 1.3.0](https://github.com/apache/mynewt-nimble)** as BLE stack.
 
-##Overview
+## Overview
 
 ![Pinetime screens](images/0.7.0/montage.jpg "PinetimeScreens")
 
@@ -23,15 +23,15 @@ As of now, here is the list of achievements of this project:
 
  - Fast and optimized LCD driver
  - BLE communication
- - Rich user interface via display, touchpanel and push button
- - Time synchronisation via BLE
+ - Rich user interface via display, touch panel and push button
+ - Time synchronization via BLE
  - Notification via BLE
  - Multiple 'apps' : 
     * Clock (displays the date, time, battery level, BLE connection status, heart rate and step count)
     * Heart rate
     * Motion
-    * System info (displays various info : BLE MAC adress, build date/time, uptime, version,...)
-    * Brightess (allows the user to configure the brightness of the display)
+    * System info (displays various info : BLE MAC adress, build date/time, uptime, version, ...)
+    * Brightness (allows the user to configure the brightness of the display)
  - Supported by 2 companion apps (development is ongoing):
     * [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/src/branch/pinetime-jf) (on Android)
     * [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS)
@@ -61,19 +61,19 @@  
     
 ## TODO - contribute
 
-This project is far from beeing finished, and there are still a lot of things to do for this project to become a firmware usable by the general public.
+This project is far from being finished, and there are still a lot of things to do for this project to become a firmware usable by the general public.
 
 Here a quick list out of my head of things to do for this project:
 
  - Improve BLE communication stability and reliability
  - Improve OTA and MCUBoot bootloader
- - Add more functionalities : Alarm, chrono, configuration, activities, heart rate logging, games,...
+ - Add more functionalities : Alarm, chronometer, configuration, activities, heart rate logging, games,...
  - Add more BLE functionalities : call notifications, agenda, configuration, data logging,...
  - Measure power consumption and improve battery life
  - Improve documentation, take better pictures and video than mine
  - Improve the UI
  - Create companion app for multiple OSes (Linux, Android, iOS) and platforms (desktop, ARM, mobile). Do not forget the other devices from Pine64 like [the Pinephone](https://www.pine64.org/pinephone/) and the [Pinebook Pro](https://www.pine64.org/pinebook-pro/). 
- - Design a simple CI (preferably selfhosted and easy to reproduce).
+ - Design a simple CI (preferably self-hosted and easy to reproduce).
  
 Do not hesitate to clone/fork the code, hack it and create pull-requests. I'll do my best to review and merge them :)
 
@@ -84,6 +84,6 @@ Here are some people I would like to highlight:
 
  - [Atc1441](https://github.com/atc1441/) : He works on an Arduino based firmware for the Pinetime and many other smartwatches based on similar hardware. He was of great help when I was implementing support for the BMA421 motion sensor and I²C driver.
  - [Koen](https://github.com/bosmoment) : He’s working on a firmware based on RiotOS. He integrated similar libs as me : NimBLE, LittleVGL,… His help was invaluable too!
- - [Lup Yuen Lee](https://github.com/lupyuen) : He is everywhere : he works on a Rust firmware, buils a MCUBoot based bootloader for the Pinetime, design a Flutter based companion app for smartphones and write a lot of articles about the Pinetime!
+ - [Lup Yuen Lee](https://github.com/lupyuen) : He is everywhere: he works on a Rust firmware, builds a MCUBoot based bootloader for the Pinetime, designs a Flutter based companion app for smartphones and writes a lot of articles about the Pinetime!
 
 *If you feel like you should appear on this list, just get in touch with me or submit a PR :)*




diff --git a/doc/SPI-LCD-driver.md b/doc/SPI-LCD-driver.md
index 3c33c258891a3764e883a4e5f28d2e30c610fa43..f787aab79d854b6b2415a2da9423a693cbd00cd9 100644
--- a/doc/SPI-LCD-driver.md
+++ b/doc/SPI-LCD-driver.md
@@ -24,17 +24,17 @@ As I said in the introduction, the datasheet will be your bedside book during your journey as a device driver designer. You'll read it from the beginning to the end once, twice, maybe ten times. Then, each time you'll want to do something new, you'll reopen the file and search for that specific paragraph or diagram than explains how the controller works so that you can figure out how to use it.
 
 The schematic of your board (the Pinetime schematics in this case) will also be very important, as you'll need to know how the LCD controller is physically connected to the MCU.
 
-How to read the datasheet? I recommand to read it from the beginning to the end (no joke) at least once. You certainly do not need to read everything in details, but it's good to know what information is available and where in the document. It'll be very useful during the developpment phase.
+How to read the datasheet? I recommend to read it from the beginning to the end (no joke) at least once. You certainly do not need to read everything in details, but it's good to know what information is available and where in the document. It'll be very useful during the development phase.
 You'll want to read some part with more attention :
 - Data color coding in 4-Line Serial Interface : how to send the pixel to be display to the controller
-- Display Data Ram : how is the memory organised
+- Display Data Ram : how is the memory organized
 - Power On/Off sequence
 - System function commands : all the commands you can send to the controller.
 
 ## One Pixel at a time
 
 
-## Bulk transfert
+## Bulk transfers
 
 ## DMA
 




diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e60c2cfe94e7d59d481c81fa469ba51c5c8c84de..2d6d6e8e5bdba88577c22ec6704c6d310e2b7e65 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -336,6 +336,7 @@   DisplayApp/Screens/Brightness.cpp
   DisplayApp/Screens/ScreenList.cpp
   DisplayApp/Screens/Label.cpp
   DisplayApp/Screens/FirmwareUpdate.cpp
+  DisplayApp/Screens/Music.cpp
   main.cpp
   drivers/St7789.cpp
   drivers/SpiNorFlash.cpp
@@ -356,6 +357,7 @@   Components/Ble/AlertNotificationClient.cpp
   Components/Ble/DfuService.cpp
   Components/Ble/CurrentTimeService.cpp
   Components/Ble/AlertNotificationService.cpp
+  Components/Ble/MusicService.cpp
   drivers/Cst816s.cpp
   FreeRTOS/port.c
   FreeRTOS/port_cmsis_systick.c




diff --git a/src/Components/Ble/MusicService.cpp b/src/Components/Ble/MusicService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ec766972986a400bca30d8f16b1d968699f6549
--- /dev/null
+++ b/src/Components/Ble/MusicService.cpp
@@ -0,0 +1,130 @@
+#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);
+  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...";
+}
+
+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) {
+
+  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];
+        }
+  }
+  return 0;
+}
+
+std::string Pinetime::Controllers::MusicService::album()
+{
+    return m_album;
+}
+
+std::string Pinetime::Controllers::MusicService::artist()
+{
+    return m_artist;
+}
+
+std::string Pinetime::Controllers::MusicService::track()
+{
+    return m_track;
+}
+
+unsigned char Pinetime::Controllers::MusicService::status()
+{
+    return m_status;
+}
+
+void Pinetime::Controllers::MusicService::event(char event)
+{
+    auto *om = ble_hs_mbuf_from_flat(&event, 1);
+    int ret;
+
+    uint16_t connectionHandle = m_system.nimble().connHandle();
+
+    if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
+        return;
+    }
+
+    ret = ble_gattc_notify_custom(connectionHandle, m_eventHandle, om);
+}
+




diff --git a/src/Components/Ble/MusicService.h b/src/Components/Ble/MusicService.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab6db572b183980efec46bd4942f729b4762d672
--- /dev/null
+++ b/src/Components/Ble/MusicService.h
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <cstdint>
+#include <array>
+#include <host/ble_gap.h>
+#include <host/ble_uuid.h>
+#include <string>
+
+//c7e50000-78fc-48fe-8e23-43b37a1942d0
+#define MUSIC_SERVICE_UUID_BASE {0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x00, 0x00, 0xe5, 0xc7}
+
+namespace Pinetime {
+  namespace System {
+    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;
+
+    };
+  }
+}
+




diff --git a/src/Components/Ble/NimbleController.cpp b/src/Components/Ble/NimbleController.cpp
index 561dbce4b38a3363cf60fe9afc6a6cbc8d639c8a..d7bbd8be1669359bf04136cfbc7aecf752501c9c 100644
--- a/src/Components/Ble/NimbleController.cpp
+++ b/src/Components/Ble/NimbleController.cpp
@@ -6,6 +6,7 @@ #include 
 #include <hal/nrf_rtc.h>
 
 #include "NimbleController.h"
+#include "MusicService.h"
 #include <services/gatt/ble_svc_gatt.h>
 #include <services/gap/ble_svc_gap.h>
 #include <host/util/util.h>
@@ -35,7 +36,8 @@         dfuService{systemTask, bleController, spiNorFlash},
         currentTimeClient{dateTimeController},
         anService{systemTask, notificationManager},
         alertNotificationClient{systemTask, notificationManager},
-        currentTimeService{dateTimeController} {
+        currentTimeService{dateTimeController},
+        musicService{systemTask} {
 
 }
 
@@ -80,6 +82,7 @@
   deviceInformationService.Init();
   currentTimeClient.Init();
   currentTimeService.Init();
+  musicService.Init();
 
   anService.Init();
 
@@ -326,5 +329,7 @@   ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this);
 }
 
 
-
+uint16_t NimbleController::connHandle() {
+    return connectionHandle;
+}
 




diff --git a/src/Components/Ble/NimbleController.h b/src/Components/Ble/NimbleController.h
index cf50d78deaad9bf0b63dcef0dc6dd326ceeaa112..dff93c8784f08fa16d3895882421465b9fbf20ac 100644
--- a/src/Components/Ble/NimbleController.h
+++ b/src/Components/Ble/NimbleController.h
@@ -7,6 +7,7 @@ #include "DeviceInformationService.h"
 #include "CurrentTimeClient.h"
 #include "DfuService.h"
 #include "CurrentTimeService.h"
+#include "MusicService.h"
 #include <host/ble_gap.h>
 
 namespace Pinetime {
@@ -15,6 +16,7 @@     class SpiNorFlash;
   }
   namespace Controllers {
     class DateTime;
+
     class NimbleController {
 
       public:
@@ -35,6 +37,11 @@         int OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
                                                   uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
 
         void StartDiscovery();
+
+        Pinetime::Controllers::MusicService& music() {return musicService;};
+
+        uint16_t connHandle();
+
       private:
         static constexpr char* deviceName = "Pinetime-JF";
         Pinetime::System::SystemTask& systemTask;
@@ -49,9 +56,10 @@         CurrentTimeClient currentTimeClient;
         AlertNotificationService anService;
         AlertNotificationClient alertNotificationClient;
         CurrentTimeService currentTimeService;
+        MusicService musicService;
 
         uint8_t addrType; // 1 = Random, 0 = PUBLIC
-        uint16_t connectionHandle;
+        uint16_t connectionHandle = 0;
 
         ble_uuid128_t dfuServiceUuid {
                 .u { .type = BLE_UUID_TYPE_128},




diff --git a/src/DisplayApp/DisplayApp.cpp b/src/DisplayApp/DisplayApp.cpp
index 8e35ef551de8692983266b9055fddc0a795854ff..46a9638565f065f1b994772d2455f8e055f623b8 100644
--- a/src/DisplayApp/DisplayApp.cpp
+++ b/src/DisplayApp/DisplayApp.cpp
@@ -15,6 +15,7 @@ #include 
 #include <DisplayApp/Screens/Gauge.h>
 #include <DisplayApp/Screens/Brightness.h>
 #include <DisplayApp/Screens/ScreenList.h>
+#include <DisplayApp/Screens/Music.h>
 #include <Components/Ble/NotificationManager.h>
 #include <DisplayApp/Screens/FirmwareUpdate.h>
 #include "../SystemTask/SystemTask.h"
@@ -189,6 +190,7 @@       case Apps::SysInfo: currentScreen.reset(new Screens::ScreenList(this, dateTimeController, batteryController, brightnessController, bleController, watchdog)); break;
       case Apps::Meter: currentScreen.reset(new Screens::Meter(this)); break;
       case Apps::Gauge: currentScreen.reset(new Screens::Gauge(this)); break;
       case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break;
+      case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break;
     }
     nextApp = Apps::None;
   }




diff --git a/src/DisplayApp/DisplayApp.h b/src/DisplayApp/DisplayApp.h
index 36f9315b5226147fe9e40784094e400f33bd4721..23f04937b635d1e47d8feb3e3a729a8c8824cbfa 100644
--- a/src/DisplayApp/DisplayApp.h
+++ b/src/DisplayApp/DisplayApp.h
@@ -42,7 +42,7 @@                    Pinetime::Controllers::NotificationManager& notificationManager);
         void Start();
         void PushMessage(Messages msg);
 
-        enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness};
+        enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music};
         void StartApp(Apps app);
 
         void SetFullRefresh(FullRefreshDirections direction);




diff --git a/src/DisplayApp/Screens/Gauge.cpp b/src/DisplayApp/Screens/Gauge.cpp
index 4c4cccd99e21faa7fd7a67ee19d9fd8bfea6a32f..fd905231fd835b5b66d92cd2b3541c68061e53f4 100644
--- a/src/DisplayApp/Screens/Gauge.cpp
+++ b/src/DisplayApp/Screens/Gauge.cpp
@@ -19,6 +19,7 @@   style.line.width = 3;
   style.text.color = LV_COLOR_WHITE;
   style.line.color = LV_COLOR_RED;                  /*Line color after the critical value*/
 
+
   /*Describe the color for the needles*/
 
   needle_colors[0] = LV_COLOR_ORANGE;




diff --git a/src/DisplayApp/Screens/Music.cpp b/src/DisplayApp/Screens/Music.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b7d198bcde58788e36f92454b28b30daee61e92
--- /dev/null
+++ b/src/DisplayApp/Screens/Music.cpp
@@ -0,0 +1,125 @@
+#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);
+  screen->OnObjectEvent(obj, event);
+}
+
+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);
+}
+
+Music::~Music() {
+  lv_obj_clean(lv_scr_act());
+}
+
+bool Music::OnButtonPushed() {
+  running = false;
+  return true;
+}
+
+bool Music::Refresh() {
+
+    if (m_artist != musicService.artist()) {
+        m_artist = musicService.artist();
+        lv_label_set_text(txtArtist, m_artist.data());
+    }
+    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, ">");
+    }
+
+  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);
+        }
+    }
+}




diff --git a/src/DisplayApp/Screens/Music.h b/src/DisplayApp/Screens/Music.h
new file mode 100644
index 0000000000000000000000000000000000000000..95cac0f0a434d7d206bb9721ccb348afd21532df
--- /dev/null
+++ b/src/DisplayApp/Screens/Music.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <cstdint>
+#include <chrono>
+#include <Components/Gfx/Gfx.h>
+#include "Screen.h"
+#include <bits/unique_ptr.h>
+#include <libs/lvgl/src/lv_core/lv_style.h>
+#include <libs/lvgl/src/lv_core/lv_obj.h>
+#include <Components/Battery/BatteryController.h>
+#include <Components/Ble/BleController.h>
+#include "../../Version.h"
+#include <Components/Ble/MusicService.h>
+#include <string>
+
+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;
+      };
+    }
+  }
+}




diff --git a/src/DisplayApp/Screens/Tile.cpp b/src/DisplayApp/Screens/Tile.cpp
index 61e3c01d7fd3ce74ffebb1390698c49196d7a688..c3a9d3806810164bcb852b2d8c0b950e0f3e2f74 100644
--- a/src/DisplayApp/Screens/Tile.cpp
+++ b/src/DisplayApp/Screens/Tile.cpp
@@ -95,7 +95,7 @@   running = false;
 }
 
 void Tile::StartGaugeApp() {
-  app->StartApp(DisplayApp::Apps::Gauge);
+  app->StartApp(DisplayApp::Apps::Music);
   running = false;
 }
 




diff --git a/src/SystemTask/SystemTask.cpp b/src/SystemTask/SystemTask.cpp
index 8f565860b9fd89d98333ac405660fc43a6d7d47c..9f57f6f6356b0d14a99dadd076f6454a7e15ba40 100644
--- a/src/SystemTask/SystemTask.cpp
+++ b/src/SystemTask/SystemTask.cpp
@@ -12,6 +12,7 @@ #include 
 #include <host/util/util.h>
 #include <drivers/InternalFlash.h>
 #include "../main.h"
+#include "Components/Ble/NimbleController.h"
 
 using namespace Pinetime::System;
 




diff --git a/src/SystemTask/SystemTask.h b/src/SystemTask/SystemTask.h
index 8fa7e7d1a31d047a9086367cd715f409dff66350..3e53baedafad7689c8050bc12c410c38619571a2 100644
--- a/src/SystemTask/SystemTask.h
+++ b/src/SystemTask/SystemTask.h
@@ -8,9 +8,10 @@ #include 
 #include <Components/Battery/BatteryController.h>
 #include <DisplayApp/DisplayApp.h>
 #include <drivers/Watchdog.h>
-#include <Components/Ble/NimbleController.h>
 #include <drivers/SpiNorFlash.h>
 #include "SystemMonitor.h"
+#include "Components/Ble/NimbleController.h"
+#include "timers.h"
 
 namespace Pinetime {
   namespace System {
@@ -36,6 +37,8 @@         void OnButtonPushed();
         void OnTouchEvent();
 
         void OnIdle();
+
+        Pinetime::Controllers::NimbleController& nimble() {return nimbleController;};
 
       private:
         TaskHandle_t taskHandle;
@@ -84,4 +87,4 @@         SystemMonitor monitor;
 #endif
     };
   }
-}
\ No newline at end of file
+}




diff --git a/src/drivers/TwiMaster.cpp b/src/drivers/TwiMaster.cpp
index 5d8fcf6b9d0fef4d10fe28058fbbe20393e381b0..4a0c536d1cf45ed2a6c422ee271b70c00dc739de 100644
--- a/src/drivers/TwiMaster.cpp
+++ b/src/drivers/TwiMaster.cpp
@@ -1,5 +1,5 @@
-#include <sdk/integration/nrfx/nrfx_log.h>
-#include <sdk/modules/nrfx/hal/nrf_gpio.h>
+#include <nrfx_log.h>
+#include <hal/nrf_gpio.h>
 #include <cstring>
 #include "TwiMaster.h"