diff options
| author | Michele Bini <michele.bini@gmail.com> | 2022-04-13 18:53:16 (GMT) |
|---|---|---|
| committer | Michele Bini <michele.bini@gmail.com> | 2022-04-13 18:53:16 (GMT) |
| commit | 531c1172a2357d53b214aaf7b29efee47d9b32e5 (patch) | |
| tree | e9c008f13900e1d3c63332a3bbc305754f8ae35c /src/components/ble | |
| parent | 27fa6bba08766831fe143fe5ca13767bedcd9072 (diff) | |
Revert "Sans notification (notification manager retained as it seems to be used by the dfu manager)"ultraredux2
This reverts commit 569e6fea41c13f33ad1374bb80ca489aaf4a7037.
Diffstat (limited to 'src/components/ble')
| -rw-r--r-- | src/components/ble/AlertNotificationClient.cpp | 186 | ||||
| -rw-r--r-- | src/components/ble/AlertNotificationClient.h | 70 | ||||
| -rw-r--r-- | src/components/ble/AlertNotificationService.cpp | 124 | ||||
| -rw-r--r-- | src/components/ble/AlertNotificationService.h | 68 | ||||
| -rw-r--r-- | src/components/ble/ImmediateAlertService.cpp | 75 | ||||
| -rw-r--r-- | src/components/ble/ImmediateAlertService.h | 39 | ||||
| -rw-r--r-- | src/components/ble/NimbleController.cpp | 9 | ||||
| -rw-r--r-- | src/components/ble/NimbleController.h | 10 |
8 files changed, 580 insertions, 1 deletions
diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp new file mode 100644 index 0000000..335845e --- /dev/null +++ b/src/components/ble/AlertNotificationClient.cpp @@ -0,0 +1,186 @@ +#include "components/ble/AlertNotificationClient.h" +#include <algorithm> +#include "components/ble/NotificationManager.h" +#include "systemtask/SystemTask.h" +#include <nrf_log.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& 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) { + 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(&ansServiceUuid.u, &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(&supportedNewAlertCategoryUuid.u, &characteristic->uuid.u) == 0) { + NRF_LOG_INFO("ANS Characteristic discovered : supportedNewAlertCategoryUuid"); + supportedNewAlertCategoryHandle = characteristic->val_handle; + } else if (characteristic != nullptr && ble_uuid_cmp(&supportedUnreadAlertCategoryUuid.u, &characteristic->uuid.u) == 0) { + NRF_LOG_INFO("ANS Characteristic discovered : supportedUnreadAlertCategoryUuid"); + supportedUnreadAlertCategoryHandle = characteristic->val_handle; + } else if (characteristic != nullptr && ble_uuid_cmp(&newAlertUuid.u, &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(&unreadAlertStatusUuid.u, &characteristic->uuid.u) == 0) { + NRF_LOG_INFO("ANS Characteristic discovered : unreadAlertStatusUuid"); + unreadAlertStatusHandle = characteristic->val_handle; + } else if (characteristic != nullptr && ble_uuid_cmp(&controlPointUuid.u, &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(&newAlertUuid.u, &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}; + + // Ignore notifications with empty message + const auto packetLen = OS_MBUF_PKTLEN(event->notify_rx.om); + if (packetLen <= headerSize) + return; + + size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize); + auto messageSize = std::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.size = messageSize; + notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; + notificationManager.Push(std::move(notif)); + + systemTask.PushMessage(Pinetime::System::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); +} diff --git a/src/components/ble/AlertNotificationClient.h b/src/components/ble/AlertNotificationClient.h new file mode 100644 index 0000000..2d6a387 --- /dev/null +++ b/src/components/ble/AlertNotificationClient.h @@ -0,0 +1,70 @@ +#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 AlertNotificationClient : public BleClient { + public: + explicit AlertNotificationClient(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: + static constexpr uint16_t ansServiceId {0x1811}; + static constexpr uint16_t supportedNewAlertCategoryId = 0x2a47; + static constexpr uint16_t supportedUnreadAlertCategoryId = 0x2a48; + static constexpr uint16_t newAlertId = 0x2a46; + static constexpr uint16_t unreadAlertStatusId = 0x2a45; + static constexpr uint16_t controlPointId = 0x2a44; + + static constexpr ble_uuid16_t ansServiceUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansServiceId}; + static constexpr ble_uuid16_t supportedNewAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, .value = supportedNewAlertCategoryId}; + static constexpr ble_uuid16_t supportedUnreadAlertCategoryUuid {.u {.type = BLE_UUID_TYPE_16}, + .value = supportedUnreadAlertCategoryId}; + static constexpr ble_uuid16_t newAlertUuid {.u {.type = BLE_UUID_TYPE_16}, .value = newAlertId}; + static constexpr ble_uuid16_t unreadAlertStatusUuid {.u {.type = BLE_UUID_TYPE_16}, .value = unreadAlertStatusId}; + static constexpr ble_uuid16_t controlPointUuid {.u {.type = BLE_UUID_TYPE_16}, .value = controlPointId}; + + 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 = 0; + uint16_t unreadAlertStatusHandle = 0; + uint16_t controlPointHandle = 0; + bool isDiscovered = false; + Pinetime::System::SystemTask& systemTask; + Pinetime::Controllers::NotificationManager& notificationManager; + std::function<void(uint16_t)> onServiceDiscovered; + bool isCharacteristicDiscovered = false; + bool isDescriptorFound = false; + }; + } +} diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp new file mode 100644 index 0000000..0481912 --- /dev/null +++ b/src/components/ble/AlertNotificationService.cpp @@ -0,0 +1,124 @@ +#include "components/ble/AlertNotificationService.h" +#include <hal/nrf_rtc.h> +#include <cstring> +#include <algorithm> +#include "components/ble/NotificationManager.h" +#include "systemtask/SystemTask.h" + +using namespace Pinetime::Controllers; + +constexpr ble_uuid16_t AlertNotificationService::ansUuid; +constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; +constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid; + +int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto anService = static_cast<AlertNotificationService*>(arg); + return anService->OnAlert(conn_handle, attr_handle, ctxt); +} + +void AlertNotificationService::Init() { + int res; + res = ble_gatts_count_cfg(serviceDefinition); + ASSERT(res == 0); + + res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); +} + +AlertNotificationService::AlertNotificationService(System::SystemTask& systemTask, NotificationManager& notificationManager) + : characteristicDefinition {{.uuid = &ansCharUuid.u, .access_cb = AlertNotificationCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE}, + {.uuid = ¬ificationEventUuid.u, + .access_cb = AlertNotificationCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_NOTIFY, + .val_handle = &eventHandle}, + {0}}, + serviceDefinition { + {/* Device Information Service */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &ansUuid.u, + .characteristics = characteristicDefinition}, + {0}, + }, + 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) { + constexpr size_t stringTerminatorSize = 1; // end of string '\0' + constexpr size_t headerSize = 3; + const auto maxMessageSize {NotificationManager::MaximumMessageSize()}; + const auto maxBufferSize {maxMessageSize + headerSize}; + + // Ignore notifications with empty message + const auto packetLen = OS_MBUF_PKTLEN(ctxt->om); + if (packetLen <= headerSize) { + return 0; + } + + size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize); + auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize)); + Categories category; + + NotificationManager::Notification notif; + os_mbuf_copydata(ctxt->om, headerSize, messageSize - 1, notif.message.data()); + os_mbuf_copydata(ctxt->om, 0, 1, &category); + notif.message[messageSize - 1] = '\0'; + notif.size = messageSize; + + // TODO convert all ANS categories to NotificationController categories + switch (category) { + case Categories::Call: + notif.category = Pinetime::Controllers::NotificationManager::Categories::IncomingCall; + break; + default: + notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; + break; + } + + auto event = Pinetime::System::Messages::OnNewNotification; + notificationManager.Push(std::move(notif)); + systemTask.PushMessage(event); + } + return 0; +} + +void AlertNotificationService::AcceptIncomingCall() { + auto response = IncomingCallResponses::Answer; + auto* om = ble_hs_mbuf_from_flat(&response, 1); + + uint16_t connectionHandle = systemTask.nimble().connHandle(); + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + + ble_gattc_notify_custom(connectionHandle, eventHandle, om); +} + +void AlertNotificationService::RejectIncomingCall() { + auto response = IncomingCallResponses::Reject; + auto* om = ble_hs_mbuf_from_flat(&response, 1); + + uint16_t connectionHandle = systemTask.nimble().connHandle(); + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + + ble_gattc_notify_custom(connectionHandle, eventHandle, om); +} + +void AlertNotificationService::MuteIncomingCall() { + auto response = IncomingCallResponses::Mute; + auto* om = ble_hs_mbuf_from_flat(&response, 1); + + uint16_t connectionHandle = systemTask.nimble().connHandle(); + + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } + + ble_gattc_notify_custom(connectionHandle, eventHandle, om); +} diff --git a/src/components/ble/AlertNotificationService.h b/src/components/ble/AlertNotificationService.h new file mode 100644 index 0000000..5c7d428 --- /dev/null +++ b/src/components/ble/AlertNotificationService.h @@ -0,0 +1,68 @@ +#pragma once +#include <cstdint> +#include <array> +#define min // workaround: nimble's min/max macros conflict with libstdc++ +#define max +#include <host/ble_gap.h> +#undef max +#undef min + +// 00020001-78fc-48fe-8e23-433b3a1942d0 +#define NOTIFICATION_EVENT_SERVICE_UUID_BASE \ + { 0xd0, 0x42, 0x19, 0x3a, 0x3b, 0x43, 0x23, 0x8e, 0xfe, 0x48, 0xfc, 0x78, 0x01, 0x00, 0x02, 0x00 } + +namespace Pinetime { + + namespace System { + class SystemTask; + } + namespace Controllers { + class NotificationManager; + + class AlertNotificationService { + public: + AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); + void Init(); + + int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + + void AcceptIncomingCall(); + void RejectIncomingCall(); + void MuteIncomingCall(); + + enum class IncomingCallResponses : uint8_t { Reject = 0x00, Answer = 0x01, Mute = 0x02 }; + + private: + enum class Categories : uint8_t { + SimpleAlert = 0x00, + Email = 0x01, + News = 0x02, + Call = 0x03, + MissedCall = 0x04, + MmsSms = 0x05, + VoiceMail = 0x06, + Schedule = 0x07, + HighPrioritizedAlert = 0x08, + InstantMessage = 0x09, + All = 0xff + }; + + static constexpr uint16_t ansId {0x1811}; + static constexpr uint16_t ansCharId {0x2a46}; + + static constexpr ble_uuid16_t ansUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansId}; + + static constexpr ble_uuid16_t ansCharUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ansCharId}; + + static constexpr ble_uuid128_t notificationEventUuid {.u {.type = BLE_UUID_TYPE_128}, .value = NOTIFICATION_EVENT_SERVICE_UUID_BASE}; + + struct ble_gatt_chr_def characteristicDefinition[3]; + struct ble_gatt_svc_def serviceDefinition[2]; + + Pinetime::System::SystemTask& systemTask; + NotificationManager& notificationManager; + + uint16_t eventHandle; + }; + } +} diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp new file mode 100644 index 0000000..c80b378 --- /dev/null +++ b/src/components/ble/ImmediateAlertService.cpp @@ -0,0 +1,75 @@ +#include "components/ble/ImmediateAlertService.h" +#include <cstring> +#include "components/ble/NotificationManager.h" +#include "systemtask/SystemTask.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& notificationManager) + : systemTask {systemTask}, + notificationManager {notificationManager}, + characteristicDefinition {{.uuid = &alertLevelUuid.u, + .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 = &immediateAlertServiceUuid.u, + .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::Messages::OnNewNotification); + } + } + + return 0; +} diff --git a/src/components/ble/ImmediateAlertService.h b/src/components/ble/ImmediateAlertService.h new file mode 100644 index 0000000..1f778ac --- /dev/null +++ b/src/components/ble/ImmediateAlertService.h @@ -0,0 +1,39 @@ +#pragma once +#define min // workaround: nimble's min/max macros conflict with libstdc++ +#define max +#include <host/ble_gap.h> +#undef max +#undef min + +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& notificationManager); + 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; + }; + } +} diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 5236619..f63d98c 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -38,9 +38,11 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask, currentTimeClient {dateTimeController}, anService {systemTask, notificationManager}, + alertNotificationClient {systemTask, notificationManager}, currentTimeService {dateTimeController}, batteryInformationService {batteryController}, - serviceDiscovery({¤tTimeClient}) { + immediateAlertService {systemTask, notificationManager}, + serviceDiscovery({¤tTimeClient, &alertNotificationClient}) { } void nimble_on_reset(int reason) { @@ -81,6 +83,7 @@ void NimbleController::Init() { anService.Init(); dfuService.Init(); batteryInformationService.Init(); + immediateAlertService.Init(); int rc; rc = ble_hs_util_ensure_addr(0); @@ -163,6 +166,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { if (event->connect.status != 0) { /* Connection failed; resume advertising. */ currentTimeClient.Reset(); + alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; bleController.Disconnect(); fastAdvCount = 0; @@ -181,6 +185,7 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { NRF_LOG_INFO("disconnect reason=%d", event->disconnect.reason); currentTimeClient.Reset(); + alertNotificationClient.Reset(); connectionHandle = BLE_HS_CONN_HANDLE_NONE; if(bleController.IsConnected()) { bleController.Disconnect(); @@ -271,6 +276,8 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { event->notify_rx.conn_handle, event->notify_rx.attr_handle, notifSize); + + alertNotificationClient.OnNotification(event); } break; case BLE_GAP_EVENT_NOTIFY_TX: diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 2069d8c..c9d6420 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -7,11 +7,14 @@ #include <host/ble_gap.h> #undef max #undef min +#include "components/ble/AlertNotificationClient.h" +#include "components/ble/AlertNotificationService.h" #include "components/ble/BatteryInformationService.h" #include "components/ble/CurrentTimeClient.h" #include "components/ble/CurrentTimeService.h" #include "components/ble/DeviceInformationService.h" #include "components/ble/DfuService.h" +#include "components/ble/ImmediateAlertService.h" #include "components/ble/ServiceDiscovery.h" namespace Pinetime { @@ -42,6 +45,10 @@ namespace Pinetime { int OnGAPEvent(ble_gap_event* event); void StartDiscovery(); + Pinetime::Controllers::AlertNotificationService& alertService() { + return anService; + }; + uint16_t connHandle(); void NotifyBatteryLevel(uint8_t level); @@ -60,8 +67,11 @@ namespace Pinetime { DeviceInformationService deviceInformationService; CurrentTimeClient currentTimeClient; + AlertNotificationService anService; + AlertNotificationClient alertNotificationClient; CurrentTimeService currentTimeService; BatteryInformationService batteryInformationService; + ImmediateAlertService immediateAlertService; ServiceDiscovery serviceDiscovery; uint8_t addrType; |
