-
-
Notifications
You must be signed in to change notification settings - Fork 1k
ANCS Support #2217
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
base: main
Are you sure you want to change the base?
ANCS Support #2217
Changes from all commits
965e69a
646c209
315f69b
fcdecbb
b9cc3c3
72df4fc
0a26a59
3cc4ece
dfa13a9
8916920
7f0e066
fce4a60
9fbc594
1bed731
670c379
5bf8406
288d167
f370d63
0ba425a
2fe3a6b
1e4989f
8ab8296
bb48b5f
c2b392b
f888483
65ead6e
b8da191
c73f016
de63dce
ec4b3a7
d653c17
5e7a77f
3669665
92673eb
fede286
5e35637
ce15d50
f47c921
8cb0ec4
1937e7e
1d17899
3450956
9c919d3
e549e89
a693cff
94b88a0
211e85e
6c89b79
d745049
34a6850
791a483
dd9865b
dd08767
07d1667
7ea3de3
ad47ee0
f636067
c1997d5
cf10a8b
4500493
202a0bd
08882ad
6347ee3
6d3d668
d6c5bac
f148fea
756201e
f3aff14
54908fb
23242e8
72c3b04
7a7f1b0
f0850c0
624cef1
4c4d21e
77f5ce2
3ae4561
f8b55d9
b29d4fb
da887a4
9244a3d
32e0cbe
59a6e8d
733935f
3a63df3
07f6b72
1599edb
2345e12
459701d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| #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 MaybeFinishDiscovery(uint16_t connectionHandle); | ||
| 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}; | ||
|
|
||
| // The Apple Notification Center Service UUID are from | ||
| // https://developer.apple.com/library/archive/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Specification/Specification.html | ||
|
|
||
| // 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 | ||
| static constexpr ble_uuid128_t notificationSourceChar { | ||
| .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 | ||
| static constexpr 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 | ||
| static constexpr 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}}; | ||
|
|
||
| static constexpr ble_uuid16_t gattServiceUuid = {BLE_UUID_TYPE_16, 0x1801}; | ||
| static constexpr ble_uuid16_t serviceChangedCharUuid = {BLE_UUID_TYPE_16, 0x2A05}; | ||
|
|
||
| enum class Categories : uint8_t { | ||
| 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}; | ||
| bool isProcessed {false}; | ||
| }; | ||
|
|
||
| std::unordered_map<uint32_t, AncsNotification> notifications; | ||
|
|
||
| std::string DecodeUtf8String(os_mbuf* om, uint16_t size, uint16_t offset); | ||
|
|
||
| bool subscriptionsDone = false; | ||
| 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
+125
to
+134
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what happened was, I used the existing BLE code for the Android notification system, and It was keeping track of if various characteristics were found of not. They are not all used together so I don't think there are 1024 states. At some point I got lost and started keeping track of each service and made some of my code conditionally run based on these booleans and it started working. I think we could maybe cut these down if we analyze where the BLE stack actually needs these confirmations. |
||
| Pinetime::System::SystemTask& systemTask; | ||
| Pinetime::Controllers::NotificationManager& notificationManager; | ||
| std::function<void(uint16_t)> onServiceDiscovered; | ||
| }; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,7 +49,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, | |
| heartRateService {*this, heartRateController}, | ||
| motionService {*this, motionController}, | ||
| fsService {systemTask, fs}, | ||
| serviceDiscovery({¤tTimeClient, &alertNotificationClient}) { | ||
| ancsClient {systemTask, notificationManager}, | ||
| serviceDiscovery({¤tTimeClient, &alertNotificationClient, &ancsClient}) { | ||
| } | ||
|
|
||
| void nimble_on_reset(int reason) { | ||
|
|
@@ -161,8 +162,9 @@ 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}; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure... I read somewhere ANCS needs to be advertised from the watch and added this, but I forgot if it actually advertises or what. Something to look into. |
||
| fields.uuids128 = uuids128; | ||
| fields.num_uuids128 = 2; | ||
| fields.uuids128_is_complete = 1; | ||
| fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO; | ||
|
|
||
|
|
@@ -200,6 +202,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; | ||
|
|
@@ -209,6 +212,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; | ||
|
|
||
|
|
@@ -223,6 +227,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(); | ||
|
|
@@ -370,6 +375,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { | |
| notifSize); | ||
|
|
||
| alertNotificationClient.OnNotification(event); | ||
| ancsClient.OnNotification(event); | ||
| } break; | ||
|
|
||
| case BLE_GAP_EVENT_NOTIFY_TX: | ||
|
|
||
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.
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
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.
If you are talking about the UUIDs, they are from the Apple ANCS spec sheet. I'll add a comment linking it and explaining this.
Here it is for quick reference: Apple ANCS