summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/host/services/ans
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/host/services/ans')
-rw-r--r--src/libs/mynewt-nimble/nimble/host/services/ans/include/services/ans/ble_svc_ans.h85
-rw-r--r--src/libs/mynewt-nimble/nimble/host/services/ans/pkg.yml34
-rw-r--r--src/libs/mynewt-nimble/nimble/host/services/ans/src/ble_svc_ans.c463
-rw-r--r--src/libs/mynewt-nimble/nimble/host/services/ans/syscfg.yml30
4 files changed, 612 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/nimble/host/services/ans/include/services/ans/ble_svc_ans.h b/src/libs/mynewt-nimble/nimble/host/services/ans/include/services/ans/ble_svc_ans.h
new file mode 100644
index 00000000..435e9e11
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/host/services/ans/include/services/ans/ble_svc_ans.h
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_SVC_ANS_
+#define H_BLE_SVC_ANS_
+
+struct ble_hs_cfg;
+
+/* 16 Bit Alert Notification Service UUID */
+#define BLE_SVC_ANS_UUID16 0x1811
+
+/* 16 Bit Alert Notification Service Characteristic UUIDs */
+#define BLE_SVC_ANS_CHR_UUID16_SUP_NEW_ALERT_CAT 0x2a47
+#define BLE_SVC_ANS_CHR_UUID16_NEW_ALERT 0x2a46
+#define BLE_SVC_ANS_CHR_UUID16_SUP_UNR_ALERT_CAT 0x2a48
+#define BLE_SVC_ANS_CHR_UUID16_UNR_ALERT_STAT 0x2a45
+#define BLE_SVC_ANS_CHR_UUID16_ALERT_NOT_CTRL_PT 0x2a44
+
+/* Alert Notification Service Category ID Bit Masks
+ *
+ * TODO: Add remaining 2 optional categories */
+#define BLE_SVC_ANS_CAT_BM_NONE 0x00
+#define BLE_SVC_ANS_CAT_BM_SIMPLE_ALERT 0x01
+#define BLE_SVC_ANS_CAT_BM_EMAIL 0x02
+#define BLE_SVC_ANS_CAT_BM_NEWS 0x04
+#define BLE_SVC_ANS_CAT_BM_CALL 0x08
+#define BLE_SVC_ANS_CAT_BM_MISSED_CALL 0x10
+#define BLE_SVC_ANS_CAT_BM_SMS 0x20
+#define BLE_SVC_ANS_CAT_BM_VOICE_MAIL 0x40
+#define BLE_SVC_ANS_CAT_BM_SCHEDULE 0x80
+
+/* Alert Notification Service Category IDs
+ *
+ * TODO: Add remaining 2 optional categories */
+#define BLE_SVC_ANS_CAT_ID_SIMPLE_ALERT 0
+#define BLE_SVC_ANS_CAT_ID_EMAIL 1
+#define BLE_SVC_ANS_CAT_ID_NEWS 2
+#define BLE_SVC_ANS_CAT_ID_CALL 3
+#define BLE_SVC_ANS_CAT_ID_MISSED_CALL 4
+#define BLE_SVC_ANS_CAT_ID_SMS 5
+#define BLE_SVC_ANS_CAT_ID_VOICE_MAIL 6
+#define BLE_SVC_ANS_CAT_ID_SCHEDULE 7
+
+/* Number of valid ANS categories
+ *
+ * TODO: Add remaining 2 optional categories */
+#define BLE_SVC_ANS_CAT_NUM 8
+
+/* Alert Notification Control Point Command IDs */
+#define BLE_SVC_ANS_CMD_EN_NEW_ALERT_CAT 0
+#define BLE_SVC_ANS_CMD_EN_UNR_ALERT_CAT 1
+#define BLE_SVC_ANS_CMD_DIS_NEW_ALERT_CAT 2
+#define BLE_SVC_ANS_CMD_DIS_UNR_ALERT_CAT 3
+#define BLE_SVC_ANS_CMD_NOT_NEW_ALERT_IMMEDIATE 4
+#define BLE_SVC_ANS_CMD_NOT_UNR_ALERT_IMMEDIATE 5
+
+/* Error Definitions */
+#define BLE_SVC_ANS_ERR_CMD_NOT_SUPPORTED 0xA0
+
+void ble_svc_ans_on_gap_connect(uint16_t conn_handle);
+
+int ble_svc_ans_new_alert_add(uint8_t cat_id,
+ const char * info_str);
+int ble_svc_ans_unr_alert_add(uint8_t cat_id);
+
+void ble_svc_ans_init(void);
+
+#endif
+
diff --git a/src/libs/mynewt-nimble/nimble/host/services/ans/pkg.yml b/src/libs/mynewt-nimble/nimble/host/services/ans/pkg.yml
new file mode 100644
index 00000000..691e566e
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/host/services/ans/pkg.yml
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: nimble/host/services/ans
+pkg.description: Alert Notification Service Server.
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+ - ans
+ - nimble
+
+pkg.deps:
+ - nimble/host
+
+pkg.init:
+ ble_svc_ans_init: 'MYNEWT_VAL(BLE_SVC_ANS_SYSINIT_STAGE)'
diff --git a/src/libs/mynewt-nimble/nimble/host/services/ans/src/ble_svc_ans.c b/src/libs/mynewt-nimble/nimble/host/services/ans/src/ble_svc_ans.c
new file mode 100644
index 00000000..5b64f18c
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/host/services/ans/src/ble_svc_ans.c
@@ -0,0 +1,463 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "host/ble_hs.h"
+#include "host/ble_gap.h"
+#include "services/ans/ble_svc_ans.h"
+
+/* Max length of new alert info string */
+#define BLE_SVC_ANS_INFO_STR_MAX_LEN 18
+/* Max length of a new alert notification, max string length + 2 bytes
+ * for category ID and count. */
+#define BLE_SVC_ANS_NEW_ALERT_MAX_LEN (BLE_SVC_ANS_INFO_STR_MAX_LEN + 2)
+
+/* Supported categories bitmasks */
+static uint8_t ble_svc_ans_new_alert_cat;
+static uint8_t ble_svc_ans_unr_alert_cat;
+
+/* Characteristic values */
+static uint8_t ble_svc_ans_new_alert_val[BLE_SVC_ANS_NEW_ALERT_MAX_LEN];
+static uint16_t ble_svc_ans_new_alert_val_len;
+static uint8_t ble_svc_ans_unr_alert_stat[2];
+static uint8_t ble_svc_ans_alert_not_ctrl_pt[2];
+
+/* Alert counts, one value for each category */
+static uint8_t ble_svc_ans_new_alert_cnt[BLE_SVC_ANS_CAT_NUM];
+static uint8_t ble_svc_ans_unr_alert_cnt[BLE_SVC_ANS_CAT_NUM];
+
+/* Characteristic value handles */
+static uint16_t ble_svc_ans_new_alert_val_handle;
+static uint16_t ble_svc_ans_unr_alert_val_handle;
+
+/* Connection handle
+ *
+ * TODO: In order to support multiple connections we would need to save
+ * the handles for every connection, not just the most recent. Then
+ * we would need to notify each connection when needed.
+ * */
+static uint16_t ble_svc_ans_conn_handle;
+
+/* Access function */
+static int
+ble_svc_ans_access(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+/* Notify new alert */
+static int
+ble_svc_ans_new_alert_notify(uint8_t cat_id, const char * info_str);
+
+/* Notify unread alert */
+static int
+ble_svc_ans_unr_alert_notify(uint8_t cat_id);
+
+/* Save written value to local characteristic value */
+static int
+ble_svc_ans_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
+ void *dst, uint16_t *len);
+
+static const struct ble_gatt_svc_def ble_svc_ans_defs[] = {
+ {
+ /*** Alert Notification Service. */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_UUID16),
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ /** Supported New Alert Catagory
+ *
+ * This characteristic exposes what categories of new
+ * alert are supported in the server.
+ */
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_CHR_UUID16_SUP_NEW_ALERT_CAT),
+ .access_cb = ble_svc_ans_access,
+ .flags = BLE_GATT_CHR_F_READ,
+ }, {
+ /** New Alert
+ *
+ * This characteristic exposes information about
+ * the count of new alerts (for a given category).
+ */
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_CHR_UUID16_NEW_ALERT),
+ .access_cb = ble_svc_ans_access,
+ .val_handle = &ble_svc_ans_new_alert_val_handle,
+ .flags = BLE_GATT_CHR_F_NOTIFY,
+ }, {
+ /** Supported Unread Alert Catagory
+ *
+ * This characteristic exposes what categories of
+ * unread alert are supported in the server.
+ */
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_CHR_UUID16_SUP_UNR_ALERT_CAT),
+ .access_cb = ble_svc_ans_access,
+ .flags = BLE_GATT_CHR_F_READ,
+ }, {
+ /** Unread Alert Status
+ *
+ * This characteristic exposes the count of unread
+ * alert events existing in the server.
+ */
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_CHR_UUID16_UNR_ALERT_STAT),
+ .access_cb = ble_svc_ans_access,
+ .val_handle = &ble_svc_ans_unr_alert_val_handle,
+ .flags = BLE_GATT_CHR_F_NOTIFY,
+ }, {
+ /** Alert Notification Control Point
+ *
+ * This characteristic allows the peer device to
+ * enable/disable the alert notification of new alert
+ * and unread event more selectively than can be done
+ * by setting or clearing the notification bit in the
+ * Client Characteristic Configuration for each alert
+ * characteristic.
+ */
+ .uuid = BLE_UUID16_DECLARE(BLE_SVC_ANS_CHR_UUID16_ALERT_NOT_CTRL_PT),
+ .access_cb = ble_svc_ans_access,
+ .flags = BLE_GATT_CHR_F_WRITE,
+ }, {
+ 0, /* No more characteristics in this service. */
+ } },
+ },
+
+ {
+ 0, /* No more services. */
+ },
+};
+
+/**
+ * ANS access function
+ */
+static int
+ble_svc_ans_access(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt,
+ void *arg)
+{
+ uint16_t uuid16;
+ int rc;
+
+ /* ANS Control point command and catagory variables */
+ uint8_t cmd_id;
+ uint8_t cat_id;
+ uint8_t cat_bit_mask;
+ int i;
+
+ uuid16 = ble_uuid_u16(ctxt->chr->uuid);
+ assert(uuid16 != 0);
+
+ switch (uuid16) {
+ case BLE_SVC_ANS_CHR_UUID16_SUP_NEW_ALERT_CAT:
+ assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+ rc = os_mbuf_append(ctxt->om, &ble_svc_ans_new_alert_cat,
+ sizeof ble_svc_ans_new_alert_cat);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+
+ case BLE_SVC_ANS_CHR_UUID16_NEW_ALERT:
+ if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+ rc = ble_svc_ans_chr_write(ctxt->om, 0,
+ sizeof ble_svc_ans_new_alert_val,
+ ble_svc_ans_new_alert_val,
+ &ble_svc_ans_new_alert_val_len);
+ return rc;
+
+ } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
+ rc = os_mbuf_append(ctxt->om, &ble_svc_ans_new_alert_val,
+ sizeof ble_svc_ans_new_alert_val);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+ case BLE_SVC_ANS_CHR_UUID16_SUP_UNR_ALERT_CAT:
+ assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+ rc = os_mbuf_append(ctxt->om, &ble_svc_ans_unr_alert_cat,
+ sizeof ble_svc_ans_unr_alert_cat);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+
+ case BLE_SVC_ANS_CHR_UUID16_UNR_ALERT_STAT:
+ if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+ rc = ble_svc_ans_chr_write(ctxt->om,
+ sizeof ble_svc_ans_unr_alert_stat,
+ sizeof ble_svc_ans_unr_alert_stat,
+ &ble_svc_ans_unr_alert_stat,
+ NULL);
+ return rc;
+ } else {
+ rc = os_mbuf_append(ctxt->om, &ble_svc_ans_unr_alert_stat,
+ sizeof ble_svc_ans_unr_alert_stat);
+ return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+
+ case BLE_SVC_ANS_CHR_UUID16_ALERT_NOT_CTRL_PT:
+ if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
+ rc = ble_svc_ans_chr_write(ctxt->om,
+ sizeof ble_svc_ans_alert_not_ctrl_pt,
+ sizeof ble_svc_ans_alert_not_ctrl_pt,
+ &ble_svc_ans_alert_not_ctrl_pt,
+ NULL);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Get command ID and category ID */
+ cmd_id = ble_svc_ans_alert_not_ctrl_pt[0];
+ cat_id = ble_svc_ans_alert_not_ctrl_pt[1];
+
+
+ /* Set cat_bit_mask to the appropriate bitmask based on cat_id */
+ if (cat_id < BLE_SVC_ANS_CAT_NUM) {
+ cat_bit_mask = (1 << cat_id);
+ } else if (cat_id == 0xff) {
+ cat_bit_mask = cat_id;
+ } else {
+ /* invalid category ID */
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+
+ switch (cmd_id) {
+ case BLE_SVC_ANS_CMD_EN_NEW_ALERT_CAT:
+ ble_svc_ans_new_alert_cat |= cat_bit_mask;
+ break;
+ case BLE_SVC_ANS_CMD_EN_UNR_ALERT_CAT:
+ ble_svc_ans_unr_alert_cat |= cat_bit_mask;
+ break;
+ case BLE_SVC_ANS_CMD_DIS_NEW_ALERT_CAT:
+ ble_svc_ans_new_alert_cat &= ~cat_bit_mask;
+ break;
+ case BLE_SVC_ANS_CMD_DIS_UNR_ALERT_CAT:
+ ble_svc_ans_unr_alert_cat &= ~cat_bit_mask;
+ break;
+ case BLE_SVC_ANS_CMD_NOT_NEW_ALERT_IMMEDIATE:
+ if (cat_id == 0xff) {
+ /* If cat_id is 0xff, notify on all enabled categories */
+ for (i = BLE_SVC_ANS_CAT_NUM - 1; i > 0; --i) {
+ if ((ble_svc_ans_new_alert_cat >> i) & 0x01) {
+ ble_svc_ans_new_alert_notify(i, NULL);
+ }
+ }
+ } else {
+ ble_svc_ans_new_alert_notify(cat_id, NULL);
+ }
+ break;
+ case BLE_SVC_ANS_CMD_NOT_UNR_ALERT_IMMEDIATE:
+ if (cat_id == 0xff) {
+ /* If cat_id is 0xff, notify on all enabled categories */
+ for (i = BLE_SVC_ANS_CAT_NUM - 1; i > 0; --i) {
+ if ((ble_svc_ans_unr_alert_cat >> i) & 0x01) {
+ ble_svc_ans_unr_alert_notify(i);
+ }
+ }
+ } else {
+ ble_svc_ans_unr_alert_notify(cat_id);
+ }
+ break;
+ default:
+ return BLE_SVC_ANS_ERR_CMD_NOT_SUPPORTED;
+ }
+ return 0;
+ } else {
+ rc = BLE_ATT_ERR_UNLIKELY;
+ }
+ return rc;
+
+ default:
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+}
+
+/**
+ * This function must be called with the connection handlewhen a gap
+ * connect event is received in order to send notifications to the
+ * client.
+ *
+ * @params conn_handle The connection handle for the current
+ * connection.
+ */
+void
+ble_svc_ans_on_gap_connect(uint16_t conn_handle)
+{
+ ble_svc_ans_conn_handle = conn_handle;
+}
+
+/**
+ * Adds a new alert to the given category then notifies the client
+ * if the given category is valid and enabled.
+ *
+ * @param cat_flag The id for the category which should
+ * should be incremented and notified
+ * @param info_str The info string to be sent to the client
+ * with the notification.
+ *
+ * @return 0 on success, non-zero error code otherwise.
+ */
+int
+ble_svc_ans_new_alert_add(uint8_t cat_id, const char * info_str)
+{
+ uint8_t cat_bit_mask;
+
+ if (cat_id < BLE_SVC_ANS_CAT_NUM) {
+ cat_bit_mask = (1 << cat_id);
+ } else {
+ return BLE_HS_EINVAL;
+ }
+
+ if ((cat_bit_mask & ble_svc_ans_new_alert_cat) == 0) {
+ return BLE_HS_EINVAL;
+ }
+
+ ble_svc_ans_new_alert_cnt[cat_id] += 1;
+ return ble_svc_ans_new_alert_notify(cat_id, info_str);
+}
+
+/**
+ * Adds an unread alert to the given category then notifies the client
+ * if the given category is valid and enabled.
+ *
+ * @param cat_flag The flag for the category which should
+ * should be incremented and notified
+ *
+ * @return 0 on success, non-zero error code otherwise.
+ */
+int
+ble_svc_ans_unr_alert_add(uint8_t cat_id)
+{
+ uint8_t cat_bit_mask;
+
+ if (cat_id < BLE_SVC_ANS_CAT_NUM) {
+ cat_bit_mask = 1 << cat_id;
+ } else {
+ return BLE_HS_EINVAL;
+ }
+
+ if ((cat_bit_mask & ble_svc_ans_unr_alert_cat) == 0) {
+ return BLE_HS_EINVAL;
+ }
+
+ ble_svc_ans_unr_alert_cnt[cat_id] += 1;
+ return ble_svc_ans_unr_alert_notify(cat_id);
+}
+
+/**
+ * Send a new alert notification to the given category with the
+ * given info string.
+ *
+ * @param cat_id The ID of the category to send the
+ * notification to.
+ * @param info_str The info string to send with the
+ * notification
+ *
+ * @return 0 on success, non-zero error code otherwise.
+ */
+static int
+ble_svc_ans_new_alert_notify(uint8_t cat_id, const char * info_str)
+{
+ int info_str_len;
+
+ /* Clear notification to remove old infomation that may persist */
+ memset(&ble_svc_ans_new_alert_val, '\0',
+ BLE_SVC_ANS_NEW_ALERT_MAX_LEN);
+
+ /* Set ID and count values */
+ ble_svc_ans_new_alert_val[0] = cat_id;
+ ble_svc_ans_new_alert_val[1] = ble_svc_ans_new_alert_cnt[cat_id];
+
+ if (info_str) {
+ info_str_len = strlen(info_str);
+ if (info_str_len > BLE_SVC_ANS_INFO_STR_MAX_LEN) {
+ /* If info_str is longer than the max string length only
+ * write up to the maximum length */
+ memcpy(&ble_svc_ans_new_alert_val[2], info_str,
+ BLE_SVC_ANS_INFO_STR_MAX_LEN);
+ } else {
+ memcpy(&ble_svc_ans_new_alert_val[2], info_str, info_str_len);
+ }
+ }
+ return ble_gattc_notify(ble_svc_ans_conn_handle,
+ ble_svc_ans_new_alert_val_handle);
+}
+
+/**
+ * Send an unread alert notification to the given category.
+ *
+ * @param cat_id The ID of the category to send the
+ * notificaiton to.
+ *
+ * @return 0 on success, non-zer0 error code otherwise.
+ */
+static int
+ble_svc_ans_unr_alert_notify(uint8_t cat_id)
+{
+ ble_svc_ans_unr_alert_stat[0] = cat_id;
+ ble_svc_ans_unr_alert_stat[1] = ble_svc_ans_unr_alert_cnt[cat_id];
+ return ble_gattc_notify(ble_svc_ans_conn_handle,
+ ble_svc_ans_unr_alert_val_handle);
+}
+
+/**
+ * Writes the received value from a characteristic write to
+ * the given destination.
+ */
+static int
+ble_svc_ans_chr_write(struct os_mbuf *om, uint16_t min_len,
+ uint16_t max_len, void *dst,
+ uint16_t *len)
+{
+ uint16_t om_len;
+ int rc;
+
+ om_len = OS_MBUF_PKTLEN(om);
+ if (om_len < min_len || om_len > max_len) {
+ return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+ }
+
+ rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
+ if (rc != 0) {
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+
+ return 0;
+}
+
+/**
+ * Initialize the ANS with initial values for enabled categories
+ * for new and unread alert characteristics. Bitwise or the
+ * catagory bitmasks to enable multiple catagories.
+ *
+ * XXX: We should technically be able to change the new alert and
+ * unread alert catagories when we have no active connections.
+ */
+void
+ble_svc_ans_init(void)
+{
+ int rc;
+
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = ble_gatts_count_cfg(ble_svc_ans_defs);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = ble_gatts_add_svcs(ble_svc_ans_defs);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ ble_svc_ans_new_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_NEW_ALERT_CAT);
+ ble_svc_ans_unr_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_UNR_ALERT_CAT);
+}
diff --git a/src/libs/mynewt-nimble/nimble/host/services/ans/syscfg.yml b/src/libs/mynewt-nimble/nimble/host/services/ans/syscfg.yml
new file mode 100644
index 00000000..74de8d96
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/host/services/ans/syscfg.yml
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+syscfg.defs:
+ BLE_SVC_ANS_NEW_ALERT_CAT:
+ description: "Initial supported new alert category bitmask."
+ value: 0
+
+ BLE_SVC_ANS_UNR_ALERT_CAT:
+ description: "Initial supported unread alert category bitmask."
+ value: 0
+
+ BLE_SVC_ANS_SYSINIT_STAGE:
+ description: >
+ Sysinit stage for the alert notification service.
+ value: 303