Merge branch 'develop' into patch-2

This commit is contained in:
JF002 2020-07-26 15:58:57 +02:00 committed by GitHub
commit 4f51d429a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 643 additions and 23 deletions

202
.github/workflows/c-cpp.yml vendored Normal file
View File

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

View File

@ -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")

View File

@ -5,7 +5,7 @@
*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 :
@ -24,14 +24,14 @@ As of now, here is the list of achievements of this project:
- Fast and optimized LCD driver
- BLE communication
- Rich user interface via display, touch panel and push button
- Time synchronisation via BLE
- 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)
* 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 @@ As of now, here is the list of achievements of this project:
## 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) : Hes 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 :)*

View File

@ -24,17 +24,17 @@ As I said in the introduction, the datasheet will be your bedside book during yo
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

View File

@ -336,6 +336,7 @@ list(APPEND SOURCE_FILES
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 @@ list(APPEND SOURCE_FILES
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

View File

@ -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);
}

View File

@ -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;
};
}
}

View File

@ -6,6 +6,7 @@
#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 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
currentTimeClient{dateTimeController},
anService{systemTask, notificationManager},
alertNotificationClient{systemTask, notificationManager},
currentTimeService{dateTimeController} {
currentTimeService{dateTimeController},
musicService{systemTask} {
}
@ -80,6 +82,7 @@ void NimbleController::Init() {
deviceInformationService.Init();
currentTimeClient.Init();
currentTimeService.Init();
musicService.Init();
anService.Init();
@ -326,5 +329,7 @@ void NimbleController::StartDiscovery() {
}
uint16_t NimbleController::connHandle() {
return connectionHandle;
}

View File

@ -7,6 +7,7 @@
#include "CurrentTimeClient.h"
#include "DfuService.h"
#include "CurrentTimeService.h"
#include "MusicService.h"
#include <host/ble_gap.h>
namespace Pinetime {
@ -15,6 +16,7 @@ namespace Pinetime {
}
namespace Controllers {
class DateTime;
class NimbleController {
public:
@ -35,6 +37,11 @@ namespace Pinetime {
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 @@ namespace Pinetime {
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},

View File

@ -15,6 +15,7 @@
#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 @@ void DisplayApp::RunningState() {
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;
}

View File

@ -42,7 +42,7 @@ namespace Pinetime {
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);

View File

@ -19,6 +19,7 @@ Gauge::Gauge(Pinetime::Applications::DisplayApp *app) : Screen(app) {
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;

View File

@ -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);
}
}
}

View File

@ -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;
};
}
}
}

View File

@ -95,7 +95,7 @@ void Tile::StartMeterApp() {
}
void Tile::StartGaugeApp() {
app->StartApp(DisplayApp::Apps::Gauge);
app->StartApp(DisplayApp::Apps::Music);
running = false;
}

View File

@ -12,6 +12,7 @@
#include <host/util/util.h>
#include <drivers/InternalFlash.h>
#include "../main.h"
#include "Components/Ble/NimbleController.h"
using namespace Pinetime::System;

View File

@ -8,9 +8,10 @@
#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 {
@ -37,6 +38,8 @@ namespace Pinetime {
void OnIdle();
Pinetime::Controllers::NimbleController& nimble() {return nimbleController;};
private:
TaskHandle_t taskHandle;

View File

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