/********************************************************************* * @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 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; }
static void hidappProcessGATTMsg( gattMsgEvent_t *pPkt ) { // Build the message first switch ( pPkt->method ) { case ATT_HANDLE_VALUE_NOTI: // First try to send out pending HID report if ( reportRetries > 0 ) { hidappSendInReport( &lastInReport ); reportRetries = 0; osal_stop_timerEx( hidappTaskId, HIDAPP_EVT_REPORT_RETRY ); } // Send incoming HID report if ( hidappSendInReport( &(pPkt->msg.handleValueNoti) ) == FALSE ) { // Save report for retries later osal_memcpy( &lastInReport, &(pPkt->msg.handleValueNoti), sizeof( attHandleValueNoti_t ) ); reportRetries = 1; osal_start_timerEx( hidappTaskId, HIDAPP_EVT_REPORT_RETRY, HIDAPP_INPUT_RETRY_TIMEOUT ); } break; case ATT_FIND_BY_TYPE_VALUE_RSP: // Response from GATT_DiscPrimaryServiceByUUID // Service found, store handles if ( pPkt->msg.findByTypeValueRsp.numInfo > 0 ) { serviceStartHandle = pPkt->msg.findByTypeValueRsp.handlesInfo[0].handle; serviceEndHandle = pPkt->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle; } // If procedure complete else if ( pPkt->hdr.status == bleProcedureComplete ) { if ( serviceStartHandle != 0 ) { if ( serviceToDiscover == GATT_SERVICE_UUID ) { // Begin the search for characteristic handle of the service readReq.startHandle = serviceStartHandle; readReq.endHandle = serviceEndHandle; readReqType.len = 2; readReqType.uuid[0] = LO_UINT16(SERVICE_CHANGED_UUID); readReqType.uuid[1] = HI_UINT16(SERVICE_CHANGED_UUID); readReq.type = readReqType; GATT_DiscCharsByUUID(connHandle, &readReq, hidappTaskId ); } else if ( serviceToDiscover == HID_SERVICE_UUID ) { // Discover all characteristics GATT_DiscAllChars( connHandle, serviceStartHandle, serviceEndHandle, hidappTaskId ); } } } break; case ATT_READ_BY_TYPE_RSP: // Response from Discover all Characteristics. // Success indicates packet with characteristic discoveries. if ( pPkt->hdr.status == SUCCESS ) { attReadByTypeRsp_t rsp = pPkt->msg.readByTypeRsp; uint8 idx = 0; if ( serviceToDiscover == GATT_SERVICE_UUID ) { // We have discovered the GATT Service Characteristic handle uint8 low = LO_UINT16(pPkt->msg.readByTypeRsp.dataList[3]); uint8 high = HI_UINT16(pPkt->msg.readByTypeRsp.dataList[4]); serviceChangeHandle = BUILD_UINT16(low, high); // Break to skip next part, it doesn't apply here break; } // Search characteristics for those with notification permissions. while( idx < ((rsp.numPairs * rsp.len ) - 1)) { // Check permissions of characteristic for notification permission if ( (rsp.dataList[idx+2] & GATT_PROP_NOTIFY ) ) { uint16* pHandle = (mouseCharHandle == GATT_INVALID_HANDLE) ? &mouseCharHandle : &keyCharHandle ; if ( pHandle == &keyCharHandle && consumerCtrlCharHandle == GATT_INVALID_HANDLE ) { pHandle = ( keyCharHandle == GATT_INVALID_HANDLE ) ? &keyCharHandle : &consumerCtrlCharHandle; } if ( *pHandle == GATT_INVALID_HANDLE ) { *pHandle = BUILD_UINT16( rsp.dataList[idx+3], rsp.dataList[idx+4] ); } } idx += rsp.len; } } // This indicates that there is no more characteristic data // to be discovered within the given handle range. else if ( pPkt->hdr.status == bleProcedureComplete ) { if ( serviceToDiscover == GATT_SERVICE_UUID ) { // Begin Service Discovery of HID Service serviceToDiscover = HID_SERVICE_UUID; hidappDiscoverService( connHandle, HID_SERVICE_UUID ); // Break to skip next part, it doesn't apply yet. break; } if ( enableCCCDs == TRUE ) { mouseCCCHandle = mouseCharHandle + 1; // Begin configuring the characteristics for notifications hidappEnableNotification( connHandle, mouseCCCHandle ); } else { serviceDiscComplete = TRUE; } } break; case ATT_WRITE_RSP: if ( pPkt->hdr.status == SUCCESS && !serviceDiscComplete ) { uint16 handle = ( keyCCCHandle == GATT_INVALID_HANDLE ) ? ( keyCCCHandle = keyCharHandle + 1 ) : ( consumerCtrlCCCHandle = consumerCtrlCharHandle + 1 ); hidappEnableNotification( connHandle, handle ); if ( consumerCtrlCCCHandle != GATT_INVALID_HANDLE) { serviceDiscComplete = TRUE; } } break; // Service Change indication case ATT_HANDLE_VALUE_IND: // Note: this logic assumes that the only indications that will be sent // will come from that GATT Service Changed Characteristic if ( pPkt->hdr.status == SUCCESS ) { serviceChange = CHANGE_OCCURED; // Acknowledge receipt of indication ATT_HandleValueCfm( pPkt->connHandle ); // Handles in server have changed while devices are connected if ( ( gapBondMgrState == PAIRED_BONDED_STATE ) && ( serviceChangeHandle == pPkt->msg.handleValueInd.handle ) ) { // Begin Service Discovery of HID Service serviceToDiscover = HID_SERVICE_UUID; hidappDiscoverService( connHandle, HID_SERVICE_UUID ); serviceChange = NO_CHANGE; } } break; default: // Unknown event break; } }
/********************************************************************* * @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; }