1.ANCS
ANCS提供了通过BLE一个简单方便的方式来访问多种事件,在iOS设备上生成的通知,如来电,错过来电,新的电子邮件,等等。为了处理ANCS通知,附件必须外围设备实现了GATT的Client。这意味着iOS实现了GATT 服务器,它提供的数据将是通知。
2.
- Notification Source: UUID: 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
- Control Point: UUID: 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
- Data Source: UUID: 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)
static uint8_t AncsApp_advData[] =
{
// Flags; this sets the device to use limited discoverable
// mode (advertises for 30 seconds at a time) instead of general
// discoverable mode (advertises indefinitely)
0x02, // length of this data
GAP_ADTYPE_FLAGS,
GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// Service Solicitation: this peripheral (NC) is looking for the ANCS service
// on the iOS device. As per Apple Bluetooth Design Guidelines, soliciting
// the ANCS service will cause the device to show up in the iOS settings app
0x11, // length of this data
GAP_ADTYPE_SERVICES_LIST_128BIT,
// ANCS service UUID
ANCS_SVC_UUID
};
//ANCS requires authentication, if the NP attempts to read/write chars on the
//NP without proper authentication, the NP will respond with insufficent_athen
//error to which we must respond with a slave security request
else if (pMsg->method == ATT_ERROR_RSP &&
pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ &&
pMsg->msg.errorRsp.errCode == ATT_ERR_INSUFFICIENT_AUTHEN)
{
uint16 conn_handle;
GAPRole_GetParameter(GAPROLE_CONNHANDLE, &conn_handle);
uint8_t mitm;
uint8_t bonding;
GAPBondMgr_GetParameter(GAPBOND_MITM_PROTECTION, &mitm);
GAPBondMgr_GetParameter(GAPBOND_BONDING_ENABLED, &bonding);
uint8_t authRequest = ((mitm & 0x01) << 2) | ((bonding & 0x01) << 1) |
(bonding & 0x01);
GAP_SendSlaveSecurityRequest(conn_handle, authRequest);
}
4.完整的code
/******************************************************************************
@file ancs.c
@brief This file contains the Simple BLE Peripheral sample application for use
with the CC2650 Bluetooth Low Energy Protocol Stack.
Group: WCS, BTS
Target Device: CC2640R2
******************************************************************************
Copyright (c) 2013-2016, Texas Instruments Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Texas Instruments Incorporated nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************
Release Name: ti-ble-3.0-stack-sdk_3_00_00
Release Date: 2016-12-21 12:44:47
*****************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include <string.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/sysbios/knl/Queue.h>
#include "hci_tl.h"
#include "gatt.h"
#include "linkdb.h"
#include "gapgattserver.h"
#include "gattservapp.h"
#include "gatt_uuid.h"
#include "peripheral.h"
#include "gapbondmgr.h"
#include "osal_snv.h"
#include "icall_apimsg.h"
#include "util.h"
#include "board.h"
#include "icall_api.h"
#include "SensorUtil.h"
#include "ancs.h"
#include "oled.h"
uint8_t ancsAppState = ANCS_STATE_IDLE;
uint16_t Ancs_connHandle=0;// Handle cacheextern
uint16_t Ancs_handleCache[HDL_CACHE_LEN];
// ANCS Service: 7905F431-B5CE-4E99-A40F-4B1E122D00D0
#define ANCS_SVC_UUID 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79
// Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
#define ANCS_NOTIF_SRC_CHAR_UUID 0x1DBD // Last 2 bytes of the 128bit-16bytes UUID
// Control point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
#define ANCS_CTRL_PT_CHAR_UUID 0xD9D9// Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)
#define ANCS_DATA_SRC_CHAR_UUID 0x7BFB
#define CHAR_DESC_HDL_UUID128_LEN 21 // 5 + 16bytes = 21
/*********************************************************************
* @fn Ancs_discoverService *
* @brief Function to handle the discovery of the ANCS service *
* @param pMsg - GATT message to process, may be NULL in DISC_ANCS_START *
* @return none */
void Ancs_discoverService(gattMsgEvent_t *pMsg)
{
static uint8_t discoveryState = DISC_ANCS_START;
if(pMsg==NULL)
discoveryState = DISC_ANCS_START;
static uint16_t Ancs_svcStartHdl;
static uint16_t Ancs_svcEndHdl;
static uint8_t Ancs_endHdlIdx;
static uint8_t isNotifCCCD = FALSE;
uint8 temp_status=0;
switch (discoveryState)
{
case DISC_ANCS_START:
{
uint8_t uuid[ATT_UUID_SIZE] = {ANCS_SVC_UUID}; // Initialize service discovery variables
Ancs_svcStartHdl = Ancs_svcEndHdl = 0;
Ancs_endHdlIdx = 0; // Discover ANCS service by UUID
temp_status=GATT_DiscPrimaryServiceByUUID(Ancs_connHandle, uuid,ATT_UUID_SIZE, ICall_getEntityId());
if(temp_status==SUCCESS)
{
discoveryState = DISC_ANCS_SVC;
}
else
{
temp_status=GATT_DiscPrimaryServiceByUUID(Ancs_connHandle, uuid,ATT_UUID_SIZE, ICall_getEntityId());
if(temp_status==SUCCESS)
{
discoveryState = DISC_ANCS_SVC;
}
}
}
break;
case DISC_ANCS_SVC: // Service found, store handles
{
if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
Ancs_svcStartHdl =ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
Ancs_svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
}
// If procedure complete
if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&pMsg->hdr.status == bleProcedureComplete) ||(pMsg->method == ATT_ERROR_RSP))
{
// If service found
if (Ancs_svcStartHdl != 0)
{
// Discover all characteristics
temp_status=GATT_DiscAllChars(Ancs_connHandle, Ancs_svcStartHdl, Ancs_svcEndHdl, ICall_getEntityId());//ICall_getEntityId()
if(temp_status == SUCCESS)
discoveryState = DISC_ANCS_CHAR;
else
{
temp_status=GATT_DiscAllChars(Ancs_connHandle, Ancs_svcStartHdl, Ancs_svcEndHdl, ICall_getEntityId());//ICall_getEntityId()
if(temp_status == SUCCESS)
discoveryState = DISC_ANCS_CHAR;
}
}
else
{
// Service not found
discoveryState = DISC_FAILED;
}
}
}
break;
case DISC_ANCS_CHAR:
{ // Characteristics found, chache them
uint8_t *pHandleValuePairList;
uint16_t handle;
uint16_t uuid;
if (pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID128_LEN)
{
pHandleValuePairList = pMsg->msg.readByTypeRsp.pDataList;
uint8_t i; // For each handle value pair in the list of chars in ANCS service
for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--)
{
// Parse characteristic declaration
handle = BUILD_UINT16(pHandleValuePairList[3],pHandleValuePairList[4]);
uuid = BUILD_UINT16(pHandleValuePairList[5],pHandleValuePairList[6]);
// If looking for end handle
if (Ancs_endHdlIdx != 0)
{
// End handle is characteristic declaration handle - 1
Ancs_handleCache[Ancs_endHdlIdx] =BUILD_UINT16(pHandleValuePairList[0], pHandleValuePairList[1]) - 1;
Ancs_endHdlIdx = 0;
}
// If UUID is of interest, cache handle
switch (uuid)
{
case ANCS_NOTIF_SRC_CHAR_UUID:
{
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_NTF_NOTIF_END;
}
break;
case ANCS_CTRL_PT_CHAR_UUID:
{
Ancs_handleCache[HDL_ANCS_CTRL_PT_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_CTRL_PT_END;
}
break;
case ANCS_DATA_SRC_CHAR_UUID:
{
Ancs_handleCache[HDL_ANCS_DATA_SRC_START] = handle;
Ancs_endHdlIdx = HDL_ANCS_DATA_SRC_END;
}
break;
default:
break;
}
pHandleValuePairList += CHAR_DESC_HDL_UUID128_LEN;
}
} // If procedure complete
if ((pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete) ||(pMsg->method == ATT_ERROR_RSP))
{
// Special case of end handle at end of service
if (Ancs_endHdlIdx != 0)
{
Ancs_handleCache[Ancs_endHdlIdx] = Ancs_svcEndHdl;
Ancs_endHdlIdx = 0;
}
// If notification source char is missing, there is something wrong
if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] == 0)
{
discoveryState = DISC_FAILED;
}
else if (Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] < Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END])
{
// Discover ANCS Notification Source CCCD
temp_status=GATT_DiscAllCharDescs(Ancs_connHandle, Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] + 1, Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END], ICall_getEntityId());
if(temp_status == SUCCESS)
{
isNotifCCCD = TRUE;
discoveryState = DISC_ANCS_CCCD;
}
else
{
temp_status=GATT_DiscAllCharDescs(Ancs_connHandle, Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] + 1, Ancs_handleCache[HDL_ANCS_NTF_NOTIF_END], ICall_getEntityId());
if(temp_status == SUCCESS)
{
isNotifCCCD = TRUE;
discoveryState = DISC_ANCS_CCCD;
}
}
}
else
{
// Missing required characteristic descriptor
Ancs_handleCache[HDL_ANCS_NTF_NOTIF_START] = 0;
discoveryState = DISC_FAILED;
}
}
// Discover all characteristics of ANCS service until end handle
else
{
temp_status=GATT_DiscAllChars(Ancs_connHandle, handle+1, Ancs_svcEndHdl, ICall_getEntityId());
if(temp_status == SUCCESS)
{
}
else
{
GATT_DiscAllChars(Ancs_connHandle, handle+1, Ancs_svcEndHdl, ICall_getEntityId());
}
}
}
break;
case DISC_ANCS_CCCD:
{
// Characteristic descriptors found
if (pMsg->method == ATT_FIND_INFO_RSP && pMsg->msg.findInfoRsp.numInfo > 0 && pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE)
{
uint8_t i; // For each handle/uuid pair
for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++)
{
// Look for CCCD
if (ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) == GATT_CLIENT_CHAR_CFG_UUID)
{
// CCCD found
// if it is Notification Source CCCD
if (isNotifCCCD == TRUE)
{
Ancs_handleCache[HDL_ANCS_NTF_CCCD] = ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
}
// else it is Data Source CCCD
else
{
Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] = ATT_BT_PAIR_HANDLE(pMsg->msg.findInfoRsp.pInfo, i);
}
break;
}
}
} // If procedure complete
if ((pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP))
{
// Discover ANCS Data Source characteristic descriptors
if (isNotifCCCD == TRUE && Ancs_handleCache[HDL_ANCS_DATA_SRC_CCCD] == 0)
{
temp_status=GATT_DiscAllCharDescs(Ancs_connHandle,Ancs_handleCache[HDL_ANCS_DATA_SRC_START] + 1, Ancs_handleCache[HDL_ANCS_DATA_SRC_END], ICall_getEntityId());
if(temp_status == SUCCESS)
{
isNotifCCCD = FALSE;
}
else
{
temp_status=GATT_DiscAllCharDescs(Ancs_connHandle,Ancs_handleCache[HDL_ANCS_DATA_SRC_START] + 1, Ancs_handleCache[HDL_ANCS_DATA_SRC_END], ICall_getEntityId());
if(temp_status == SUCCESS)
{
isNotifCCCD = FALSE;
}
}
}
else
{
discoveryState = DISC_IDLE;
ancsAppState = ANCS_STATE_READY;
while (SUCCESS != Ancs_subsNotifSrc()){}
while (SUCCESS != Ancs_subsDataSrc()){}
display_timer_data(14,"ancs6",5);
}
}
}
break;
default:
break;
}
}
void Ancs_disconnected(void)
{
// Initialize state variables
//AncsApp_discState = DISC_IDLE;
ancsAppState = ANCS_STATE_IDLE;
Ancs_unSubsNotifSrc();
Ancs_unSubsDataSrc();
// Invalidate connection variables.
Ancs_connHandle = 0xffff;
}
/******************************************************************************
@file ancs.h
@brief This file contains the Simple BLE Peripheral sample application
definitions and prototypes.
Group: WCS, BTS
Target Device: CC2640R2
******************************************************************************/
#ifndef ANCS_H
#define ANCS_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "SensorUtil.h"
/*********************************************************************
* INCLUDES
*/
// ANCS discovery states
enum
{
DISC_IDLE = 0x00, // Idle state
DISC_ANCS_START = 0x10, // ANCS service
DISC_ANCS_SVC, // Discover service
DISC_ANCS_CHAR, // Discover all characteristics
DISC_ANCS_CCCD, // Discover ANCS CCCD
DISC_FAILED = 0xFF // Discovery failed
};// ANCS handle cache indexes
enum
{
HDL_ANCS_NTF_NOTIF_START, // ANCS notification characteristic start handle
HDL_ANCS_NTF_NOTIF_END, // ANCS notification characteristic end handle
HDL_ANCS_NTF_CCCD, // ANCS notification CCCD
HDL_ANCS_CTRL_PT_START,
HDL_ANCS_CTRL_PT_END,
HDL_ANCS_DATA_SRC_START, // ANCS data source characteristic start handle
HDL_ANCS_DATA_SRC_END, // ANCS data source characteristic end handle
HDL_ANCS_DATA_SRC_CCCD, // ANCS data source CCCD
HDL_CACHE_LEN
};
enum
{
ANCS_STATE_IDLE = 0,
ANCS_STATE_DISCOVERY,
ANCS_STATE_READY,
};
/********************************************************************* * TYPEDEFS */
typedef int32 notificationUID_t;
typedef struct
{
uint8 attrID; //
uint16 maxLen; // Some attributes need to have length
} ctrlPtCmdParamAttrWithLen_t;
typedef struct
{
uint8 attrID; //
} ctrlPtCmdParamAttr_t;
typedef struct _ancsCSKey_t
{
uint_least16_t hwikey;
uint_least16_t taskkey;
} _ancsCSKey_t;
/********************************************************************* * MACROS */
// CommandID Values
#define CommandIDGetNotificationAttributes 0 // CommandIDGetNotificationAttributes
#define CommandIDGetAppAttributes 1 // CommandIDGetAppAttributes
#define CommandIDPerformNotificationAction 2 // CommandIDPerformNotificationAction
#define ActionIDPositive 0
#define ActionIDNegative 1// Notification AttributeID Values
#define NotificationAttributeIDAppIdentifier 0 //
#define NotificationAttributeIDTitle 1 // (Needs to be followed by a 2-bytes max length parameter)
#define NotificationAttributeIDSubtitle 2 // (Needs to be followed by a 2-bytes max length parameter)
#define NotificationAttributeIDMessage 3 // (Needs to be followed by a 2-bytes max length parameter)
#define NotificationAttributeIDMessageSize 4
#define NotificationAttributeIDDate 5
#define NotificationAttributeIDPositiveActionLabel 6
#define NotificationAttributeIDNegativeActionLabel 7// EventID Values
#define EventIDNotificationAdded 0
#define EventIDNotificationModified 1
#define EventIDNotificationRemoved 2// EventFlags
#define EventFlagSilent 0x01 // (1 << 0)
#define EventFlagImportant 0x02 // (1 << 1)
#define EventFlagPreExisting 0x04 // (1 << 2)
#define EventFlagPositiveAction 0x08 // (1 << 3)
#define EventFlagNegativeAction 0x10 // (1 << 4)// CategoryID Values
#define CategoryIDOther 0
#define CategoryIDIncomingCall 1
#define CategoryIDMissedCall 2
#define CategoryIDVoicemail 3
#define CategoryIDSocial 4
#define CategoryIDSchedule 5
#define CategoryIDEmail 6
#define CategoryIDNews 7
#define CategoryIDHealthAndFitness 8
#define CategoryIDBusinessAndFinance 9
#define CategoryIDLocation 10
#define CategoryIDEntertainment 11//Define ANCS Client Flags
#define CLIENT_NONE 0x00
#define CLIENT_IMPORTANT_ALERT 0x01
#define CLIENT_POSITIVE_ACT 0x02
#define CLIENT_NEG_ACT 0x04
/********************************************************************* * GLOBAL */
enum
{
CCCD_CONFIG_NOTIF = 0x00,
CCCD_CONFIG_DATA,
CCCD_CONFIG_DONE
};// Connection handleextern
/********************************************************************* * FUNCTIONS */
/* * ANCS service discovery functions. */
extern void Ancs_disconnected(void);
extern void Ancs_discoverService(gattMsgEvent_t *pMsg);
extern uint8_t Ancs_discStart(void);
extern uint8_t Ancs_discGattMsg(uint8_t state, gattMsgEvent_t *pMsg);
extern uint8_t Ancs_subsNotifSrc(void);
extern uint8_t Ancs_unSubsNotifSrc(void);
extern uint8_t Ancs_subsDataSrc(void);
extern uint8_t Ancs_unSubsDataSrc(void);
extern void Ancs_performPositiveAction();
extern void Ancs_performNegativeAction();
/* * ANCS notification handling function. */
extern void Ancs_handleNotification(gattMsgEvent_t *pMsg);
/*********************************************************************
*********************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* SIMPLEBLEPERIPHERAL_H */
5.官方;https://github.com/ti-simplelink/ble_examples/tree/ble_examples-2.1/Projects/ble/ancs