/********************************************************************* * @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_SERV_UUID), HI_UINT16(CURRENT_TIME_SERV_UUID) }; // Initialize service discovery variables timeAppSvcStartHdl = timeAppSvcEndHdl = 0; timeAppEndHdlIdx = 0; // Discover service by UUID GATT_DiscPrimaryServiceByUUID( gapConnHandle, uuid, ATT_BT_UUID_SIZE, thermometerTaskId ); 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 = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); timeAppSvcEndHdl = 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 ( timeAppSvcStartHdl != 0 ) { // Discover all characteristics GATT_DiscAllChars( gapConnHandle, timeAppSvcStartHdl, timeAppSvcEndHdl, thermometerTaskId ); 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.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 ( 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], thermometerTaskId ); 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 ( ATT_BT_PAIR_UUID(pMsg->msg.findInfoRsp.pInfo, i) == GATT_CLIENT_CHAR_CFG_UUID ) { // CCCD found timeAppHdlCache[HDL_CURR_TIME_CT_TIME_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 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 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; }