Created
July 8, 2024 19:35
-
-
Save ejohnso49/ac6559fee341f4a121b5b1b96e8109bf to your computer and use it in GitHub Desktop.
Zephyr + MDS
This file contains hidden or 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
# | |
# Copyright (c) 2022 Nordic Semiconductor ASA | |
# | |
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | |
# | |
menuconfig BT_MDS | |
bool "Memfault Diagnostic service" | |
depends on !MEMFAULT_HTTP_ENABLE | |
select BT_NRF_SERVICES | |
help | |
Enable GATT Memfault Diagnostic BLE service. | |
if BT_MDS | |
config BT_MDS_MAX_URI_LENGTH | |
int "Maiximum URI length" | |
default 64 | |
help | |
Maximum URI length where diagnostic data should be forwarded to. | |
choice BT_MDS_PERM | |
prompt "Characteristic attributes permition" | |
default BT_MDS_PERM_RW_ENCRYPT if BT_SMP | |
default BT_MDS_PERM_RW | |
help | |
Default permissions for Memfault Diagnostic characteristic attributes. | |
config BT_MDS_PERM_RW | |
bool "Read and write allowed" | |
config BT_MDS_PERM_RW_ENCRYPT | |
bool "Require encryption for access" | |
depends on BT_SMP | |
config BT_MDS_PERM_RW_AUTHEN | |
bool "Require encryption using authenticated link-key for access" | |
depends on BT_SMP | |
endchoice | |
config BT_MDS_PIPELINE_COUNT | |
int "Number of chunks pipelined in the Bluetooth stack" | |
default 2 | |
range 1 BT_CONN_TX_MAX | |
help | |
Number of the Memfault chunks pipelined in the Bluetooth stack. Pipelining chunks in the | |
Bluetooth stack reduces latency related to delivering subsequent data to the stack. | |
config BT_MDS_DATA_POLL_INTERVAL | |
int "Data poll interval" | |
default 60000 | |
help | |
Memfault data poll interval in milliseconds. If there is any memfault data it will | |
be send after each interval expiration. | |
module = BT_MDS | |
module-str = MDS | |
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" | |
endif # BT_MDS | |
# TODO: Remove if already sourced in other Kconfig files | |
source "Kconfig.zephyr" |
This file contains hidden or 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
/* | |
* Copyright (c) 2022 Nordic Semiconductor ASA | |
* | |
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | |
*/ | |
/** @file | |
* @brief Memfault Diagnostic GATT Service (MDS) | |
*/ | |
#include <string.h> | |
#include <zephyr/logging/log.h> | |
#include <zephyr/bluetooth/gatt.h> | |
// TODO: Modify path as necessary | |
#include "mds.h" | |
#include <zephyr/net/buf.h> | |
#include <zephyr/sys/atomic.h> | |
#include <zephyr/sys/__assert.h> | |
#include <memfault/components.h> | |
LOG_MODULE_REGISTER(mds, CONFIG_BT_MDS_LOG_LEVEL); | |
#ifndef CONFIG_BT_MDS_PERM_RW | |
#define CONFIG_BT_MDS_PERM_RW 0 | |
#endif | |
#ifndef CONFIG_BT_MDS_PERM_RW_ENCRYPT | |
#define CONFIG_BT_MDS_PERM_RW_ENCRYPT 0 | |
#endif | |
#ifndef CONFIG_BT_MDS_PERM_RW_AUTHEN | |
#define CONFIG_BT_MDS_PERM_RW_AUTHEN 0 | |
#endif | |
#define MDS_GATT_PERM_READ ( \ | |
CONFIG_BT_MDS_PERM_RW_AUTHEN ? \ | |
BT_GATT_PERM_READ_AUTHEN : (CONFIG_BT_MDS_PERM_RW_ENCRYPT ? \ | |
BT_GATT_PERM_READ_ENCRYPT : BT_GATT_PERM_READ) \ | |
) | |
#define MDS_GATT_PERM_WRITE ( \ | |
CONFIG_BT_MDS_PERM_RW_AUTHEN ? \ | |
BT_GATT_PERM_WRITE_AUTHEN : (CONFIG_BT_MDS_PERM_RW_ENCRYPT ? \ | |
BT_GATT_PERM_WRITE_ENCRYPT : BT_GATT_PERM_WRITE) \ | |
) | |
#define MDS_MAX_URI_LENGTH CONFIG_BT_MDS_MAX_URI_LENGTH | |
#define MDS_URI_BASE \ | |
MEMFAULT_HTTP_APIS_DEFAULT_SCHEME "://" MEMFAULT_HTTP_CHUNKS_API_HOST "/api/v0/chunks/" | |
#define MDS_AUTH_KEY "Memfault-Project-Key:" CONFIG_MEMFAULT_NCS_PROJECT_KEY | |
#define DATA_POLL_INTERVAL CONFIG_BT_MDS_DATA_POLL_INTERVAL | |
/* Memfault chunk number maximum value. Chunk number should overlaps after reaching this value. */ | |
#define MDS_CHUNK_NUMBER_MAX_VALUE BIT_MASK(5) | |
#define MAX_PIPELINE CONFIG_BT_MDS_PIPELINE_COUNT | |
#define STREAM_ENABLED BIT(0) | |
/* Application error code defined by the MDS. | |
* According to BLE Core v5.3 Vol 3, Part F 3.4.1. | |
*/ | |
enum mds_att_error { | |
MDS_ATT_ERROR_CLIENT_ALREADY_SUBSCRIBED = 0x80, | |
MDS_ATT_ERROR_CLIENT_NOT_SUBSCRIBED = 0x81 | |
}; | |
enum data_export_mode { | |
DATA_EXPORT_MODE_STREAMING_DISABLE = 0x00, | |
DATA_EXPORT_MODE_STREAMING_ENABLE = 0x01 | |
}; | |
enum mds_read_char { | |
MDS_READ_CHAR_SUPPORTED_FEATURES, | |
MDS_READ_CHAR_DEVICE_IDENTIFIER, | |
MDS_READ_CHAR_DATA_URI, | |
MDS_READ_CHAR_AUTHORIZATION | |
}; | |
struct mds { | |
const struct bt_mds_cb *cb; | |
struct bt_conn *conn; | |
atomic_t send_cnt; | |
atomic_t stream_state; | |
uint8_t chunk_number; | |
}; | |
struct mds_data_export_nfy { | |
uint8_t chunk_number:5; | |
uint8_t rfu:3; | |
uint8_t data[]; | |
}; | |
struct mds_subscription { | |
bool subscribed; | |
const struct bt_conn *conn; | |
const struct bt_gatt_attr *attr; | |
}; | |
static struct mds mds_instance = { | |
.send_cnt = ATOMIC_INIT(MAX_PIPELINE) | |
}; | |
static void mds_work_handler(struct k_work *work); | |
K_WORK_DELAYABLE_DEFINE(mds_work, mds_work_handler); | |
/* System workqueue thread cannot be preempted to ensure proper service operations. | |
* Make sure here that system workqueue is a cooperative thread. | |
*/ | |
BUILD_ASSERT(CONFIG_SYSTEM_WORKQUEUE_PRIORITY < 0); | |
static ssize_t supported_feature_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, | |
void *buf, uint16_t len, uint16_t offset) | |
{ | |
static const uint8_t supported_features; | |
LOG_DBG("MDS supported feature read, handle: %u, conn: %p", bt_gatt_attr_get_handle(attr), | |
(void *)conn); | |
return bt_gatt_attr_read(conn, attr, buf, len, offset, &supported_features, | |
sizeof(supported_features)); | |
} | |
static ssize_t device_identifier_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, | |
void *buf, uint16_t len, uint16_t offset) | |
{ | |
sMemfaultDeviceInfo info; | |
size_t device_identifier_length; | |
LOG_DBG("MDS Device Identifier characteristic read, handle: %u, conn: %p", | |
bt_gatt_attr_get_handle(attr), (void *)conn); | |
memfault_platform_get_device_info(&info); | |
device_identifier_length = strlen(info.device_serial); | |
return bt_gatt_attr_read(conn, attr, buf, len, offset, info.device_serial, | |
device_identifier_length); | |
} | |
static ssize_t data_uri_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, | |
void *buf, uint16_t len, uint16_t offset) | |
{ | |
sMemfaultDeviceInfo info; | |
char uri[MDS_MAX_URI_LENGTH]; | |
size_t uri_base_length = strlen(MDS_URI_BASE); | |
size_t uri_sn_length; | |
size_t uri_length; | |
LOG_DBG("MDS Data URI characteristic read, handle: %u, conn: %p", | |
bt_gatt_attr_get_handle(attr), (void *)conn); | |
memfault_platform_get_device_info(&info); | |
uri_sn_length = strlen(info.device_serial); | |
uri_length = uri_base_length + uri_sn_length; | |
if (uri_length > sizeof(uri)) { | |
LOG_ERR("Too long URI"); | |
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); | |
} | |
memcpy(uri, MDS_URI_BASE, uri_base_length); | |
memcpy(&uri[uri_base_length], info.device_serial, uri_sn_length); | |
return bt_gatt_attr_read(conn, attr, buf, len, offset, uri, | |
uri_length); | |
} | |
static ssize_t authorization_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, | |
void *buf, uint16_t len, uint16_t offset) | |
{ | |
static const char *auth_key = MDS_AUTH_KEY; | |
size_t auth_key_len = strlen(auth_key); | |
LOG_DBG("MDS Authorization characteristic read, handle: %u, conn: %p", | |
bt_gatt_attr_get_handle(attr), (void *)conn); | |
return bt_gatt_attr_read(conn, attr, buf, len, offset, auth_key, auth_key_len); | |
} | |
static ssize_t mds_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, | |
uint16_t len, uint16_t offset) | |
{ | |
ssize_t ret; | |
enum mds_read_char characteristic = (enum mds_read_char)attr->user_data; | |
if (mds_instance.cb->access_enable) { | |
if (!mds_instance.cb->access_enable(conn)) { | |
return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED); | |
} | |
} | |
switch (characteristic) { | |
case MDS_READ_CHAR_SUPPORTED_FEATURES: | |
ret = supported_feature_read(conn, attr, buf, len, offset); | |
break; | |
case MDS_READ_CHAR_DEVICE_IDENTIFIER: | |
ret = device_identifier_read(conn, attr, buf, len, offset); | |
break; | |
case MDS_READ_CHAR_DATA_URI: | |
ret = data_uri_read(conn, attr, buf, len, offset); | |
break; | |
case MDS_READ_CHAR_AUTHORIZATION: | |
ret = authorization_read(conn, attr, buf, len, offset); | |
break; | |
default: | |
ret = BT_GATT_ERR(BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); | |
break; | |
} | |
return ret; | |
} | |
static void stream_enable(struct bt_conn *conn) | |
{ | |
/* Check if stream is already enabled. */ | |
if (atomic_test_and_set_bit(&mds_instance.stream_state, STREAM_ENABLED)) { | |
return; | |
} | |
if (!mds_instance.conn) { | |
mds_instance.conn = conn; | |
} | |
k_work_schedule(&mds_work, K_NO_WAIT); | |
} | |
static void stream_disable(struct bt_conn *conn) | |
{ | |
atomic_clear_bit(&mds_instance.stream_state, STREAM_ENABLED); | |
/* This context cannot be preempted by the system workqueue so we can cancel workqueue here | |
* without checking a return value. | |
*/ | |
(void)k_work_cancel_delayable(&mds_work); | |
} | |
static bool stream_mode_handler(struct bt_conn *conn, enum data_export_mode stream_mode) | |
{ | |
bool valid = true; | |
switch (stream_mode) { | |
case DATA_EXPORT_MODE_STREAMING_ENABLE: | |
stream_enable(conn); | |
break; | |
case DATA_EXPORT_MODE_STREAMING_DISABLE: | |
stream_disable(conn); | |
break; | |
default: | |
valid = false; | |
break; | |
} | |
return valid; | |
} | |
static ssize_t data_export_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, | |
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) | |
{ | |
enum data_export_mode mode; | |
LOG_DBG("MDS Data Export characteristic write, handle %u, conn: %p", | |
bt_gatt_attr_get_handle(attr), (void *)conn); | |
if (!bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { | |
LOG_DBG("MDS Data Export notification are disabled"); | |
return BT_GATT_ERR(MDS_ATT_ERROR_CLIENT_NOT_SUBSCRIBED); | |
} | |
if (mds_instance.cb->access_enable) { | |
if (!mds_instance.cb->access_enable(conn)) { | |
return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); | |
} | |
} | |
if (offset != 0) { | |
LOG_WRN("MDS Data Export invalid write offset"); | |
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); | |
} | |
if (len != sizeof(uint8_t)) { | |
LOG_WRN("MDS Data Export invalid attribute length"); | |
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); | |
} | |
mode = (enum data_export_mode)(((uint8_t *)buf)[0]); | |
if (!stream_mode_handler(conn, mode)) { | |
LOG_WRN("MDS Data Export characteristic write invalid value"); | |
return BT_GATT_ERR(BT_ATT_ERR_OUT_OF_RANGE); | |
} | |
return len; | |
} | |
static void data_export_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) | |
{ | |
LOG_DBG("MDS Data Export CCCD changed, handle: %u, value: 0x%04X", | |
bt_gatt_attr_get_handle(attr), value); | |
} | |
static void conn_subscription_check(struct bt_conn *conn, void *user_data) | |
{ | |
struct mds_subscription *mds_subscription = user_data; | |
if (bt_gatt_is_subscribed(conn, mds_subscription->attr, BT_GATT_CCC_NOTIFY)) { | |
mds_subscription->conn = conn; | |
mds_subscription->subscribed = true; | |
} | |
} | |
static ssize_t data_export_ccc_write(struct bt_conn *conn, | |
const struct bt_gatt_attr *attr, uint16_t value) | |
{ | |
struct mds_subscription mds_subscription = { | |
.attr = attr | |
}; | |
if ((value != BT_GATT_CCC_NOTIFY) && (value != 0)) { | |
return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); | |
} | |
/* Allow only one subscription to the Memfault Data Export characteristic. */ | |
bt_conn_foreach(BT_CONN_TYPE_LE, conn_subscription_check, &mds_subscription); | |
if (mds_subscription.subscribed && (mds_subscription.conn != conn)) { | |
LOG_WRN("Memfault Data Export characteristic is already subscribed"); | |
return BT_GATT_ERR(MDS_ATT_ERROR_CLIENT_ALREADY_SUBSCRIBED); | |
} | |
if (mds_instance.cb->access_enable) { | |
if (!mds_instance.cb->access_enable(conn)) { | |
return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); | |
} | |
} | |
if ((value == 0) && (conn == mds_instance.conn)) { | |
stream_disable(conn); | |
} | |
return sizeof(value); | |
} | |
static struct _bt_gatt_ccc mds_data_export_ccc = BT_GATT_CCC_INITIALIZER(data_export_ccc_changed, | |
data_export_ccc_write, | |
NULL); | |
BT_GATT_SERVICE_DEFINE(mds_svc, | |
BT_GATT_PRIMARY_SERVICE(BT_UUID_MEMFAULT_DIAG), | |
BT_GATT_CHARACTERISTIC(BT_UUID_MDS_SUPPORTED_FEATURES, BT_GATT_CHRC_READ, | |
MDS_GATT_PERM_READ, mds_read, NULL, | |
(void *)MDS_READ_CHAR_SUPPORTED_FEATURES), | |
BT_GATT_CHARACTERISTIC(BT_UUID_MDS_DEVICE_IDENTIFIER, BT_GATT_CHRC_READ, | |
MDS_GATT_PERM_READ, mds_read, NULL, | |
(void *)MDS_READ_CHAR_DEVICE_IDENTIFIER), | |
BT_GATT_CHARACTERISTIC(BT_UUID_MDS_DATA_URI, BT_GATT_CHRC_READ, | |
MDS_GATT_PERM_READ, mds_read, NULL, (void *)MDS_READ_CHAR_DATA_URI), | |
BT_GATT_CHARACTERISTIC(BT_UUID_MDS_AUTHORIZATION, BT_GATT_CHRC_READ, | |
MDS_GATT_PERM_READ, mds_read, NULL, | |
(void *)MDS_READ_CHAR_AUTHORIZATION), | |
BT_GATT_CHARACTERISTIC(BT_UUID_MDS_DATA_EXPORT, BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE, | |
MDS_GATT_PERM_WRITE, NULL, data_export_write, | |
NULL), | |
BT_GATT_CCC_MANAGED(&mds_data_export_ccc, (MDS_GATT_PERM_READ | MDS_GATT_PERM_WRITE)) | |
); | |
static void disconnected(struct bt_conn *conn, uint8_t reason) | |
{ | |
if (conn == mds_instance.conn) { | |
stream_disable(conn); | |
/* Clean up connection */ | |
mds_instance.conn = NULL; | |
mds_instance.chunk_number = 0; | |
atomic_set(&mds_instance.send_cnt, MAX_PIPELINE); | |
/* It is called from a workqueue context, so checking the error codes is no needed, | |
* here. | |
*/ | |
k_work_cancel_delayable(&mds_work); | |
} | |
} | |
BT_CONN_CB_DEFINE(conn_callbacks) = { | |
.disconnected = disconnected, | |
}; | |
static void mds_sent_cb(struct bt_conn *conn, void *user_data) | |
{ | |
atomic_inc(&mds_instance.send_cnt); | |
k_work_reschedule(&mds_work, K_NO_WAIT); | |
} | |
static size_t chunk_data_length_get(struct bt_conn *conn) | |
{ | |
static const size_t att_header_length = 0x03; | |
size_t length; | |
if (!conn) { | |
return 0; | |
} | |
length = bt_gatt_get_mtu(conn); | |
if (length < (att_header_length + sizeof(struct mds_data_export_nfy))) { | |
LOG_ERR("MTU value too low: %d or link is disconnected", length); | |
return 0; | |
} | |
/* According to BLE Core v5.3 Vol 3, Part F 3.4.7.1 maximum supported length of the | |
* notification is (ATT_MTU - 3). | |
*/ | |
length -= att_header_length; | |
length -= sizeof(struct mds_data_export_nfy); | |
return length; | |
} | |
static int chunk_send(struct bt_conn *conn, struct net_buf_simple *buf) | |
{ | |
struct bt_gatt_notify_params params = {0}; | |
static struct bt_gatt_attr *attr; | |
__ASSERT(conn, "Invalid parameters"); | |
__ASSERT(buf, "Invalid parameters"); | |
if (!attr) { | |
attr = bt_gatt_find_by_uuid(mds_svc.attrs, mds_svc.attr_count, | |
BT_UUID_MDS_DATA_EXPORT); | |
} | |
__ASSERT_NO_MSG(attr); | |
params.attr = attr; | |
params.data = buf->data; | |
params.len = buf->len; | |
params.func = mds_sent_cb; | |
return bt_gatt_notify_cb(conn, ¶ms); | |
} | |
static uint8_t chunk_number_update(uint8_t chunk_number) | |
{ | |
return ++chunk_number & MDS_CHUNK_NUMBER_MAX_VALUE; | |
} | |
static int mds_data_send(struct bt_conn *conn) | |
{ | |
int err; | |
bool data_available; | |
struct mds_data_export_nfy *data_export_nfy; | |
size_t chunk_max_size = chunk_data_length_get(mds_instance.conn); | |
size_t chunk_size = chunk_max_size; | |
NET_BUF_SIMPLE_DEFINE(buf, (sizeof(struct mds_data_export_nfy) + chunk_max_size)); | |
data_export_nfy = net_buf_simple_add(&buf, | |
sizeof(struct mds_data_export_nfy) + chunk_max_size); | |
if (!data_export_nfy) { | |
LOG_ERR("Cannot allocate place for memfault chunk data"); | |
return -ENOMEM; | |
} | |
data_available = memfault_packetizer_get_chunk(data_export_nfy->data, &chunk_size); | |
if (data_available) { | |
data_export_nfy->chunk_number = mds_instance.chunk_number; | |
data_export_nfy->rfu = 0; | |
/* If chunk size is smaller than maximum chunk size then shrink the buffer to actual | |
* packet size. | |
*/ | |
(void)net_buf_simple_remove_mem(&buf, (chunk_max_size - chunk_size)); | |
err = chunk_send(conn, &buf); | |
if (err) { | |
memfault_packetizer_abort(); | |
LOG_WRN("Failed to send Memfault diagnostic chunk, err %d", err); | |
return err; | |
} | |
LOG_DBG("Memfault diagnostic data chunk %d successfully sent", | |
mds_instance.chunk_number); | |
mds_instance.chunk_number = chunk_number_update(mds_instance.chunk_number); | |
return chunk_size; | |
} | |
return 0; | |
} | |
static void mds_work_handler(struct k_work *work) | |
{ | |
int err; | |
bool data_available; | |
if (!atomic_test_bit(&mds_instance.stream_state, STREAM_ENABLED)) { | |
return; | |
} | |
err = mds_data_send(mds_instance.conn); | |
if (err > 0) { | |
atomic_dec(&mds_instance.send_cnt); | |
} | |
data_available = memfault_packetizer_data_available(); | |
if (data_available) { | |
if (atomic_get(&mds_instance.send_cnt)) { | |
k_work_reschedule(&mds_work, K_NO_WAIT); | |
} | |
return; | |
} | |
/* Reschedule the workqueue here to check if there is any new Memfault data. */ | |
k_work_reschedule(&mds_work, K_MSEC(DATA_POLL_INTERVAL)); | |
} | |
int bt_mds_cb_register(const struct bt_mds_cb *cb) | |
{ | |
if (mds_instance.cb) { | |
return -EALREADY; | |
} | |
mds_instance.cb = cb; | |
return 0; | |
} |
This file contains hidden or 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
/* | |
* Copyright (c) 2022 Nordic Semiconductor ASA | |
* | |
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause | |
*/ | |
#ifndef MDS_H_ | |
#define MDS_H_ | |
#include <zephyr/bluetooth/conn.h> | |
#include <zephyr/bluetooth/uuid.h> | |
/**@file | |
* @defgroup bt_mds Memfault Diagnostic GATT service API | |
* @{ | |
* @brief API for the Memfault Diagnostic GATT service (MDS). | |
*/ | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
/** @brief UUID of the Memfault Diagnostic Service. */ | |
#define BT_UUID_MDS_VAL \ | |
BT_UUID_128_ENCODE(0x54220000, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
/** @brief UUID of the MDS Supported Features Characteristic. */ | |
#define BT_UUID_MDS_SUPPORTED_FEATURES_VAL \ | |
BT_UUID_128_ENCODE(0x54220001, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
/** @brief UUID of the MDS Device Identifier Characteristic. */ | |
#define BT_UUID_MDS_DEVICE_IDENTIFIER_VAL \ | |
BT_UUID_128_ENCODE(0x54220002, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
/** @brief UUID of the MDS Data URI Characteristic. */ | |
#define BT_UUID_MDS_DATA_URI_VAL \ | |
BT_UUID_128_ENCODE(0x54220003, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
/** @brief UUID of the MDS Authorization Characteristic. */ | |
#define BT_UUID_MDS_AUTHORIZATION_VAL \ | |
BT_UUID_128_ENCODE(0x54220004, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
/** @brief UUID of the MDS Data Export Characteristic. */ | |
#define BT_UUID_MDS_DATA_EXPORT_VAL \ | |
BT_UUID_128_ENCODE(0x54220005, 0xf6a5, 0x4007, 0xa371, 0x722f4ebd8436) | |
#define BT_UUID_MEMFAULT_DIAG BT_UUID_DECLARE_128(BT_UUID_MDS_VAL) | |
#define BT_UUID_MDS_SUPPORTED_FEATURES BT_UUID_DECLARE_128(BT_UUID_MDS_SUPPORTED_FEATURES_VAL) | |
#define BT_UUID_MDS_DEVICE_IDENTIFIER BT_UUID_DECLARE_128(BT_UUID_MDS_DEVICE_IDENTIFIER_VAL) | |
#define BT_UUID_MDS_DATA_URI BT_UUID_DECLARE_128(BT_UUID_MDS_DATA_URI_VAL) | |
#define BT_UUID_MDS_AUTHORIZATION BT_UUID_DECLARE_128(BT_UUID_MDS_AUTHORIZATION_VAL) | |
#define BT_UUID_MDS_DATA_EXPORT BT_UUID_DECLARE_128(BT_UUID_MDS_DATA_EXPORT_VAL) | |
/** @brief Memfault Diagnostic Service callback structure. | |
*/ | |
struct bt_mds_cb { | |
/** @brief A callback for enabling Memfault access. | |
* | |
* If this callback is not implemented, any connected peer can access the Memfault | |
* characteristics and descriptors data, including write access to them, without | |
* authentication. | |
* | |
* The Memfault Diagnostic service allows only one client subscription. | |
* | |
* @param[in] conn Connection object. | |
* | |
* @retval True if peer associated with connection object has granted access to | |
* the Memfault data. | |
* False if access to the Memfault data is forbidden. | |
*/ | |
bool (*access_enable)(struct bt_conn *conn); | |
}; | |
/** @brief Register the Memfault Diagnostic service callback. | |
* | |
* This function should be called before enabling Bluetooth stack to ensure proper access grating | |
* to MDS characteristics data through @p access_enable callback. | |
* | |
* @param[in] cb Memfault callback structure. This parameter can be set to NULL but it will let the | |
* first connected client access the Memfault data without authentication. | |
* | |
* @retval 0 If the operation was successful. | |
* Otherwise, a negative error code is returned | |
*/ | |
int bt_mds_cb_register(const struct bt_mds_cb *cb); | |
#ifdef __cplusplus | |
} | |
#endif | |
/** | |
*@} | |
*/ | |
#endif /* MDS_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment