first submission
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*********************************************************************/
|
||||
Reference in New Issue
Block a user