// Discover Service void BLECtrlDiscoverService(uint16 connHandle, uint8 task_id) { GATT_DiscPrimaryServiceByUUID( connHandle, blectrlServUUID, blectrlServUUIDLen, task_id ); // TODO Verify uuid_len == 2 }
/********************************************************************* * @fn oadManagerSvcDiscovery * * @brief OAD Service discovery. * * @return none */ static void oadManagerSvcDiscovery(void) { uint8 oadServUUID[ATT_UUID_SIZE] = { TI_BASE_UUID_128( OAD_SERVICE_UUID ) }; // Initialize service discovery variables oadSvcStartHdl = oadSvcEndHdl = 0; if (GATT_DiscPrimaryServiceByUUID(oadManagerConnHandle, oadServUUID, ATT_UUID_SIZE, oadManagerTaskId) != SUCCESS) { (void)osal_set_event(oadManagerTaskId, SVC_DISCOVERY_EVT); } }
/********************************************************************* * @fn controlBLECentralStartDiscovery * * @brief Start service discovery. * * @return none */ static void controlBLECentralStartDiscovery( void ) { uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(PARAM_BLE_CAR_IN_PROFILE_SERV_UUID), HI_UINT16(PARAM_BLE_CAR_IN_PROFILE_SERV_UUID) }; // Initialize cached handles simpleBLESvcStartHdl = simpleBLESvcEndHdl = simpleBLECharHdl = 0; simpleBLEDiscState = BLE_DISC_STATE_SVC; // Discovery simple BLE service GATT_DiscPrimaryServiceByUUID( simpleBLEConnHandle, uuid, ATT_BT_UUID_SIZE, simpleBLETaskId ); }
static void simpleBLECentralStartDiscovery( void ){ uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(WANTED_SERVICE_UUID),HI_UINT16(WANTED_SERVICE_UUID ) }; // Initialize cached handles // HandleRangeStart = HandleRangeEnd = BLEChar.handle = 0; // Discovery simple BLE service uint8 dis_result; if(dis_result = GATT_DiscPrimaryServiceByUUID(CurrentConnectionInfo.Handle, uuid, ATT_BT_UUID_SIZE, MasterSlaveSwitchTaskID )){ LCDPrintText("GATT error:",0,PRINT_VALUE); //LCDPrintText("switch_time:",record_switch_times,PRINT_VALUE); } }
/********************************************************************* * @fn SimpleServiceDiscovery_discoverService * * @brief Perform discovery of the given simpleService_t structure. * This function is to be called inside the GATT discovery event * callback to process the service discovery. * * @param connHandle - connection handle * entity - ICall entity of the calling task * *service - pointer to the service struct * *pMsg - pointer to the received gattMsgEvent_t * * @return SIMPLE_DISCOVERY_SUCCESSFUL, SIMPLE_DISCOVERY_FINDING_SERVICE, * SIMPLE_DISCOVERY_FINDING_CHAR or SIMPLE_DISCOVERY_UNSUCCESSFUL. */ uint32_t SimpleServiceDiscovery_discoverService(uint16_t connHandle, ICall_EntityID entity, simpleService_t *service, gattMsgEvent_t *pMsg) { uint32_t retVal = 0; switch (discoveryState) { case BLE_DISC_STATE_IDLE: { discoveryState = BLE_DISC_STATE_SVC; // Discovery the service GATT_DiscPrimaryServiceByUUID(connHandle, service->uuid.uuid, service->uuid.len, entity); retVal = SIMPLE_DISCOVERY_FINDING_SERVICE; break; } case BLE_DISC_STATE_SVC: { // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { service->startHandle = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); service->endHandle = 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->startHandle != 0) { discoveryState = BLE_DISC_STATE_CHAR; GATT_DiscAllCharDescs(connHandle, service->startHandle, service->endHandle, entity); retVal = SIMPLE_DISCOVERY_FINDING_CHAR; } else { discoveryState = BLE_DISC_STATE_IDLE; retVal = SIMPLE_DISCOVERY_UNSUCCESSFUL; } } break; } case BLE_DISC_STATE_CHAR: { // Characteristic found, store handle if (pMsg->method == ATT_FIND_INFO_RSP) { if (pMsg->msg.findInfoRsp.numInfo > 0) { SimpleServiceDiscovery_processFindInfoRsp(pMsg->msg.findInfoRsp, service); } if (pMsg->hdr.status == bleProcedureComplete) { discoveryState = BLE_DISC_STATE_IDLE; retVal = SIMPLE_DISCOVERY_SUCCESSFUL; } } break; } default: break; } return retVal; }
/********************************************************************* * @fn simpleTopology_processGATTDiscEvent * * @brief Process GATT discovery event * * @return none */ static void simpleTopology_processGATTDiscEvent(gattMsgEvent_t *pMsg) { if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated LCD_WRITE_STRING_VALUE("MTU Size:", pMsg->msg.mtuEvt.MTU, 10, LCD_PAGE4); } else if (discState == BLE_DISC_STATE_MTU) { // MTU size response received, discover simple BLE service if (pMsg->method == ATT_EXCHANGE_MTU_RSP) { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID), HI_UINT16(SIMPLEPROFILE_SERV_UUID) }; discState = BLE_DISC_STATE_SVC; // Discovery simple BLE service VOID GATT_DiscPrimaryServiceByUUID(connHandle, uuid, ATT_BT_UUID_SIZE, selfEntity); } } else if (discState == BLE_DISC_STATE_SVC) { // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); 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 (svcStartHdl != 0) { attReadByTypeReq_t req; // Discover characteristic discState = BLE_DISC_STATE_CHAR; req.startHandle = svcStartHdl; req.endHandle = 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); VOID GATT_ReadUsingCharUUID(connHandle, &req, selfEntity); } } } else if (discState == BLE_DISC_STATE_CHAR) { // Characteristic found, store handle if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && (pMsg->msg.readByTypeRsp.numPairs > 0)) { //find index to store handle uint8_t connIndex = gapRoleInfo_Find(connHandle); charHdl[connIndex] = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0], pMsg->msg.readByTypeRsp.pDataList[1]); LCD_WRITE_STRING("Simple Svc Found", LCD_PAGE6); } discState = BLE_DISC_STATE_IDLE; } }
/********************************************************************* * @fn GlucoseDevInfoDisc * * @brief Current glucose service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8_t GlucoseDevInfoDisc(uint8_t state, gattMsgEvent_t *pMsg) { uint8_t newState = state; switch (state) { case DISC_DEVINFO_START: { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(DEVINFO_SERV_UUID), HI_UINT16(DEVINFO_SERV_UUID) }; // Initialize service discovery variables glucoseSvcStartHdl = glucoseSvcEndHdl = 0; glucoseEndHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID(glucCollConnHandle, uuid, ATT_BT_UUID_SIZE, glucCollTaskId); newState = DISC_DEVINFO_SVC; } break; case DISC_DEVINFO_SVC: // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { glucoseSvcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); glucoseSvcEndHdl = 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 (glucoseSvcStartHdl != 0) { // Discover all characteristics GATT_DiscAllChars(glucCollConnHandle, glucoseSvcStartHdl, glucoseSvcEndHdl, glucCollTaskId); newState = DISC_DEVINFO_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_DEVINFO_CHAR: { uint8_t i; uint8_t *p; uint16_t handle; uint16_t uuid; // Characteristics found if (pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN) { // For each characteristic declaration p = pMsg->msg.readByTypeRsp.pDataList; for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If UUID is of interest, store handle switch (uuid) { case MANUFACTURER_NAME_UUID: glucoseHdlCache[HDL_DEVINFO_MANUFACTURER_NAME] = handle; break; case SYSTEM_ID_UUID: glucoseHdlCache[HDL_DEVINFO_SYSTEM_ID] = handle; break; case MODEL_NUMBER_UUID: glucoseHdlCache[HDL_DEVINFO_MODEL_NUM] = handle; break; default: break; } p += CHAR_DESC_HDL_UUID16_LEN; } } // If procedure complete if ((pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { // If didn't find required device info if (glucoseHdlCache[HDL_DEVINFO_MANUFACTURER_NAME] == 0 || glucoseHdlCache[HDL_DEVINFO_SYSTEM_ID] == 0 || glucoseHdlCache[HDL_DEVINFO_MODEL_NUM] == 0) { newState = DISC_FAILED; } else { newState = DISC_IDLE; } } } break; default: break; } return newState; }
/********************************************************************* * @fn GlucoseDisc * * @brief Current glucose service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8_t GlucoseDisc(uint8_t state, gattMsgEvent_t *pMsg) { uint8_t newState = state; switch (state) { case DISC_GLUCOSE_START: { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(GLUCOSE_SERV_UUID), HI_UINT16(GLUCOSE_SERV_UUID) }; // Initialize service discovery variables glucoseSvcStartHdl = glucoseSvcEndHdl = 0; glucoseEndHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID(glucCollConnHandle, uuid, ATT_BT_UUID_SIZE, glucCollTaskId); newState = DISC_GLUCOSE_SVC; } break; case DISC_GLUCOSE_SVC: // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { glucoseSvcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); glucoseSvcEndHdl = 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 (glucoseSvcStartHdl != 0) { // Discover all characteristics GATT_DiscAllChars(glucCollConnHandle, glucoseSvcStartHdl, glucoseSvcEndHdl, glucCollTaskId); newState = DISC_GLUCOSE_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_GLUCOSE_CHAR: { uint8_t i; uint8_t *p; uint16_t handle; uint16_t uuid; // Characteristics found if (pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN) { // For each characteristic declaration p = pMsg->msg.readByTypeRsp.pDataList; for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If looking for end handle if (glucoseEndHdlIdx != 0) { // End handle is one less than handle of characteristic declaration glucoseHdlCache[glucoseEndHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1; glucoseEndHdlIdx = 0; } // If UUID is of interest, store handle switch (uuid) { case GLUCOSE_MEAS_UUID: glucoseHdlCache[HDL_GLUCOSE_START] = handle; glucoseEndHdlIdx = HDL_GLUCOSE_END; break; case GLUCOSE_CONTEXT_UUID: glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] = handle; glucoseEndHdlIdx = HDL_GLUCOSE_CONTEXT_END; break; case RECORD_CTRL_PT_UUID: glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] = handle; glucoseEndHdlIdx = HDL_GLUCOSE_CTL_PNT_END; break; case GLUCOSE_FEATURE_UUID: glucoseHdlCache[HDL_GLUCOSE_FEATURE] = handle; break; default: break; } p += CHAR_DESC_HDL_UUID16_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 (glucoseEndHdlIdx != 0) { glucoseHdlCache[glucoseEndHdlIdx] = glucoseSvcEndHdl; glucoseEndHdlIdx = 0; } // If didn't find glucose characteristic if (glucoseHdlCache[HDL_GLUCOSE_START] == 0) { newState = DISC_FAILED; } else if (glucoseHdlCache[HDL_GLUCOSE_START] < glucoseHdlCache[HDL_GLUCOSE_END]) { // Discover characteristic descriptors GATT_DiscAllCharDescs(glucCollConnHandle, glucoseHdlCache[HDL_GLUCOSE_START] + 1, glucoseHdlCache[HDL_GLUCOSE_END], glucCollTaskId); newState = DISC_GLUCOSE_CCCD; } else { newState = DISC_IDLE; } } } break; case DISC_GLUCOSE_CCCD: { uint8_t i; // Characteristic descriptors found if (pMsg->method == ATT_FIND_INFO_RSP && pMsg->msg.findInfoRsp.numInfo > 0 && pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) { attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp); // For each handle/uuid pair for (i = 0; i < pRsp->numInfo; i++) { // Look for CCCD if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID ) { // CCCD found glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] = ATT_BT_PAIR_HANDLE( pRsp->pInfo, i ); break; } } } // If procedure complete if ((pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { // If CCCD found if (glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] != 0) { // Should we look for unread category status CCCD if (glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] < glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_END]) { // Discover unread category status characteristic descriptors GATT_DiscAllCharDescs(glucCollConnHandle, glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_START] + 1, glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_END], glucCollTaskId); newState = DISC_GLUCOSE_CTL_PNT_CCCD; } else { // Missing required characteristic newState = DISC_FAILED; } } else { // Missing required characteristic descriptor glucoseHdlCache[HDL_GLUCOSE_MEAS_CCCD] = 0; newState = DISC_FAILED; } } } break; case DISC_GLUCOSE_CTL_PNT_CCCD: { uint8_t i; // Characteristic descriptors found if (pMsg->method == ATT_FIND_INFO_RSP && pMsg->msg.findInfoRsp.numInfo > 0 && pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) { attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp); // For each handle/uuid pair for (i = 0; i < pRsp->numInfo; i++) { // Look for CCCD if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID ) { // CCCD found glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] = ATT_BT_PAIR_HANDLE( pRsp->pInfo, i ); break; } } } // If procedure complete if ((pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { // If CCCD found if (glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] != 0) { // Should we look for unread category status CCCD if (glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] < glucoseHdlCache[HDL_GLUCOSE_CONTEXT_END]) { // Discover unread category status characteristic descriptors GATT_DiscAllCharDescs(glucCollConnHandle, glucoseHdlCache[HDL_GLUCOSE_CONTEXT_START] + 1, glucoseHdlCache[HDL_GLUCOSE_CONTEXT_END], glucCollTaskId); newState = DISC_GLUCOSE_CONTEXT_CCCD; } else { // Done newState = DISC_IDLE; } } else { // Missing required characteristic descriptor glucoseHdlCache[HDL_GLUCOSE_CTL_PNT_CCCD] = 0; newState = DISC_FAILED; } } } break; case DISC_GLUCOSE_CONTEXT_CCCD: { uint8_t i; // Characteristic descriptors found if (pMsg->method == ATT_FIND_INFO_RSP && pMsg->msg.findInfoRsp.numInfo > 0 && pMsg->msg.findInfoRsp.format == ATT_HANDLE_BT_UUID_TYPE) { attFindInfoRsp_t *pRsp = &(pMsg->msg.findInfoRsp); // For each handle/uuid pair for (i = 0; i < pRsp->numInfo; i++) { // Look for CCCD if ( ATT_BT_PAIR_UUID( pRsp->pInfo, i ) == GATT_CLIENT_CHAR_CFG_UUID ) { // CCCD found glucoseHdlCache[HDL_GLUCOSE_CONTEXT_CCCD] = ATT_BT_PAIR_HANDLE( pRsp->pInfo, i ); break; } } } // If procedure complete if ((pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { newState = DISC_IDLE; } } break; default: break; } return newState; }
/********************************************************************* * @fn hidappDiscoverService * * @brief Discover service using UUID. * * @param connHandle - connection handle to do discovery on * @param svcUuid - service UUID to discover * * @return none */ static void hidappDiscoverService( uint16 connHandle, uint16 svcUuid ) { uint8 uuid[2] = {LO_UINT16(svcUuid), HI_UINT16(svcUuid)}; VOID GATT_DiscPrimaryServiceByUUID( connHandle, uuid, ATT_BT_UUID_SIZE, hidappTaskId ); }
/********************************************************************* * @fn TimeAppDiscCurrTime() * * @brief Current time service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8 TimeAppDiscCurrTime( uint8 state, gattMsgEvent_t *pMsg ) { uint8 newState = state; switch ( state ) { case DISC_CURR_TIME_START: { uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(CURRENT_TIME_SVC_UUID), HI_UINT16(CURRENT_TIME_SVC_UUID) }; // Initialize service discovery variables timeAppSvcStartHdl = timeAppSvcEndHdl = 0; timeAppEndHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID( gapConnHandle, uuid, ATT_BT_UUID_SIZE, bloodPressureTaskId ); newState = DISC_CURR_TIME_SVC; } break; case DISC_CURR_TIME_SVC: // Service found, store handles if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0 ) { timeAppSvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle; timeAppSvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; } // 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 ( timeAppSvcStartHdl != 0 ) { // Discover all characteristics GATT_DiscAllChars( gapConnHandle, timeAppSvcStartHdl, timeAppSvcEndHdl, bloodPressureTaskId ); newState = DISC_CURR_TIME_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_CURR_TIME_CHAR: { // Characteristics found if ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN) { uint8 i; uint8 *p; uint16 handle; uint16 uuid; // For each characteristic declaration p = pMsg->msg.readByTypeRsp.dataList; for ( i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i-- ) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If looking for end handle if ( timeAppEndHdlIdx != 0 ) { // End handle is one less than handle of characteristic declaration timeAppHdlCache[timeAppEndHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1; timeAppEndHdlIdx = 0; } // If UUID is of interest, store handle switch ( uuid ) { case CT_TIME_UUID: timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] = handle; timeAppEndHdlIdx = HDL_CURR_TIME_CT_TIME_END; break; default: break; } p += CHAR_DESC_HDL_UUID16_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 ( timeAppEndHdlIdx != 0 ) { timeAppHdlCache[timeAppEndHdlIdx] = timeAppSvcEndHdl; timeAppEndHdlIdx = 0; } // If didn't find time characteristic if ( timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] == 0 ) { newState = DISC_FAILED; } else if ( timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] <timeAppHdlCache[HDL_CURR_TIME_CT_TIME_END] ) { // Discover characteristic descriptors GATT_DiscAllCharDescs( gapConnHandle, timeAppHdlCache[HDL_CURR_TIME_CT_TIME_START] + 1, timeAppHdlCache[HDL_CURR_TIME_CT_TIME_END], bloodPressureTaskId ); newState = DISC_CURR_TIME_CT_TIME_CCCD; } else { newState = DISC_IDLE; } } } break; case DISC_CURR_TIME_CT_TIME_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 i; // For each handle/uuid pair for ( i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++ ) { // Look for CCCD if ( (pMsg->msg.findInfoRsp.info.btPair[i].uuid[0] == LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID)) && (pMsg->msg.findInfoRsp.info.btPair[i].uuid[1] == HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID)) ) { // CCCD found timeAppHdlCache[HDL_CURR_TIME_CT_TIME_CCCD] = pMsg->msg.findInfoRsp.info.btPair[i].handle; break; } } } // If procedure complete if ( ( pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete ) || ( pMsg->method == ATT_ERROR_RSP ) ) { newState = DISC_IDLE; } } break; default: break; } return newState; }
/********************************************************************* * @fn softCmdDiscGenCtrl() * * @brief Generic control service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8 softCmdDiscGenCtrl( uint8 state, gattMsgEvent_t *pMsg ) { uint8 newState = state; switch ( state ) { case DISC_GEN_CTRL_START: { uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(GEN_CTRL_SERVICE_UUID), HI_UINT16(GEN_CTRL_SERVICE_UUID) }; // Initialize service discovery variables softCmdSvcStartHdl = softCmdSvcEndHdl = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID( softCmdConnHandle, uuid, ATT_BT_UUID_SIZE, softCmdTaskId ); newState = DISC_GEN_CTRL_SVC; } break; case DISC_GEN_CTRL_SVC: // Service found, store handles if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0 ) { softCmdSvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle; softCmdSvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; } // 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 ( softCmdSvcStartHdl != 0 ) { // Discover all characteristics GATT_DiscAllChars( softCmdConnHandle, softCmdSvcStartHdl, softCmdSvcEndHdl, softCmdTaskId ); newState = DISC_GEN_CTRL_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_GEN_CTRL_CHAR: { uint8 i; uint8 *p; uint16 handle; uint16 uuid; // Characteristics found if ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN ) { // For each characteristic declaration p = pMsg->msg.readByTypeRsp.dataList; for ( i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i-- ) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If UUID is of interest, store handle switch ( uuid ) { case GEN_CMD_UUID: softCmdHdlCache[HDL_GEN_CTRL_GEN_CMD] = handle; break; case CMD_ENUM_UUID: softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM] = handle; break; default: break; } p += CHAR_DESC_HDL_UUID16_LEN; } } // If procedure complete if ( ( pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete ) || ( pMsg->method == ATT_ERROR_RSP ) ) { // If didn't find Generic Command then fail if ( softCmdHdlCache[HDL_GEN_CTRL_GEN_CMD] == 0 ) { newState = DISC_FAILED; } // If found Command Enumeration read it else if ( softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM] != 0 ) { attReadReq_t readReq; readReq.handle = softCmdHdlCache[HDL_GEN_CTRL_CMD_ENUM]; GATT_ReadCharValue( softCmdConnHandle, &readReq, softCmdTaskId ); newState = DISC_GEN_CTRL_READ_ENUM; } else { newState = DISC_IDLE; } } } break; case DISC_GEN_CTRL_READ_ENUM: // Currently nothing is done when this characteristic is read newState = DISC_IDLE; break; default: break; } return newState; }
/********************************************************************* * @fn Time_discAlertNtf() * * @brief Alert notification service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8_t Time_discAlertNtf(uint8_t state, gattMsgEvent_t *pMsg) { uint8_t newState = state; switch (state) { case DISC_ALERT_NTF_START: { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(ALERT_NOTIF_SERV_UUID), HI_UINT16(ALERT_NOTIF_SERV_UUID) }; // Initialize service discovery variables Time_svcStartHdl = Time_svcEndHdl = 0; Time_endHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID(Time_connHandle, uuid, ATT_BT_UUID_SIZE, ICall_getEntityId()); newState = DISC_ALERT_NTF_SVC; } break; case DISC_ALERT_NTF_SVC: // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { Time_svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); Time_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 (Time_svcStartHdl != 0) { // Discover all characteristics GATT_DiscAllChars(Time_connHandle, Time_svcStartHdl, Time_svcEndHdl, ICall_getEntityId()); newState = DISC_ALERT_NTF_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_ALERT_NTF_CHAR: { // Characteristics found if (pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN) { uint8_t i; uint8_t *p; uint16_t handle; uint16_t uuid; p = pMsg->msg.readByTypeRsp.pDataList; // For each characteristic declaration for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If looking for end handle if (Time_endHdlIdx != 0) { // End handle is one less than handle of characteristic declaration Time_handleCache[Time_endHdlIdx] = BUILD_UINT16(p[0], p[1]) - 1; Time_endHdlIdx = 0; } // If UUID is of interest, store handle switch (uuid) { case ALERT_NOTIF_CTRL_PT_UUID: Time_handleCache[HDL_ALERT_NTF_CTRL] = handle; break; case UNREAD_ALERT_STATUS_UUID: Time_handleCache[HDL_ALERT_NTF_UNREAD_START] = handle; Time_endHdlIdx = HDL_ALERT_NTF_UNREAD_END; break; case NEW_ALERT_UUID: Time_handleCache[HDL_ALERT_NTF_NEW_START] = handle; Time_endHdlIdx = HDL_ALERT_NTF_NEW_END; break; case SUP_NEW_ALERT_CAT_UUID: Time_handleCache[HDL_ALERT_NTF_NEW_CAT] = handle; break; case SUP_UNREAD_ALERT_CAT_UUID: Time_handleCache[HDL_ALERT_NTF_UNREAD_CAT] = handle; break; default: break; } p += CHAR_DESC_HDL_UUID16_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 (Time_endHdlIdx != 0) { Time_handleCache[Time_endHdlIdx] = Time_svcEndHdl; Time_endHdlIdx = 0; } // If didn't find new alert characteristic if (Time_handleCache[HDL_ALERT_NTF_NEW_START] == 0) { newState = DISC_FAILED; } else if (Time_handleCache[HDL_ALERT_NTF_NEW_START] < Time_handleCache[HDL_ALERT_NTF_NEW_END]) { // Discover incoming alert characteristic descriptors GATT_DiscAllCharDescs(Time_connHandle, Time_handleCache[HDL_ALERT_NTF_NEW_START] + 1, Time_handleCache[HDL_ALERT_NTF_NEW_END], ICall_getEntityId()); newState = DISC_ALERT_NTF_NEW_CCCD; } else { // Missing required characteristic descriptor Time_handleCache[HDL_ALERT_NTF_NEW_START] = 0; newState = DISC_FAILED; } } } break; case DISC_ALERT_NTF_NEW_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 Time_handleCache[HDL_ALERT_NTF_NEW_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)) { // If CCCD found if (Time_handleCache[HDL_ALERT_NTF_NEW_CCCD] != 0) { // Should we look for unread category status CCCD if (Time_handleCache[HDL_ALERT_NTF_UNREAD_START] < Time_handleCache[HDL_ALERT_NTF_UNREAD_END]) { // Discover unread category status characteristic descriptors GATT_DiscAllCharDescs(Time_connHandle, Time_handleCache[HDL_ALERT_NTF_UNREAD_START] + 1, Time_handleCache[HDL_ALERT_NTF_UNREAD_END], ICall_getEntityId()); newState = DISC_ALERT_NTF_UNREAD_CCCD; } else { // Done newState = DISC_IDLE; } } else { // Missing required characteristic descriptor Time_handleCache[HDL_ALERT_NTF_NEW_START] = 0; newState = DISC_FAILED; } } } break; case DISC_ALERT_NTF_UNREAD_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 Time_handleCache[HDL_ALERT_NTF_UNREAD_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)) { newState = DISC_IDLE; } } break; default: break; } return newState; }
/********************************************************************* * @fn Time_discRefTime() * * @brief Reference time service and characteristic discovery. * * @param state - Discovery state. * @param pMsg - GATT message. * * @return New discovery state. */ static uint8_t Time_discRefTime(uint8_t state, gattMsgEvent_t *pMsg) { uint8_t newState = state; switch (state) { case DISC_REF_TIME_START: { uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(REF_TIME_UPDATE_SERV_UUID), HI_UINT16(REF_TIME_UPDATE_SERV_UUID) }; // Initialize service discovery variables Time_svcStartHdl = Time_svcEndHdl = 0; Time_endHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID(Time_connHandle, uuid, ATT_BT_UUID_SIZE, ICall_getEntityId()); newState = DISC_REF_TIME_SVC; } break; case DISC_REF_TIME_SVC: // Service found, store handles if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && pMsg->msg.findByTypeValueRsp.numInfo > 0) { Time_svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); Time_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 (Time_svcStartHdl != 0) { // Discover all characteristics GATT_DiscAllChars(Time_connHandle, Time_svcStartHdl, Time_svcEndHdl, ICall_getEntityId()); newState = DISC_REF_TIME_CHAR; } else { // Service not found newState = DISC_FAILED; } } break; case DISC_REF_TIME_CHAR: { // Characteristics found if (pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->msg.readByTypeRsp.numPairs > 0 && pMsg->msg.readByTypeRsp.len == CHAR_DESC_HDL_UUID16_LEN) { uint8_t i; uint8_t *p; uint16_t handle; uint16_t uuid; p = pMsg->msg.readByTypeRsp.pDataList; // For each characteristic declaration for (i = pMsg->msg.readByTypeRsp.numPairs; i > 0; i--) { // Parse characteristic declaration handle = BUILD_UINT16(p[3], p[4]); uuid = BUILD_UINT16(p[5], p[6]); // If UUID is of interest, store handle switch (uuid) { case TIME_UPDATE_CTRL_PT_UUID: Time_handleCache[HDL_REF_TIME_UPD_CTRL] = handle; break; case TIME_UPDATE_STATE_UUID: Time_handleCache[HDL_REF_TIME_UPD_STATE] = handle; break; default: break; } p += CHAR_DESC_HDL_UUID16_LEN; } } // If procedure complete if ((pMsg->method == ATT_READ_BY_TYPE_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { // If didn't find mandatory characteristics if (Time_handleCache[HDL_REF_TIME_UPD_CTRL] == 0 || Time_handleCache[HDL_REF_TIME_UPD_STATE] == 0) { newState = DISC_FAILED; } else { newState = DISC_IDLE; } } } break; default: break; } return newState; }