first submission
This commit is contained in:
@@ -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, ¬if);
|
||||
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(¬if);
|
||||
|
||||
bt_ancs_do_ns_notif_cb(ancs_c, err, ¬if);
|
||||
}
|
||||
|
||||
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 */
|
||||
Reference in New Issue
Block a user