Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ANCS Support #2217

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
965e69a
Started working on ANCS
cyberneel Dec 19, 2024
646c209
Started working on he client, which is the correct half that needs to…
cyberneel Dec 20, 2024
315f69b
Formatting
cyberneel Dec 21, 2024
fcdecbb
Added RTT logging
cyberneel Dec 21, 2024
b9cc3c3
Added debugging through watch notifications
cyberneel Dec 24, 2024
72df4fc
Removed encryption of battery and added required pairing on connect G…
cyberneel Dec 29, 2024
0a26a59
ANCS Partially works
cyberneel Dec 29, 2024
3cc4ece
Started working on using Control Point and Data Source:
cyberneel Dec 30, 2024
dfa13a9
More debugging
cyberneel Dec 31, 2024
8916920
Got Datsource to somewhat work and notifications now show title.
cyberneel Dec 31, 2024
7f0e066
Fixed check to only let new notifications pass (maybe)
cyberneel Dec 31, 2024
fce4a60
Proper Notification works.
cyberneel Jan 1, 2025
9fbc594
Fixed the event flag detection. Only shows a notification when it's new.
cyberneel Jan 2, 2025
1bed731
Fixed first letter in Subtitle being cut off
cyberneel Jan 2, 2025
670c379
Improve message display
liamcharger Jan 2, 2025
5bf8406
Updated notification, Title and Subtitle are in the orange test and m…
cyberneel Jan 2, 2025
288d167
Implemented Incoming Calls to ANCS
cyberneel Jan 3, 2025
f370d63
Turned off non important debugs
cyberneel Jan 3, 2025
0ba425a
Formatted Code
cyberneel Jan 3, 2025
2fe3a6b
Remove RTT settings
liamcharger Jan 3, 2025
1e4989f
Removed more debug notifications
cyberneel Jan 4, 2025
8ab8296
Added check for special characters and show unknown symbol.
cyberneel Jan 5, 2025
bb48b5f
removed all debug notifications
cyberneel Jan 5, 2025
c2b392b
Ignore silent notifications
cyberneel Jan 5, 2025
f888483
Make trunacated messages end in "..." to indicate that message has mo…
cyberneel Jan 5, 2025
65ead6e
Fix typos and remove unnecessary commented code
liamcharger Jan 16, 2025
b8da191
Merge branch 'main' into ancs
liamcharger Jan 16, 2025
de63dce
Merge branch 'main' into ancs
liamcharger Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ list(APPEND SOURCE_FILES
components/ble/SimpleWeatherService.cpp
components/ble/NavigationService.cpp
components/ble/BatteryInformationService.cpp
components/ble/AppleNotificationCenterClient.cpp
components/ble/FSService.cpp
components/ble/ImmediateAlertService.cpp
components/ble/ServiceDiscovery.cpp
Expand Down Expand Up @@ -526,6 +527,7 @@ list(APPEND RECOVERY_SOURCE_FILES
components/ble/MusicService.cpp
components/ble/SimpleWeatherService.cpp
components/ble/BatteryInformationService.cpp
components/ble/AppleNotificationCenterClient.cpp
components/ble/FSService.cpp
components/ble/ImmediateAlertService.cpp
components/ble/ServiceDiscovery.cpp
Expand Down Expand Up @@ -642,6 +644,7 @@ set(INCLUDE_FILES
components/ble/DeviceInformationService.h
components/ble/CurrentTimeClient.h
components/ble/AlertNotificationClient.h
components/ble/AppleNotificationCenterClient.h
components/ble/DfuService.h
components/firmwarevalidator/FirmwareValidator.h
components/ble/BatteryInformationService.h
Expand Down
514 changes: 514 additions & 0 deletions src/components/ble/AppleNotificationCenterClient.cpp

Large diffs are not rendered by default.

134 changes: 134 additions & 0 deletions src/components/ble/AppleNotificationCenterClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#pragma once

#include <cstdint>
#include <functional>
#define min // workaround: nimble's min/max macros conflict with libstdc++
#define max
#include <host/ble_gap.h>
#undef max
#undef min
#include "components/ble/BleClient.h"
#include <unordered_map>
#include <string>

namespace Pinetime {

namespace System {
class SystemTask;
}

namespace Controllers {
class NotificationManager;

class AppleNotificationCenterClient : public BleClient {
public:
explicit AppleNotificationCenterClient(Pinetime::System::SystemTask& systemTask,
Pinetime::Controllers::NotificationManager& notificationManager);

bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service);
int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic);
int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle,
const ble_gatt_error* error,
uint16_t characteristicValueHandle,
const ble_gatt_dsc* descriptor);
int OnControlPointWrite(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute);
void OnNotification(ble_gap_event* event);
void Reset();
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override;
void DebugNotification(const char* msg) const;

void AcceptIncomingCall(uint32_t notificationUid);
void RejectIncomingCall(uint32_t notificationUid);

static constexpr uint8_t maxTitleSize {20};
static constexpr uint8_t maxSubtitleSize {15};
static constexpr uint8_t maxMessageSize {120};

// 7905F431-B5CE-4E99-A40F-4B1E122D00D0
static constexpr ble_uuid128_t ancsUuid {
.u {.type = BLE_UUID_TYPE_128},
.value = {0xd0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79}};

private:
// 9FBF120D-6301-42D9-8C58-25E699A21DBD
const ble_uuid128_t notificationSourceChar {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these constants can be static constexpr

.u {.type = BLE_UUID_TYPE_128},
.value = {0xBD, 0x1D, 0xA2, 0x99, 0xE6, 0x25, 0x58, 0x8C, 0xD9, 0x42, 0x01, 0x63, 0x0D, 0x12, 0xBF, 0x9F}};
// 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9
const ble_uuid128_t controlPointChar {
.u {.type = BLE_UUID_TYPE_128},
.value = {0xD9, 0xD9, 0xAA, 0xFD, 0xBD, 0x9B, 0x21, 0x98, 0xA8, 0x49, 0xE1, 0x45, 0xF3, 0xD8, 0xD1, 0x69}};
// 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
const ble_uuid128_t dataSourceChar {
.u {.type = BLE_UUID_TYPE_128},
.value = {0xFB, 0x7B, 0x7C, 0xCE, 0x6A, 0xB3, 0x44, 0xBE, 0xB5, 0x4B, 0xD6, 0x24, 0xE9, 0xC6, 0xEA, 0x22}};

const ble_uuid16_t gattServiceUuid = {BLE_UUID_TYPE_16, 0x1801};
const ble_uuid16_t serviceChangedCharUuid = {BLE_UUID_TYPE_16, 0x2A05};

enum class Categories : uint8_t {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all of these constants above and below, is there a reference document somewhere? It would be great to have the URL linked in a comment

Other = 0,
IncomingCall = 1,
MissedCall = 2,
Voicemail = 3,
Social = 4,
Schedule = 5,
Email = 6,
News = 7,
HealthAndFitness = 8,
BuissnessAndFinance = 9,
Location = 10,
Entertainment = 11
};

enum class EventIds : uint8_t { Added = 0, Modified = 1, Removed = 2 };

enum class EventFlags : uint8_t {
Silent = (1 << 0),
Important = (1 << 1),
PreExisting = (1 << 2),
PositiveAction = (1 << 3),
NegativeAction = (1 << 4)
};

struct AncsNotification {
uint8_t eventId {0};
uint8_t eventFlags {0};
uint8_t category {0};
uint32_t uuid {0};
};

std::unordered_map<uint32_t, AncsNotification> notifications;

std::string DecodeUtf8String(os_mbuf* om, uint16_t size, uint16_t offset);

uint16_t ancsStartHandle {0};
uint16_t ancsEndHandle {0};
uint16_t notificationSourceHandle {0};
uint16_t controlPointHandle {0};
uint16_t dataSourceHandle {0};
uint16_t notificationSourceDescriptorHandle {0};
uint16_t controlPointDescriptorHandle {0};
uint16_t dataSourceDescriptorHandle {0};

uint16_t gattStartHandle {0};
uint16_t gattEndHandle {0};
uint16_t serviceChangedHandle {0};
uint16_t serviceChangedDescriptorHandle {0};
bool isGattDiscovered {false};
bool isGattCharacteristicDiscovered {false};
bool isGattDescriptorFound {false};
bool isDiscovered {false};
bool isCharacteristicDiscovered {false};
bool isDescriptorFound {false};
bool isControlCharacteristicDiscovered {false};
bool isControlDescriptorFound {false};
bool isDataCharacteristicDiscovered {false};
bool isDataDescriptorFound {false};
Comment on lines +119 to +128
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Massive networks of booleans like this scare me a bit. There are theoretically 2^10 = 1024 states here. Could this be refactored into a state enum somehow?

Pinetime::System::SystemTask& systemTask;
Pinetime::Controllers::NotificationManager& notificationManager;
std::function<void(uint16_t)> onServiceDiscovered;
};
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a trailing newline (this applies to some other files too)

13 changes: 10 additions & 3 deletions src/components/ble/NimbleController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
heartRateService {*this, heartRateController},
motionService {*this, motionController},
fsService {systemTask, fs},
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
ancsClient {systemTask, notificationManager},
serviceDiscovery({&currentTimeClient, &alertNotificationClient, &ancsClient}) {
}

void nimble_on_reset(int reason) {
Expand Down Expand Up @@ -161,8 +162,10 @@ void NimbleController::StartAdvertising() {
fields.uuids16 = &HeartRateService::heartRateServiceUuid;
fields.num_uuids16 = 1;
fields.uuids16_is_complete = 1;
fields.uuids128 = &DfuService::serviceUuid;
fields.num_uuids128 = 1;
const ble_uuid128_t uuids128[2] = {DfuService::serviceUuid, AppleNotificationCenterClient::ancsUuid};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is all OK size wise? I have vague memories of there not being space in the advertisement packet for more 128bit UUIDS. Could be totally wrong on this

// fields.uuids128 = &DfuService::serviceUuid;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment

fields.uuids128 = uuids128;
fields.num_uuids128 = 2;
fields.uuids128_is_complete = 1;
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;

Expand Down Expand Up @@ -200,6 +203,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
/* Connection failed; resume advertising. */
currentTimeClient.Reset();
alertNotificationClient.Reset();
ancsClient.Reset();
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
bleController.Disconnect();
fastAdvCount = 0;
Expand All @@ -209,6 +213,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
bleController.Connect();
systemTask.PushMessage(Pinetime::System::Messages::BleConnected);
// Service discovery is deferred via systemtask
ble_gap_security_initiate(event->connect.conn_handle);
}
break;

Expand All @@ -223,6 +228,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {

currentTimeClient.Reset();
alertNotificationClient.Reset();
ancsClient.Reset();
connectionHandle = BLE_HS_CONN_HANDLE_NONE;
if (bleController.IsConnected()) {
bleController.Disconnect();
Expand Down Expand Up @@ -370,6 +376,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) {
notifSize);

alertNotificationClient.OnNotification(event);
ancsClient.OnNotification(event);
} break;

case BLE_GAP_EVENT_NOTIFY_TX:
Expand Down
6 changes: 6 additions & 0 deletions src/components/ble/NimbleController.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "components/ble/MotionService.h"
#include "components/ble/SimpleWeatherService.h"
#include "components/fs/FS.h"
#include "components/ble/AppleNotificationCenterClient.h"

namespace Pinetime {
namespace Drivers {
Expand Down Expand Up @@ -67,6 +68,10 @@ namespace Pinetime {
return anService;
};

Pinetime::Controllers::AppleNotificationCenterClient& ancs() {
return ancsClient;
};

Pinetime::Controllers::SimpleWeatherService& weather() {
return weatherService;
};
Expand Down Expand Up @@ -106,6 +111,7 @@ namespace Pinetime {
HeartRateService heartRateService;
MotionService motionService;
FSService fsService;
AppleNotificationCenterClient ancsClient;
ServiceDiscovery serviceDiscovery;

uint8_t addrType;
Expand Down
2 changes: 2 additions & 0 deletions src/components/ble/NotificationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace Pinetime {
Id id = 0;
bool valid = false;

uint32_t ancsUid = 0;

const char* Message() const;
const char* Title() const;
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/ble/ServiceDiscovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

using namespace Pinetime::Controllers;

ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 2>&& clients) : clients {clients} {
ServiceDiscovery::ServiceDiscovery(std::array<BleClient*, 3>&& clients) : clients {clients} {
}

void ServiceDiscovery::StartDiscovery(uint16_t connectionHandle) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/ble/ServiceDiscovery.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ namespace Pinetime {

class ServiceDiscovery {
public:
ServiceDiscovery(std::array<BleClient*, 2>&& bleClients);
ServiceDiscovery(std::array<BleClient*, 3>&& bleClients);

void StartDiscovery(uint16_t connectionHandle);

private:
BleClient** clientIterator;
std::array<BleClient*, 2> clients;
std::array<BleClient*, 3> clients;
void OnServiceDiscovered(uint16_t connectionHandle);
void DiscoverNextService(uint16_t connectionHandle);
};
Expand Down
2 changes: 2 additions & 0 deletions src/displayapp/DisplayApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
currentScreen = std::make_unique<Screens::Notifications>(this,
notificationManager,
systemTask->nimble().alertService(),
systemTask->nimble().ancs(),
motorController,
*systemTask,
Screens::Notifications::Modes::Normal);
Expand All @@ -570,6 +571,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
currentScreen = std::make_unique<Screens::Notifications>(this,
notificationManager,
systemTask->nimble().alertService(),
systemTask->nimble().ancs(),
motorController,
*systemTask,
Screens::Notifications::Modes::Preview);
Expand Down
2 changes: 1 addition & 1 deletion src/displayapp/fonts/fonts.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"sources": [
{
"file": "JetBrainsMono-Bold.ttf",
"range": "0x20-0x7e, 0x410-0x44f, 0xB0"
"range": "0x20-0x7e, 0x410-0x44f, 0xB0, 0xBF, 0xFFFD"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quite like this addition semantically. How does it look on hardware? If this is the way to go, should the normal notification service need to be ported to this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is 0xBF needed?

},
{
"file": "FontAwesome5-Solid+Brands+Regular.woff",
Expand Down
Loading
Loading