BLE_TYQ_BJQ_CH584M/APP/multiCentral.c

1252 lines
45 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************************
* INCLUDES
*/
#include "CONFIG.h"
#include "gattprofile.h"
#include "multiCentral.h"
#include "bsp_uart.h"
#include "log.h"
#undef LOG_ENABLE
#define LOG_ENABLE 1
/*********************************************************************
* MACROS
*/
// Length of bd addr as a string
#define B_ADDR_STR_LEN 15
/*********************************************************************
* CONSTANTS
*/
// Maximum number of scan responses
#define DEFAULT_MAX_SCAN_RES 10
// Scan duration in 0.625ms 扫描窗口要小于等于扫描间隔
#define DEFAULT_SCAN_DURATION 2400
// Connection min interval in 1.25ms
#define DEFAULT_MIN_CONNECTION_INTERVAL 20 //25ms连接一次 范围为7.5ms~4s之间
// Connection max interval in 1.25ms
#define DEFAULT_MAX_CONNECTION_INTERVAL 100 //125ms连接一次
// Connection supervision timeout in 10ms
#define DEFAULT_CONNECTION_TIMEOUT 100 //10100ms~320032s
// Discovey mode (limited, general, all)
#define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL
// TRUE to use active scan
#define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE
// TRUE to use white list during discovery
// #define DEFAULT_DISCOVERY_WHITE_LIST FALSE
#define DEFAULT_DISCOVERY_WHITE_LIST FALSE
// TRUE to use high scan duty cycle when creating link
#define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE
// TRUE to use white list when creating link
#define DEFAULT_LINK_WHITE_LIST FALSE
// Default read RSSI period in 0.625ms
#define DEFAULT_RSSI_PERIOD 2400
// Minimum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 100
// Maximum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 400
// Slave latency to use parameter update
#define DEFAULT_UPDATE_SLAVE_LATENCY 5
// Supervision timeout value (units of 10ms)
#define DEFAULT_UPDATE_CONN_TIMEOUT 200
// Default passcode
#define DEFAULT_PASSCODE 0
// Default GAP pairing mode
#define DEFAULT_PAIRING_MODE GAPBOND_PAIRING_MODE_WAIT_FOR_REQ
// Default MITM mode (TRUE to require passcode or OOB when pairing)
#define DEFAULT_MITM_MODE TRUE
// Default bonding mode, TRUE to bond, max bonding 6 devices
#define DEFAULT_BONDING_MODE TRUE
// Default GAP bonding I/O capabilities
#define DEFAULT_IO_CAPABILITIES GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT
// Default service discovery timer delay in 0.625ms
#define DEFAULT_SVC_DISCOVERY_DELAY 1600
// Default parameter update delay in 0.625ms
#define DEFAULT_PARAM_UPDATE_DELAY 3200
// Default read or write timer delay in 0.625ms
#define DEFAULT_READ_OR_WRITE_DELAY 100
// Default write CCCD delay in 0.625ms
#define DEFAULT_WRITE_CCCD_DELAY 1600
// Establish link timeout in 0.625ms
#define ESTABLISH_LINK_TIMEOUT 3200
// Application states
enum
{
BLE_STATE_IDLE,
BLE_STATE_CONNECTING,
BLE_STATE_CONNECTED,
BLE_STATE_DISCONNECTING
};
// Discovery states
enum
{
BLE_DISC_STATE_IDLE, // Idle
BLE_DISC_STATE_SVC, // Service discovery
BLE_DISC_STATE_CHAR, // Characteristic discovery
BLE_DISC_STATE_CCCD, // client characteristic configuration discovery
};
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
// Task ID for internal task/event processing
static uint8_t centralTaskId;
// Number of scan results
static uint8_t centralScanRes;
// Scan result list
static gapDevRec_t centralDevList[DEFAULT_MAX_SCAN_RES];
// Peer device address
static peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = {
// {0xcf, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
{0xe1, 0X51, 0x89, 0x88, 0x19, 0x70},
// {0x03, 0x02, 0x03, 0xE4, 0xC2, 0x84},
};
// Connection item list
static centralConnItem_t centralConnList[CENTRAL_MAX_CONNECTION];
// Value to write
static uint8_t centralCharVal = 0x01;
// Value read/write toggle
static uint8_t centralDoWrite = TRUE;
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void centralProcessGATTMsg(gattMsgEvent_t *pMsg);
static void centralRssiCB(uint16_t connHandle, int8_t rssi);
static void centralEventCB(gapRoleEvent_t *pEvent);
static void centralHciMTUChangeCB(uint16_t connHandle, uint16_t maxTxOctets, uint16_t maxRxOctets);
static void centralPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
uint8_t uiInputs, uint8_t uiOutputs);
static void centralPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status);
static uint16_t connect0_ProcessEvent(uint8_t task_id, uint16_t events);
static void central_ProcessTMOSMsg(tmos_event_hdr_t *pMsg);
static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg);
static void centralConnIistStartDiscovery_0(void);
static void centralAddDeviceInfo(uint8_t *pAddr, uint8_t addrType);
static void centralInitConnItem(uint8_t task_id, centralConnItem_t *centralConnList);
static uint8_t centralAddrCmp(peerAddrDefItem_t *PeerAddrDef, uint8_t *addr);
static void centralConnIistStartDiscovery_1(void);
static uint16_t connect1_ProcessEvent(uint8_t task_id, uint16_t events);
/*********************************************************************
* PROFILE CALLBACKS
*/
// GAP Role Callbacks
static gapCentralRoleCB_t centralRoleCB = {
centralRssiCB, // RSSI callback
centralEventCB, // Event callback
centralHciMTUChangeCB // MTU change callback
};
// Bond Manager Callbacks
static gapBondCBs_t centralBondCB = {
centralPasscodeCB,// 连接时需要使用有密码的函数。
centralPairStateCB//配对时的回调函数
};
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn Central_Init
*
* @brief Initialization function for the Central App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notification).
*
* @param task_id - the ID assigned by TMOS. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void Central_Init()
{
centralTaskId = TMOS_ProcessEventRegister(Central_ProcessEvent);//注册事件处理函数,将返回的任务赋值给变量
// Setup GAP
GAP_SetParamValue(TGAP_DISC_SCAN_WIND, DEFAULT_SCAN_DURATION);//扫描窗口
GAP_SetParamValue(TGAP_DISC_SCAN, DEFAULT_SCAN_DURATION);//扫描连续时间单位0.625ms 4800*0.625ms = 3000ms
GAP_SetParamValue(TGAP_DISC_SCAN_INT, DEFAULT_SCAN_DURATION);////扫描间隔,需要>=扫描窗口
GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, DEFAULT_MIN_CONNECTION_INTERVAL);////设置链路层连接间隔,这里是最小连接间隔
GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, DEFAULT_MAX_CONNECTION_INTERVAL);//最大连续间隔
GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);//连接超时时间
// Setup the GAP Bond Manager
{
uint32_t passkey = DEFAULT_PASSCODE;//PASSKEY 是在配对过程中用于验证设备身份的一种方式
uint8_t pairMode = DEFAULT_PAIRING_MODE;//(配对模式)配对模式定义了设备进行配对过程中的行为和要求
uint8_t mitm = DEFAULT_MITM_MODE;//MIMT模式定义了是否需要保护免受中间人攻击的配对过程
uint8_t ioCap = DEFAULT_IO_CAPABILITIES;//IO能力定义了设备对配对过程的输入输出能力
uint8_t bonding = DEFAULT_BONDING_MODE;//(绑定模式)绑定模式定义了设备在配对后是否应该建立安全的绑定关系
GAPBondMgr_SetParameter(GAPBOND_CENT_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
GAPBondMgr_SetParameter(GAPBOND_CENT_PAIRING_MODE, sizeof(uint8_t), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_CENT_MITM_PROTECTION, sizeof(uint8_t), &mitm);
GAPBondMgr_SetParameter(GAPBOND_CENT_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_CENT_BONDING_ENABLED, sizeof(uint8_t), &bonding);
}
// Init Connection Item
centralInitConnItem(centralTaskId, centralConnList);
// Initialize GATT Client
GATT_InitClient();//初始化通用规范属性客户端
// Register to receive incoming ATT Indications/Notifications
GATT_RegisterForInd(centralTaskId);
// Setup a delayed profile startup
tmos_set_event(centralTaskId, START_DEVICE_EVT);
}
/*********************************************************************
* @fn centralInitConnItem
*
* @brief Init Connection Item
*
* @param task_id -
* centralConnList -
*
* @return NULL
*/
static void centralInitConnItem(uint8_t task_id, centralConnItem_t *centralConnList)
{
uint8_t connItem;
for(connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
{
centralConnList[connItem].taskID = TMOS_ProcessEventRegister(Central_ProcessEvent);
centralConnList[connItem].connHandle = GAP_CONNHANDLE_INIT;
centralConnList[connItem].state = BLE_STATE_IDLE;
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
centralConnList[connItem].procedureInProgress = FALSE;
centralConnList[connItem].charHdl = 0;
centralConnList[connItem].svcStartHdl = 0;
centralConnList[connItem].svcEndHdl = 0;
centralConnList[connItem].cccHdl = 0;
}
}
/*********************************************************************
* @fn Central_ProcessEvent
*
* @brief Central Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*中央应用程序任务事件处理器。调用此函数来处理任务的所有事件。事件包括定时器、消息和任何其他用户定义的事件。
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed
*/
uint16_t Central_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(centralTaskId)) != NULL)
{
central_ProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if(events & START_DEVICE_EVT)
{
// Start the Device 启动设备
GAPRole_CentralStartDevice(centralTaskId, &centralBondCB, &centralRoleCB);
return (events ^ START_DEVICE_EVT);
}
//终止现有连接
if(events & ESTABLISH_LINK_TIMEOUT_EVT)
{
GAPRole_TerminateLink(INVALID_CONNHANDLE);
return (events ^ ESTABLISH_LINK_TIMEOUT_EVT);
}
if(task_id == centralConnList[CONNECT0_ITEM].taskID)
{
return connect0_ProcessEvent(task_id, events);
}
else if(task_id == centralConnList[CONNECT1_ITEM].taskID)
{
return connect1_ProcessEvent(task_id, events);
}
// else if(task_id == centralConnList[CONNECT2_ITEM].taskID)
// {
// return connect2_ProcessEvent(task_id, events);
// }
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn connect0_ProcessEvent
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static uint16_t connect0_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & START_SVC_DISCOVERY_EVT)
{
// start service discovery
centralConnIistStartDiscovery_0();
return (events ^ START_SVC_DISCOVERY_EVT);
}
if(events & START_READ_OR_WRITE_EVT)
{
if(centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
{
if(centralDoWrite)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT0_ITEM].charHdl;
req.len = 1;
req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
*req.pValue = centralCharVal;
if(GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
else
{
// Do a read
attReadReq_t req;
req.handle = centralConnList[CONNECT0_ITEM].charHdl;
if(GATT_ReadCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
}
}
}
return (events ^ START_READ_OR_WRITE_EVT);
}
if(events & START_PARAM_UPDATE_EVT)
{
// start connect parameter update
GAPRole_UpdateLink(centralConnList[CONNECT0_ITEM].connHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT);
return (events ^ START_PARAM_UPDATE_EVT);
}
if(events & START_WRITE_CCCD_EVT)
{
if(centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT0_ITEM].cccHdl;
req.len = 2;
req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
req.pValue[0] = 1;
req.pValue[1] = 0;
if(GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
return (events ^ START_WRITE_CCCD_EVT);
}
if(events & START_READ_RSSI_EVT)
{
GAPRole_ReadRssiCmd(centralConnList[CONNECT0_ITEM].connHandle);
tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
return (events ^ START_READ_RSSI_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn connect1_ProcessEvent
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static uint16_t connect1_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & START_SVC_DISCOVERY_EVT)
{
// start service discovery
centralConnIistStartDiscovery_1();
return (events ^ START_SVC_DISCOVERY_EVT);
}
if(events & START_READ_OR_WRITE_EVT)
{
if(centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
{
if(centralDoWrite)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT1_ITEM].charHdl;
req.len = 1;//发送的长度
req.pValue = GATT_bm_alloc(centralConnList[CONNECT1_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
*req.pValue = centralCharVal;//发送的数据
if(GATT_WriteCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)//发送函数
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
tmos_start_task(centralConnList[CONNECT1_ITEM].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
else
{
// Do a read
attReadReq_t req;
req.handle = centralConnList[CONNECT1_ITEM].charHdl;
if(GATT_ReadCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)//读取函数
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
}
}
}
return (events ^ START_READ_OR_WRITE_EVT);
}
if(events & START_PARAM_UPDATE_EVT)
{
// start connect parameter update
GAPRole_UpdateLink(centralConnList[CONNECT1_ITEM].connHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT);
return (events ^ START_PARAM_UPDATE_EVT);
}
if(events & START_WRITE_CCCD_EVT)
{
if(centralConnList[CONNECT1_ITEM].procedureInProgress == FALSE)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT1_ITEM].cccHdl;
req.len = 2;
req.pValue = GATT_bm_alloc(centralConnList[CONNECT1_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
req.pValue[0] = 1;
req.pValue[1] = 0;
if(GATT_WriteCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
return (events ^ START_WRITE_CCCD_EVT);
}
if(events & START_READ_RSSI_EVT)
{
GAPRole_ReadRssiCmd(centralConnList[CONNECT1_ITEM].connHandle);
tmos_start_task(centralConnList[CONNECT1_ITEM].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
return (events ^ START_READ_RSSI_EVT);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn central_ProcessTMOSMsg
*
* @brief Process an incoming task message.
*
* @param pMsg - message to process
*
* @return none
*/
static void central_ProcessTMOSMsg(tmos_event_hdr_t *pMsg)
{
switch(pMsg->event)
{
case GATT_MSG_EVENT:
centralProcessGATTMsg((gattMsgEvent_t *)pMsg);
break;
}
}
/*********************************************************************
* @fn centralProcessGATTMsg
*
* @brief Process GATT messages
*
* @return none
*/
static void centralProcessGATTMsg(gattMsgEvent_t *pMsg)
{
uint8_t connItem;
for(connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
{
if(centralConnList[connItem].connHandle == pMsg->connHandle)
break;
}
if(connItem == CENTRAL_MAX_CONNECTION)
{
return;
// Should not go there
}
if(centralConnList[connItem].state != BLE_STATE_CONNECTED)
{
// In case a GATT message came after a connection has dropped,
// ignore the message
GATT_bm_free(&pMsg->msg, pMsg->method);
return;
}
if((pMsg->method == ATT_EXCHANGE_MTU_RSP) || ((pMsg->method == ATT_ERROR_RSP) &&
(pMsg->msg.errorRsp.reqOpcode == ATT_EXCHANGE_MTU_REQ)))
{
if(pMsg->method == ATT_ERROR_RSP)
{
uint8_t status = pMsg->msg.errorRsp.errCode;
PRINT("Exchange MTU Error: %x\r\n", status);
}
centralConnList[connItem].procedureInProgress = FALSE;
}
if(pMsg->method == ATT_MTU_UPDATED_EVENT)
{
PRINT("MTU: %x\r\n", pMsg->msg.mtuEvt.MTU);
}
if((pMsg->method == ATT_READ_RSP) ||
((pMsg->method == ATT_ERROR_RSP) &&
(pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
{
if(pMsg->method == ATT_ERROR_RSP)
{
uint8_t status = pMsg->msg.errorRsp.errCode;
PRINT("Read Error: %x\r\n", status);
}
else
{
// After a successful read, display the read value
PRINT("Read rsp: %x\r\n", *pMsg->msg.readRsp.pValue);
}
centralConnList[connItem].procedureInProgress = FALSE;
}
else if((pMsg->method == ATT_WRITE_RSP) ||
((pMsg->method == ATT_ERROR_RSP) &&
(pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
{
if(pMsg->method == ATT_ERROR_RSP == ATT_ERROR_RSP)
{
uint8_t status = pMsg->msg.errorRsp.errCode;
PRINT("Write Error: %x\r\n", status);
}
else
{
// After a succesful write, display the value that was written and increment value
PRINT("Write sent: %x\r\n", centralCharVal);
}
centralConnList[connItem].procedureInProgress = FALSE;
}
else if(pMsg->method == ATT_HANDLE_VALUE_NOTI)
{
PRINT("Receive noti: %x\r\n", *pMsg->msg.handleValueNoti.pValue);
}
else if(centralConnList[connItem].discState != BLE_DISC_STATE_IDLE)
{
centralGATTDiscoveryEvent(connItem, pMsg);
}
GATT_bm_free(&pMsg->msg, pMsg->method);
}
/*********************************************************************
* @fn centralRssiCB
*
* @brief RSSI callback.
*
* @param connHandle - connection handle
* @param rssi - RSSI
*
* @return none
*/
static void centralRssiCB(uint16_t connHandle, int8_t rssi)
{
PRINT("RSSI -%d dB Conn - %x \r\n", -rssi, connHandle);
}
/*********************************************************************
* @fn centralHciMTUChangeCB
*
* @brief MTU changed callback.
*
* @param maxTxOctets - Max tx octets
* @param maxRxOctets - Max rx octets
*
* @return none
*/
static void centralHciMTUChangeCB(uint16_t connHandle, uint16_t maxTxOctets, uint16_t maxRxOctets)
{
}
/*********************************************************************
* @fn centralEventCB
*
* @brief Central event callback function.
*
* @param pEvent - pointer to event structure
*
* @return none
*/
static void centralEventCB(gapRoleEvent_t *pEvent)
{
uint8_t advdata[32] = {0};
switch(pEvent->gap.opcode)
{
case GAP_DEVICE_INIT_DONE_EVENT:
{
PRINT("Discovering...\r\n");
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);//开始扫描设备
}
break;
case GAP_DEVICE_INFO_EVENT:
{
// Add device to list
centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
}
break;
case GAP_DEVICE_DISCOVERY_EVENT:
{
uint8_t i;
// See if peer device has been discovered
for(i = 0; i < centralScanRes; i++)
{
if(centralAddrCmp(PeerAddrDef, centralDevList[i].addr))
break;
}
/*Peer device not found*/
if(i == centralScanRes)
{
PRINT("Device not found...\r\n");
centralScanRes = 0;
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
PRINT("Discovering...\r\n");
}
else// Peer device found
{
PRINT("Device found...\r\n");
GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
DEFAULT_LINK_WHITE_LIST,
centralDevList[i].addrType,
centralDevList[i].addr);
// Start establish link timeout event
tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);
PRINT("Connecting...\r\n");
}
}
break;
case GAP_LINK_ESTABLISHED_EVENT:
{
tmos_stop_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT);//关闭连接超时任务
if(pEvent->gap.hdr.status == SUCCESS)
{
uint8_t connItem;
for(connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
{
if(centralConnList[connItem].connHandle == GAP_CONNHANDLE_INIT)
break;
}
if(connItem == CENTRAL_MAX_CONNECTION)
{
GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
PRINT("Connection max...\r\n");
}
else
{
centralConnList[connItem].state = BLE_STATE_CONNECTED;
centralConnList[connItem].connHandle = pEvent->linkCmpl.connectionHandle;
PRINT("Conn %x - Int %x \r\n", pEvent->linkCmpl.connectionHandle, pEvent->linkCmpl.connInterval);
if(connItem == CONNECT0_ITEM)
{
centralConnList[connItem].procedureInProgress = TRUE;
// Initiate service discovery 开启枚举服务任务
tmos_start_task(centralConnList[connItem].taskID, START_SVC_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY);
// Initiate connect parameter update 开始连接参数更新任务
tmos_start_task(centralConnList[connItem].taskID, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);
// Start RSSI polling
tmos_start_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
}
// else if(connItem == CONNECT1_ITEM)
// {
// }
// else if(connItem == CONNECT2_ITEM)
// {
// }
PRINT("Connected...\r\n");
// See if need discover again
for(connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
{
if(centralConnList[connItem].connHandle == GAP_CONNHANDLE_INIT)
break;
}
if(connItem < CENTRAL_MAX_CONNECTION)
{
PRINT("Discovering...\r\n");
centralScanRes = 0;
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
}
}
}
else
{
PRINT("Connect Failed...Reason:%X\r\n", pEvent->gap.hdr.status);
PRINT("Discovering...\r\n");
centralScanRes = 0;
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);//重新开始扫描
}
}
break;
case GAP_LINK_TERMINATED_EVENT: //断开连接事件,打印断开连接原因,并重新开始扫描
{
uint8_t connItem;
for(connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
{
if(centralConnList[connItem].connHandle == pEvent->linkTerminate.connectionHandle)
break;
}
if(connItem == CENTRAL_MAX_CONNECTION)
{
// Should not go there
}
PRINT(" %x Disconnected...Reason:%x\r\n", centralConnList[connItem].connHandle, pEvent->linkTerminate.reason);
centralConnList[connItem].state = BLE_STATE_IDLE;
centralConnList[connItem].connHandle = GAP_CONNHANDLE_INIT;
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
centralConnList[connItem].charHdl = 0;
centralConnList[connItem].procedureInProgress = FALSE;
centralScanRes = 0;
tmos_stop_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT);
PRINT("Discovering...\r\n");
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
}
break;
case GAP_LINK_PARAM_UPDATE_EVENT:
{
PRINT("Update %x - Int %x \r\n", pEvent->linkUpdate.connectionHandle, pEvent->linkUpdate.connInterval);
}
break;
default:
break;
}
}
/*********************************************************************
* @fn pairStateCB
*
* @brief Pairing state callback.
*
* @return none
*/
static void centralPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status)
{
if(state == GAPBOND_PAIRING_STATE_STARTED)
{
PRINT("Connection %04x - Pairing started:%d\r\n", connHandle, status);
}
else if(state == GAPBOND_PAIRING_STATE_COMPLETE)
{
if(status == SUCCESS)
{
PRINT("Connection %04x - Pairing success\r\n", connHandle);
}
else
{
PRINT("Connection %04x - Pairing fail\r\n", connHandle);
}
}
else if(state == GAPBOND_PAIRING_STATE_BONDED)
{
if(status == SUCCESS)
{
PRINT("Connection %04x - Bonding success\r\n", connHandle);
}
}
else if(state == GAPBOND_PAIRING_STATE_BOND_SAVED)
{
if(status == SUCCESS)
{
PRINT("Connection %04x - Bond save success\r\n", connHandle);
}
else
{
PRINT("Connection %04x - Bond save failed: %d\r\n", connHandle, status);
}
}
}
/*********************************************************************
* @fn centralPasscodeCB
*
* @brief Passcode callback.
*
* @return none
*/
static void centralPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
uint8_t uiInputs, uint8_t uiOutputs)
{
uint32_t passcode;
// Create random passcode
passcode = tmos_rand();
passcode %= 1000000;
// Display passcode to user
if(uiOutputs != 0)
{
PRINT("Passcode:%06d\r\n", (int)passcode);
}
// Send passcode response
GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
}
/*********************************************************************
* @fn centralConnIistStartDiscovery_0
*
* @brief Start connection 0 service discovery.
*
* @return none
*/
static void centralConnIistStartDiscovery_0(void)
{
uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)};
// Initialize cached handles
centralConnList[CONNECT0_ITEM].svcStartHdl = centralConnList[CONNECT0_ITEM].svcEndHdl = centralConnList[CONNECT0_ITEM].charHdl = 0;
centralConnList[CONNECT0_ITEM].discState = BLE_DISC_STATE_SVC;
// Discovery simple BLE service
GATT_DiscPrimaryServiceByUUID(centralConnList[CONNECT0_ITEM].connHandle,
uuid,
ATT_BT_UUID_SIZE,
centralTaskId);
}
/*********************************************************************
* @fn centralConnIistStartDiscovery_1
*
* @brief Start connection 1 service discovery.
*
* @return none
*/
static void centralConnIistStartDiscovery_1(void)
{
uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)};
// Initialize cached handles
centralConnList[CONNECT1_ITEM].svcStartHdl = centralConnList[CONNECT1_ITEM].svcEndHdl = centralConnList[CONNECT1_ITEM].charHdl = 0;
centralConnList[CONNECT1_ITEM].discState = BLE_DISC_STATE_SVC;
// Discovery simple BLE service
GATT_DiscPrimaryServiceByUUID(centralConnList[CONNECT1_ITEM].connHandle,
uuid,
ATT_BT_UUID_SIZE,
centralTaskId);
}
/*********************************************************************
* @fn centralGATTDiscoveryEvent
*
* @brief Process GATT discovery event
*
* @return none
*/
static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg)
{
attReadByTypeReq_t req;
if(connItem == CONNECT0_ITEM)
{
if(centralConnList[connItem].discState == BLE_DISC_STATE_SVC)
{
// Service found, store handles
if(pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
centralConnList[connItem].svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
centralConnList[connItem].svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
// Display Profile Service handle range
PRINT("Found Profile Service handle : %x ~ %x \r\n", centralConnList[connItem].svcStartHdl, centralConnList[connItem].svcEndHdl);
}
// If procedure complete
if((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP))
{
if(centralConnList[connItem].svcStartHdl != 0)
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CHAR;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CHAR)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do read or write
tmos_start_task(centralConnList[connItem].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);//开启一个读写测试任务
// Display Characteristic 1 handle
PRINT("Found Characteristic 1 handle : %x \r\n", centralConnList[0].charHdl);
}
if((pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP))
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CCCD;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);//根据UUID寻找其句柄
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CCCD)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].cccHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do write CCCD
tmos_start_task(centralConnList[connItem].taskID, START_WRITE_CCCD_EVT, DEFAULT_WRITE_CCCD_DELAY);//开启一个使能从机notify的定时器任务
// Display Characteristic 1 handle
PRINT("Found client characteristic configuration handle : %x \r\n", centralConnList[connItem].cccHdl);//输出的句柄值
}
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
}
}
else if(connItem == CONNECT1_ITEM)
{
if(centralConnList[connItem].discState == BLE_DISC_STATE_SVC)
{
// Service found, store handles
if(pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
centralConnList[connItem].svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
centralConnList[connItem].svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
// Display Profile Service handle range
PRINT("Found Profile Service handle : %x ~ %x \r\n", centralConnList[connItem].svcStartHdl, centralConnList[connItem].svcEndHdl);
}
// If procedure complete
if((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
if(centralConnList[connItem].svcStartHdl != 0)
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CHAR;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CHAR)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do read or write
tmos_start_task(centralConnList[connItem].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
// Display Characteristic 1 handle
PRINT("Found Characteristic 1 handle : %x \r\n", centralConnList[0].charHdl);
}
if((pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CCCD;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CCCD)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].cccHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do write CCCD
tmos_start_task(centralConnList[connItem].taskID, START_WRITE_CCCD_EVT, DEFAULT_WRITE_CCCD_DELAY);
// Display Characteristic 1 handle
PRINT("Found client characteristic configuration handle : %x \r\n", centralConnList[connItem].cccHdl);
}
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
}
}
// else if(connItem == CONNECT2_ITEM)
// {
// }
}
/*********************************************************************
* @fn centralAddDeviceInfo
*
* @brief Add a device to the device discovery result list
*
* @return none
*/
static void centralAddDeviceInfo(uint8_t *pAddr, uint8_t addrType)
{
uint8_t i;
// If result count not at max
if(centralScanRes < DEFAULT_MAX_SCAN_RES)
{
// Check if device is already in scan results
for(i = 0; i < centralScanRes; i++)
{
if(tmos_memcmp(pAddr, centralDevList[i].addr, B_ADDR_LEN))
{
return;
}
}
// Add addr to scan result list
tmos_memcpy(centralDevList[centralScanRes].addr, pAddr, B_ADDR_LEN);
centralDevList[centralScanRes].addrType = addrType;
// Increment scan result count
centralScanRes++;
// Display device addr
PRINT("Device %d - Addr %x %x %x %x %x %x \r\n", centralScanRes,
centralDevList[centralScanRes - 1].addr[0],
centralDevList[centralScanRes - 1].addr[1],
centralDevList[centralScanRes - 1].addr[2],
centralDevList[centralScanRes - 1].addr[3],
centralDevList[centralScanRes - 1].addr[4],
centralDevList[centralScanRes - 1].addr[5]);
}
}
/*********************************************************************
* @fn centralAddrCmp
*
* @brief none
*
* @return none
*/
static uint8_t centralAddrCmp(peerAddrDefItem_t *PeerAddrDef, uint8_t *addr)
{
uint8_t i;
for(i = 0; i < CENTRAL_MAX_CONNECTION; i++)
{
if(tmos_memcmp(PeerAddrDef[i].peerAddr, addr, B_ADDR_LEN))
break;
}
if(i == CENTRAL_MAX_CONNECTION)
{
return FALSE;
}
else
{
return TRUE;
}
}
/************************ endfile @ central **************************/