first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
@@ -0,0 +1,220 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#include "config.h"
#include "ancs_client.h"
#include "ancs_client_internal.h"
#include "ancs_app_attr_get.h"
#ifdef CONFIG_ANCS_APP_ATTR_GET_DBG
#define LOG_DBG PRINT
#else
#define LOG_DBG
#endif
struct buf_simple {
/** Pointer to the start of data in the buffer. */
uint8_t *data;
/**
* Length of the data behind the data pointer.
*
* #size not determine the max length!
*/
uint16_t len;
/** Amount of data that buf_simple#__buf can store. */
uint16_t size;
/** Start of the data storage. Not to be accessed directly
* (the data pointer should be used instead).
*/
uint8_t *__buf;
};
/**@brief Enumeration for keeping track of the state-based encoding while requesting
* app attributes.
*/
enum encode_app_attr {
/** Currently encoding the command ID. */
APP_ATTR_COMMAND_ID,
/** Currently encoding the app ID. */
APP_ATTR_APP_ID,
/** Currently encoding the attribute ID. */
APP_ATTR_ATTR_ID,
/** Encoding done. */
APP_ATTR_DONE,
/** Encoding aborted. */
APP_ATTR_ABORT
};
/**@brief Function for determining whether an attribute is requested.
*
* @param[in] ancs_c iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
*
* @return True If it is requested
* @return False If it is not requested.
*/
static bool app_attr_is_requested(struct bt_ancs_client *ancs_c,
uint32_t attr_id)
{
return ancs_c->ancs_app_attr_list[attr_id].get;
}
/**@brief Function for encoding the command ID as part of assembling a "get app attributes" command.
*
* @param[in,out] buf Pointer to the BLE GATT write buffer structure.
*/
static enum encode_app_attr app_attr_encode_cmd_id(struct buf_simple *buf)
{
LOG_DBG("Encoding command ID.");
size_t tailroom = buf->size - (buf->data - buf->__buf) - buf->len;
if(tailroom < 1) {
return APP_ATTR_ABORT;
}
/* Encode Command ID. */
*(buf->data + buf->len) = BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
buf->len += 1;
return APP_ATTR_APP_ID;
}
/**@brief Function for encoding the app ID as part of assembling a "get app attributes" command.
*
* @param[in,out] buf Pointer to the BLE GATT write buffer structure.
* @param[in] app_id The app ID of the app for which to request app attributes.
* @param[in] app_id_len Length of the app ID.
*/
static enum encode_app_attr app_attr_encode_app_id(struct buf_simple *buf,
const uint8_t *app_id,
const uint32_t app_id_len)
{
LOG_DBG("Encoding app ID.");
size_t tailroom = buf->size - (buf->data - buf->__buf) - buf->len;
if (tailroom < app_id_len + 1) {
return APP_ATTR_ABORT;
}
/* Encode app identifier. */
tmos_memcpy((buf->data + buf->len), app_id, app_id_len);
buf->len += app_id_len;
*(buf->data + buf->len) = '\0';
buf->len += 1;
return APP_ATTR_ATTR_ID;
}
/**@brief Function for encoding the attribute ID as part of assembling a
* "get app attributes" command.
*
* @param[in] ancs_c iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
* @param[in,out] buf Pointer to the BLE GATT write buffer structure.
*/
static enum encode_app_attr app_attr_encode_attr_id(
struct bt_ancs_client *ancs_c, struct buf_simple *buf)
{
uint32_t i;
LOG_DBG("Encoding attribute ID.");
ancs_c->number_of_requested_attr = 0;
/* Encode Attribute ID. */
for (i = 0; i < BT_ANCS_APP_ATTR_COUNT; i++) {
if (app_attr_is_requested(ancs_c, i)) {
size_t tailroom = buf->size - (buf->data - buf->__buf) - buf->len;
if (tailroom < 1) {
return APP_ATTR_ABORT;
}
*(buf->data + buf->len) = i;
buf->len += 1;
ancs_c->number_of_requested_attr++;
}
}
return APP_ATTR_DONE;
}
/**@brief Function for sending a "get app attributes" request.
*
* @details Since the app ID may not fit in a single write, long write
* with a state machine is used to encode the "get app attributes" request.
*
* @param[in] ancs_c iOS notification structure. This structure must be supplied by
* the application. It identifies the particular client instance to use.
* @param[in] app_id The app ID of the app for which to request app attributes.
* @param[in] app_id_len Length of the app ID.
*/
static int app_attr_get(struct bt_ancs_client *ancs_c, const uint8_t *app_id,
uint32_t app_id_len, bt_ancs_write_cb func)
{
enum encode_app_attr state = APP_ATTR_COMMAND_ID;
int err;
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING)) {
return -EBUSY;
}
struct buf_simple buf;
buf.__buf = ancs_c->cp_data;
buf.len = 0U;
buf.size = sizeof(ancs_c->cp_data);
while (state != APP_ATTR_DONE && state != APP_ATTR_ABORT) {
switch (state) {
case APP_ATTR_COMMAND_ID:
state = app_attr_encode_cmd_id(&buf);
break;
case APP_ATTR_APP_ID:
state = app_attr_encode_app_id(&buf,
app_id, app_id_len);
break;
case APP_ATTR_ATTR_ID:
state = app_attr_encode_attr_id(ancs_c, &buf);
break;
case APP_ATTR_DONE:
break;
case APP_ATTR_ABORT:
break;
default:
break;
}
}
if (state == APP_ATTR_DONE) {
bt_ancs_cp_write(ancs_c, buf.len, func);
ancs_c->parse_info.expected_number_of_attrs =
ancs_c->number_of_requested_attr;
} else {
err = -ENOMEM;
}
return err;
}
int bt_ancs_app_attr_request(struct bt_ancs_client *ancs_c,
const uint8_t *app_id, uint32_t len,
bt_ancs_write_cb func)
{
if (!len) {
return -EINVAL;
}
ancs_c->parse_info.parse_state = BT_ANCS_PARSE_STATE_COMMAND_ID;
return app_attr_get(ancs_c, app_id, len, func);
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#ifndef BT_ANCS_APP_ATTR_GET_H__
#define BT_ANCS_APP_ATTR_GET_H__
/** @file
*
* @addtogroup bt_ancs_client
* @{
*/
#include "ancs_client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function for requesting attributes for an app.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] app_id App identifier of the app for which to request app attributes.
* @param[in] len Length of the app identifier.
* @param[in] func Callback function for handling NP write response.
*
* @retval 0 If all operations were successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_app_attr_request(struct bt_ancs_client *ancs_c,
const uint8_t *app_id, uint32_t len,
bt_ancs_write_cb func);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* BT_ANCS_APP_ATTR_GET_H__ */
@@ -0,0 +1,366 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#include <sys/byteorder.h>
#include "ancs_client.h"
#include "ancs_client_internal.h"
#include "ancs_attr_parser.h"
#include "config.h"
#ifdef CONFIG_ANCS_ATTR_PARSER_DBG
#define LOG_DBG PRINT
#else
#define LOG_DBG
#endif
static bool all_req_attrs_parsed(struct bt_ancs_client *ancs_c)
{
return !ancs_c->parse_info.expected_number_of_attrs;
}
static bool attr_is_requested(struct bt_ancs_client *ancs_c,
struct bt_ancs_attr attr)
{
return ancs_c->parse_info.attr_list[attr.attr_id].get;
}
/**@brief Function for parsing command id and notification id.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details UID and command ID will be received only once at the beginning of the first
* GATT notification of a new attribute request for a given iOS notification.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] index Pointer to an index that helps us keep track of the current data
* to be parsed.
*
* @return The next parse state.
*/
static enum bt_ancs_parse_state command_id_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
enum bt_ancs_parse_state parse_state;
ancs_c->parse_info.command_id =
(enum bt_ancs_cmd_id_val)data_src[(*index)++];
switch (ancs_c->parse_info.command_id) {
case BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
ancs_c->attr_response.command_id = BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
ancs_c->parse_info.attr_list = ancs_c->ancs_notif_attr_list;
ancs_c->parse_info.attr_count = BT_ANCS_NOTIF_ATTR_COUNT;
parse_state = BT_ANCS_PARSE_STATE_NOTIF_UID;
break;
case BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
ancs_c->attr_response.command_id = BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
ancs_c->parse_info.attr_list = ancs_c->ancs_app_attr_list;
ancs_c->parse_info.attr_count = BT_ANCS_APP_ATTR_COUNT;
ancs_c->parse_info.current_app_id_index = 0;
parse_state = BT_ANCS_PARSE_STATE_APP_ID;
break;
default:
/* no valid command_id, abort the rest of the parsing procedure. */
LOG_DBG("Invalid Command ID\n");
parse_state = BT_ANCS_PARSE_STATE_DONE;
break;
}
return parse_state;
}
static enum bt_ancs_parse_state notif_uid_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
ancs_c->attr_response.notif_uid = sys_get_le32(&data_src[*index]);
*index += sizeof(uint32_t);
return BT_ANCS_PARSE_STATE_ATTR_ID;
}
static enum bt_ancs_parse_state app_id_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
if (ancs_c->parse_info.current_app_id_index >= sizeof(ancs_c->attr_response.app_id)) {
LOG_DBG("App ID cannot be stored in response buffer.\n");
return BT_ANCS_PARSE_STATE_DONE;
}
ancs_c->attr_response.app_id[ancs_c->parse_info.current_app_id_index] =
data_src[(*index)++];
if (ancs_c->attr_response.app_id[ancs_c->parse_info.current_app_id_index] !=
'\0') {
ancs_c->parse_info.current_app_id_index++;
return BT_ANCS_PARSE_STATE_APP_ID;
} else {
return BT_ANCS_PARSE_STATE_ATTR_ID;
}
}
/**@brief Function for parsing the id of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details We only request attributes that are registered with @ref bt_ancs_attr_add
* once they have been reveiced we stop parsing.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] index Pointer to an index that helps us keep track of the current data
* to be parsed.
*
* @return The next parse state.
*/
static enum bt_ancs_parse_state attr_id_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
ancs_c->attr_response.attr.attr_id = data_src[(*index)++];
if (ancs_c->attr_response.attr.attr_id >= ancs_c->parse_info.attr_count) {
LOG_DBG("Attribute ID Invalid.\n");
return BT_ANCS_PARSE_STATE_DONE;
}
ancs_c->attr_response.attr.attr_data =
ancs_c->parse_info.attr_list[ancs_c->attr_response.attr.attr_id]
.attr_data;
if (all_req_attrs_parsed(ancs_c)) {
LOG_DBG("All requested attributes received. \n");
return BT_ANCS_PARSE_STATE_DONE;
}
if (attr_is_requested(ancs_c, ancs_c->attr_response.attr)) {
ancs_c->parse_info.expected_number_of_attrs--;
}
LOG_DBG("Attribute ID %i \n", ancs_c->attr_response.attr.attr_id);
return BT_ANCS_PARSE_STATE_ATTR_LEN1;
}
/**@brief Function for parsing the length of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details The Length is 2 bytes. Since there is a chance we reveice the bytes in two different
* GATT notifications, we parse only the first byte here and then set the state machine
* ready to parse the next byte.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] index Pointer to an index that helps us keep track of the current data
* to be parsed.
*
* @return The next parse state.
*/
static enum bt_ancs_parse_state attr_len1_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
ancs_c->attr_response.attr.attr_len = data_src[(*index)++];
return BT_ANCS_PARSE_STATE_ATTR_LEN2;
}
/**@brief Function for parsing the length of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details Second byte of the length field. If the length is zero, it means that the attribute
* is not present and the state machine is set to parse the next attribute.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] index Pointer to an index that helps us keep track of the current data
* to be parsed.
*
* @return The next parse state.
*/
static enum bt_ancs_parse_state attr_len2_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
ancs_c->attr_response.attr.attr_len |= (data_src[(*index)++] << 8);
ancs_c->parse_info.current_attr_index = 0;
if (ancs_c->attr_response.attr.attr_len != 0) {
/* If the attribute has a length but there is no allocated
* space for this attribute
*/
if (!ancs_c->parse_info.attr_list[ancs_c->attr_response.attr.attr_id].attr_len ||
!ancs_c->parse_info.attr_list[ancs_c->attr_response.attr.attr_id].attr_data) {
return BT_ANCS_PARSE_STATE_ATTR_SKIP;
} else {
return BT_ANCS_PARSE_STATE_ATTR_DATA;
}
} else {
LOG_DBG("Attribute LEN %i \n", ancs_c->attr_response.attr.attr_len);
if (attr_is_requested(ancs_c, ancs_c->attr_response.attr)) {
bt_ancs_do_ds_notif_cb(ancs_c, &ancs_c->attr_response);
}
if (all_req_attrs_parsed(ancs_c)) {
return BT_ANCS_PARSE_STATE_DONE;
} else {
return BT_ANCS_PARSE_STATE_ATTR_ID;
}
}
}
/**@brief Function for parsing the data of an iOS attribute.
* Used in the @ref parse_get_notif_attrs_response state machine.
*
* @details Read the data of the attribute into our local buffer.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] index Pointer to an index that helps us keep track of the current data
* to be parsed.
*
* @return The next parse state.
*/
static enum bt_ancs_parse_state attr_data_parse(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
/* We have not reached the end of the attribute, nor our max allocated internal size.
* Proceed with copying data over to our buffer.
*/
if ((ancs_c->parse_info.current_attr_index <
ancs_c->parse_info.attr_list[ancs_c->attr_response.attr.attr_id].attr_len) &&
(ancs_c->parse_info.current_attr_index <
ancs_c->attr_response.attr.attr_len)) {
/* Un-comment this line to see every byte of an attribute as it is parsed.
* Commented out by default since it can overflow the uart buffer.
*/
/* LOG_DBG("Byte copied to buffer: %c\n", data_src[(*index)]); */
ancs_c->attr_response.attr
.attr_data[ancs_c->parse_info.current_attr_index++] =
data_src[(*index)++];
}
/* We have reached the end of the attribute, or our max allocated internal size.
* Stop copying data over to our buffer. NUL-terminate at the current index.
*/
if ((ancs_c->parse_info.current_attr_index ==
ancs_c->attr_response.attr.attr_len) ||
(ancs_c->parse_info.current_attr_index ==
ancs_c->parse_info.attr_list[ancs_c->attr_response.attr.attr_id].attr_len -
1)) {
if (attr_is_requested(ancs_c, ancs_c->attr_response.attr)) {
ancs_c->attr_response.attr.attr_data
[ancs_c->parse_info.current_attr_index] = '\0';
}
/* If our max buffer size is smaller than the remaining attribute data, we must
* increase index to skip the data until the start of the next attribute.
*/
if (ancs_c->parse_info.current_attr_index <
ancs_c->attr_response.attr.attr_len) {
return BT_ANCS_PARSE_STATE_ATTR_SKIP;
}
LOG_DBG("Attribute finished!\n");
if (attr_is_requested(ancs_c, ancs_c->attr_response.attr)) {
bt_ancs_do_ds_notif_cb(ancs_c, &ancs_c->attr_response);
}
if (all_req_attrs_parsed(ancs_c)) {
return BT_ANCS_PARSE_STATE_DONE;
} else {
return BT_ANCS_PARSE_STATE_ATTR_ID;
}
}
return BT_ANCS_PARSE_STATE_ATTR_DATA;
}
static enum bt_ancs_parse_state attr_skip(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
uint32_t *index)
{
/* We have not reached the end of the attribute, nor our max allocated internal size.
* Proceed with copying data over to our buffer.
*/
if (ancs_c->parse_info.current_attr_index < ancs_c->attr_response.attr.attr_len) {
ancs_c->parse_info.current_attr_index++;
(*index)++;
}
/* At the end of the attribute, determine if it should be passed to event handler and
* continue parsing the next attribute ID if we are not done with all the attributes.
*/
if (ancs_c->parse_info.current_attr_index ==
ancs_c->attr_response.attr.attr_len) {
if (attr_is_requested(ancs_c, ancs_c->attr_response.attr)) {
bt_ancs_do_ds_notif_cb(ancs_c, &ancs_c->attr_response);
}
if (all_req_attrs_parsed(ancs_c)) {
return BT_ANCS_PARSE_STATE_DONE;
} else {
return BT_ANCS_PARSE_STATE_ATTR_ID;
}
}
return BT_ANCS_PARSE_STATE_ATTR_SKIP;
}
void bt_ancs_parse_get_attrs_response(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
const uint16_t data_len)
{
uint32_t index;
for (index = 0; index < data_len;) {
switch (ancs_c->parse_info.parse_state) {
case BT_ANCS_PARSE_STATE_COMMAND_ID:
ancs_c->parse_info.parse_state =
command_id_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_NOTIF_UID:
ancs_c->parse_info.parse_state =
notif_uid_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_APP_ID:
ancs_c->parse_info.parse_state =
app_id_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_ATTR_ID:
ancs_c->parse_info.parse_state =
attr_id_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_ATTR_LEN1:
ancs_c->parse_info.parse_state =
attr_len1_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_ATTR_LEN2:
ancs_c->parse_info.parse_state =
attr_len2_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_ATTR_DATA:
ancs_c->parse_info.parse_state =
attr_data_parse(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_ATTR_SKIP:
ancs_c->parse_info.parse_state =
attr_skip(ancs_c, data_src, &index);
break;
case BT_ANCS_PARSE_STATE_DONE:
LOG_DBG("Parse state: Done \n");
index = data_len;
break;
default:
/* Default case will never trigger intentionally.
* Go to the DONE state to minimize the consequences.
*/
ancs_c->parse_info.parse_state = BT_ANCS_PARSE_STATE_DONE;
break;
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#ifndef BT_ANCS_ATTR_PARSER_H__
#define BT_ANCS_ATTR_PARSER_H__
/** @file
*
* @addtogroup bt_ancs_client
* @{
*/
#include "ancs_client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function for parsing notification or app attribute response data.
*
* @details The data that comes from the Notification Provider can be much longer than what
* would fit in a single GATT notification. Therefore, this function relies on a
* state-oriented switch case.
* UID and command ID will be received only once at the beginning of the first
* GATT notification of a new attribute request for a given iOS notification.
* After this, we can loop several ATTR_ID > LENGTH > DATA > ATTR_ID > LENGTH > DATA until
* we have received all attributes we wanted as a Notification Consumer.
* The Notification Provider can also simply stop sending attributes.
*
* 1 byte | 4 bytes |1 byte |2 bytes |... X bytes ... |1 bytes| 2 bytes| ... X bytes ...
* --------|-------------|-------|--------|----------------|-------|--------|----------------
* CMD_ID | NOTIF_UID |ATTR_ID| LENGTH | DATA |ATTR_ID| LENGTH | DATA
*
* @param[in] ancs_c ANCS client instance to which the event belongs.
* @param[in] data_src Pointer to data that was received from the Notification Provider.
* @param[in] data_len Length of the data that was received from the Notification Provider.
*/
void bt_ancs_parse_get_attrs_response(struct bt_ancs_client *ancs_c,
const uint8_t *data_src,
const uint16_t data_len);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* BT_ANCS_ATTR_PARSER_H__ */
@@ -0,0 +1,545 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
/*********************************************************************
* INCLUDES
*/
#include <stdlib.h>
#include <sys/byteorder.h>
#include "string.h"
#include "config.h"
#include "ancs.h"
#include "ancs_client.h"
#include "ancs_client_internal.h"
#include "ancs_attr_parser.h"
#include "ancs_app_attr_get.h"
/*********************************************************************
* MACROS
*/
/**< Index of the Event ID field when parsing notifications. */
#define BT_ANCS_NOTIF_EVT_ID_INDEX 0
/**< Index of the Flags field when parsing notifications. */
#define BT_ANCS_NOTIF_FLAGS_INDEX 1
/**< Index of the Category ID field when parsing notifications. */
#define BT_ANCS_NOTIF_CATEGORY_ID_INDEX 2
/**< Index of the Category Count field when parsing notifications. */
#define BT_ANCS_NOTIF_CATEGORY_CNT_INDEX 3
/**< Index of the Notification UID field when parsing notifications. */
#define BT_ANCS_NOTIF_NOTIF_UID 4
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
/*********************************************************************
* LOCAL FUNCTIONS
*/
/**@brief Function for checking whether the data in an iOS notification is out of bounds.
*
* @param[in] notif An iOS notification.
*
* @retval 0 If the notification is within bounds.
* @retval -1 If the notification is out of bounds.
*/
static int bt_ancs_verify_notification_format(const struct bt_ancs_evt_notif *notif)
{
if ((notif->evt_id >= BT_ANCS_EVT_ID_COUNT) ||
(notif->category_id >= BT_ANCS_CATEGORY_ID_COUNT)) {
return -1;
}
return 0;
}
/**@brief Function for receiving and validating notifications received from
* the Notification Provider.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to the data that was received from the Notification Provider.
* @param[in] len Length of the data that was received from the Notification Provider.
*/
static void parse_notif(struct bt_ancs_client *ancs_c,
const uint8_t *data_src, const uint16_t len)
{
int err;
struct bt_ancs_evt_notif notif;
if (len != BT_ANCS_NOTIF_DATA_LENGTH) {
bt_ancs_do_ns_notif_cb(ancs_c, -EINVAL, &notif);
return;
}
notif.evt_id = (enum bt_ancs_evt_id_values)
data_src[BT_ANCS_NOTIF_EVT_ID_INDEX];
notif.evt_flags.silent =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_SILENT) &
0x01;
notif.evt_flags.important =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_IMPORTANT) &
0x01;
notif.evt_flags.pre_existing =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_PREEXISTING) &
0x01;
notif.evt_flags.positive_action =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_POSITIVE_ACTION) &
0x01;
notif.evt_flags.negative_action =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_NEGATIVE_ACTION) &
0x01;
notif.category_id = (enum bt_ancs_category_id_val)
data_src[BT_ANCS_NOTIF_CATEGORY_ID_INDEX];
notif.category_count =
data_src[BT_ANCS_NOTIF_CATEGORY_CNT_INDEX];
notif.notif_uid =
sys_get_le32(&data_src[BT_ANCS_NOTIF_NOTIF_UID]);
err = bt_ancs_verify_notification_format(&notif);
bt_ancs_do_ns_notif_cb(ancs_c, err, &notif);
}
int bt_ancs_client_init(struct bt_ancs_client *ancs_c)
{
if (!ancs_c) {
return -EINVAL;
}
memset(ancs_c, 0, sizeof(struct bt_ancs_client));
return 0;
}
void ancs_reinit(struct bt_ancs_client *ancs_c)
{
ancs_c->conn = 0;
ancs_c->handle_cp = 0;
ancs_c->handle_ns = 0;
ancs_c->handle_ns_ccc = 0;
ancs_c->handle_ds = 0;
ancs_c->handle_ds_ccc = 0;
ancs_c->state = 0;
}
int bt_ancs_subscribe_notification_source(struct bt_ancs_client *ancs_c,
bt_ancs_ns_notif_cb func)
{
int err;
if (!ancs_c || !func) {
return -EINVAL;
}
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED)) {
return -EALREADY;
}
ancs_c->ns_notif_cb = func;
ancs_c->ns_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ns_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ns_notif_params.len = 2;
ancs_c->ns_notif_params.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ns_notif_params.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ns_notif_params.handle = ancs_c->handle_ns_ccc;
ancs_c->ns_notif_params.cmd = 0;
ancs_c->ns_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ns_notif_params, ancs_taskid);
if (err) {
atomic_clear_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED);
GATT_bm_free((gattMsg_t *)&ancs_c->ns_notif_params, ATT_WRITE_REQ);
PRINT("Subscribe Notification Source failed (err %d)\n", err);
} else {
PRINT("Notification Source subscribed\n");
}
return err;
}
int bt_ancs_subscribe_data_source(struct bt_ancs_client *ancs_c,
bt_ancs_ds_notif_cb func)
{
int err;
if (!ancs_c || !func) {
return -EINVAL;
}
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED)) {
return -EALREADY;
}
ancs_c->ds_notif_cb = func;
ancs_c->ds_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ds_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ds_notif_params.len = 2;
ancs_c->ds_notif_params.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ds_notif_params.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ds_notif_params.handle = ancs_c->handle_ds_ccc;
ancs_c->ds_notif_params.cmd = 0;
ancs_c->ds_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ds_notif_params, ancs_taskid);
if (err) {
atomic_clear_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED);
GATT_bm_free((gattMsg_t *)&ancs_c->ds_notif_params, ATT_WRITE_REQ);
PRINT("Subscribe Notification Source failed (err %d)\n", err);
} else {
PRINT("Data Source subscribed\n");
}
return err;
}
int bt_ancs_unsubscribe_notification_source(struct bt_ancs_client *ancs_c)
{
int err;
if (!ancs_c) {
return -EINVAL;
}
if (!atomic_test_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED)) {
return -EFAULT;
}
ancs_c->ns_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ns_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ns_notif_params.len = 2;
ancs_c->ns_notif_params.pValue[0] = 0;
ancs_c->ns_notif_params.pValue[1] = 0;
ancs_c->ns_notif_params.handle = ancs_c->handle_ds;
ancs_c->ns_notif_params.cmd = 0;
ancs_c->ns_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ns_notif_params, ancs_taskid);
if (err) {
PRINT("Unsubscribe Notification Source failed (err %d)\n", err);
GATT_bm_free((gattMsg_t *)&ancs_c->ns_notif_params, ATT_WRITE_REQ);
} else {
atomic_clear_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED);
PRINT("Notification Source unsubscribed\n");
}
return err;
}
int bt_ancs_unsubscribe_data_source(struct bt_ancs_client *ancs_c)
{
int err;
if (!ancs_c) {
return -EINVAL;
}
if (!atomic_test_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED)) {
return -EFAULT;
}
ancs_c->ds_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ds_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ds_notif_params.len = 2;
ancs_c->ds_notif_params.pValue[0] = 0;
ancs_c->ds_notif_params.pValue[1] = 0;
ancs_c->ds_notif_params.handle = ancs_c->handle_ns;
ancs_c->ds_notif_params.cmd = 0;
ancs_c->ds_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ds_notif_params, ancs_taskid);
if (err) {
PRINT("Unsubscribe Data Source failed (err %d)\n", err);
GATT_bm_free((gattMsg_t *)&ancs_c->ds_notif_params, ATT_WRITE_REQ);
} else {
atomic_clear_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED);
PRINT("Data Source unsubscribed\n");
}
return err;
}
static uint16_t encode_notif_action(uint8_t *encoded_data, uint32_t uid,
enum bt_ancs_action_id_values action_id)
{
uint8_t index = 0;
encoded_data[index++] = BT_ANCS_COMMAND_ID_PERFORM_NOTIF_ACTION;
sys_put_le32(uid, &encoded_data[index]);
index += sizeof(uint32_t);
encoded_data[index++] = (uint8_t)action_id;
return index;
}
int bt_ancs_cp_write(struct bt_ancs_client *ancs_c, uint16_t len,
bt_ancs_write_cb func)
{
int err;
attWriteReq_t *write_params = &ancs_c->cp_write_params;;
write_params->pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, len, NULL, 0);
if(!write_params->pValue){
return -ENOBUFS;
}
ancs_c->cp_write_cb = func;
write_params->handle = ancs_c->handle_cp;
write_params->len = len;
tmos_memcpy(write_params->pValue, ancs_c->cp_data, len);
write_params->sig = 0;
write_params->cmd = 0;
err = GATT_WriteCharValue(ancs_c->conn, write_params, ancs_taskid);
if(err) {
atomic_clear_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING);
GATT_bm_free((gattMsg_t *)write_params, ATT_WRITE_REQ);
PRINT("write error: %#x\n", err);
}
return err;
}
int bt_ancs_notification_action(struct bt_ancs_client *ancs_c, uint32_t uuid,
enum bt_ancs_action_id_values action_id,
bt_ancs_write_cb func)
{
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING)) {
return -EBUSY;
}
uint8_t *data = ancs_c->cp_data;
uint16_t len = encode_notif_action(data, uuid, action_id);
return bt_ancs_cp_write(ancs_c, len, func);
}
static int bt_ancs_get_notif_attrs(struct bt_ancs_client *ancs_c,
const uint32_t uid, bt_ancs_write_cb func)
{
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING)) {
return -EBUSY;
}
uint32_t index = 0;
uint8_t *data = ancs_c->cp_data;
ancs_c->number_of_requested_attr = 0;
/* Encode Command ID. */
*(data + index++) = BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
/* Encode Notification UID. */
sys_put_le32(uid, data + index);
index += sizeof(uint32_t);
/* Encode Attribute ID. */
for(uint32_t attr = 0; attr < BT_ANCS_NOTIF_ATTR_COUNT; attr++) {
if (ancs_c->ancs_notif_attr_list[attr].get) {
*(data + index++) = (uint8_t)attr;
if ((attr == BT_ANCS_NOTIF_ATTR_ID_TITLE) ||
(attr == BT_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
(attr == BT_ANCS_NOTIF_ATTR_ID_MESSAGE)) {
/* Encode Length field. Only applicable for
* Title, Subtitle, and Message.
*/
sys_put_le16(ancs_c->ancs_notif_attr_list[attr]
.attr_len,
data + index);
index += sizeof(uint16_t);
}
ancs_c->number_of_requested_attr++;
}
}
ancs_c->parse_info.expected_number_of_attrs =
ancs_c->number_of_requested_attr;
return bt_ancs_cp_write(ancs_c, index, func);
}
int bt_ancs_request_attrs(struct bt_ancs_client *ancs_c,
const struct bt_ancs_evt_notif *notif,
bt_ancs_write_cb func)
{
int err;
err = bt_ancs_verify_notification_format(notif);
if (err) {
return err;
}
ancs_c->parse_info.parse_state = BT_ANCS_PARSE_STATE_COMMAND_ID;
return bt_ancs_get_notif_attrs(ancs_c, notif->notif_uid, func);
}
int bt_ancs_register_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_notif_attr_id_val id,
uint8_t *data, const uint16_t len)
{
if (!ancs_c || !data) {
return -EINVAL;
}
if (!len || len > BT_ANCS_ATTR_DATA_MAX) {
return -EINVAL;
}
if ((size_t)id >= BT_ANCS_NOTIF_ATTR_COUNT) {
return -EINVAL;
}
ancs_c->ancs_notif_attr_list[id].get = true;
ancs_c->ancs_notif_attr_list[id].attr_len = len;
ancs_c->ancs_notif_attr_list[id].attr_data = data;
return 0;
}
int bt_ancs_register_app_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_app_attr_id_val id,
uint8_t *data, const uint16_t len)
{
if (!ancs_c || !data) {
return -EINVAL;
}
if (!len || len > BT_ANCS_ATTR_DATA_MAX) {
return -EINVAL;
}
if ((size_t)id >= BT_ANCS_APP_ATTR_COUNT) {
return -EINVAL;
}
ancs_c->ancs_app_attr_list[id].get = true;
ancs_c->ancs_app_attr_list[id].attr_len = len;
ancs_c->ancs_app_attr_list[id].attr_data = data;
return 0;
}
int bt_ancs_request_app_attr(struct bt_ancs_client *ancs_c,
const uint8_t *app_id, uint32_t len,
bt_ancs_write_cb func)
{
return bt_ancs_app_attr_request(ancs_c, app_id, len, func);
}
/*********************************************************************
* @fn Ancs_handleNotification
*
* @brief Handle notifications.
*
* @param pMsg - GATT message.
*
* @return none
*/
void Ancs_handleNotification(gattMsgEvent_t *pMsg)
{
static uint8_t importantAlertCnt = 0;
uint8_t i;
// Look up the handle in the handle cache
for (i = 0; i < HDL_CACHE_LEN; i++)
{
if (pMsg->msg.handleValueNoti.handle == Ancs_handleCache[i])
{
break;
}
}
// Perform processing for this handle
switch (i)
{
case HDL_ANCS_NTF_NOTIF_START:
{
parse_notif(&ancs_c, pMsg->msg.handleValueNoti.pValue,
pMsg->msg.handleValueNoti.len);
}
break;
case HDL_ANCS_DATA_SRC_START:
{
bt_ancs_parse_get_attrs_response(&ancs_c,
pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len);
}
break;
default:
break;
}
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,605 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#ifndef ANCS_CLIENT_H_
#define ANCS_CLIENT_H_
#include <stdbool.h>
#include <sys/atomic.h>
#include "config.h"
#define EPERM 1 /**< Not owner */
#define ENOENT 2 /**< No such file or directory */
#define ESRCH 3 /**< No such context */
#define EINTR 4 /**< Interrupted system call */
#define EIO 5 /**< I/O error */
#define ENXIO 6 /**< No such device or address */
#define E2BIG 7 /**< Arg list too long */
#define ENOEXEC 8 /**< Exec format error */
#define EBADF 9 /**< Bad file number */
#define ECHILD 10 /**< No children */
#define EAGAIN 11 /**< No more contexts */
#define ENOMEM 12 /**< Not enough core */
#define EACCES 13 /**< Permission denied */
#define EFAULT 14 /**< Bad address */
#define ENOTBLK 15 /**< Block device required */
#define EBUSY 16 /**< Mount device busy */
#define EEXIST 17 /**< File exists */
#define EXDEV 18 /**< Cross-device link */
#define ENODEV 19 /**< No such device */
#define ENOTDIR 20 /**< Not a directory */
#define EISDIR 21 /**< Is a directory */
#define EINVAL 22 /**< Invalid argument */
#define ENFILE 23 /**< File table overflow */
#define EMFILE 24 /**< Too many open files */
#define ENOTTY 25 /**< Not a typewriter */
#define ETXTBSY 26 /**< Text file busy */
#define EFBIG 27 /**< File too large */
#define ENOSPC 28 /**< No space left on device */
#define ESPIPE 29 /**< Illegal seek */
#define EROFS 30 /**< Read-only file system */
#define EMLINK 31 /**< Too many links */
#define EPIPE 32 /**< Broken pipe */
#define EDOM 33 /**< Argument too large */
#define ERANGE 34 /**< Result too large */
#define ENOMSG 35 /**< Unexpected message type */
#define EDEADLK 45 /**< Resource deadlock avoided */
#define ENOLCK 46 /**< No locks available */
#define ENOSTR 60 /**< STREAMS device required */
#define ENODATA 61 /**< Missing expected message data */
#define ETIME 62 /**< STREAMS timeout occurred */
#define ENOSR 63 /**< Insufficient memory */
#define EPROTO 71 /**< Generic STREAMS error */
#define EBADMSG 77 /**< Invalid STREAMS message */
#define ENOSYS 88 /**< Function not implemented */
#define ENOTEMPTY 90 /**< Directory not empty */
#define ENAMETOOLONG 91 /**< File name too long */
#define ELOOP 92 /**< Too many levels of symbolic links */
#define EOPNOTSUPP 95 /**< Operation not supported on socket */
#define EPFNOSUPPORT 96 /**< Protocol family not supported */
#define ECONNRESET 104 /**< Connection reset by peer */
#define ENOBUFS 105 /**< No buffer space available */
#define EAFNOSUPPORT 106 /**< Addr family not supported */
#define EPROTOTYPE 107 /**< Protocol wrong type for socket */
#define ENOTSOCK 108 /**< Socket operation on non-socket */
#define ENOPROTOOPT 109 /**< Protocol not available */
#define ESHUTDOWN 110 /**< Can't send after socket shutdown */
#define ECONNREFUSED 111 /**< Connection refused */
#define EADDRINUSE 112 /**< Address already in use */
#define ECONNABORTED 113 /**< Software caused connection abort */
#define ENETUNREACH 114 /**< Network is unreachable */
#define ENETDOWN 115 /**< Network is down */
#define ETIMEDOUT 116 /**< Connection timed out */
#define EHOSTDOWN 117 /**< Host is down */
#define EHOSTUNREACH 118 /**< No route to host */
#define EINPROGRESS 119 /**< Operation now in progress */
#define EALREADY 120 /**< Operation already in progress */
#define EDESTADDRREQ 121 /**< Destination address required */
#define EMSGSIZE 122 /**< Message size */
#define EPROTONOSUPPORT 123 /**< Protocol not supported */
#define ESOCKTNOSUPPORT 124 /**< Socket type not supported */
#define EADDRNOTAVAIL 125 /**< Can't assign requested address */
#define ENETRESET 126 /**< Network dropped connection on reset */
#define EISCONN 127 /**< Socket is already connected */
#define ENOTCONN 128 /**< Socket is not connected */
#define ETOOMANYREFS 129 /**< Too many references: can't splice */
#define ENOTSUP 134 /**< Unsupported value */
#define EILSEQ 138 /**< Illegal byte sequence */
#define EOVERFLOW 139 /**< Value overflow */
#define ECANCELED 140 /**< Operation canceled */
#define EWOULDBLOCK EAGAIN /**< Operation would block */
/** Maximum data length of an iOS notification attribute. */
#define BT_ANCS_ATTR_DATA_MAX 32
/** Number of iOS notification categories: Other, Incoming Call, Missed Call,
* Voice Mail, Social, Schedule, Email, News, Health and Fitness, Business and
* Finance, Location, Entertainment.
*/
#define BT_ANCS_CATEGORY_ID_COUNT 12
/** Number of iOS notification attributes: AppIdentifier, Title, Subtitle,
* Message, MessageSize, Date, PositiveActionLabel, NegativeActionLabel.
*/
#define BT_ANCS_NOTIF_ATTR_COUNT 8
/** Number of iOS application attributes: DisplayName. */
#define BT_ANCS_APP_ATTR_COUNT 1
/** Number of iOS notification events: Added, Modified, Removed. */
#define BT_ANCS_EVT_ID_COUNT 3
/** @brief Length of the iOS notification data. */
#define BT_ANCS_NOTIF_DATA_LENGTH 8
/** 0b.......1 Silent: First (LSB) bit is set. All flags can be active
* at the same time.
*/
#define BT_ANCS_EVENT_FLAG_SILENT 0
/** 0b......1. Important: Second (LSB) bit is set. All flags can be active
* at the same time.
*/
#define BT_ANCS_EVENT_FLAG_IMPORTANT 1
/** 0b.....1.. Pre-existing: Third (LSB) bit is set. All flags can be active
* at the same time.
*/
#define BT_ANCS_EVENT_FLAG_PREEXISTING 2
/** 0b....1... Positive action: Fourth (LSB) bit is set. All flags can be active
* at the same time.
*/
#define BT_ANCS_EVENT_FLAG_POSITIVE_ACTION 3
/** 0b...1.... Negative action: Fifth (LSB) bit is set. All flags can be active
* at the same time.
*/
#define BT_ANCS_EVENT_FLAG_NEGATIVE_ACTION 4
/** @defgroup BT_ATT_ANCS_NP_ERROR_CODES Notification Provider (iOS) Error Codes
* @{
*/
/** The command ID is unknown to the NP. */
#define BT_ATT_ERR_ANCS_NP_UNKNOWN_COMMAND 0xA0
/** The command format is invalid. */
#define BT_ATT_ERR_ANCS_NP_INVALID_COMMAND 0xA1
/** One or more parameters do not exist in the NP. */
#define BT_ATT_ERR_ANCS_NP_INVALID_PARAMETER 0xA2
/** The action failed to be performed by the NP. */
#define BT_ATT_ERR_ANCS_NP_ACTION_FAILED 0xA3
/** @} */
/**@brief Category IDs for iOS notifications. */
enum bt_ancs_category_id_val {
/** The iOS notification belongs to the "Other" category. */
BT_ANCS_CATEGORY_ID_OTHER,
/** The iOS notification belongs to the "Incoming Call" category. */
BT_ANCS_CATEGORY_ID_INCOMING_CALL,
/** The iOS notification belongs to the "Missed Call" category. */
BT_ANCS_CATEGORY_ID_MISSED_CALL,
/** The iOS notification belongs to the "Voice Mail" category. */
BT_ANCS_CATEGORY_ID_VOICE_MAIL,
/** The iOS notification belongs to the "Social" category. */
BT_ANCS_CATEGORY_ID_SOCIAL,
/** The iOS notification belongs to the "Schedule" category. */
BT_ANCS_CATEGORY_ID_SCHEDULE,
/** The iOS notification belongs to the "Email" category. */
BT_ANCS_CATEGORY_ID_EMAIL,
/** The iOS notification belongs to the "News" category. */
BT_ANCS_CATEGORY_ID_NEWS,
/** The iOS notification belongs to the "Health and Fitness" category. */
BT_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS,
/** The iOS notification belongs to the "Business and Finance" category. */
BT_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE,
/** The iOS notification belongs to the "Location" category. */
BT_ANCS_CATEGORY_ID_LOCATION,
/** The iOS notification belongs to the "Entertainment" category. */
BT_ANCS_CATEGORY_ID_ENTERTAINMENT
};
/**@brief Event IDs for iOS notifications. */
enum bt_ancs_evt_id_values {
/** The iOS notification was added. */
BT_ANCS_EVENT_ID_NOTIFICATION_ADDED,
/** The iOS notification was modified. */
BT_ANCS_EVENT_ID_NOTIFICATION_MODIFIED,
/** The iOS notification was removed. */
BT_ANCS_EVENT_ID_NOTIFICATION_REMOVED
};
/**@brief Control point command IDs that the Notification Consumer can send
* to the Notification Provider.
*/
enum bt_ancs_cmd_id_val {
/** Requests attributes to be sent from the NP to the NC for a given
* notification.
*/
BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES,
/** Requests attributes to be sent from the NP to the NC for a given
* iOS app.
*/
BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES,
/** Requests an action to be performed on a given notification.
* For example, dismiss an alarm.
*/
BT_ANCS_COMMAND_ID_PERFORM_NOTIF_ACTION
};
/**@brief IDs for actions that can be performed for iOS notifications. */
enum bt_ancs_action_id_values {
/** Positive action. */
BT_ANCS_ACTION_ID_POSITIVE = 0,
/** Negative action. */
BT_ANCS_ACTION_ID_NEGATIVE
};
/**@brief App attribute ID values.
* @details Currently, only one value is defined. However, the number of app
* attributes might increase. For this reason, they are stored in an enumeration.
*/
enum bt_ancs_app_attr_id_val {
/** Command used to get the display name for an app identifier. */
BT_ANCS_APP_ATTR_ID_DISPLAY_NAME = 0
};
/**@brief IDs for iOS notification attributes. */
enum bt_ancs_notif_attr_id_val {
/** Identifies that the attribute data is of an "App Identifier" type. */
BT_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER = 0,
/** Identifies that the attribute data is a "Title". */
BT_ANCS_NOTIF_ATTR_ID_TITLE,
/** Identifies that the attribute data is a "Subtitle". */
BT_ANCS_NOTIF_ATTR_ID_SUBTITLE,
/** Identifies that the attribute data is a "Message". */
BT_ANCS_NOTIF_ATTR_ID_MESSAGE,
/** Identifies that the attribute data is a "Message Size". */
BT_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE,
/** Identifies that the attribute data is a "Date". */
BT_ANCS_NOTIF_ATTR_ID_DATE,
/** The notification has a "Positive action" that can be executed associated with it. */
BT_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL,
/** The notification has a "Negative action" that can be executed associated with it. */
BT_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL
};
/**@brief Flags for iOS notifications. */
struct bt_ancs_notif_flags {
/** If this flag is set, the notification has a low priority. */
uint8_t silent : 1;
/** If this flag is set, the notification has a high priority. */
uint8_t important : 1;
/** If this flag is set, the notification is pre-existing. */
uint8_t pre_existing : 1;
/** If this flag is set, the notification has a positive action that can be taken. */
uint8_t positive_action : 1;
/** If this flag is set, the notification has a negative action that can be taken. */
uint8_t negative_action : 1;
};
/**@brief Parsing states for received iOS notification and app attributes. */
enum bt_ancs_parse_state {
/** Parsing the command ID. */
BT_ANCS_PARSE_STATE_COMMAND_ID,
/** Parsing the notification UID. */
BT_ANCS_PARSE_STATE_NOTIF_UID,
/** Parsing app ID. */
BT_ANCS_PARSE_STATE_APP_ID,
/** Parsing attribute ID. */
BT_ANCS_PARSE_STATE_ATTR_ID,
/** Parsing the LSB of the attribute length. */
BT_ANCS_PARSE_STATE_ATTR_LEN1,
/** Parsing the MSB of the attribute length. */
BT_ANCS_PARSE_STATE_ATTR_LEN2,
/** Parsing the attribute data. */
BT_ANCS_PARSE_STATE_ATTR_DATA,
/** Parsing is skipped for the rest of an attribute (or entire attribute). */
BT_ANCS_PARSE_STATE_ATTR_SKIP,
/** Parsing for one attribute is done. */
BT_ANCS_PARSE_STATE_DONE
};
/**@brief iOS notification structure. */
struct bt_ancs_evt_notif {
/** Notification UID. */
uint32_t notif_uid;
/** Whether the notification was added, removed, or modified. */
enum bt_ancs_evt_id_values evt_id;
/** Bitmask to signal whether a special condition applies to the
* notification. For example, "Silent" or "Important".
*/
struct bt_ancs_notif_flags evt_flags;
/** Classification of the notification type. For example, email or
* location.
*/
enum bt_ancs_category_id_val category_id;
/** Current number of active notifications for this category ID. */
uint8_t category_count;
};
/**@brief iOS attribute structure. This type is used for both notification
* attributes and app attributes.
*/
struct bt_ancs_attr {
/** Length of the received attribute data. */
uint16_t attr_len;
/** Classification of the attribute type. For example, "Title" or "Date". */
uint32_t attr_id;
/** Pointer to where the memory is allocated for storing incoming attributes. */
uint8_t *attr_data;
};
/**@brief iOS notification attribute content requested by the application. */
struct bt_ancs_attr_list {
/** Boolean to determine whether this attribute will be requested from
* the Notification Provider.
*/
bool get;
/** Attribute ID: AppIdentifier(0), Title(1), Subtitle(2), Message(3),
* MessageSize(4), Date(5), PositiveActionLabel(6),
* NegativeActionLabel(7).
*/
uint32_t attr_id;
/** Length of the attribute. If more data is received from the
* Notification Provider, all the data beyond this length is discarded.
*/
uint16_t attr_len;
/** Pointer to where the memory is allocated for storing incoming attributes. */
uint8_t *attr_data;
};
struct bt_ancs_client;
/**@brief Attribute response structure. */
struct bt_ancs_attr_response {
/** Command ID. */
enum bt_ancs_cmd_id_val command_id;
/** iOS notification attribute or app attribute, depending on the
* Command ID.
*/
struct bt_ancs_attr attr;
/** Notification UID. */
uint32_t notif_uid;
/** App identifier. */
uint8_t app_id[BT_ANCS_ATTR_DATA_MAX];
};
/**@brief Notification Source notification callback function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] err 0 if the notification is valid.
* Otherwise, contains a (negative) error code.
* @param[in] notif iOS notification structure.
*/
typedef void (*bt_ancs_ns_notif_cb)(struct bt_ancs_client *ancs_c, int err,
const struct bt_ancs_evt_notif *notif);
/**@brief Data Source notification callback function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] response Attribute response structure.
*/
typedef void (*bt_ancs_ds_notif_cb)(struct bt_ancs_client *ancs_c,
const struct bt_ancs_attr_response *response);
/**@brief Write response callback function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] err ATT error code.
*/
typedef void (*bt_ancs_write_cb)(struct bt_ancs_client *ancs_c,
uint8_t err);
struct bt_ancs_parse_sm {
/** The current list of attributes that are being parsed. This will
* point to either ancs_notif_attr_list or ancs_app_attr_list in
* struct bt_ancs_client.
*/
struct bt_ancs_attr_list *attr_list;
/** Number of possible attributes. When parsing begins, it is set to
* either @ref BT_ANCS_NOTIF_ATTR_COUNT or @ref BT_ANCS_APP_ATTR_COUNT.
*/
uint32_t attr_count;
/** The number of attributes expected upon receiving attributes. Keeps
* track of when to stop reading incoming attributes.
*/
uint32_t expected_number_of_attrs;
/** ANCS notification attribute parsing state. */
enum bt_ancs_parse_state parse_state;
/** Variable to keep track of what command type is being parsed
* ( @ref BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES or
* @ref BT_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES).
*/
enum bt_ancs_cmd_id_val command_id;
/** Attribute that the parsed data is copied into. */
uint8_t *data_dest;
/** Variable to keep track of the parsing progress, for the given attribute. */
uint16_t current_attr_index;
/** Variable to keep track of the parsing progress, for the given app identifier. */
uint32_t current_app_id_index;
};
/**@brief ANCS client instance, which contains various status information. */
struct bt_ancs_client {
/** Connection object. */
uint8_t conn;
/** Internal state. */
atomic_t state;
/** Handle of the Control Point Characteristic. */
uint16_t handle_cp;
/** Handle of the Notification Source Characteristic. */
uint16_t handle_ns;
/** Handle of the CCCD of the Notification Source Characteristic. */
uint16_t handle_ns_ccc;
/** Handle of the Data Source Characteristic. */
uint16_t handle_ds;
/** Handle of the CCCD of the Data Source Characteristic. */
uint16_t handle_ds_ccc;
/** GATT write parameters for Control Point Characteristic. */
attWriteReq_t cp_write_params;
/** Callback function for Control Point GATT write. */
bt_ancs_write_cb cp_write_cb;
/** Data buffer for Control Point GATT write. */
uint8_t cp_data[100];
/** GATT subscribe parameters for Notification Source Characteristic. */
attWriteReq_t ns_notif_params;
/** Callback function for Notification Source notification. */
bt_ancs_ns_notif_cb ns_notif_cb;
/** GATT subscribe parameters for Data Source Characteristic. */
attWriteReq_t ds_notif_params;
/** Callback function for Data Source notification. */
bt_ancs_ds_notif_cb ds_notif_cb;
/** For all attributes: contains information about whether the
* attributes are to be requested upon attribute request, and
* the length and buffer of where to store attribute data.
*/
struct bt_ancs_attr_list
ancs_notif_attr_list[BT_ANCS_NOTIF_ATTR_COUNT];
/** For all app attributes: contains information about whether the
* attributes are to be requested upon attribute request, and the
* length and buffer of where to store attribute data.
*/
struct bt_ancs_attr_list
ancs_app_attr_list[BT_ANCS_APP_ATTR_COUNT];
/** The number of attributes that are to be requested when an iOS
* notification attribute request is made.
*/
uint32_t number_of_requested_attr;
/** Structure containing different information used to parse incoming
* attributes correctly (from data_source characteristic).
*/
struct bt_ancs_parse_sm parse_info;
/** Allocate memory for the attribute response here.
*/
struct bt_ancs_attr_response attr_response;
};
/**@brief Function for initializing the ANCS client.
*
* @param[out] ancs_c ANCS client instance. This structure must be
* supplied by the application. It is initialized by
* this function and will later be used to identify
* this particular client instance.
*
* @retval 0 If the client was initialized successfully.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_client_init(struct bt_ancs_client *ancs_c);
void ancs_reinit(struct bt_ancs_client *ancs_c);
/**@brief Function for writing to the CCCD to enable notifications from
* the Apple Notification Service.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] func Callback function for handling notification.
*
* @retval 0 If writing to the CCCD was successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_subscribe_notification_source(struct bt_ancs_client *ancs_c,
bt_ancs_ns_notif_cb func);
/**@brief Function for writing to the CCCD to enable data source notifications from the ANCS.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] func Callback function for handling notification.
*
* @retval 0 If writing to the CCCD was successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_subscribe_data_source(struct bt_ancs_client *ancs_c,
bt_ancs_ds_notif_cb func);
/**@brief Function for writing to the CCCD to disable notifications from the ANCS.
*
* @param[in] ancs_c ANCS client instance
*
* @retval 0 If writing to the CCCD was successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_unsubscribe_notification_source(struct bt_ancs_client *ancs_c);
/**@brief Function for writing to the CCCD to disable data source notifications from the ANCS.
*
* @param[in] ancs_c ANCS client instance.
*
* @retval 0 If writing to the CCCD was successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_unsubscribe_data_source(struct bt_ancs_client *ancs_c);
/**@brief Function for registering attributes that will be requested when
* @ref bt_ancs_request_attrs is called.
*
* @param[in] ancs_c ANCS client instance on which the attribute is registered.
* @param[in] id ID of the attribute that is added.
* @param[in] data Pointer to the buffer where the data of the attribute can be stored.
* @param[in] len Length of the buffer where the data of the attribute can be stored.
*
* @retval 0 If all operations are successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_register_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_notif_attr_id_val id,
uint8_t *data, const uint16_t len);
/**@brief Function for registering attributes that will be requested when
* @ref bt_ancs_request_app_attr is called.
*
* @param[in] ancs_c ANCS client instance on which the attribute is registered.
* @param[in] id ID of the attribute that is added.
* @param[in] data Pointer to the buffer where the data of the attribute can be stored.
* @param[in] len Length of the buffer where the data of the attribute can be stored.
*
* @retval 0 If all operations are successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_register_app_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_app_attr_id_val id,
uint8_t *data, const uint16_t len);
/**@brief Function for requesting attributes for a notification.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] notif Pointer to the notification whose attributes will be requested from
* the Notification Provider.
* @param[in] func Callback function for handling NP write response.
*
* @retval 0 If all operations are successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_request_attrs(struct bt_ancs_client *ancs_c,
const struct bt_ancs_evt_notif *notif,
bt_ancs_write_cb func);
/**@brief Function for requesting attributes for a given app.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] app_id App identifier of the app for which the app attributes are requested.
* @param[in] len Length of the app identifier.
* @param[in] func Callback function for handling NP write response.
*
* @retval 0 If all operations are successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_request_app_attr(struct bt_ancs_client *ancs_c,
const uint8_t *app_id, uint32_t len,
bt_ancs_write_cb func);
/**@brief Function for performing a notification action.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] uuid The UUID of the notification for which to perform the action.
* @param[in] action_id Perform a positive or negative action.
* @param[in] func Callback function for handling NP write response.
*
* @retval 0 If the operation is successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_notification_action(struct bt_ancs_client *ancs_c, uint32_t uuid,
enum bt_ancs_action_id_values action_id,
bt_ancs_write_cb func);
void Ancs_handleNotification(gattMsgEvent_t *pMsg);
#endif /* ANCS_CLIENT_H_ */
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
#ifndef BT_ANCS_CLIENT_INTERNAL_H_
#define BT_ANCS_CLIENT_INTERNAL_H_
#include "ancs_client.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
ANCS_BT_CONNECTED,
ANCS_BT_DISCOVERY_COMPLETE,
ANCS_NS_NOTIF_ENABLED,
ANCS_DS_NOTIF_ENABLED,
ANCS_CP_WRITE_PENDING
};
/**@brief Call Notification Source notification callback function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] err 0 if the notification is valid.
* Otherwise, contains a (negative) error code.
* @param[in] notif iOS notification structure.
*/
static inline void bt_ancs_do_ns_notif_cb(struct bt_ancs_client *ancs_c, int err,
const struct bt_ancs_evt_notif *notif)
{
if (ancs_c->ns_notif_cb) {
ancs_c->ns_notif_cb(ancs_c, err, notif);
}
}
/**@brief Call Data Source notification callback function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] response Attribute response structure.
*/
static inline void bt_ancs_do_ds_notif_cb(struct bt_ancs_client *ancs_c,
const struct bt_ancs_attr_response *response)
{
if (ancs_c->ds_notif_cb) {
ancs_c->ds_notif_cb(ancs_c, response);
}
}
/**@brief Internal function for writing to ANCS Control Point.
*
* The caller is expected to set the ANCS_CP_WRITE_PENDING and to set up
* the Control Point data buffer before calling this function.
*
* @param[in] ancs_c ANCS client instance.
* @param[in] len Length of data in Control Point data buffer.
* @param[in] func Callback function for handling NP write response.
*
* @retval 0 If the operation is successful.
* Otherwise, a (negative) error code is returned.
*/
int bt_ancs_cp_write(struct bt_ancs_client *ancs_c, uint16_t len,
bt_ancs_write_cb func);
#ifdef __cplusplus
}
#endif
#endif /* BT_ANCS_CLIENT_INTERNAL_H_ */
@@ -0,0 +1,589 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : devinfoservice.c
* Author : WCH
* Version : V1.0
* Date : 2018/12/10
* Description : Device information service
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "CONFIG.h"
#include "devinfoservice.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
// Device information service
const uint8_t devInfoServUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(DEVINFO_SERV_UUID), HI_UINT16(DEVINFO_SERV_UUID)};
// System ID
const uint8_t devInfoSystemIdUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(SYSTEM_ID_UUID), HI_UINT16(SYSTEM_ID_UUID)};
// Model Number String
const uint8_t devInfoModelNumberUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(MODEL_NUMBER_UUID), HI_UINT16(MODEL_NUMBER_UUID)};
// Serial Number String
const uint8_t devInfoSerialNumberUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(SERIAL_NUMBER_UUID), HI_UINT16(SERIAL_NUMBER_UUID)};
// Firmware Revision String
const uint8_t devInfoFirmwareRevUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(FIRMWARE_REV_UUID), HI_UINT16(FIRMWARE_REV_UUID)};
// Hardware Revision String
const uint8_t devInfoHardwareRevUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(HARDWARE_REV_UUID), HI_UINT16(HARDWARE_REV_UUID)};
// Software Revision String
const uint8_t devInfoSoftwareRevUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(SOFTWARE_REV_UUID), HI_UINT16(SOFTWARE_REV_UUID)};
// Manufacturer Name String
const uint8_t devInfoMfrNameUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(MANUFACTURER_NAME_UUID), HI_UINT16(MANUFACTURER_NAME_UUID)};
// IEEE 11073-20601 Regulatory Certification Data List
const uint8_t devInfo11073CertUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(IEEE_11073_CERT_DATA_UUID), HI_UINT16(IEEE_11073_CERT_DATA_UUID)};
// PnP ID
const uint8_t devInfoPnpIdUUID[ATT_BT_UUID_SIZE] = {
LO_UINT16(PNP_ID_UUID), HI_UINT16(PNP_ID_UUID)};
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
/*********************************************************************
* Profile Attributes - variables
*/
// Device Information Service attribute
static const gattAttrType_t devInfoService = {ATT_BT_UUID_SIZE, devInfoServUUID};
// System ID characteristic
static uint8_t devInfoSystemIdProps = GATT_PROP_READ;
static uint8_t devInfoSystemId[DEVINFO_SYSTEM_ID_LEN] = {0, 0, 0, 0, 0, 0, 0, 0};
// Model Number String characteristic
static uint8_t devInfoModelNumberProps = GATT_PROP_READ;
static const uint8_t devInfoModelNumber[] = "Model Number";
// Serial Number String characteristic
static uint8_t devInfoSerialNumberProps = GATT_PROP_READ;
static const uint8_t devInfoSerialNumber[] = "Serial Number";
// Firmware Revision String characteristic
static uint8_t devInfoFirmwareRevProps = GATT_PROP_READ;
static const uint8_t devInfoFirmwareRev[] = "Firmware Revision";
// Hardware Revision String characteristic
static uint8_t devInfoHardwareRevProps = GATT_PROP_READ;
static const uint8_t devInfoHardwareRev[] = "Hardware Revision";
// Software Revision String characteristic
static uint8_t devInfoSoftwareRevProps = GATT_PROP_READ;
static const uint8_t devInfoSoftwareRev[] = "Software Revision";
// Manufacturer Name String characteristic
static uint8_t devInfoMfrNameProps = GATT_PROP_READ;
static const uint8_t devInfoMfrName[] = "Manufacturer Name";
// IEEE 11073-20601 Regulatory Certification Data List characteristic
static uint8_t devInfo11073CertProps = GATT_PROP_READ;
static const uint8_t devInfo11073Cert[] = {
DEVINFO_11073_BODY_EXP, // authoritative body type
0x00, // authoritative body structure type
// authoritative body data follows below:
'e', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l'};
// System ID characteristic
static uint8_t devInfoPnpIdProps = GATT_PROP_READ;
static uint8_t devInfoPnpId[DEVINFO_PNP_ID_LEN] = {
1, // Vendor ID source (1=Bluetooth SIG)
LO_UINT16(0x07D7), HI_UINT16(0x07D7), // Vendor ID (WCH)
LO_UINT16(0x0000), HI_UINT16(0x0000), // Product ID (vendor-specific)
LO_UINT16(0x0110), HI_UINT16(0x0110) // Product version (JJ.M.N)
};
/*********************************************************************
* Profile Attributes - Table
*/
static gattAttribute_t devInfoAttrTbl[] = {
// Device Information Service
{
{ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */
GATT_PERMIT_AUTHEN_READ, /* permissions */
0, /* handle */
(uint8_t *)&devInfoService /* pValue */
},
// System ID Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_AUTHEN_READ,
0,
&devInfoSystemIdProps},
// System ID Value
{
{ATT_BT_UUID_SIZE, devInfoSystemIdUUID},
GATT_PERMIT_AUTHEN_READ,
0,
(uint8_t *)devInfoSystemId},
// Model Number String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoModelNumberProps},
// Model Number Value
{
{ATT_BT_UUID_SIZE, devInfoModelNumberUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoModelNumber},
// Serial Number String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoSerialNumberProps},
// Serial Number Value
{
{ATT_BT_UUID_SIZE, devInfoSerialNumberUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoSerialNumber},
// Firmware Revision String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoFirmwareRevProps},
// Firmware Revision Value
{
{ATT_BT_UUID_SIZE, devInfoFirmwareRevUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoFirmwareRev},
// Hardware Revision String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoHardwareRevProps},
// Hardware Revision Value
{
{ATT_BT_UUID_SIZE, devInfoHardwareRevUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoHardwareRev},
// Software Revision String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoSoftwareRevProps},
// Software Revision Value
{
{ATT_BT_UUID_SIZE, devInfoSoftwareRevUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoSoftwareRev},
// Manufacturer Name String Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoMfrNameProps},
// Manufacturer Name Value
{
{ATT_BT_UUID_SIZE, devInfoMfrNameUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoMfrName},
// IEEE 11073-20601 Regulatory Certification Data List Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfo11073CertProps},
// IEEE 11073-20601 Regulatory Certification Data List Value
{
{ATT_BT_UUID_SIZE, devInfo11073CertUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfo11073Cert},
// PnP ID Declaration
{
{ATT_BT_UUID_SIZE, characterUUID},
GATT_PERMIT_READ,
0,
&devInfoPnpIdProps},
// PnP ID Value
{
{ATT_BT_UUID_SIZE, devInfoPnpIdUUID},
GATT_PERMIT_READ,
0,
(uint8_t *)devInfoPnpId}
};
/*********************************************************************
* LOCAL FUNCTIONS
*/
static bStatus_t devInfo_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method);
/*********************************************************************
* PROFILE CALLBACKS
*/
// Device Info Service Callbacks
gattServiceCBs_t devInfoCBs = {
devInfo_ReadAttrCB, // Read callback function pointer
NULL, // Write callback function pointer
NULL // Authorization callback function pointer
};
/*********************************************************************
* NETWORK LAYER CALLBACKS
*/
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn DevInfo_AddService
*
* @brief Initializes the Device Information service by registering
* GATT attributes with the GATT server.
*
* @return Success or Failure
*/
bStatus_t DevInfo_AddService(void)
{
// Register GATT attribute list and CBs with GATT Server App
return GATTServApp_RegisterService(devInfoAttrTbl,
GATT_NUM_ATTRS(devInfoAttrTbl),
GATT_MAX_ENCRYPT_KEY_SIZE,
&devInfoCBs);
}
/*********************************************************************
* @fn DevInfo_SetParameter
*
* @brief Set a Device Information parameter.
*
* @param param - Profile parameter ID
* @param len - length of data to write
* @param value - pointer to data to write. This is dependent on
* the parameter ID and WILL be cast to the appropriate
* data type (example: data type of uint16_t will be cast to
* uint16_t pointer).
*
* @return bStatus_t
*/
bStatus_t DevInfo_SetParameter(uint8_t param, uint8_t len, void *value)
{
bStatus_t ret = SUCCESS;
switch(param)
{
case DEVINFO_SYSTEM_ID:
tmos_memcpy(devInfoSystemId, value, len);
break;
default:
ret = INVALIDPARAMETER;
break;
}
return (ret);
}
/*********************************************************************
* @fn DevInfo_GetParameter
*
* @brief Get a Device Information parameter.
*
* @param param - Profile parameter ID
* @param value - pointer to data to get. This is dependent on
* the parameter ID and WILL be cast to the appropriate
* data type (example: data type of uint16_t will be cast to
* uint16_t pointer).
*
* @return bStatus_t
*/
bStatus_t DevInfo_GetParameter(uint8_t param, void *value)
{
bStatus_t ret = SUCCESS;
switch(param)
{
case DEVINFO_SYSTEM_ID:
tmos_memcpy(value, devInfoSystemId, sizeof(devInfoSystemId));
break;
case DEVINFO_MODEL_NUMBER:
tmos_memcpy(value, devInfoModelNumber, sizeof(devInfoModelNumber));
break;
case DEVINFO_SERIAL_NUMBER:
tmos_memcpy(value, devInfoSerialNumber, sizeof(devInfoSerialNumber));
break;
case DEVINFO_FIRMWARE_REV:
tmos_memcpy(value, devInfoFirmwareRev, sizeof(devInfoFirmwareRev));
break;
case DEVINFO_HARDWARE_REV:
tmos_memcpy(value, devInfoHardwareRev, sizeof(devInfoHardwareRev));
break;
case DEVINFO_SOFTWARE_REV:
tmos_memcpy(value, devInfoSoftwareRev, sizeof(devInfoSoftwareRev));
break;
case DEVINFO_MANUFACTURER_NAME:
tmos_memcpy(value, devInfoMfrName, sizeof(devInfoMfrName));
break;
case DEVINFO_11073_CERT_DATA:
tmos_memcpy(value, devInfo11073Cert, sizeof(devInfo11073Cert));
break;
case DEVINFO_PNP_ID:
tmos_memcpy(value, devInfoPnpId, sizeof(devInfoPnpId));
break;
default:
ret = INVALIDPARAMETER;
break;
}
return (ret);
}
/*********************************************************************
* @fn devInfo_ReadAttrCB
*
* @brief Read an attribute.
*
* @param connHandle - connection message was received on
* @param pAttr - pointer to attribute
* @param pValue - pointer to data to be read
* @param pLen - length of data to be read
* @param offset - offset of the first octet to be read
* @param maxLen - maximum length of data to be read
*
* @return Success or Failure
*/
static bStatus_t devInfo_ReadAttrCB(uint16_t connHandle, gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t *pLen, uint16_t offset, uint16_t maxLen, uint8_t method)
{
bStatus_t status = SUCCESS;
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch(uuid)
{
case SYSTEM_ID_UUID:
// verify offset
if(offset >= sizeof(devInfoSystemId))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length
*pLen = MIN(maxLen, (sizeof(devInfoSystemId) - offset));
// copy data
tmos_memcpy(pValue, &devInfoSystemId[offset], *pLen);
}
break;
case MODEL_NUMBER_UUID:
// verify offset
if(offset >= (sizeof(devInfoModelNumber) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoModelNumber) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoModelNumber[offset], *pLen);
}
break;
case SERIAL_NUMBER_UUID:
// verify offset
if(offset >= (sizeof(devInfoSerialNumber) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoSerialNumber) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoSerialNumber[offset], *pLen);
}
break;
case FIRMWARE_REV_UUID:
// verify offset
if(offset >= (sizeof(devInfoFirmwareRev) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoFirmwareRev) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoFirmwareRev[offset], *pLen);
}
break;
case HARDWARE_REV_UUID:
// verify offset
if(offset >= (sizeof(devInfoHardwareRev) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoHardwareRev) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoHardwareRev[offset], *pLen);
}
break;
case SOFTWARE_REV_UUID:
// verify offset
if(offset >= (sizeof(devInfoSoftwareRev) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoSoftwareRev) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoSoftwareRev[offset], *pLen);
}
break;
case MANUFACTURER_NAME_UUID:
// verify offset
if(offset >= (sizeof(devInfoMfrName) - 1))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length (exclude null terminating character)
*pLen = MIN(maxLen, ((sizeof(devInfoMfrName) - 1) - offset));
// copy data
tmos_memcpy(pValue, &devInfoMfrName[offset], *pLen);
}
break;
case IEEE_11073_CERT_DATA_UUID:
// verify offset
if(offset >= sizeof(devInfo11073Cert))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length
*pLen = MIN(maxLen, (sizeof(devInfo11073Cert) - offset));
// copy data
tmos_memcpy(pValue, &devInfo11073Cert[offset], *pLen);
}
break;
case PNP_ID_UUID:
// verify offset
if(offset >= sizeof(devInfoPnpId))
{
status = ATT_ERR_INVALID_OFFSET;
}
else
{
// determine read length
*pLen = MIN(maxLen, (sizeof(devInfoPnpId) - offset));
// copy data
tmos_memcpy(pValue, &devInfoPnpId[offset], *pLen);
}
break;
default:
*pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
return (status);
}
/*********************************************************************
*********************************************************************/
@@ -0,0 +1,109 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : devinfoservice.h
* Author : WCH
* Version : V1.0
* Date : 2018/12/11
* Description :
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef DEVINFOSERVICE_H
#define DEVINFOSERVICE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************************************************************
* INCLUDES
*/
/*********************************************************************
* CONSTANTS
*/
// Device Information Service Parameters
#define DEVINFO_SYSTEM_ID 0
#define DEVINFO_MODEL_NUMBER 1
#define DEVINFO_SERIAL_NUMBER 2
#define DEVINFO_FIRMWARE_REV 3
#define DEVINFO_HARDWARE_REV 4
#define DEVINFO_SOFTWARE_REV 5
#define DEVINFO_MANUFACTURER_NAME 6
#define DEVINFO_11073_CERT_DATA 7
#define DEVINFO_PNP_ID 8
// IEEE 11073 authoritative body values
#define DEVINFO_11073_BODY_EMPTY 0
#define DEVINFO_11073_BODY_IEEE 1
#define DEVINFO_11073_BODY_CONTINUA 2
#define DEVINFO_11073_BODY_EXP 254
// System ID length
#define DEVINFO_SYSTEM_ID_LEN 8
// PnP ID length
#define DEVINFO_PNP_ID_LEN 7
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* MACROS
*/
/*********************************************************************
* Profile Callbacks
*/
/*********************************************************************
* API FUNCTIONS
*/
/*
* DevInfo_AddService- Initializes the Device Information service by registering
* GATT attributes with the GATT server.
*
*/
extern bStatus_t DevInfo_AddService(void);
/*********************************************************************
* @fn DevInfo_SetParameter
*
* @brief Set a Device Information parameter.
*
* @param param - Profile parameter ID
* @param len - length of data to right
* @param value - pointer to data to write. This is dependent on
* the parameter ID and WILL be cast to the appropriate
* data type (example: data type of uint16_t will be cast to
* uint16_t pointer).
*
* @return bStatus_t
*/
bStatus_t DevInfo_SetParameter(uint8_t param, uint8_t len, void *value);
/*
* DevInfo_GetParameter - Get a Device Information parameter.
*
* param - Profile parameter ID
* value - pointer to data to write. This is dependent on
* the parameter ID and WILL be cast to the appropriate
* data type (example: data type of uint16_t will be cast to
* uint16_t pointer).
*/
extern bStatus_t DevInfo_GetParameter(uint8_t param, void *value);
/*********************************************************************
*********************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* DEVINFOSERVICE_H */