/********************************************************************* * @fn pairStateCB * * @brief Pairing state callback. * * @return none */ static void timeAppPairStateCB( uint16 connHandle, uint8 state, uint8 status ) { if ( state == GAPBOND_PAIRING_STATE_STARTED ) { timeAppPairingStarted = TRUE; } else if ( state == GAPBOND_PAIRING_STATE_COMPLETE ) { timeAppPairingStarted = FALSE; if ( status == SUCCESS ) { linkDBItem_t *pItem; if ( (pItem = linkDB_Find( gapConnHandle )) != NULL ) { // Store bonding state of pairing timeAppBonded = ( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND ); if ( timeAppBonded ) { osal_memcpy( timeAppBondedAddr, pItem->addr, B_ADDR_LEN ); } } // If discovery was postponed start discovery if ( timeAppDiscPostponed && timeAppDiscoveryCmpl == FALSE ) { timeAppDiscPostponed = FALSE; osal_set_event( thermometerTaskId, TH_START_DISCOVERY_EVT ); } } } }
/*--------------------------------------------------------------------------- * Callback indicating the current state of pairing. *-------------------------------------------------------------------------*/ static void pairStateCB( uint16 connHandle, uint8 state, uint8 status ) { if ( state == GAPBOND_PAIRING_STATE_STARTED ) { // } else if ( state == GAPBOND_PAIRING_STATE_COMPLETE ) { if ( status == SUCCESS ) { linkDBItem_t *pItem; if ( (pItem = linkDB_Find(connHandle )) != NULL ) { if (( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND )) { //cbLED_flash(cbLED_GREEN, 3, 250, 500); } } } else { // } } else if ( state == GAPBOND_PAIRING_STATE_BONDED ) { //cbLED_flash(cbLED_GREEN, 5, 250, 500); } }
/********************************************************************* * @brief Set/clear the service change indication in a bond record. * * Public function defined in gapperiphbondmgr.h. */ bStatus_t GAPBondMgr_ServiceChangeInd( uint16 connectionHandle, uint8 setParam ) { bStatus_t ret = bleNoResources; // return value if ( connectionHandle == 0xFFFF ) { uint8 idx; // loop counter // Run through the bond database and update the Service Change indication for ( idx = 0; idx < GAP_BONDINGS_MAX; idx++ ) { if ( gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam ) ) { ret = SUCCESS; } } // If the service change indication is TRUE, tell the connected devices if ( setParam ) { // Run connected database linkDB_PerformFunc( gapBondMgrSendServiceChange ); } } else { // Find connection information linkDBItem_t *pLinkItem = linkDB_Find( connectionHandle ); if ( pLinkItem ) { uint8 idx; // loop counter idx = GAPBondMgr_ResolveAddr( pLinkItem->addrType, pLinkItem->addr, NULL ); if ( idx < GAP_BONDINGS_MAX ) { // Bond found, update it. VOID gapBondMgrChangeState( idx, GAP_BONDED_STATE_SERVICE_CHANGED, setParam ); ret = SUCCESS; } // If the service change indication is TRUE, tell the connected device if ( setParam ) { gapBondMgrSendServiceChange( pLinkItem ); } } else { ret = bleNotConnected; } } return ( ret ); }
/********************************************************************* * @fn pairStateCB * * @brief Pairing state callback. * * @return none */ static void timeAppPairStateCB( uint16 connHandle, uint8 state, uint8 status ) { if ( state == GAPBOND_PAIRING_STATE_STARTED ) { timeAppPairingStarted = TRUE; LCD_WRITE_STRING( "Pairing started", HAL_LCD_LINE_1 ); } else if ( state == GAPBOND_PAIRING_STATE_COMPLETE ) { timeAppPairingStarted = FALSE; if ( status == SUCCESS ) { linkDBItem_t *pItem; if ( (pItem = linkDB_Find( timeAppConnHandle )) != NULL ) { // Store bonding state of pairing timeAppBonded = ( (pItem->stateFlags & LINK_BOUND) == LINK_BOUND ); if ( timeAppBonded ) { osal_memcpy( timeAppBondedAddr, pItem->addr, B_ADDR_LEN ); } } // If discovery was postponed start discovery if ( timeAppDiscPostponed && timeAppDiscoveryCmpl == FALSE ) { timeAppDiscPostponed = FALSE; osal_set_event( timeAppTaskId, START_DISCOVERY_EVT ); } LCD_WRITE_STRING( "Pairing success", HAL_LCD_LINE_1 ); } else { LCD_WRITE_STRING_VALUE( "Pairing fail", status, 10, HAL_LCD_LINE_1 ); } } else if ( state == GAPBOND_PAIRING_STATE_BONDED ) { if ( status == SUCCESS ) { LCD_WRITE_STRING( "Bonding success", HAL_LCD_LINE_1 ); } } }
/********************************************************************* * @fn softCmdGapStateCB * * @brief Notification from the profile of a state change. * * @param newState - new state * * @return none */ static void softCmdGapStateCB( gaprole_States_t newState ) { // if connected if (newState == GAPROLE_CONNECTED) { linkDBItem_t *pItem; // Get connection handle GAPRole_GetParameter( GAPROLE_CONNHANDLE, &softCmdConnHandle ); // Get peer bd address if ( (pItem = linkDB_Find( softCmdConnHandle )) != NULL) { // If connected to device without bond do service discovery if ( !osal_memcmp( pItem->addr, softCmdBondedAddr, B_ADDR_LEN ) ) { softCmdDiscoveryCmpl = FALSE; } // Initiate service discovery if necessary if ( softCmdDiscoveryCmpl == FALSE ) { osal_start_timerEx( softCmdTaskId, START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY ); } } } // if disconnected else if (softCmdGapState == GAPROLE_CONNECTED && newState != GAPROLE_CONNECTED) { softCmdDisconnected(); // reset client characteristic configuration descriptors uint16 param = GATT_CFG_NO_OPERATION; Batt_SetParameter(BATT_PARAM_LVL_ST_CHAR_CFG, sizeof(uint16), (uint8 *) ¶m); } softCmdGapState = newState; }
/********************************************************************* * @fn gapRole_ProcessGAPMsg * * @brief Process an incoming task message. * * @param pMsg - message to process * * @return none */ void gapBondMgr_ProcessGAPMsg( gapEventHdr_t *pMsg ) { switch ( pMsg->opcode ) { case GAP_PASSKEY_NEEDED_EVENT: { gapPasskeyNeededEvent_t *pPkt = (gapPasskeyNeededEvent_t *)pMsg; if ( pGapBondCB && pGapBondCB->passcodeCB ) { // Ask app for a passcode pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs ); } else { // No app support, use the default passcode if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS ) { VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED ); } } } break; case GAP_AUTHENTICATION_COMPLETE_EVENT: { gapAuthCompleteEvent_t *pPkt = (gapAuthCompleteEvent_t *)pMsg; // Should we save bonding information if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) ) { gapBondRec_t bondRec; VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ; // Do we have a public address in the data? if ( pPkt->pIdentityInfo ) { VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN ); } else { linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle ); if ( pLinkItem ) { VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN ); } else { // We don't have an address, so ignore the message. break; } } // Save off of the authentication state bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0; VOID gapBondMgrAddBond( &bondRec, (gapBondLTK_t *)pPkt->pSecurityInfo, (gapBondLTK_t *)pPkt->pDevSecInfo, ((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )), ((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )), ((uint32)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->signCounter : GAP_INIT_SIGN_COUNTER )) ); } // Call app state callback if ( pGapBondCB && pGapBondCB->pairStateCB ) { pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status ); } } break; case GAP_BOND_COMPLETE_EVENT: // This message is received when the bonding is complete. If hdr.status is SUCCESS // then call app state callback. If hdr.status is NOT SUCCESS, the connection will be // dropped at the LL because of a MIC failure, so again nothing to do. if ( pGapBondCB && pGapBondCB->pairStateCB && pMsg->hdr.status == SUCCESS ) { pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status ); } break; case GAP_SIGNATURE_UPDATED_EVENT: { uint8 idx; gapSignUpdateEvent_t *pPkt = (gapSignUpdateEvent_t *)pMsg; idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL ); if ( idx < GAP_BONDINGS_MAX ) { // Save the sign counter VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) ); } } break; case GAP_PAIRING_REQ_EVENT: { gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg; if ( gapBond_AutoFail != FALSE ) { // Auto Fail TEST MODE (DON'T USE THIS) - Sends pre-setup reason VOID GAP_TerminateAuth( pPkt->connectionHandle, gapBond_AutoFailReason ); } else if ( gapBond_PairingMode == GAPBOND_PAIRING_MODE_NO_PAIRING ) { // No Pairing - Send error VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED ); } else { gapAuthParams_t params; linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle ); // Requesting bonding? if ( pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING ) { if ( pLinkItem ) { if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPkt->pairReq.keyDist.mIdKey == FALSE) ) { uint8 publicAddr[B_ADDR_LEN]; // Check if we already have the public address in NV if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE ) { // Can't bond to a non-public address if we don't know the public address VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ ); break; } } } else { // Can't find the connection, ignore the message break; } } VOID osal_memset( ¶ms, 0, sizeof ( gapAuthParams_t ) ); // Setup the pairing parameters params.connectionHandle = pPkt->connectionHandle; params.secReqs.ioCaps = gapBond_IOCap; params.secReqs.oobAvailable = gapBond_OOBDataFlag; params.secReqs.maxEncKeySize = gapBond_KeySize; // TBD - Should we distribute keys if bonding is turned off??? params.secReqs.keyDist.sEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SENCKEY) ? TRUE : FALSE; params.secReqs.keyDist.sIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SIDKEY) ? TRUE : FALSE; params.secReqs.keyDist.mEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MENCKEY) ? TRUE : FALSE; params.secReqs.keyDist.mIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MIDKEY) ? TRUE : FALSE; params.secReqs.keyDist.mSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_MSIGN) ? TRUE : FALSE; params.secReqs.keyDist.sSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_SSIGN) ? TRUE : FALSE; // Is bond manager setup for OOB data? if ( gapBond_OOBDataFlag ) { VOID osal_memcpy( params.secReqs.oob, gapBond_OOBData, KEYLEN ); } if ( (pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING) && (gapBond_Bonding) ) { params.secReqs.authReq |= SM_AUTH_STATE_BONDING; if ( pLinkItem->addrType != ADDRTYPE_PUBLIC ) { // Force a master ID key params.secReqs.keyDist.mIdKey = TRUE; } } // Is Bond Manager setup for passkey protection? if ( gapBond_MITM ) { params.secReqs.authReq |= SM_AUTH_STATE_AUTHENTICATED; } VOID GAP_Authenticate( ¶ms, &(pPkt->pairReq) ); } // Call app state callback if ( pGapBondCB && pGapBondCB->pairStateCB ) { pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_STARTED, pPkt->hdr.status ); } } break; default: break; } }
//static void peripheralStateNotificationCB( gaprole_States_t newState ) static void peripheralStateNotificationCB( gaprole_States_t* newState ) { // if connected if ( *newState == GAPROLE_CONNECTED ) { linkDBItem_t *pItem; // Get connection handle GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle ); // Get peer bd address if ( (pItem = linkDB_Find( gapConnHandle )) != NULL) { // If connected to device without bond do service discovery if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) ) { timeAppDiscoveryCmpl = FALSE; } else { timeAppDiscoveryCmpl = TRUE; } // if this was last connection address don't do discovery if(osal_memcmp( pItem->addr, lastConnAddr, B_ADDR_LEN )) { timeAppDiscoveryCmpl = TRUE; connectedToLastAddress = true; } else { //save the last connected address osal_memcpy(lastConnAddr, pItem->addr, B_ADDR_LEN ); } // Initiate service discovery if necessary if ( timeAppDiscoveryCmpl == FALSE ) { osal_start_timerEx( thermometerTaskId, TH_START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY ); } //on connection initiate disconnect timer in 20 seconds osal_start_timerEx( thermometerTaskId, TH_DISCONNECT_EVT, 20000 ); } } // if disconnected else if ( gapProfileState == GAPROLE_CONNECTED && *newState != GAPROLE_CONNECTED ) { timeAppDisconnected(); //always stop intermediate timer osal_stop_timerEx( thermometerTaskId, TH_PERIODIC_IMEAS_EVT ); } // if started else if ( *newState == GAPROLE_STARTED ) { // Initialize time clock timeAppClockInit(); } gapProfileState = *newState; updateUI(); }
/********************************************************************* * @fn gapProfileStateCB * * @brief Notification from the profile of a state change. * * @param newState - new state * * @return none */ static void peripheralStateNotificationCB( gaprole_States_t newState ) { // if connected if ( newState == GAPROLE_CONNECTED ) { linkDBItem_t *pItem; HalLedSet ( HAL_LED_1, HAL_LED_MODE_OFF ); // Get connection handle GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle ); // Get peer bd address if ( (pItem = linkDB_Find( gapConnHandle )) != NULL) { // If connected to device without bond do service discovery if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) ) { timeAppDiscoveryCmpl = FALSE; } else { timeAppDiscoveryCmpl = TRUE; } // if this was last connection address don't do discovery if(osal_memcmp( pItem->addr, lastConnAddr, B_ADDR_LEN )) { timeAppDiscoveryCmpl = TRUE; connectedToLastAddress = true; } else { //save the last connected address osal_memcpy(lastConnAddr, pItem->addr, B_ADDR_LEN ); } // Initiate service discovery if necessary if ( timeAppDiscoveryCmpl == FALSE ) { // osal_start_timerEx( bloodPressureTaskId, BP_START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY ); } } } // if disconnected else if ( gapProfileState == GAPROLE_CONNECTED && newState != GAPROLE_CONNECTED ) { timeAppDisconnected(); //always stop intermediate timer osal_stop_timerEx( bloodPressureTaskId, BP_TIMER_CUFF_EVT ); // stop disconnect timer osal_stop_timerEx( bloodPressureTaskId, BP_DISCONNECT_PERIOD ); } // if started else if ( newState == GAPROLE_STARTED ) { // Initialize time clock display //timeAppClockInit(); } gapProfileState = newState; updateUI(); }
/********************************************************************* * @fn timeAppGapStateCB * * @brief Notification from the profile of a state change. * * @param newState - new state * * @return none */ static void timeAppGapStateCB( gaprole_States_t newState ) { // if connected if ( newState == GAPROLE_CONNECTED ) { linkDBItem_t *pItem; // Get connection handle GAPRole_GetParameter( GAPROLE_CONNHANDLE, &timeAppConnHandle ); // Get peer bd address if ( (pItem = linkDB_Find( timeAppConnHandle )) != NULL) { // If connected to device without bond do service discovery if ( !osal_memcmp( pItem->addr, timeAppBondedAddr, B_ADDR_LEN ) ) { timeAppDiscoveryCmpl = FALSE; } // Initiate service discovery if necessary if ( timeAppDiscoveryCmpl == FALSE ) { osal_start_timerEx( timeAppTaskId, START_DISCOVERY_EVT, DEFAULT_DISCOVERY_DELAY ); } // Perform configuration of characteristics on connection setup else { timeAppConfigState = timeAppConfigNext( TIMEAPP_CONFIG_CONN_START ); } } LCD_WRITE_STRING( "Connected", HAL_LCD_LINE_1 ); LCD_WRITE_STRING( "", HAL_LCD_LINE_2 ); } // if disconnected else if ( timeAppGapState == GAPROLE_CONNECTED && newState != GAPROLE_CONNECTED ) { uint8 advState = TRUE; timeAppDisconnected(); if ( newState == GAPROLE_WAITING_AFTER_TIMEOUT ) { // link loss timeout-- use fast advertising GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_FAST_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_FAST_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_FAST_ADV_DURATION ); } else { // Else use slow advertising GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_SLOW_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_SLOW_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_SLOW_ADV_DURATION ); } // Enable advertising GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advState ); LCD_WRITE_STRING( "Disconnected", HAL_LCD_LINE_1 ); LCD_WRITE_STRING( "", HAL_LCD_LINE_2 ); } // if advertising stopped else if ( timeAppGapState == GAPROLE_ADVERTISING && newState == GAPROLE_WAITING ) { // if advertising stopped by user if ( timeAppAdvCancelled ) { timeAppAdvCancelled = FALSE; } // if fast advertising switch to slow else if ( GAP_GetParamValue( TGAP_GEN_DISC_ADV_INT_MIN ) == DEFAULT_FAST_ADV_INTERVAL ) { uint8 advState = TRUE; GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MIN, DEFAULT_SLOW_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_INT_MAX, DEFAULT_SLOW_ADV_INTERVAL ); GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_SLOW_ADV_DURATION ); GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &advState ); } } // if started else if ( newState == GAPROLE_STARTED ) { #ifndef CC2540_MINIDK uint8 bdAddr[B_ADDR_LEN]; GAPRole_GetParameter( GAPROLE_BD_ADDR, &bdAddr ); LCD_WRITE_STRING( "Time App", HAL_LCD_LINE_1 ); LCD_WRITE_STRING( bdAddr2Str( bdAddr ), HAL_LCD_LINE_2 ); #endif // Initialize time clock after writing first two lines of LCD timeAppClockInit(); } timeAppGapState = newState; }