InfiniTime.git

ref: 0ce98c7ac7ba66acaf504be9bb042796e12f2733

src/components/ble/AlertNotificationService.cpp


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "AlertNotificationService.h"
#include <hal/nrf_rtc.h>
#include <cstring>
#include <algorithm>
#include "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 = (ble_uuid_t*) &ansCharUuid,
                               .access_cb = AlertNotificationCallback,
                               .arg = this,
                               .flags = BLE_GATT_CHR_F_WRITE},
                              {.uuid = (ble_uuid_t*) &notificationEventUuid,
                               .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 = (ble_uuid_t*) &ansUuid,
       .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);
}