forked from InfiniTimeOrg/InfiniTime
-
Notifications
You must be signed in to change notification settings - Fork 1
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
[DRAFT] Apple Notification Center Service Implementation #1
Open
scandinave
wants to merge
8
commits into
develop
Choose a base branch
from
ancs
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1924694
Implement notification source characteristic
scandinave 343b472
Bind notification event with PineTime notification manager
scandinave 157f10e
added some function signatures for the other chars
4ee3cfe
Fix type in variable name
scandinave c9fff74
fixed it to compile
357b993
Add flag for secure connection
scandinave bc2b4fa
add draft for client implementation
88c10cd
merged server char security flags
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
#include "components/ble/AppleNotificationCenterClient.h" | ||
#include <algorithm> | ||
#include "components/ble/NotificationManager.h" | ||
#include "systemtask/SystemTask.h" | ||
|
||
using namespace Pinetime::Controllers; | ||
|
||
|
||
int OnDiscoveryEventCallback(uint16_t conn_handle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg) { | ||
auto client = static_cast<AppleNotificationCenterClient*>(arg); | ||
return client->OnDiscoveryEvent(conn_handle, error, service); | ||
} | ||
|
||
int OnANCSCharacteristicDiscoveredCallback(uint16_t conn_handle, | ||
const struct ble_gatt_error* error, | ||
const struct ble_gatt_chr* chr, | ||
void* arg) { | ||
auto client = static_cast<AppleNotificationCenterClient*>(arg); | ||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr); | ||
} | ||
|
||
int OnANCSDescriptorDiscoveryEventCallback( | ||
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<AppleNotificationCenterClient*>(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<AppleNotificationCenterClient*>(arg); | ||
return client->OnNewAlertSubcribe(conn_handle, error, attr); | ||
} | ||
|
||
AppleNotificationCenterClient::AppleNotificationCenterClient(Pinetime::System::SystemTask& systemTask, | ||
Pinetime::Controllers::NotificationManager& notificationManager) | ||
: systemTask {systemTask}, notificationManager {notificationManager} { | ||
} | ||
|
||
bool AppleNotificationCenterClient::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("ANCS Discovery found, starting characteristics discovery"); | ||
|
||
ble_gattc_disc_all_chrs(connectionHandle, ancsStartHandle, ancsEndHandle, OnANCSCharacteristicDiscoveredCallback, this); | ||
} else { | ||
NRF_LOG_INFO("ANCS not found"); | ||
onServiceDiscovered(connectionHandle); | ||
} | ||
return true; | ||
} | ||
|
||
if (service != nullptr && ble_uuid_cmp(&ancsUuid.u, &service->uuid.u) == 0) { | ||
NRF_LOG_INFO("ANCS discovered : 0x%x - 0x%x", service->start_handle, service->end_handle); | ||
ancsStartHandle = service->start_handle; | ||
ancsEndHandle = service->end_handle; | ||
isDiscovered = true; | ||
} | ||
return false; | ||
} | ||
|
||
int AppleNotificationCenterClient::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("ANCS Characteristic discovery ERROR"); | ||
onServiceDiscovered(connectionHandle); | ||
return 0; | ||
} | ||
|
||
if (characteristic == nullptr && error->status == BLE_HS_EDONE) { | ||
NRF_LOG_INFO("ANCS Characteristic discovery complete"); | ||
if (isCharacteristicDiscovered) { | ||
ble_gattc_disc_all_dscs(connectionHandle, notificationSourceHandle, ancsEndHandle, OnANCSDescriptorDiscoveryEventCallback, this); | ||
} else { | ||
onServiceDiscovered(connectionHandle); | ||
} | ||
} else { | ||
if (characteristic != nullptr && ble_uuid_cmp(¬ificationSourceChar.u, &characteristic->uuid.u) == 0) { | ||
NRF_LOG_INFO("ANCS Characteristic discovered: Notification Source"); | ||
notificationSourceHandle = characteristic->val_handle; | ||
// notificationSourceDefHandle = characteristic->def_handle; | ||
isCharacteristicDiscovered = true; | ||
} | ||
} | ||
return 0; | ||
} | ||
|
||
int AppleNotificationCenterClient::OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error* error, uint16_t characteristicValueHandle, const ble_gatt_dsc* descriptor) { | ||
if (error->status == 0) { | ||
if (characteristicValueHandle == notificationSourceHandle && ble_uuid_cmp(¬ificationSourceChar.u, &descriptor->uuid.u)) { | ||
if (notificationSourceDescriptorHandle == 0) { | ||
NRF_LOG_INFO("ANCS Descriptor discovered : %d", descriptor->handle); | ||
notificationSourceDescriptorHandle = descriptor->handle; | ||
isDescriptorFound = true; | ||
uint8_t value[2] {1, 0}; | ||
ble_gattc_write_flat(connectionHandle, notificationSourceDescriptorHandle, value, sizeof(value), NewAlertSubcribeCallback, this); | ||
} | ||
} | ||
} else { | ||
if (!isDescriptorFound) | ||
onServiceDiscovered(connectionHandle); | ||
} | ||
return 0; | ||
} | ||
|
||
int AppleNotificationCenterClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) { | ||
if (error->status == 0) { | ||
NRF_LOG_INFO("ANCS New alert subscribe OK"); | ||
} else { | ||
NRF_LOG_INFO("ANCS New alert subscribe ERROR"); | ||
} | ||
onServiceDiscovered(connectionHandle); | ||
|
||
return 0; | ||
} | ||
|
||
void AppleNotificationCenterClient::OnNotification(ble_gap_event* event) { | ||
if (event->notify_rx.attr_handle == notificationSourceHandle) { | ||
NotificationManager::Notification notif; | ||
notif.message = std::array<char, 101> {"Hello\0World"}; | ||
notif.size = 11; | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; | ||
notificationManager.Push(std::move(notif)); | ||
|
||
systemTask.PushMessage(Pinetime::System::Messages::OnNewNotification); | ||
} | ||
} | ||
|
||
void AppleNotificationCenterClient::Reset() { | ||
ancsStartHandle = 0; | ||
ancsEndHandle = 0; | ||
notificationSourceHandle = 0; | ||
notificationSourceDescriptorHandle = 0; | ||
isDiscovered = false; | ||
isCharacteristicDiscovered = false; | ||
isDescriptorFound = false; | ||
} | ||
|
||
void AppleNotificationCenterClient::Discover(uint16_t connectionHandle, std::function<void(uint16_t)> onServiceDiscovered) { | ||
NRF_LOG_INFO("[ANCS] Starting discovery"); | ||
this->onServiceDiscovered = onServiceDiscovered; | ||
ble_gattc_disc_svc_by_uuid(connectionHandle, &ancsUuid.u, OnDiscoveryEventCallback, this); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#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" | ||
|
||
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); | ||
void OnNotification(ble_gap_event* event); | ||
void Reset(); | ||
void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; | ||
|
||
private: | ||
// 7905F431-B5CE-4E99-A40F-4B1E122D00D0 | ||
const ble_uuid128_t ancsUuid { | ||
{BLE_UUID_TYPE_128}, | ||
{0xd0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0x24, 0x99, 0x0E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79} | ||
}; | ||
|
||
// 9FBF120D-6301-42D9-8C58-25E699A21DBD | ||
const ble_uuid128_t notificationSourceChar { | ||
{BLE_UUID_TYPE_128}, | ||
{0xBD, 0x1D, 0xA2, 0x99, 0xE6, 0x25, 0x58, 0X0C, 0xD9, 0x02, 0x01, 0x63, 0x0D, 0x12, 0xBF, 0x9F} | ||
}; | ||
// 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 | ||
const ble_uuid128_t controlPointChar { | ||
{BLE_UUID_TYPE_128}, | ||
{0xD9, 0xD9, 0xAA, 0xFD, 0xBD, 0x9B, 0x21, 0X18,0xA8, 0x09,0xE1, 0x45, 0xF3, 0xD8, 0xD1, 0x69 } | ||
}; | ||
// 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB | ||
const ble_uuid128_t dataSourceChar { | ||
{BLE_UUID_TYPE_128}, | ||
{0xFB, 0x7B, 0x7C, 0xCE, 0x6A, 0xB3, 0x44, 0X3E,0xB5, 0x0B,0xD6, 0x24, 0xE9, 0xC6, 0xEA, 0x22 } | ||
}; | ||
|
||
uint16_t ancsStartHandle {0}; | ||
uint16_t ancsEndHandle {0}; | ||
uint16_t notificationSourceHandle {0}; | ||
//uint16_t controlPointHandle {0}; | ||
//uint16_t dataSourceHandle {0}; | ||
uint16_t notificationSourceDescriptorHandle {0}; | ||
bool isDiscovered {false}; | ||
bool isCharacteristicDiscovered {false}; | ||
bool isDescriptorFound {false}; | ||
Pinetime::System::SystemTask& systemTask; | ||
Pinetime::Controllers::NotificationManager& notificationManager; | ||
std::function<void(uint16_t)> onServiceDiscovered; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
#include "components/ble/AppleNotificationCenterService.h" | ||
#include <hal/nrf_rtc.h> | ||
#include "components/ble/NotificationManager.h" | ||
#include "systemtask/SystemTask.h" | ||
|
||
using namespace Pinetime::Controllers; | ||
|
||
constexpr ble_uuid128_t AppleNotificationCenterService::ancsSvc; | ||
constexpr ble_uuid128_t AppleNotificationCenterService::ancsChar; | ||
constexpr ble_uuid128_t AppleNotificationCenterService::dataSourceChar; | ||
constexpr ble_uuid128_t AppleNotificationCenterService::controlPointChar; | ||
|
||
int AppleNotificationCenterAlertCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { | ||
auto ancService = static_cast<AppleNotificationCenterService*>(arg); | ||
return ancService->OnAlert(conn_handle, attr_handle, ctxt); | ||
} | ||
|
||
int AppleNotificationCenterDataCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { | ||
auto ancService = static_cast<AppleNotificationCenterService*>(arg); | ||
return ancService->OnData(conn_handle, attr_handle, ctxt); | ||
} | ||
|
||
void AppleNotificationCenterService::Init() { | ||
int res; | ||
res = ble_gatts_count_cfg(serviceDefinition); | ||
ASSERT(res == 0); | ||
|
||
res = ble_gatts_add_svcs(serviceDefinition); | ||
ASSERT(res == 0); | ||
} | ||
|
||
AppleNotificationCenterService::AppleNotificationCenterService(System::SystemTask& systemTask, NotificationManager& notificationManager) | ||
: characteristicDefinition { | ||
{ | ||
.uuid = &ancsChar.u, | ||
.access_cb = AppleNotificationCenterAlertCallback, | ||
.arg = this, | ||
.flags = BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC | BLE_GATT_CHR_F_WRITE_AUTHEN | ||
}, | ||
{ | ||
.uuid = &dataSourceChar.u, | ||
.access_cb = AppleNotificationCenterDataCallback, | ||
.arg = this, | ||
.flags = BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE_ENC | BLE_GATT_CHR_F_WRITE_AUTHEN | ||
}, | ||
{0} | ||
}, | ||
serviceDefinition { | ||
{/* Device Information Service */ | ||
.type = BLE_GATT_SVC_TYPE_PRIMARY, | ||
.uuid = &ancsSvc.u, | ||
.characteristics = characteristicDefinition | ||
}, | ||
{0}, | ||
}, | ||
systemTask {systemTask}, | ||
notificationManager {notificationManager} { | ||
} | ||
|
||
// Handle notification | ||
int AppleNotificationCenterService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { | ||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { | ||
Event event; | ||
EventFlag eventFlag; | ||
Category category; | ||
size_t categoryCount; | ||
uint32_t notificationUUID; | ||
|
||
NotificationManager::Notification notif; | ||
os_mbuf_copydata(ctxt->om, 0, 1, &event); | ||
os_mbuf_copydata(ctxt->om, 1, 1, &eventFlag); | ||
os_mbuf_copydata(ctxt->om, 2, 1, &category); | ||
os_mbuf_copydata(ctxt->om, 3, 1, &categoryCount); | ||
os_mbuf_copydata(ctxt->om, 4, 4, ¬ificationUUID); | ||
|
||
switch (category) { | ||
case Category::Email: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::Email; | ||
break; | ||
case Category::IncomingCall: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall; | ||
break; | ||
case Category::MissedCall: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::MissedCall; | ||
break; | ||
case Category::News: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::News; | ||
break; | ||
case Category::Schedule: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::Sms; | ||
break; | ||
case Category::Voicemail: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::VoiceMail; | ||
break; | ||
default: | ||
notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; | ||
break; | ||
} | ||
|
||
notif.message = std::array<char, 101> {"Hello\0World"}; | ||
notif.size = 11; | ||
|
||
auto notifEvent = Pinetime::System::Messages::OnNewNotification; | ||
notificationManager.Push(std::move(notif)); | ||
systemTask.PushMessage(notifEvent); | ||
|
||
} | ||
return 0; | ||
} | ||
|
||
// Handle data from dataSourceChar | ||
int AppleNotificationCenterService::OnData(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { | ||
return 0; | ||
} | ||
|
||
// Send a Get Notification Attributes command to Control Point | ||
void AppleNotificationCenterService::GetNotificationAttribute() {} | ||
// Send a Get App Attributes command to Control Point | ||
void AppleNotificationCenterService::GetAppAttributes() {} | ||
// Send a Perform Notification Action command to Control Point | ||
void AppleNotificationCenterService::PerformNotificationAction() {} | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the last comparison needed?
This callback is called only for notificationSourceChar's descriptors, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to recall this. This handles the notification subscription, right? Then we also want this for the dataSourceChar as well, but this code as it is just tries to detect an incoming message and then to show a dummy "Hello World" Notification. So this should stay in, because later on, there will be another case.