first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
@@ -0,0 +1,545 @@
/*
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
*
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*/
/*********************************************************************
* INCLUDES
*/
#include <stdlib.h>
#include <sys/byteorder.h>
#include "string.h"
#include "config.h"
#include "ancs.h"
#include "ancs_client.h"
#include "ancs_client_internal.h"
#include "ancs_attr_parser.h"
#include "ancs_app_attr_get.h"
/*********************************************************************
* MACROS
*/
/**< Index of the Event ID field when parsing notifications. */
#define BT_ANCS_NOTIF_EVT_ID_INDEX 0
/**< Index of the Flags field when parsing notifications. */
#define BT_ANCS_NOTIF_FLAGS_INDEX 1
/**< Index of the Category ID field when parsing notifications. */
#define BT_ANCS_NOTIF_CATEGORY_ID_INDEX 2
/**< Index of the Category Count field when parsing notifications. */
#define BT_ANCS_NOTIF_CATEGORY_CNT_INDEX 3
/**< Index of the Notification UID field when parsing notifications. */
#define BT_ANCS_NOTIF_NOTIF_UID 4
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
/*********************************************************************
* LOCAL FUNCTIONS
*/
/**@brief Function for checking whether the data in an iOS notification is out of bounds.
*
* @param[in] notif An iOS notification.
*
* @retval 0 If the notification is within bounds.
* @retval -1 If the notification is out of bounds.
*/
static int bt_ancs_verify_notification_format(const struct bt_ancs_evt_notif *notif)
{
if ((notif->evt_id >= BT_ANCS_EVT_ID_COUNT) ||
(notif->category_id >= BT_ANCS_CATEGORY_ID_COUNT)) {
return -1;
}
return 0;
}
/**@brief Function for receiving and validating notifications received from
* the Notification Provider.
*
* @param[in] ancs_c Pointer to an ANCS instance to which the event belongs.
* @param[in] data_src Pointer to the data that was received from the Notification Provider.
* @param[in] len Length of the data that was received from the Notification Provider.
*/
static void parse_notif(struct bt_ancs_client *ancs_c,
const uint8_t *data_src, const uint16_t len)
{
int err;
struct bt_ancs_evt_notif notif;
if (len != BT_ANCS_NOTIF_DATA_LENGTH) {
bt_ancs_do_ns_notif_cb(ancs_c, -EINVAL, &notif);
return;
}
notif.evt_id = (enum bt_ancs_evt_id_values)
data_src[BT_ANCS_NOTIF_EVT_ID_INDEX];
notif.evt_flags.silent =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_SILENT) &
0x01;
notif.evt_flags.important =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_IMPORTANT) &
0x01;
notif.evt_flags.pre_existing =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_PREEXISTING) &
0x01;
notif.evt_flags.positive_action =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_POSITIVE_ACTION) &
0x01;
notif.evt_flags.negative_action =
(data_src[BT_ANCS_NOTIF_FLAGS_INDEX] >>
BT_ANCS_EVENT_FLAG_NEGATIVE_ACTION) &
0x01;
notif.category_id = (enum bt_ancs_category_id_val)
data_src[BT_ANCS_NOTIF_CATEGORY_ID_INDEX];
notif.category_count =
data_src[BT_ANCS_NOTIF_CATEGORY_CNT_INDEX];
notif.notif_uid =
sys_get_le32(&data_src[BT_ANCS_NOTIF_NOTIF_UID]);
err = bt_ancs_verify_notification_format(&notif);
bt_ancs_do_ns_notif_cb(ancs_c, err, &notif);
}
int bt_ancs_client_init(struct bt_ancs_client *ancs_c)
{
if (!ancs_c) {
return -EINVAL;
}
memset(ancs_c, 0, sizeof(struct bt_ancs_client));
return 0;
}
void ancs_reinit(struct bt_ancs_client *ancs_c)
{
ancs_c->conn = 0;
ancs_c->handle_cp = 0;
ancs_c->handle_ns = 0;
ancs_c->handle_ns_ccc = 0;
ancs_c->handle_ds = 0;
ancs_c->handle_ds_ccc = 0;
ancs_c->state = 0;
}
int bt_ancs_subscribe_notification_source(struct bt_ancs_client *ancs_c,
bt_ancs_ns_notif_cb func)
{
int err;
if (!ancs_c || !func) {
return -EINVAL;
}
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED)) {
return -EALREADY;
}
ancs_c->ns_notif_cb = func;
ancs_c->ns_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ns_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ns_notif_params.len = 2;
ancs_c->ns_notif_params.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ns_notif_params.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ns_notif_params.handle = ancs_c->handle_ns_ccc;
ancs_c->ns_notif_params.cmd = 0;
ancs_c->ns_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ns_notif_params, ancs_taskid);
if (err) {
atomic_clear_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED);
GATT_bm_free((gattMsg_t *)&ancs_c->ns_notif_params, ATT_WRITE_REQ);
PRINT("Subscribe Notification Source failed (err %d)\n", err);
} else {
PRINT("Notification Source subscribed\n");
}
return err;
}
int bt_ancs_subscribe_data_source(struct bt_ancs_client *ancs_c,
bt_ancs_ds_notif_cb func)
{
int err;
if (!ancs_c || !func) {
return -EINVAL;
}
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED)) {
return -EALREADY;
}
ancs_c->ds_notif_cb = func;
ancs_c->ds_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ds_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ds_notif_params.len = 2;
ancs_c->ds_notif_params.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ds_notif_params.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
ancs_c->ds_notif_params.handle = ancs_c->handle_ds_ccc;
ancs_c->ds_notif_params.cmd = 0;
ancs_c->ds_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ds_notif_params, ancs_taskid);
if (err) {
atomic_clear_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED);
GATT_bm_free((gattMsg_t *)&ancs_c->ds_notif_params, ATT_WRITE_REQ);
PRINT("Subscribe Notification Source failed (err %d)\n", err);
} else {
PRINT("Data Source subscribed\n");
}
return err;
}
int bt_ancs_unsubscribe_notification_source(struct bt_ancs_client *ancs_c)
{
int err;
if (!ancs_c) {
return -EINVAL;
}
if (!atomic_test_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED)) {
return -EFAULT;
}
ancs_c->ns_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ns_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ns_notif_params.len = 2;
ancs_c->ns_notif_params.pValue[0] = 0;
ancs_c->ns_notif_params.pValue[1] = 0;
ancs_c->ns_notif_params.handle = ancs_c->handle_ds;
ancs_c->ns_notif_params.cmd = 0;
ancs_c->ns_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ns_notif_params, ancs_taskid);
if (err) {
PRINT("Unsubscribe Notification Source failed (err %d)\n", err);
GATT_bm_free((gattMsg_t *)&ancs_c->ns_notif_params, ATT_WRITE_REQ);
} else {
atomic_clear_bit(&ancs_c->state, ANCS_NS_NOTIF_ENABLED);
PRINT("Notification Source unsubscribed\n");
}
return err;
}
int bt_ancs_unsubscribe_data_source(struct bt_ancs_client *ancs_c)
{
int err;
if (!ancs_c) {
return -EINVAL;
}
if (!atomic_test_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED)) {
return -EFAULT;
}
ancs_c->ds_notif_params.pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, 2, NULL, 0);
if(!ancs_c->ds_notif_params.pValue){
return -ENOBUFS;
}
ancs_c->ds_notif_params.len = 2;
ancs_c->ds_notif_params.pValue[0] = 0;
ancs_c->ds_notif_params.pValue[1] = 0;
ancs_c->ds_notif_params.handle = ancs_c->handle_ns;
ancs_c->ds_notif_params.cmd = 0;
ancs_c->ds_notif_params.sig = 0;
err = GATT_WriteCharValue(ancs_c->conn, &ancs_c->ds_notif_params, ancs_taskid);
if (err) {
PRINT("Unsubscribe Data Source failed (err %d)\n", err);
GATT_bm_free((gattMsg_t *)&ancs_c->ds_notif_params, ATT_WRITE_REQ);
} else {
atomic_clear_bit(&ancs_c->state, ANCS_DS_NOTIF_ENABLED);
PRINT("Data Source unsubscribed\n");
}
return err;
}
static uint16_t encode_notif_action(uint8_t *encoded_data, uint32_t uid,
enum bt_ancs_action_id_values action_id)
{
uint8_t index = 0;
encoded_data[index++] = BT_ANCS_COMMAND_ID_PERFORM_NOTIF_ACTION;
sys_put_le32(uid, &encoded_data[index]);
index += sizeof(uint32_t);
encoded_data[index++] = (uint8_t)action_id;
return index;
}
int bt_ancs_cp_write(struct bt_ancs_client *ancs_c, uint16_t len,
bt_ancs_write_cb func)
{
int err;
attWriteReq_t *write_params = &ancs_c->cp_write_params;;
write_params->pValue = GATT_bm_alloc(ancs_c->conn, ATT_WRITE_REQ, len, NULL, 0);
if(!write_params->pValue){
return -ENOBUFS;
}
ancs_c->cp_write_cb = func;
write_params->handle = ancs_c->handle_cp;
write_params->len = len;
tmos_memcpy(write_params->pValue, ancs_c->cp_data, len);
write_params->sig = 0;
write_params->cmd = 0;
err = GATT_WriteCharValue(ancs_c->conn, write_params, ancs_taskid);
if(err) {
atomic_clear_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING);
GATT_bm_free((gattMsg_t *)write_params, ATT_WRITE_REQ);
PRINT("write error: %#x\n", err);
}
return err;
}
int bt_ancs_notification_action(struct bt_ancs_client *ancs_c, uint32_t uuid,
enum bt_ancs_action_id_values action_id,
bt_ancs_write_cb func)
{
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING)) {
return -EBUSY;
}
uint8_t *data = ancs_c->cp_data;
uint16_t len = encode_notif_action(data, uuid, action_id);
return bt_ancs_cp_write(ancs_c, len, func);
}
static int bt_ancs_get_notif_attrs(struct bt_ancs_client *ancs_c,
const uint32_t uid, bt_ancs_write_cb func)
{
if (atomic_test_and_set_bit(&ancs_c->state, ANCS_CP_WRITE_PENDING)) {
return -EBUSY;
}
uint32_t index = 0;
uint8_t *data = ancs_c->cp_data;
ancs_c->number_of_requested_attr = 0;
/* Encode Command ID. */
*(data + index++) = BT_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
/* Encode Notification UID. */
sys_put_le32(uid, data + index);
index += sizeof(uint32_t);
/* Encode Attribute ID. */
for(uint32_t attr = 0; attr < BT_ANCS_NOTIF_ATTR_COUNT; attr++) {
if (ancs_c->ancs_notif_attr_list[attr].get) {
*(data + index++) = (uint8_t)attr;
if ((attr == BT_ANCS_NOTIF_ATTR_ID_TITLE) ||
(attr == BT_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
(attr == BT_ANCS_NOTIF_ATTR_ID_MESSAGE)) {
/* Encode Length field. Only applicable for
* Title, Subtitle, and Message.
*/
sys_put_le16(ancs_c->ancs_notif_attr_list[attr]
.attr_len,
data + index);
index += sizeof(uint16_t);
}
ancs_c->number_of_requested_attr++;
}
}
ancs_c->parse_info.expected_number_of_attrs =
ancs_c->number_of_requested_attr;
return bt_ancs_cp_write(ancs_c, index, func);
}
int bt_ancs_request_attrs(struct bt_ancs_client *ancs_c,
const struct bt_ancs_evt_notif *notif,
bt_ancs_write_cb func)
{
int err;
err = bt_ancs_verify_notification_format(notif);
if (err) {
return err;
}
ancs_c->parse_info.parse_state = BT_ANCS_PARSE_STATE_COMMAND_ID;
return bt_ancs_get_notif_attrs(ancs_c, notif->notif_uid, func);
}
int bt_ancs_register_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_notif_attr_id_val id,
uint8_t *data, const uint16_t len)
{
if (!ancs_c || !data) {
return -EINVAL;
}
if (!len || len > BT_ANCS_ATTR_DATA_MAX) {
return -EINVAL;
}
if ((size_t)id >= BT_ANCS_NOTIF_ATTR_COUNT) {
return -EINVAL;
}
ancs_c->ancs_notif_attr_list[id].get = true;
ancs_c->ancs_notif_attr_list[id].attr_len = len;
ancs_c->ancs_notif_attr_list[id].attr_data = data;
return 0;
}
int bt_ancs_register_app_attr(struct bt_ancs_client *ancs_c,
const enum bt_ancs_app_attr_id_val id,
uint8_t *data, const uint16_t len)
{
if (!ancs_c || !data) {
return -EINVAL;
}
if (!len || len > BT_ANCS_ATTR_DATA_MAX) {
return -EINVAL;
}
if ((size_t)id >= BT_ANCS_APP_ATTR_COUNT) {
return -EINVAL;
}
ancs_c->ancs_app_attr_list[id].get = true;
ancs_c->ancs_app_attr_list[id].attr_len = len;
ancs_c->ancs_app_attr_list[id].attr_data = data;
return 0;
}
int bt_ancs_request_app_attr(struct bt_ancs_client *ancs_c,
const uint8_t *app_id, uint32_t len,
bt_ancs_write_cb func)
{
return bt_ancs_app_attr_request(ancs_c, app_id, len, func);
}
/*********************************************************************
* @fn Ancs_handleNotification
*
* @brief Handle notifications.
*
* @param pMsg - GATT message.
*
* @return none
*/
void Ancs_handleNotification(gattMsgEvent_t *pMsg)
{
static uint8_t importantAlertCnt = 0;
uint8_t i;
// Look up the handle in the handle cache
for (i = 0; i < HDL_CACHE_LEN; i++)
{
if (pMsg->msg.handleValueNoti.handle == Ancs_handleCache[i])
{
break;
}
}
// Perform processing for this handle
switch (i)
{
case HDL_ANCS_NTF_NOTIF_START:
{
parse_notif(&ancs_c, pMsg->msg.handleValueNoti.pValue,
pMsg->msg.handleValueNoti.len);
}
break;
case HDL_ANCS_DATA_SRC_START:
{
bt_ancs_parse_get_attrs_response(&ancs_c,
pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len);
}
break;
default:
break;
}
}
/*********************************************************************
*********************************************************************/