Merge branch 'develop' into master
|
@ -1,12 +1,28 @@
|
|||
.idea/
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
**/CMakeCache.txt
|
||||
CMakeFiles/
|
||||
**/CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
|
||||
# Resulting binary files
|
||||
*.a
|
||||
*.so
|
||||
*.s
|
||||
*.hex
|
||||
*.bin
|
||||
!bootloader/bootloader-5.0.4.bin
|
||||
*.map
|
||||
*.out
|
||||
pinetime*.cbp
|
||||
|
||||
# InfiniTime's files
|
||||
core
|
||||
sdk
|
||||
src/Version.h
|
||||
docker/post_build.sh
|
||||
Testing/Temporary/
|
||||
|
||||
# Linux
|
||||
**/.directory
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<Objective-C>
|
||||
<option name="INDENT_NAMESPACE_MEMBERS" value="2" />
|
||||
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
|
||||
<option name="INDENT_CLASS_MEMBERS" value="2" />
|
||||
<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" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<option name="WRAP_ON_TYPING" value="1" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="LABEL_INDENT_ABSOLUTE" value="true" />
|
||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -1,10 +1,10 @@
|
|||
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")
|
||||
|
||||
if (NOT ARM_NONE_EABI_TOOLCHAIN_PATH)
|
||||
message(FATAL_ERROR "The path to the toolchain (arm-non-eabi) must be specified on the command line (add -DARM_NONE_EABI_TOOLCHAIN_PATH=<path>")
|
||||
message(FATAL_ERROR "The path to the toolchain (arm-none-eabi) must be specified on the command line (add -DARM_NONE_EABI_TOOLCHAIN_PATH=<path>")
|
||||
endif ()
|
||||
|
||||
if (NOT NRF5_SDK_PATH)
|
||||
|
|
|
@ -45,13 +45,14 @@ As of now, here is the list of achievements of this project:
|
|||
## Documentation
|
||||
|
||||
### Develop
|
||||
- [Generate the fonts and symbols](src/DisplayApp/Fonts/Readme.md)
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/Readme.md)
|
||||
|
||||
### Build, flash and debug
|
||||
- [Project branches](doc/branches.md)
|
||||
- [Versioning](doc/versioning.md)
|
||||
- [Files included in the release notes](doc/filesInReleaseNotes.md)
|
||||
- [Build the project](doc/buildAndProgram.md)
|
||||
- [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md)
|
||||
- [Build the project with Docker](doc/buildWithDocker.md)
|
||||
- [Bootloader, OTA and DFU](./bootloader/README.md)
|
||||
- [Stub using NRF52-DK](./doc/PinetimeStubWithNrf52DK.md)
|
||||
|
|
|
@ -162,7 +162,7 @@ class NrfBleDfuController(object, metaclass=ABCMeta):
|
|||
self.ble_conn.sendline('characteristics')
|
||||
|
||||
try:
|
||||
self.ble_conn.expect([uuid], timeout=2)
|
||||
self.ble_conn.expect([uuid], timeout=10)
|
||||
handles = re.findall(b'.*handle: (0x....),.*char value handle: (0x....)', self.ble_conn.before)
|
||||
(handle, value_handle) = handles[-1]
|
||||
except pexpect.TIMEOUT as e:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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`
|
||||
|
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 187 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
@ -22,3 +22,23 @@ Then, you can submit a pull-request for review. Try to describe your pull reques
|
|||
Other contributors can post comments about the pull request, maybe ask for more info or adjustements in the code.
|
||||
|
||||
Once the pull request is reviewed an accepted, it'll be merge in **develop** and will be released in the next release version of the firmware.
|
||||
|
||||
# Coding convention
|
||||
## Language
|
||||
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
||||
|
||||
It's OK to include C code if this code comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||
|
||||
## Coding style
|
||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||
|
||||
- **Identation** : 2 spaces, no tabulation
|
||||
- **Opening brace** at the end of the line
|
||||
- **Naming** : Choose self-describing variable name
|
||||
- **class** : PascalCase
|
||||
- **namespace** : PascalCase
|
||||
- **variable** : camelCase, **no** prefix/suffix ('_', 'm_',...) for class members
|
||||
- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`)
|
||||
- **Includes** :
|
||||
- files from the project : `#include "relative/path/to/the/file.h"`
|
||||
- external files and std : `#include <file.h>`
|
|
@ -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,...
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# OpenOCD and STLink
|
||||
OpenOCD (**Open O**n **C**hip **D**ebugger) is an open source tool that interfaces with many SWD/JTAG debugger to provide debugging and *in-system* programming for embedded target devices.
|
||||
|
||||
It supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
|
||||
|
||||
It works on X86 computers, as well as ARM/ARM64 computers and SBC (like the RaspberryPi and Pine64 Pinebook Pro) !
|
||||
|
||||
## Installation
|
||||
We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 correctly.
|
||||
|
||||
- Fetch the sources from GIT, and build and install it:
|
||||
|
||||
```
|
||||
git clone https://git.code.sf.net/p/openocd/code openocd-code
|
||||
|
||||
cd openocd-code
|
||||
|
||||
./bootstrap
|
||||
./configure --enable-stlink
|
||||
make -j 4
|
||||
sudo make install
|
||||
```
|
||||
|
||||
- Configure UDEV to allow OpenOCD to open the interface to your STLinkV2:
|
||||
```
|
||||
sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
|
||||
sudo udevadm control --reload-rules
|
||||
```
|
||||
|
||||
- You can now plug your STLinkV2 in a USB port and run OpenOCD to see if it's working correctly:
|
||||
|
||||
```
|
||||
$ openocd -f interface/stlink.cfg -f target/nrf52.cfg
|
||||
Open On-Chip Debugger 0.10.0+dev-01411-g051e80812-dirty (2020-09-28-20:16)
|
||||
Licensed under GNU GPL v2
|
||||
For bug reports, read
|
||||
http://openocd.org/doc/doxygen/bugs.html
|
||||
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
|
||||
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
|
||||
|
||||
nRF52 device has a CTRL-AP dedicated to recover the device from AP lock.
|
||||
A high level adapter (like a ST-Link) you are currently using cannot access
|
||||
the CTRL-AP so 'nrf52_recover' command will not work.
|
||||
Do not enable UICR APPROTECT.
|
||||
|
||||
Info : Listening on port 6666 for tcl connections
|
||||
Info : Listening on port 4444 for telnet connections
|
||||
Info : clock speed 1000 kHz
|
||||
Info : STLINK V2J34S7 (API v2) VID:PID 0483:3748
|
||||
Info : Target voltage: 3.294340
|
||||
Error: init mode failed (unable to connect to the target)
|
||||
```
|
||||
Ok, OpenOCD is running and it detects my STLinkV2. The last error shows that I've not connected the STLinkV2 to the PineTime.
|
||||
|
||||
## Configuration files
|
||||
OpenOCD is configured using configuration files.
|
||||
First, we need a common configuration file for the project : **openocd-stlink.ocd**:
|
||||
```
|
||||
source [find interface/stlink.cfg]
|
||||
|
||||
gdb_flash_program enable
|
||||
gdb_breakpoint_override hard
|
||||
|
||||
source [find target/nrf52.cfg]
|
||||
```
|
||||
This file specifies to OpenOCD which debugger and target it will be connected to..
|
||||
|
||||
Then, we use various *user files* to use OpenOCD to flash InfiniTime binary files.
|
||||
|
||||
This files flashes the bootloader and the application firmware : **flash_bootloader_app.ocd**:
|
||||
```
|
||||
init
|
||||
|
||||
program <build directory>/bootloader.bin verify 0x00000000
|
||||
program <build directory>/image-0.8.2.bin verify 0x00008000
|
||||
|
||||
reset
|
||||
```
|
||||
|
||||
And this one flashes the graphics flasher (it writes the bootloader graphics into the SPI NOR flash memory) : **flash_graphics.ocd**:
|
||||
```
|
||||
init
|
||||
|
||||
program <build directory>/pinetime-graphics-0.8.2.bin verify 0x00000000
|
||||
|
||||
reset
|
||||
```
|
||||
|
||||
## Examples
|
||||
### Flash bootloader and application
|
||||
```
|
||||
openocd -f ./openocd-stlink.cfg -f ./flash_bootloader_app.ocd
|
||||
```
|
||||
|
||||
### Flash graphics flasher
|
||||
```
|
||||
openocd -f ./openocd-stlink.cfg -f ./flash_graphics.ocd
|
||||
```
|
||||
|
||||
## Connect the STLinkV2 to the PineTime
|
||||
Here is an example using the pogo pins:
|
||||
![SWD pinout](../images/swd_pinout.jpg)
|
||||
![Pogo pins](../images/pogopins.jpg)
|
||||
|
||||
You can find more information about the SWD wiring [on the wiki](https://wiki.pine64.org/index.php?title=PineTime_devkit_wiring).
|
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 1.4 MiB |
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
}
|
|
@ -289,58 +289,63 @@ set(LVGL_SRC
|
|||
libs/lvgl/src/lv_objx/lv_slider.c
|
||||
libs/lvgl/src/lv_objx/lv_ddlist.c
|
||||
libs/lvgl/src/lv_objx/lv_ddlist.h
|
||||
libs/lvgl/src/lv_objx/lv_line.c
|
||||
libs/lvgl/src/lv_objx/lv_line.h
|
||||
)
|
||||
|
||||
list(APPEND IMAGE_FILES
|
||||
DisplayApp/Icons/battery/os_battery_error.c
|
||||
DisplayApp/Icons/battery/os_battery_100.c
|
||||
DisplayApp/Icons/battery/os_battery_090.c
|
||||
DisplayApp/Icons/battery/os_battery_080.c
|
||||
DisplayApp/Icons/battery/os_battery_070.c
|
||||
DisplayApp/Icons/battery/os_battery_060.c
|
||||
DisplayApp/Icons/battery/os_battery_050.c
|
||||
DisplayApp/Icons/battery/os_battery_040.c
|
||||
DisplayApp/Icons/battery/os_battery_030.c
|
||||
DisplayApp/Icons/battery/os_battery_020.c
|
||||
DisplayApp/Icons/battery/os_battery_010.c
|
||||
DisplayApp/Icons/battery/os_battery_005.c
|
||||
displayapp/icons/battery/os_battery_error.c
|
||||
displayapp/icons/battery/os_battery_100.c
|
||||
displayapp/icons/battery/os_battery_090.c
|
||||
displayapp/icons/battery/os_battery_080.c
|
||||
displayapp/icons/battery/os_battery_070.c
|
||||
displayapp/icons/battery/os_battery_060.c
|
||||
displayapp/icons/battery/os_battery_050.c
|
||||
displayapp/icons/battery/os_battery_040.c
|
||||
displayapp/icons/battery/os_battery_030.c
|
||||
displayapp/icons/battery/os_battery_020.c
|
||||
displayapp/icons/battery/os_battery_010.c
|
||||
displayapp/icons/battery/os_battery_005.c
|
||||
|
||||
DisplayApp/Icons/battery/os_batterycharging_100.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_090.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_080.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_070.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_060.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_050.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_040.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_030.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_020.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_010.c
|
||||
DisplayApp/Icons/battery/os_batterycharging_005.c
|
||||
displayapp/icons/battery/os_batterycharging_100.c
|
||||
displayapp/icons/battery/os_batterycharging_090.c
|
||||
displayapp/icons/battery/os_batterycharging_080.c
|
||||
displayapp/icons/battery/os_batterycharging_070.c
|
||||
displayapp/icons/battery/os_batterycharging_060.c
|
||||
displayapp/icons/battery/os_batterycharging_050.c
|
||||
displayapp/icons/battery/os_batterycharging_040.c
|
||||
displayapp/icons/battery/os_batterycharging_030.c
|
||||
displayapp/icons/battery/os_batterycharging_020.c
|
||||
displayapp/icons/battery/os_batterycharging_010.c
|
||||
displayapp/icons/battery/os_batterycharging_005.c
|
||||
|
||||
DisplayApp/Icons/bluetooth/os_bt_connected.c
|
||||
DisplayApp/Icons/bluetooth/os_bt_disconnected.c
|
||||
displayapp/icons/bluetooth/os_bt_connected.c
|
||||
displayapp/icons/bluetooth/os_bt_disconnected.c
|
||||
)
|
||||
|
||||
list(APPEND SOURCE_FILES
|
||||
Logging/NrfLogger.cpp
|
||||
DisplayApp/DisplayApp.cpp
|
||||
DisplayApp/Screens/Screen.cpp
|
||||
DisplayApp/Screens/Clock.cpp
|
||||
DisplayApp/Screens/Tile.cpp
|
||||
DisplayApp/Screens/Meter.cpp
|
||||
DisplayApp/Screens/Gauge.cpp
|
||||
DisplayApp/Screens/InfiniPaint.cpp
|
||||
DisplayApp/Screens/DropDownDemo.cpp
|
||||
DisplayApp/Screens/Modal.cpp
|
||||
DisplayApp/Screens/BatteryIcon.cpp
|
||||
DisplayApp/Screens/BleIcon.cpp
|
||||
DisplayApp/Screens/Brightness.cpp
|
||||
DisplayApp/Screens/SystemInfo.cpp
|
||||
DisplayApp/Screens/Label.cpp
|
||||
DisplayApp/Screens/FirmwareUpdate.cpp
|
||||
DisplayApp/Screens/Music.cpp
|
||||
DisplayApp/Screens/FirmwareValidation.cpp
|
||||
DisplayApp/Screens/ApplicationList.cpp
|
||||
BootloaderVersion.cpp
|
||||
logging/NrfLogger.cpp
|
||||
displayapp/DisplayApp.cpp
|
||||
displayapp/screens/Screen.cpp
|
||||
displayapp/screens/Clock.cpp
|
||||
displayapp/screens/Tile.cpp
|
||||
displayapp/screens/Meter.cpp
|
||||
displayapp/screens/Gauge.cpp
|
||||
displayapp/screens/InfiniPaint.cpp
|
||||
displayapp/screens/DropDownDemo.cpp
|
||||
displayapp/screens/Modal.cpp
|
||||
displayapp/screens/BatteryIcon.cpp
|
||||
displayapp/screens/BleIcon.cpp
|
||||
displayapp/screens/NotificationIcon.cpp
|
||||
displayapp/screens/Brightness.cpp
|
||||
displayapp/screens/SystemInfo.cpp
|
||||
displayapp/screens/Label.cpp
|
||||
displayapp/screens/FirmwareUpdate.cpp
|
||||
displayapp/screens/Music.cpp
|
||||
displayapp/screens/FirmwareValidation.cpp
|
||||
displayapp/screens/ApplicationList.cpp
|
||||
displayapp/screens/Notifications.cpp
|
||||
main.cpp
|
||||
drivers/St7789.cpp
|
||||
drivers/SpiNorFlash.cpp
|
||||
|
@ -349,30 +354,33 @@ list(APPEND SOURCE_FILES
|
|||
drivers/Watchdog.cpp
|
||||
drivers/DebugPins.cpp
|
||||
drivers/InternalFlash.cpp
|
||||
Components/Battery/BatteryController.cpp
|
||||
Components/Ble/BleController.cpp
|
||||
Components/Ble/NotificationManager.cpp
|
||||
Components/DateTime/DateTimeController.cpp
|
||||
Components/Brightness/BrightnessController.cpp
|
||||
Components/Ble/NimbleController.cpp
|
||||
Components/Ble/DeviceInformationService.cpp
|
||||
Components/Ble/CurrentTimeClient.cpp
|
||||
Components/Ble/AlertNotificationClient.cpp
|
||||
Components/Ble/DfuService.cpp
|
||||
Components/Ble/CurrentTimeService.cpp
|
||||
Components/Ble/AlertNotificationService.cpp
|
||||
Components/Ble/MusicService.cpp
|
||||
Components/FirmwareValidator/FirmwareValidator.cpp
|
||||
components/battery/BatteryController.cpp
|
||||
components/ble/BleController.cpp
|
||||
components/ble/NotificationManager.cpp
|
||||
components/datetime/DateTimeController.cpp
|
||||
components/brightness/BrightnessController.cpp
|
||||
components/ble/NimbleController.cpp
|
||||
components/ble/DeviceInformationService.cpp
|
||||
components/ble/CurrentTimeClient.cpp
|
||||
components/ble/AlertNotificationClient.cpp
|
||||
components/ble/DfuService.cpp
|
||||
components/ble/CurrentTimeService.cpp
|
||||
components/ble/AlertNotificationService.cpp
|
||||
components/ble/MusicService.cpp
|
||||
components/ble/BatteryInformationService.cpp
|
||||
components/ble/ImmediateAlertService.cpp
|
||||
components/ble/ServiceDiscovery.cpp
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
drivers/Cst816s.cpp
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
FreeRTOS/port_cmsis.c
|
||||
|
||||
DisplayApp/LittleVgl.cpp
|
||||
DisplayApp/Fonts/jetbrains_mono_extrabold_compressed.c
|
||||
DisplayApp/Fonts/jetbrains_mono_bold_20.c
|
||||
displayapp/LittleVgl.cpp
|
||||
displayapp/fonts/jetbrains_mono_extrabold_compressed.c
|
||||
displayapp/fonts/jetbrains_mono_bold_20.c
|
||||
|
||||
SystemTask/SystemTask.cpp
|
||||
systemtask/SystemTask.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
)
|
||||
|
||||
|
@ -385,38 +393,41 @@ list(APPEND GRAPHICS_SOURCE_FILES
|
|||
drivers/SpiNorFlash.cpp
|
||||
drivers/SpiMaster.cpp
|
||||
drivers/Spi.cpp
|
||||
Logging/NrfLogger.cpp
|
||||
logging/NrfLogger.cpp
|
||||
|
||||
Components/Gfx/Gfx.cpp
|
||||
components/gfx/Gfx.cpp
|
||||
drivers/St7789.cpp
|
||||
Components/Brightness/BrightnessController.cpp
|
||||
components/brightness/BrightnessController.cpp
|
||||
|
||||
graphics.cpp
|
||||
)
|
||||
|
||||
set(INCLUDE_FILES
|
||||
Logging/Logger.h
|
||||
Logging/NrfLogger.h
|
||||
DisplayApp/DisplayApp.h
|
||||
DisplayApp/TouchEvents.h
|
||||
DisplayApp/Screens/Screen.h
|
||||
DisplayApp/Screens/Clock.h
|
||||
DisplayApp/Screens/Tile.h
|
||||
DisplayApp/Screens/Meter.h
|
||||
DisplayApp/Screens/Gauge.h
|
||||
DisplayApp/Screens/InfiniPaint.h
|
||||
DisplayApp/Screens/DropDownDemo.h
|
||||
DisplayApp/Screens/Modal.h
|
||||
DisplayApp/Screens/BatteryIcon.h
|
||||
DisplayApp/Screens/BleIcon.cpp
|
||||
DisplayApp/Screens/Brightness.h
|
||||
DisplayApp/Screens/SystemInfo.h
|
||||
DisplayApp/Screens/ScreenList.h
|
||||
DisplayApp/Screens/Label.h
|
||||
DisplayApp/Screens/FirmwareUpdate.h
|
||||
DisplayApp/Screens/FirmwareValidation.h
|
||||
DisplayApp/Screens/ApplicationList.h
|
||||
DisplayApp/Apps.h
|
||||
BootloaderVersion.h
|
||||
logging/Logger.h
|
||||
logging/NrfLogger.h
|
||||
displayapp/DisplayApp.h
|
||||
displayapp/TouchEvents.h
|
||||
displayapp/screens/Screen.h
|
||||
displayapp/screens/Clock.h
|
||||
displayapp/screens/Tile.h
|
||||
displayapp/screens/Meter.h
|
||||
displayapp/screens/Gauge.h
|
||||
displayapp/screens/InfiniPaint.h
|
||||
displayapp/screens/DropDownDemo.h
|
||||
displayapp/screens/Modal.h
|
||||
displayapp/screens/BatteryIcon.h
|
||||
displayapp/screens/BleIcon.h
|
||||
displayapp/screens/NotificationIcon.h
|
||||
displayapp/screens/Brightness.h
|
||||
displayapp/screens/SystemInfo.h
|
||||
displayapp/screens/ScreenList.h
|
||||
displayapp/screens/Label.h
|
||||
displayapp/screens/FirmwareUpdate.h
|
||||
displayapp/screens/FirmwareValidation.h
|
||||
displayapp/screens/ApplicationList.h
|
||||
displayapp/Apps.h
|
||||
displayapp/screens/Notifications.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
drivers/SpiMaster.h
|
||||
|
@ -424,17 +435,21 @@ set(INCLUDE_FILES
|
|||
drivers/Watchdog.h
|
||||
drivers/DebugPins.h
|
||||
drivers/InternalFlash.h
|
||||
Components/Battery/BatteryController.h
|
||||
Components/Ble/BleController.h
|
||||
Components/Ble/NotificationManager.h
|
||||
Components/DateTime/DateTimeController.h
|
||||
Components/Brightness/BrightnessController.h
|
||||
Components/Ble/NimbleController.h
|
||||
Components/Ble/DeviceInformationService.h
|
||||
Components/Ble/CurrentTimeClient.h
|
||||
Components/Ble/AlertNotificationClient.h
|
||||
Components/Ble/DfuService.h
|
||||
Components/FirmwareValidator/FirmwareValidator.h
|
||||
components/battery/BatteryController.h
|
||||
components/ble/BleController.h
|
||||
components/ble/NotificationManager.h
|
||||
components/datetime/DateTimeController.h
|
||||
components/brightness/BrightnessController.h
|
||||
components/ble/NimbleController.h
|
||||
components/ble/DeviceInformationService.h
|
||||
components/ble/CurrentTimeClient.h
|
||||
components/ble/AlertNotificationClient.h
|
||||
components/ble/DfuService.h
|
||||
components/firmwarevalidator/FirmwareValidator.h
|
||||
components/ble/BatteryInformationService.h
|
||||
components/ble/ImmediateAlertService.h
|
||||
components/ble/ServiceDiscovery.h
|
||||
components/ble/BleClient.h
|
||||
drivers/Cst816s.h
|
||||
FreeRTOS/portmacro.h
|
||||
FreeRTOS/portmacro_cmsis.h
|
||||
|
@ -446,10 +461,10 @@ set(INCLUDE_FILES
|
|||
libs/date/includes/date/julian.h
|
||||
libs/date/includes/date/ptz.h
|
||||
libs/date/includes/date/tz_private.h
|
||||
DisplayApp/LittleVgl.h
|
||||
SystemTask/SystemTask.h
|
||||
SystemTask/SystemMonitor.h
|
||||
DisplayApp/Screens/Symbols.h
|
||||
displayapp/LittleVgl.h
|
||||
systemtask/SystemTask.h
|
||||
systemtask/SystemMonitor.h
|
||||
displayapp/screens/Symbols.h
|
||||
drivers/TwiMaster.h
|
||||
)
|
||||
|
||||
|
@ -548,7 +563,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)
|
||||
|
@ -715,6 +730,34 @@ elseif(USE_GDB_CLIENT)
|
|||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
elseif (USE_OPENOCD)
|
||||
if (USE_CMSIS_DAP)
|
||||
add_custom_target(FLASH_ERASE
|
||||
COMMAND ${OPENOCD_BIN_PATH} -c 'source [find interface/cmsis-dap.cfg]' -c 'transport select swd'
|
||||
-c 'source [find target/nrf52.cfg]'
|
||||
-c 'init'
|
||||
-c 'halt'
|
||||
-c 'nrf5 mass_erase'
|
||||
-c 'halt'
|
||||
-c 'reset'
|
||||
-c 'exit'
|
||||
COMMENT "erasing flashing"
|
||||
)
|
||||
add_custom_target("FLASH_${EXECUTABLE_NAME}"
|
||||
DEPENDS ${EXECUTABLE_NAME}
|
||||
COMMAND ${OPENOCD_BIN_PATH}
|
||||
-c 'tcl_port disabled'
|
||||
-c 'gdb_port 3333'
|
||||
-c 'telnet_port 4444'
|
||||
-c 'source [find interface/cmsis-dap.cfg]'
|
||||
-c 'transport select swd'
|
||||
-c 'source [find target/nrf52.cfg]'
|
||||
-c 'halt'
|
||||
-c "program \"${EXECUTABLE_NAME}.hex\""
|
||||
-c 'reset'
|
||||
-c 'shutdown'
|
||||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
else ()
|
||||
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"
|
||||
|
@ -724,6 +767,5 @@ elseif(USE_OPENOCD)
|
|||
COMMAND ${OPENOCD_BIN_PATH} -c "tcl_port disabled" -c "gdb_port 3333" -c "telnet_port 4444" -f interface/stlink.cfg -c 'transport select hla_swd' -f target/nrf52.cfg -c "program \"${EXECUTABLE_NAME}.hex\"" -c reset -c shutdown
|
||||
COMMENT "flashing ${EXECUTABLE_NAME}.hex"
|
||||
)
|
||||
|
||||
endif ()
|
||||
|
||||
endif ()
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
#include <SystemTask/SystemTask.h>
|
||||
#include "NotificationManager.h"
|
||||
|
||||
#include "AlertNotificationClient.h"
|
||||
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::ansServiceUuid;
|
||||
|
||||
constexpr ble_uuid16_t AlertNotificationClient::supportedNewAlertCategoryUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::supportedUnreadAlertCategoryUuid ;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::newAlertUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
||||
|
||||
int Pinetime::Controllers::NewAlertSubcribeCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
||||
}
|
||||
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager) :
|
||||
systemTask{systemTask}, notificationManager{notificationManager}{
|
||||
|
||||
}
|
||||
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service) {
|
||||
if(service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Discovery complete");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(service != nullptr && ble_uuid_cmp(((ble_uuid_t*)&ansServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS discovered : 0x%x", service->start_handle);
|
||||
ansStartHandle = service->start_handle;
|
||||
ansEndHandle = service->end_handle;
|
||||
isDiscovered = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if(error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
||||
} else {
|
||||
if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)&supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
||||
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)&supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
||||
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)&newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
||||
newAlertHandle = characteristic->val_handle;
|
||||
newAlertDefHandle = characteristic->def_handle;
|
||||
} else if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)&unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
||||
unreadAlertStatusHandle = characteristic->val_handle;
|
||||
} else if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)&controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
||||
controlPointHandle = characteristic->val_handle;
|
||||
}else
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
ble_gatt_attr *attribute) {
|
||||
if(error->status == 0) {
|
||||
NRF_LOG_INFO("ANS New alert subscribe OK");
|
||||
} else {
|
||||
NRF_LOG_INFO("ANS New alert subscribe ERROR");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc *descriptor) {
|
||||
if(error->status == 0) {
|
||||
if(characteristicValueHandle == newAlertHandle && ble_uuid_cmp(((ble_uuid_t*)&newAlertUuid), &descriptor->uuid.u)) {
|
||||
if(newAlertDescriptorHandle == 0) {
|
||||
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
||||
newAlertDescriptorHandle = descriptor->handle;
|
||||
uint8_t value[2];
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
ble_gattc_write_flat(connectionHandle, newAlertDescriptorHandle, value, sizeof(value), NewAlertSubcribeCallback, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
|
||||
if(event->notify_rx.attr_handle == newAlertHandle) {
|
||||
// TODO implement this with more memory safety (and constexpr)
|
||||
static const size_t maxBufferSize{21};
|
||||
static const size_t maxMessageSize{18};
|
||||
size_t bufferSize = min(OS_MBUF_PKTLEN(event->notify_rx.om), maxBufferSize);
|
||||
|
||||
uint8_t data[bufferSize];
|
||||
os_mbuf_copydata(event->notify_rx.om, 0, bufferSize, data);
|
||||
|
||||
char *s = (char *) &data[3];
|
||||
auto messageSize = min(maxMessageSize, (bufferSize-3));
|
||||
|
||||
for (uint i = 0; i < messageSize-1; i++) {
|
||||
if (s[i] == 0x00) {
|
||||
s[i] = 0x0A;
|
||||
}
|
||||
}
|
||||
s[messageSize-1] = '\0';
|
||||
|
||||
notificationManager.Push(Pinetime::Controllers::NotificationManager::Categories::SimpleAlert, s, messageSize);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
}
|
||||
}
|
||||
|
||||
bool AlertNotificationClient::IsDiscovered() const {
|
||||
return isDiscovered;
|
||||
}
|
||||
|
||||
uint16_t AlertNotificationClient::StartHandle() const {
|
||||
return ansStartHandle;
|
||||
}
|
||||
|
||||
uint16_t AlertNotificationClient::EndHandle() const {
|
||||
return ansEndHandle;
|
||||
}
|
||||
|
||||
uint16_t AlertNotificationClient::NewAlerthandle() const {
|
||||
return newAlertHandle;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
#include <hal/nrf_rtc.h>
|
||||
#include "CurrentTimeClient.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
|
||||
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime& dateTimeController) : dateTimeController{dateTimeController} {
|
||||
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Init() {
|
||||
|
||||
}
|
||||
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service) {
|
||||
if(service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("CTS Discovery complete");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(service != nullptr && ble_uuid_cmp(((ble_uuid_t*)&ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS discovered : 0x%x", service->start_handle);
|
||||
isDiscovered = true;
|
||||
ctsStartHandle = service->start_handle;
|
||||
ctsEndHandle = service->end_handle;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if(characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovery complete");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(characteristic != nullptr && ble_uuid_cmp(((ble_uuid_t*)¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
currentTimeHandle = characteristic->val_handle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute) {
|
||||
if(error->status == 0) {
|
||||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||
CtsData result;
|
||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
} else {
|
||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CurrentTimeClient::IsDiscovered() const {
|
||||
return isDiscovered;
|
||||
}
|
||||
|
||||
uint16_t CurrentTimeClient::StartHandle() const {
|
||||
return ctsStartHandle;
|
||||
}
|
||||
|
||||
uint16_t CurrentTimeClient::EndHandle() const {
|
||||
return ctsEndHandle;
|
||||
}
|
||||
|
||||
uint16_t CurrentTimeClient::CurrentTimeHandle() const {
|
||||
return currentTimeHandle;
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
#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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
#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;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include <cstring>
|
||||
#include "NotificationManager.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
void NotificationManager::Push(Pinetime::Controllers::NotificationManager::Categories category,
|
||||
const char *message, uint8_t currentMessageSize) {
|
||||
// TODO handle edge cases on read/write index
|
||||
auto checkedSize = std::min(currentMessageSize, uint8_t{18});
|
||||
auto& notif = notifications[writeIndex];
|
||||
std::memcpy(notif.message.data(), message, checkedSize);
|
||||
notif.message[checkedSize] = '\0';
|
||||
notif.category = category;
|
||||
|
||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
||||
if(!empty && writeIndex == readIndex)
|
||||
readIndex = writeIndex + 1;
|
||||
}
|
||||
|
||||
NotificationManager::Notification Pinetime::Controllers::NotificationManager::Pop() {
|
||||
// TODO handle edge cases on read/write index
|
||||
NotificationManager::Notification notification = notifications[readIndex];
|
||||
|
||||
if(readIndex != writeIndex) {
|
||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
||||
}
|
||||
|
||||
// TODO Check move optimization on return
|
||||
return notification;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class NotificationManager {
|
||||
public:
|
||||
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
|
||||
static constexpr uint8_t MessageSize{18};
|
||||
|
||||
struct Notification {
|
||||
std::array<char, MessageSize+1> message;
|
||||
Categories category = Categories::Unknown;
|
||||
};
|
||||
|
||||
void Push(Categories category, const char* message, uint8_t messageSize);
|
||||
Notification Pop();
|
||||
|
||||
|
||||
private:
|
||||
static constexpr uint8_t TotalNbNotifications = 5;
|
||||
std::array<Notification, TotalNbNotifications> notifications;
|
||||
uint8_t readIndex = 0;
|
||||
uint8_t writeIndex = 0;
|
||||
bool empty = true;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#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 <drivers/St7789.h>
|
||||
#include <DisplayApp/LittleVgl.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
#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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "../TouchEvents.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
class DisplayApp;
|
||||
namespace Screens {
|
||||
class Screen {
|
||||
public:
|
||||
Screen(DisplayApp* app) : app{app} {}
|
||||
virtual ~Screen() = default;
|
||||
|
||||
// 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
|
||||
virtual bool OnButtonPushed() { return false; }
|
||||
|
||||
// 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; }
|
||||
|
||||
protected:
|
||||
DisplayApp* app;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <drivers/include/nrfx_saadc.h>
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include <algorithm>
|
||||
#include "BatteryController.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
@ -34,7 +35,9 @@ void Battery::Update() {
|
|||
|
||||
// see https://forum.pine64.org/showthread.php?tid=8147
|
||||
voltage = (value * 2.0f) / (1024/3.0f);
|
||||
percentRemaining = ((voltage - 3.55)*100)*3.9;
|
||||
percentRemaining = ((voltage - 3.55f)*100.0f)*3.9f;
|
||||
percentRemaining = std::max(percentRemaining, 0.0f);
|
||||
percentRemaining = std::min(percentRemaining, 100.0f);
|
||||
|
||||
// NRF_LOG_INFO("BATTERY " NRF_LOG_FLOAT_MARKER " %% - " NRF_LOG_FLOAT_MARKER " v", NRF_LOG_FLOAT(percentRemaining), NRF_LOG_FLOAT(voltage));
|
||||
// NRF_LOG_INFO("POWER Charging : %d - Power : %d", isCharging, isPowerPresent);
|
|
@ -0,0 +1,194 @@
|
|||
#include <systemtask/SystemTask.h>
|
||||
#include "NotificationManager.h"
|
||||
|
||||
#include "AlertNotificationClient.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::ansServiceUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::supportedNewAlertCategoryUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::supportedUnreadAlertCategoryUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::newAlertUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::unreadAlertStatusUuid;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::controlPointUuid;
|
||||
|
||||
namespace {
|
||||
int
|
||||
OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnAlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||
}
|
||||
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg) {
|
||||
auto client = static_cast<AlertNotificationClient *>(arg);
|
||||
return client->OnNewAlertSubcribe(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
AlertNotificationClient::AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
}
|
||||
|
||||
bool AlertNotificationClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("ANS Discovery found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ansStartHandle, ansEndHandle,
|
||||
OnAlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("ANS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ansServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
ansStartHandle = service->start_handle;
|
||||
ansEndHandle = service->end_handle;
|
||||
isDiscovered = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if (error->status != 0 && error->status != BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery ERROR");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovery complete");
|
||||
if (isCharacteristicDiscovered) {
|
||||
ble_gattc_disc_all_dscs(connectionHandle,
|
||||
newAlertHandle, ansEndHandle,
|
||||
OnAlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
} else
|
||||
onServiceDiscovered(connectionHandle);
|
||||
} else {
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedNewAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid");
|
||||
supportedNewAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &supportedUnreadAlertCategoryUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid");
|
||||
supportedUnreadAlertCategoryHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : newAlertUuid");
|
||||
newAlertHandle = characteristic->val_handle;
|
||||
newAlertDefHandle = characteristic->def_handle;
|
||||
isCharacteristicDiscovered = true;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &unreadAlertStatusUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid");
|
||||
unreadAlertStatusHandle = characteristic->val_handle;
|
||||
} else if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &controlPointUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("ANS Characteristic discovered : controlPointUuid");
|
||||
controlPointHandle = characteristic->val_handle;
|
||||
} else NRF_LOG_INFO("ANS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
ble_gatt_attr *attribute) {
|
||||
if (error->status == 0) {
|
||||
NRF_LOG_INFO("ANS New alert subscribe OK");
|
||||
} else {
|
||||
NRF_LOG_INFO("ANS New alert subscribe ERROR");
|
||||
}
|
||||
onServiceDiscovered(connectionHandle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertNotificationClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc *descriptor) {
|
||||
if (error->status == 0) {
|
||||
if (characteristicValueHandle == newAlertHandle &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) &newAlertUuid), &descriptor->uuid.u)) {
|
||||
if (newAlertDescriptorHandle == 0) {
|
||||
NRF_LOG_INFO("ANS Descriptor discovered : %d", descriptor->handle);
|
||||
newAlertDescriptorHandle = descriptor->handle;
|
||||
isDescriptorFound = true;
|
||||
uint8_t value[2];
|
||||
value[0] = 1;
|
||||
value[1] = 0;
|
||||
ble_gattc_write_flat(connectionHandle, newAlertDescriptorHandle, value, sizeof(value), NewAlertSubcribeCallback, this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!isDescriptorFound)
|
||||
onServiceDiscovered(connectionHandle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AlertNotificationClient::OnNotification(ble_gap_event *event) {
|
||||
if (event->notify_rx.attr_handle == newAlertHandle) {
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize{NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
|
||||
const auto dbgPacketLen = OS_MBUF_PKTLEN(event->notify_rx.om);
|
||||
size_t bufferSize = min(dbgPacketLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = min(maxMessageSize, (bufferSize - headerSize));
|
||||
|
||||
NotificationManager::Notification notif;
|
||||
os_mbuf_copydata(event->notify_rx.om, headerSize, messageSize - 1, notif.message.data());
|
||||
notif.message[messageSize - 1] = '\0';
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
|
||||
notificationManager.Push(std::move(notif));
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
}
|
||||
}
|
||||
|
||||
void AlertNotificationClient::Reset() {
|
||||
ansStartHandle = 0;
|
||||
ansEndHandle = 0;
|
||||
supportedNewAlertCategoryHandle = 0;
|
||||
supportedUnreadAlertCategoryHandle = 0;
|
||||
newAlertHandle = 0;
|
||||
newAlertDescriptorHandle = 0;
|
||||
newAlertDefHandle = 0;
|
||||
unreadAlertStatusHandle = 0;
|
||||
controlPointHandle = 0;
|
||||
isDiscovered = false;
|
||||
isCharacteristicDiscovered = false;
|
||||
isDescriptorFound = false;
|
||||
}
|
||||
|
||||
void AlertNotificationClient::Discover(uint16_t connectionHandle, std::function<void(uint16_t)> onServiceDiscovered) {
|
||||
NRF_LOG_INFO("[ANS] Starting discovery");
|
||||
this->onServiceDiscovered = onServiceDiscovered;
|
||||
ble_gattc_disc_svc_by_uuid(connectionHandle, &ansServiceUuid.u, OnDiscoveryEventCallback, this);
|
||||
}
|
|
@ -3,16 +3,12 @@
|
|||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <host/ble_gap.h>
|
||||
#include "BleClient.h"
|
||||
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
int NewAlertSubcribeCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg);
|
||||
|
||||
class AlertNotificationClient {
|
||||
class AlertNotificationClient : public BleClient {
|
||||
public:
|
||||
explicit AlertNotificationClient(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
|
@ -24,13 +20,9 @@ namespace Pinetime {
|
|||
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle, const ble_gatt_dsc *descriptor);
|
||||
void OnNotification(ble_gap_event *event);
|
||||
bool IsDiscovered() const;
|
||||
uint16_t StartHandle() const;
|
||||
uint16_t EndHandle() const;
|
||||
void Reset();
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
static constexpr const ble_uuid16_t &Uuid() { return ansServiceUuid; }
|
||||
|
||||
uint16_t NewAlerthandle() const;
|
||||
private:
|
||||
static constexpr uint16_t ansServiceId{0x1811};
|
||||
static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47;
|
||||
|
@ -64,18 +56,21 @@ namespace Pinetime {
|
|||
.value = controlPointId
|
||||
};
|
||||
|
||||
uint16_t ansStartHandle;
|
||||
uint16_t ansEndHandle;
|
||||
uint16_t supportedNewAlertCategoryHandle;
|
||||
uint16_t supportedUnreadAlertCategoryHandle;
|
||||
uint16_t newAlertHandle;
|
||||
uint16_t ansStartHandle = 0;
|
||||
uint16_t ansEndHandle = 0;
|
||||
uint16_t supportedNewAlertCategoryHandle = 0;
|
||||
uint16_t supportedUnreadAlertCategoryHandle = 0;
|
||||
uint16_t newAlertHandle = 0;
|
||||
uint16_t newAlertDescriptorHandle = 0;
|
||||
uint16_t newAlertDefHandle;
|
||||
uint16_t unreadAlertStatusHandle;
|
||||
uint16_t controlPointHandle;
|
||||
uint16_t newAlertDefHandle = 0;
|
||||
uint16_t unreadAlertStatusHandle = 0;
|
||||
uint16_t controlPointHandle = 0;
|
||||
bool isDiscovered = false;
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
bool isCharacteristicDiscovered = false;
|
||||
bool isDescriptorFound = false;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include <hal/nrf_rtc.h>
|
||||
#include "NotificationManager.h"
|
||||
#include <SystemTask/SystemTask.h>
|
||||
#include <systemtask/SystemTask.h>
|
||||
|
||||
#include "AlertNotificationService.h"
|
||||
#include <cstring>
|
||||
|
@ -48,33 +48,28 @@ AlertNotificationService::AlertNotificationService ( System::SystemTask& systemT
|
|||
{
|
||||
0
|
||||
},
|
||||
}, m_systemTask{systemTask}, m_notificationManager{notificationManager} {
|
||||
}, systemTask{systemTask}, notificationManager{notificationManager} {
|
||||
}
|
||||
|
||||
int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
// TODO implement this with more memory safety (and constexpr)
|
||||
static const size_t maxBufferSize{21};
|
||||
static const size_t maxMessageSize{18};
|
||||
size_t bufferSize = min(OS_MBUF_PKTLEN(ctxt->om), maxBufferSize);
|
||||
constexpr size_t stringTerminatorSize = 1; // end of string '\0'
|
||||
constexpr size_t headerSize = 3;
|
||||
const auto maxMessageSize {NotificationManager::MaximumMessageSize()};
|
||||
const auto maxBufferSize{maxMessageSize + headerSize};
|
||||
|
||||
uint8_t data[bufferSize];
|
||||
os_mbuf_copydata(ctxt->om, 0, bufferSize, data);
|
||||
const auto dbgPacketLen = OS_MBUF_PKTLEN(ctxt->om);
|
||||
size_t bufferSize = min(dbgPacketLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = min(maxMessageSize, (bufferSize-headerSize));
|
||||
|
||||
char *s = (char *) &data[3];
|
||||
auto messageSize = min(maxMessageSize, (bufferSize-3));
|
||||
NotificationManager::Notification notif;
|
||||
os_mbuf_copydata(ctxt->om, headerSize, messageSize-1, notif.message.data());
|
||||
notif.message[messageSize-1] = '\0';
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
|
||||
notificationManager.Push(std::move(notif));
|
||||
|
||||
for (uint i = 0; i < messageSize-1; i++) {
|
||||
if (s[i] == 0x00) {
|
||||
s[i] = 0x0A;
|
||||
}
|
||||
}
|
||||
s[messageSize-1] = '\0';
|
||||
|
||||
m_notificationManager.Push(Pinetime::Controllers::NotificationManager::Categories::SimpleAlert, s, messageSize);
|
||||
m_systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -32,8 +32,8 @@ namespace Pinetime {
|
|||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
Pinetime::System::SystemTask &m_systemTask;
|
||||
NotificationManager &m_notificationManager;
|
||||
Pinetime::System::SystemTask &systemTask;
|
||||
NotificationManager ¬ificationManager;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#include "BatteryInformationService.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid;
|
||||
constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid;
|
||||
|
||||
|
||||
|
||||
int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto* batteryInformationService = static_cast<BatteryInformationService*>(arg);
|
||||
return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) :
|
||||
batteryController{batteryController},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &batteryLevelUuid,
|
||||
.access_cb = BatteryInformationServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &batteryLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &batteryInformationServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
}
|
||||
|
||||
void BatteryInformationService::Init() {
|
||||
int res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle,
|
||||
ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == batteryLevelHandle) {
|
||||
NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle);
|
||||
static uint8_t batteryValue = batteryController.PercentRemaining();
|
||||
int res = os_mbuf_append(context->om, &batteryValue, 1);
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
class Battery;
|
||||
class BatteryInformationService {
|
||||
public:
|
||||
BatteryInformationService(Controllers::Battery& batteryController);
|
||||
void Init();
|
||||
|
||||
int
|
||||
OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
static constexpr uint16_t batteryLevelId {0x2A19};
|
||||
|
||||
static constexpr ble_uuid16_t batteryInformationServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryInformationServiceId
|
||||
};
|
||||
|
||||
static constexpr ble_uuid16_t batteryLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = batteryLevelId
|
||||
};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t batteryLevelHandle;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers{
|
||||
class BleClient {
|
||||
public:
|
||||
virtual void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) = 0;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
#include <hal/nrf_rtc.h>
|
||||
#include "CurrentTimeClient.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t CurrentTimeClient::ctsServiceUuid;
|
||||
constexpr ble_uuid16_t CurrentTimeClient::currentTimeCharacteristicUuid;
|
||||
|
||||
namespace {
|
||||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
return client->OnDiscoveryEvent(conn_handle, error, service);
|
||||
}
|
||||
|
||||
int OnCurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
return client->OnCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) {
|
||||
auto client = static_cast<CurrentTimeClient *>(arg);
|
||||
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTimeClient::CurrentTimeClient(DateTime &dateTimeController) : dateTimeController{dateTimeController} {
|
||||
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Init() {
|
||||
|
||||
}
|
||||
|
||||
bool CurrentTimeClient::OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_svc *service) {
|
||||
if (service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isDiscovered) {
|
||||
NRF_LOG_INFO("CTS found, starting characteristics discovery");
|
||||
|
||||
ble_gattc_disc_all_chrs(connectionHandle, ctsStartHandle, ctsEndHandle,
|
||||
OnCurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("CTS not found");
|
||||
onServiceDiscovered(connectionHandle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (service != nullptr && ble_uuid_cmp(((ble_uuid_t *) &ctsServiceUuid), &service->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle);
|
||||
isDiscovered = true;
|
||||
ctsStartHandle = service->start_handle;
|
||||
ctsEndHandle = service->end_handle;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
if (isCharacteristicDiscovered) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovery complete, fetching time");
|
||||
ble_gattc_read(conn_handle, currentTimeHandle, CurrentTimeReadCallback, this);
|
||||
} else {
|
||||
NRF_LOG_INFO("CTS Characteristic discovery unsuccessful");
|
||||
onServiceDiscovered(conn_handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (characteristic != nullptr &&
|
||||
ble_uuid_cmp(((ble_uuid_t *) ¤tTimeCharacteristicUuid), &characteristic->uuid.u) == 0) {
|
||||
NRF_LOG_INFO("CTS Characteristic discovered : 0x%x", characteristic->val_handle);
|
||||
isCharacteristicDiscovered = true;
|
||||
currentTimeHandle = characteristic->val_handle;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_attr *attribute) {
|
||||
if (error->status == 0) {
|
||||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||
CtsData result;
|
||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", result.year,
|
||||
result.month, result.dayofmonth,
|
||||
result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(result.year, result.month, result.dayofmonth,
|
||||
0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
} else {
|
||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||
}
|
||||
|
||||
onServiceDiscovered(conn_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Reset() {
|
||||
isDiscovered = false;
|
||||
isCharacteristicDiscovered = false;
|
||||
}
|
||||
|
||||
void CurrentTimeClient::Discover(uint16_t connectionHandle, std::function<void(uint16_t)> onServiceDiscovered) {
|
||||
NRF_LOG_INFO("[CTS] Starting discovery");
|
||||
this->onServiceDiscovered = onServiceDiscovered;
|
||||
ble_gattc_disc_svc_by_uuid(connectionHandle, &ctsServiceUuid.u, OnDiscoveryEventCallback, this);
|
||||
}
|
|
@ -1,26 +1,27 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <Components/DateTime/DateTimeController.h>
|
||||
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "BleClient.h"
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
||||
class CurrentTimeClient {
|
||||
class CurrentTimeClient : public BleClient {
|
||||
public:
|
||||
explicit CurrentTimeClient(DateTime& dateTimeController);
|
||||
void Init();
|
||||
void Reset();
|
||||
bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error, const ble_gatt_svc *service);
|
||||
int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic);
|
||||
int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error *error, const ble_gatt_attr *attribute);
|
||||
bool IsDiscovered() const;
|
||||
uint16_t StartHandle() const;
|
||||
uint16_t EndHandle() const;
|
||||
uint16_t CurrentTimeHandle() const;
|
||||
static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; }
|
||||
static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; }
|
||||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
|
||||
|
||||
private:
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t year;
|
||||
|
@ -45,11 +46,14 @@ namespace Pinetime {
|
|||
.value = currentTimeCharacteristicId
|
||||
};
|
||||
|
||||
uint16_t currentTimeHandle;
|
||||
DateTime& dateTimeController;
|
||||
bool isDiscovered = false;
|
||||
uint16_t ctsStartHandle;
|
||||
uint16_t ctsEndHandle;
|
||||
|
||||
bool isCharacteristicDiscovered = false;
|
||||
uint16_t currentTimeHandle;
|
||||
std::function<void(uint16_t)> onServiceDiscovered;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <Components/DateTime/DateTimeController.h>
|
||||
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
namespace Pinetime {
|
|
@ -1,6 +1,7 @@
|
|||
#include <Components/Ble/BleController.h>
|
||||
#include <SystemTask/SystemTask.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "components/ble/BleController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "DfuService.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
|
@ -0,0 +1,82 @@
|
|||
#include <systemtask/SystemTask.h>
|
||||
#include <cstring>
|
||||
#include "ImmediateAlertService.h"
|
||||
#include "AlertNotificationService.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid;
|
||||
constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid;
|
||||
|
||||
namespace {
|
||||
int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
|
||||
auto *immediateAlertService = static_cast<ImmediateAlertService *>(arg);
|
||||
return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
const char* ToString(ImmediateAlertService::Levels level) {
|
||||
switch (level) {
|
||||
case ImmediateAlertService::Levels::NoAlert: return "Alert : None";
|
||||
case ImmediateAlertService::Levels::HighAlert: return "Alert : High";
|
||||
case ImmediateAlertService::Levels::MildAlert: return "Alert : Mild";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImmediateAlertService::ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager) :
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager},
|
||||
characteristicDefinition{
|
||||
{
|
||||
.uuid = (ble_uuid_t *) &alertLevelUuid,
|
||||
.access_cb = AlertLevelCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = &alertLevelHandle
|
||||
},
|
||||
{
|
||||
0
|
||||
}
|
||||
},
|
||||
serviceDefinition{
|
||||
{
|
||||
/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t *) &immediateAlertServiceUuid,
|
||||
.characteristics = characteristicDefinition
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
}{
|
||||
|
||||
}
|
||||
|
||||
void ImmediateAlertService::Init() {
|
||||
int res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context) {
|
||||
if(attributeHandle == alertLevelHandle) {
|
||||
if(context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
auto alertLevel = static_cast<Levels>(context->om->om_data[0]);
|
||||
auto* alertString = ToString(alertLevel);
|
||||
|
||||
NotificationManager::Notification notif;
|
||||
std::memcpy(notif.message.data(), alertString, strlen(alertString));
|
||||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert;
|
||||
notificationManager.Push(std::move(notif));
|
||||
|
||||
systemTask.PushMessage(Pinetime::System::SystemTask::Messages::OnNewNotification);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
class NotificationManager;
|
||||
class ImmediateAlertService {
|
||||
public:
|
||||
enum class Levels : uint8_t {
|
||||
NoAlert = 0,
|
||||
MildAlert = 1,
|
||||
HighAlert = 2
|
||||
};
|
||||
|
||||
ImmediateAlertService(Pinetime::System::SystemTask &systemTask,
|
||||
Pinetime::Controllers::NotificationManager ¬ificationManager);
|
||||
void Init();
|
||||
int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
NotificationManager& notificationManager;
|
||||
|
||||
static constexpr uint16_t immediateAlertServiceId {0x1802};
|
||||
static constexpr uint16_t alertLevelId {0x2A06};
|
||||
|
||||
static constexpr ble_uuid16_t immediateAlertServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = immediateAlertServiceId
|
||||
};
|
||||
|
||||
static constexpr ble_uuid16_t alertLevelUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = alertLevelId
|
||||
};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint16_t alertLevelHandle;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +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);
|
||||
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];
|
||||
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() {
|
||||
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) {
|
||||
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::getAlbum() {
|
||||
return albumName;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::MusicService::getArtist() {
|
||||
return artistName;
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::MusicService::getTrack() {
|
||||
return trackName;
|
||||
}
|
||||
|
||||
bool Pinetime::Controllers::MusicService::isPlaying() {
|
||||
return playing;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
/* 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>
|
||||
#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:
|
||||
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 {
|
||||
NotPlaying = 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
|
||||
#include <Components/DateTime/DateTimeController.h>
|
||||
|
||||
#include <SystemTask/SystemTask.h>
|
||||
#include <Components/Ble/NotificationManager.h>
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include <systemtask/SystemTask.h>
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include <hal/nrf_rtc.h>
|
||||
|
||||
#include "NimbleController.h"
|
||||
#include "MusicService.h"
|
||||
#include <services/gatt/ble_svc_gatt.h>
|
||||
|
@ -14,18 +11,13 @@
|
|||
#include <host/ble_hs.h>
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
// TODO I'm not satisfied by how this code looks like (AlertNotificationClient and CurrentTimeClient must
|
||||
// expose too much data, too many callbacks -> NimbleController -> CTS/ANS client.
|
||||
// Let's try to improve this code (and keep it working!)
|
||||
|
||||
NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
||||
Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController,
|
||||
Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Controllers::Battery& batteryController,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash) :
|
||||
systemTask{systemTask},
|
||||
bleController{bleController},
|
||||
|
@ -37,8 +29,10 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
|
|||
anService{systemTask, notificationManager},
|
||||
alertNotificationClient{systemTask, notificationManager},
|
||||
currentTimeService{dateTimeController},
|
||||
musicService{systemTask} {
|
||||
|
||||
musicService{systemTask},
|
||||
batteryInformationService{batteryController},
|
||||
immediateAlertService{systemTask, notificationManager},
|
||||
serviceDiscovery({¤tTimeClient, &alertNotificationClient}) {
|
||||
}
|
||||
|
||||
int GAPEventCallback(struct ble_gap_event *event, void *arg) {
|
||||
|
@ -46,33 +40,6 @@ int GAPEventCallback(struct ble_gap_event *event, void *arg) {
|
|||
return nimbleController->OnGAPEvent(event);
|
||||
}
|
||||
|
||||
int CurrentTimeCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<NimbleController*>(arg);
|
||||
return client->OnCTSCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int AlertNotificationCharacteristicDiscoveredCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_chr *chr, void *arg) {
|
||||
auto client = static_cast<NimbleController*>(arg);
|
||||
return client->OnANSCharacteristicDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int CurrentTimeReadCallback(uint16_t conn_handle, const struct ble_gatt_error *error,
|
||||
struct ble_gatt_attr *attr, void *arg) {
|
||||
auto client = static_cast<NimbleController*>(arg);
|
||||
return client->OnCurrentTimeReadResult(conn_handle, error, attr);
|
||||
}
|
||||
|
||||
int AlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc *dsc,
|
||||
void *arg) {
|
||||
auto client = static_cast<NimbleController*>(arg);
|
||||
return client->OnANSDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||
}
|
||||
|
||||
void NimbleController::Init() {
|
||||
while (!ble_hs_synced()) {}
|
||||
|
||||
|
@ -83,10 +50,10 @@ void NimbleController::Init() {
|
|||
currentTimeClient.Init();
|
||||
currentTimeService.Init();
|
||||
musicService.Init();
|
||||
|
||||
anService.Init();
|
||||
|
||||
dfuService.Init();
|
||||
batteryInformationService.Init();
|
||||
immediateAlertService.Init();
|
||||
int res;
|
||||
res = ble_hs_util_ensure_addr(0);
|
||||
ASSERT(res == 0);
|
||||
|
@ -105,7 +72,7 @@ void NimbleController::Init() {
|
|||
}
|
||||
|
||||
void NimbleController::StartAdvertising() {
|
||||
if(ble_gap_adv_active()) return;
|
||||
if(bleController.IsConnected() || ble_gap_conn_active() || ble_gap_adv_active()) return;
|
||||
|
||||
ble_svc_gap_device_name_set(deviceName);
|
||||
|
||||
|
@ -155,15 +122,6 @@ void NimbleController::StartAdvertising() {
|
|||
// the application has been woken up, for example.
|
||||
}
|
||||
|
||||
int OnAllSvrDisco(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
const struct ble_gatt_svc *service,
|
||||
void *arg) {
|
||||
auto nimbleController = static_cast<NimbleController*>(arg);
|
||||
return nimbleController->OnDiscoveryEvent(conn_handle, error, service);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
|
@ -194,6 +152,8 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
NRF_LOG_INFO("disconnect; reason=%d", event->disconnect.reason);
|
||||
|
||||
/* Connection terminated; resume advertising. */
|
||||
currentTimeClient.Reset();
|
||||
alertNotificationClient.Reset();
|
||||
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
|
||||
bleController.Disconnect();
|
||||
StartAdvertising();
|
||||
|
@ -266,65 +226,8 @@ int NimbleController::OnGAPEvent(ble_gap_event *event) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int NimbleController::OnDiscoveryEvent(uint16_t i, const ble_gatt_error *error, const ble_gatt_svc *service) {
|
||||
if(service == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("Service Discovery complete");
|
||||
if(currentTimeClient.IsDiscovered()) {
|
||||
ble_gattc_disc_all_chrs(connectionHandle, currentTimeClient.StartHandle(), currentTimeClient.EndHandle(),
|
||||
CurrentTimeCharacteristicDiscoveredCallback, this);
|
||||
|
||||
} else if(alertNotificationClient.IsDiscovered()) {
|
||||
ble_gattc_disc_all_chrs(connectionHandle, alertNotificationClient.StartHandle(), alertNotificationClient.EndHandle(),
|
||||
AlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
}
|
||||
}
|
||||
|
||||
alertNotificationClient.OnDiscoveryEvent(i, error, service);
|
||||
currentTimeClient.OnDiscoveryEvent(i, error, service);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimbleController::OnCTSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if(characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("CTS characteristic Discovery complete");
|
||||
ble_gattc_read(connectionHandle, currentTimeClient.CurrentTimeHandle(), CurrentTimeReadCallback, this);
|
||||
return 0;
|
||||
}
|
||||
return currentTimeClient.OnCharacteristicDiscoveryEvent(connectionHandle, error, characteristic);
|
||||
}
|
||||
|
||||
int NimbleController::OnANSCharacteristicDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
const ble_gatt_chr *characteristic) {
|
||||
if(characteristic == nullptr && error->status == BLE_HS_EDONE) {
|
||||
NRF_LOG_INFO("ANS characteristic Discovery complete");
|
||||
ble_gattc_disc_all_dscs(connectionHandle,
|
||||
alertNotificationClient.NewAlerthandle(), alertNotificationClient.EndHandle(),
|
||||
AlertNotificationDescriptorDiscoveryEventCallback, this);
|
||||
return 0;
|
||||
}
|
||||
return alertNotificationClient.OnCharacteristicsDiscoveryEvent(connectionHandle, error, characteristic);
|
||||
}
|
||||
|
||||
int NimbleController::OnCurrentTimeReadResult(uint16_t connectionHandle, const ble_gatt_error *error, ble_gatt_attr *attribute) {
|
||||
currentTimeClient.OnCurrentTimeReadResult(connectionHandle, error, attribute);
|
||||
|
||||
if (alertNotificationClient.IsDiscovered()) {
|
||||
ble_gattc_disc_all_chrs(connectionHandle, alertNotificationClient.StartHandle(),
|
||||
alertNotificationClient.EndHandle(),
|
||||
AlertNotificationCharacteristicDiscoveredCallback, this);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NimbleController::OnANSDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error *error,
|
||||
uint16_t characteristicValueHandle,
|
||||
const ble_gatt_dsc *descriptor) {
|
||||
return alertNotificationClient.OnDescriptorDiscoveryEventCallback(connectionHandle, error, characteristicValueHandle, descriptor);
|
||||
}
|
||||
|
||||
void NimbleController::StartDiscovery() {
|
||||
ble_gattc_disc_all_svcs(connectionHandle, OnAllSvrDisco, this);
|
||||
serviceDiscovery.StartDiscovery(connectionHandle);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "AlertNotificationService.h"
|
||||
#include "AlertNotificationClient.h"
|
||||
#include "DeviceInformationService.h"
|
||||
|
@ -8,6 +9,9 @@
|
|||
#include "DfuService.h"
|
||||
#include "CurrentTimeService.h"
|
||||
#include "MusicService.h"
|
||||
#include "BatteryInformationService.h"
|
||||
#include "ImmediateAlertService.h"
|
||||
#include "ServiceDiscovery.h"
|
||||
#include <host/ble_gap.h>
|
||||
|
||||
namespace Pinetime {
|
||||
|
@ -22,7 +26,7 @@ namespace Pinetime {
|
|||
public:
|
||||
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
|
||||
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
|
||||
Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash);
|
||||
void Init();
|
||||
void StartAdvertising();
|
||||
int OnGAPEvent(ble_gap_event *event);
|
||||
|
@ -57,6 +61,8 @@ namespace Pinetime {
|
|||
AlertNotificationClient alertNotificationClient;
|
||||
CurrentTimeService currentTimeService;
|
||||
MusicService musicService;
|
||||
BatteryInformationService batteryInformationService;
|
||||
ImmediateAlertService immediateAlertService;
|
||||
|
||||
uint8_t addrType; // 1 = Random, 0 = PUBLIC
|
||||
uint16_t connectionHandle = 0;
|
||||
|
@ -66,6 +72,8 @@ namespace Pinetime {
|
|||
.value = {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
|
||||
0xDE, 0xEF, 0x12, 0x12, 0x30, 0x15, 0x00, 0x00}
|
||||
};
|
||||
|
||||
ServiceDiscovery serviceDiscovery;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "NotificationManager.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr uint8_t NotificationManager::MessageSize;
|
||||
|
||||
|
||||
void NotificationManager::Push(NotificationManager::Notification &¬if) {
|
||||
notif.id = GetNextId();
|
||||
notif.valid = true;
|
||||
notifications[writeIndex] = std::move(notif);
|
||||
writeIndex = (writeIndex + 1 < TotalNbNotifications) ? writeIndex + 1 : 0;
|
||||
if(!empty)
|
||||
readIndex = (readIndex + 1 < TotalNbNotifications) ? readIndex + 1 : 0;
|
||||
else empty = false;
|
||||
|
||||
newNotification = true;
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetLastNotification() {
|
||||
NotificationManager::Notification notification = notifications[readIndex];
|
||||
notification.index = 1;
|
||||
return notification;
|
||||
}
|
||||
|
||||
NotificationManager::Notification::Id NotificationManager::GetNextId() {
|
||||
return nextId++;
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetNext(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == (notifications.end()-1))
|
||||
result = *(notifications.begin());
|
||||
else
|
||||
result = *(currentIterator+1);
|
||||
|
||||
if(result.id <= id) return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
return result;
|
||||
}
|
||||
|
||||
NotificationManager::Notification NotificationManager::GetPrevious(NotificationManager::Notification::Id id) {
|
||||
auto currentIterator = std::find_if(notifications.begin(), notifications.end(), [id](const Notification& n){return n.valid && n.id == id;});
|
||||
if(currentIterator == notifications.end() || currentIterator->id != id) return Notification{};
|
||||
|
||||
auto& lastNotification = notifications[readIndex];
|
||||
|
||||
NotificationManager::Notification result;
|
||||
|
||||
if(currentIterator == notifications.begin())
|
||||
result = *(notifications.end()-1);
|
||||
else
|
||||
result = *(currentIterator-1);
|
||||
|
||||
if(result.id >= id) return {};
|
||||
|
||||
result.index = (lastNotification.id - result.id)+1;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NotificationManager::AreNewNotificationsAvailable() {
|
||||
return newNotification;
|
||||
}
|
||||
|
||||
bool NotificationManager::ClearNewNotificationFlag() {
|
||||
return newNotification.exchange(false);
|
||||
}
|
||||
|
||||
size_t NotificationManager::NbNotifications() const {
|
||||
return std::count_if(notifications.begin(), notifications.end(), [](const Notification& n){ return n.valid;});
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class NotificationManager {
|
||||
public:
|
||||
enum class Categories {Unknown, SimpleAlert, Email, News, IncomingCall, MissedCall, Sms, VoiceMail, Schedule, HighProriotyAlert, InstantMessage };
|
||||
static constexpr uint8_t MessageSize{100};
|
||||
|
||||
struct Notification {
|
||||
using Id = uint8_t;
|
||||
Id id;
|
||||
bool valid = false;
|
||||
uint8_t index;
|
||||
std::array<char, MessageSize+1> message;
|
||||
Categories category = Categories::Unknown;
|
||||
};
|
||||
Notification::Id nextId {0};
|
||||
|
||||
void Push(Notification&& notif);
|
||||
Notification GetLastNotification();
|
||||
Notification GetNext(Notification::Id id);
|
||||
Notification GetPrevious(Notification::Id id);
|
||||
bool ClearNewNotificationFlag();
|
||||
bool AreNewNotificationsAvailable();
|
||||
|
||||
static constexpr uint8_t MaximumMessageSize() { return MessageSize; };
|
||||
size_t NbNotifications() const;
|
||||
|
||||
private:
|
||||
Notification::Id GetNextId();
|
||||
static constexpr uint8_t TotalNbNotifications = 5;
|
||||
std::array<Notification, TotalNbNotifications> notifications;
|
||||
uint8_t readIndex = 0;
|
||||
uint8_t writeIndex = 0;
|
||||
bool empty = true;
|
||||
std::atomic<bool> newNotification{false};
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include <libraries/log/nrf_log.h>
|
||||
#include "ServiceDiscovery.h"
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients{clients} {
|
||||
|
||||
}
|
||||
|
||||
void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
|
||||
NRF_LOG_INFO("[Discovery] Starting discovery");
|
||||
clientIterator = clients.begin();
|
||||
DiscoverNextService(connectionHandle);
|
||||
}
|
||||
|
||||
void ServiceDiscovery::OnServiceDiscovered(uint16_t connectionHandle) {
|
||||
clientIterator++;
|
||||
if(clientIterator != clients.end()) {
|
||||
DiscoverNextService(connectionHandle);
|
||||
} else {
|
||||
NRF_LOG_INFO("End of service discovery");
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceDiscovery::DiscoverNextService(uint16_t connectionHandle) {
|
||||
NRF_LOG_INFO("[Discovery] Discover next service");
|
||||
|
||||
auto discoverNextService = [this](uint16_t connectionHandle){
|
||||
this->OnServiceDiscovered(connectionHandle);
|
||||
};
|
||||
(*clientIterator)->Discover(connectionHandle, discoverNextService);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include "BleClient.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class ServiceDiscovery {
|
||||
public:
|
||||
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
|
||||
|
||||
void StartDiscovery(uint16_t connectionHandle);
|
||||
|
||||
|
||||
private:
|
||||
BleClient** clientIterator;
|
||||
std::array<BleClient*, 2> clients;
|
||||
void OnServiceDiscovered(uint16_t connectionHandle);
|
||||
void DiscoverNextService(uint16_t connectionHandle);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
namespace Pinetime {
|
||||
namespace Applications {
|
||||
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music, FirmwareValidation, Paint};
|
||||
enum class Apps {None, Launcher, Clock, SysInfo, Meter, Gauge, Brightness, Music, FirmwareValidation, Paint, Notifications};
|
||||
}
|
||||
}
|
|
@ -1,24 +1,26 @@
|
|||
#include <string>
|
||||
|
||||
#include "DisplayApp.h"
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include <nrf_font.h>
|
||||
#include <queue.h>
|
||||
#include <Components/DateTime/DateTimeController.h>
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include <drivers/Cst816s.h>
|
||||
#include <string>
|
||||
#include <DisplayApp/Screens/Tile.h>
|
||||
#include <DisplayApp/Screens/Meter.h>
|
||||
#include <DisplayApp/Screens/Gauge.h>
|
||||
#include <DisplayApp/Screens/Brightness.h>
|
||||
#include <DisplayApp/Screens/SystemInfo.h>
|
||||
#include <DisplayApp/Screens/Music.h>
|
||||
#include <Components/Ble/NotificationManager.h>
|
||||
#include <DisplayApp/Screens/FirmwareUpdate.h>
|
||||
#include <DisplayApp/Screens/ApplicationList.h>
|
||||
#include <DisplayApp/Screens/FirmwareValidation.h>
|
||||
#include <DisplayApp/Screens/InfiniPaint.h>
|
||||
#include "../SystemTask/SystemTask.h"
|
||||
#include "displayapp/screens/Notifications.h"
|
||||
#include "displayapp/screens/Tile.h"
|
||||
#include "displayapp/screens/Meter.h"
|
||||
#include "displayapp/screens/Gauge.h"
|
||||
#include "displayapp/screens/Brightness.h"
|
||||
#include "displayapp/screens/SystemInfo.h"
|
||||
#include "displayapp/screens/Music.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "displayapp/screens/FirmwareUpdate.h"
|
||||
#include "displayapp/screens/ApplicationList.h"
|
||||
#include "displayapp/screens/FirmwareValidation.h"
|
||||
#include "displayapp/screens/InfiniPaint.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
using namespace Pinetime::Applications;
|
||||
|
||||
|
@ -34,7 +36,7 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
|
|||
dateTimeController{dateTimeController},
|
||||
watchdog{watchdog},
|
||||
touchPanel{touchPanel},
|
||||
currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController) },
|
||||
currentScreen{new Screens::Clock(this, dateTimeController, batteryController, bleController, notificationManager) },
|
||||
systemTask{systemTask},
|
||||
notificationManager{notificationManager} {
|
||||
msgQueue = xQueueCreate(queueSize, itemSize);
|
||||
|
@ -43,13 +45,13 @@ DisplayApp::DisplayApp(Drivers::St7789 &lcd, Components::LittleVgl &lvgl, Driver
|
|||
}
|
||||
|
||||
void DisplayApp::Start() {
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "DisplayApp", 512, this, 0, &taskHandle))
|
||||
if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 512, this, 0, &taskHandle))
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
void DisplayApp::Process(void *instance) {
|
||||
auto *app = static_cast<DisplayApp *>(instance);
|
||||
NRF_LOG_INFO("DisplayApp task started!");
|
||||
NRF_LOG_INFO("displayapp task started!");
|
||||
app->InitHw();
|
||||
|
||||
// Send a dummy notification to unlock the lvgl display driver for the first iteration
|
||||
|
@ -113,8 +115,12 @@ void DisplayApp::Refresh() {
|
|||
// clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining());
|
||||
break;
|
||||
case Messages::NewNotification: {
|
||||
auto notification = notificationManager.Pop();
|
||||
modal->Show(notification.message.data());
|
||||
if(onClockApp) {
|
||||
currentScreen.reset(nullptr);
|
||||
lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Up);
|
||||
onClockApp = false;
|
||||
currentScreen.reset(new Screens::Notifications(this, notificationManager, Screens::Notifications::Modes::Preview));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Messages::TouchEvent: {
|
||||
|
@ -148,7 +154,7 @@ void DisplayApp::Refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
// lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::Down);
|
||||
// lvgl.SetFullRefresh(components::LittleVgl::FullRefreshDirections::Down);
|
||||
// currentScreen.reset(nullptr);
|
||||
// if(toggle) {
|
||||
// currentScreen.reset(new Screens::Tile(this));
|
||||
|
@ -190,7 +196,7 @@ void DisplayApp::RunningState() {
|
|||
case Apps::None:
|
||||
case Apps::Launcher: currentScreen.reset(new Screens::ApplicationList(this)); break;
|
||||
case Apps::Clock:
|
||||
currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController));
|
||||
currentScreen.reset(new Screens::Clock(this, dateTimeController, batteryController, bleController, notificationManager));
|
||||
onClockApp = true;
|
||||
break;
|
||||
// case Apps::Test: currentScreen.reset(new Screens::Message(this)); break;
|
||||
|
@ -201,6 +207,7 @@ void DisplayApp::RunningState() {
|
|||
case Apps::Brightness : currentScreen.reset(new Screens::Brightness(this, brightnessController)); break;
|
||||
case Apps::Music : currentScreen.reset(new Screens::Music(this, systemTask.nimble().music())); break;
|
||||
case Apps::FirmwareValidation: currentScreen.reset(new Screens::FirmwareValidation(this, validator)); break;
|
||||
case Apps::Notifications: currentScreen.reset(new Screens::Notifications(this, notificationManager, Screens::Notifications::Modes::Normal)); break;
|
||||
}
|
||||
nextApp = Apps::None;
|
||||
}
|
|
@ -3,21 +3,21 @@
|
|||
#include <task.h>
|
||||
#include <drivers/St7789.h>
|
||||
#include <drivers/SpiMaster.h>
|
||||
#include <Components/Gfx/Gfx.h>
|
||||
#include <bits/unique_ptr.h>
|
||||
#include <queue.h>
|
||||
#include <Components/Battery/BatteryController.h>
|
||||
#include <Components/Brightness/BrightnessController.h>
|
||||
#include <Components/Ble/BleController.h>
|
||||
#include <Components/DateTime/DateTimeController.h>
|
||||
#include "../drivers/Cst816s.h"
|
||||
#include "components/gfx/Gfx.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
#include "components/brightness/BrightnessController.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "components/firmwarevalidator/FirmwareValidator.h"
|
||||
#include "drivers/Cst816s.h"
|
||||
#include "LittleVgl.h"
|
||||
#include <date/date.h>
|
||||
#include <DisplayApp/Screens/Clock.h>
|
||||
#include "displayapp/screens/Clock.h"
|
||||
#include "displayapp/screens/Modal.h"
|
||||
#include <drivers/Watchdog.h>
|
||||
#include <DisplayApp/Screens/Modal.h>
|
||||
#include <Components/Ble/NotificationManager.h>
|
||||
#include <Components/FirmwareValidator/FirmwareValidator.h>
|
||||
#include "TouchEvents.h"
|
||||
#include "Apps.h"
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |