/******************************************************************** * @fn gapRole_connUpdate * * @brief Start the connection update procedure * * @param handleFailure - what to do if the update does not occur. * Method may choose to terminate connection, try again, * or take no action * @param pConnParams - connection parameters to use * * @return SUCCESS: operation was successful. * INVALIDPARAMETER: Data can not fit into one packet. * MSG_BUFFER_NOT_AVAIL: No HCI buffer is available. * bleInvalidRange: * bleIncorrectMode: invalid profile role. * bleAlreadyInRequestedMode: already updating link parameters. * bleNotConnected: Connection is down * bleMemAllocError: Memory allocation error occurred. * bleNoResources: No available resource */ bStatus_t gapRole_connUpdate(uint8_t handleFailure, gapRole_updateConnParams_t *pConnParams) { bStatus_t status; linkDBInfo_t pInfo; //ensure connection exists linkDB_GetInfo(pConnParams->connHandle, &pInfo); if (!(pInfo.stateFlags & LINK_CONNECTED)) { return (bleNotConnected); } // Make sure we don't send an L2CAP Connection Parameter Update Request // command within TGAP(conn_param_timeout) of an L2CAP Connection Parameter // Update Response being received. if (Util_isActive(&updateTimeoutClock) == FALSE) { uint16_t timeout = GAP_GetParamValue(TGAP_CONN_PARAM_TIMEOUT); #if defined(L2CAP_CONN_UPDATE) l2capParamUpdateReq_t updateReq; updateReq.intervalMin = pConnParams->minConnInterval; updateReq.intervalMax = pConnParams->maxConnInterval; updateReq.slaveLatency = pConnParams->slaveLatency; updateReq.timeoutMultiplier = pConnParams->timeoutMultiplier; status = L2CAP_ConnParamUpdateReq(pConnParams->connHandle, &updateReq, selfEntity); #else gapUpdateLinkParamReq_t linkParams; linkParams.connectionHandle = pConnParams->connHandle; linkParams.intervalMin = pConnParams->minConnInterval; linkParams.intervalMax = pConnParams->maxConnInterval; linkParams.connLatency = pConnParams->slaveLatency; linkParams.connTimeout = pConnParams->timeoutMultiplier; status = GAP_UpdateLinkParamReq( &linkParams ); #endif // L2CAP_CONN_UPDATE if(status == SUCCESS) { //store update params for possible resending paramUpdateNoSuccessOption = handleFailure; VOID memcpy(&gapRole_updateConnParams, pConnParams, sizeof(gapRole_updateConnParams_t)); // start timeout clock Util_restartClock(&updateTimeoutClock, timeout); } } else { return(blePending); } return status; }
/********************************************************************* * @fn gapRole_processGAPMsg * * @brief Process an incoming task message. * * @param pMsg - message to process * * @return none */ static uint8_t gapRole_processGAPMsg(gapEventHdr_t *pMsg) { uint8_t notify = FALSE; // State changed notify the app? (default no) switch (pMsg->opcode) { case GAP_DEVICE_INIT_DONE_EVENT: { gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg; bStatus_t stat = pPkt->hdr.status; if (stat == SUCCESS) { // Save off the generated keys VOID osal_snv_write(BLE_NVID_IRK, KEYLEN, gapRole_IRK); VOID osal_snv_write(BLE_NVID_CSRK, KEYLEN, gapRole_SRK); // Save off the information VOID memcpy(gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN); // Update the advertising data stat = GAP_UpdateAdvertisingData(selfEntity, TRUE, gapRole_AdvertDataLen, gapRole_AdvertData); } if (stat != SUCCESS) { gapRole_abort(); } notify = TRUE; } break; case GAP_ADV_DATA_UPDATE_DONE_EVENT: { gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *)pMsg; if (pPkt->hdr.status == SUCCESS) { if (pPkt->adType) { // Setup the Response Data pPkt->hdr.status = GAP_UpdateAdvertisingData(selfEntity, FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData); } else if (Util_isActive(&startAdvClock) == FALSE) { // Start advertising gapRole_setEvent(START_ADVERTISING_EVT); } } if (pPkt->hdr.status != SUCCESS) { // Set into Error state gapRole_abort(); notify = TRUE; } } break; case GAP_MAKE_DISCOVERABLE_DONE_EVENT: case GAP_END_DISCOVERABLE_DONE_EVENT: { gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *)pMsg; if (pPkt->hdr.status == SUCCESS) { if (pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT) { gapRole_AdvEnabled = TRUE; } else // GAP_END_DISCOVERABLE_DONE_EVENT { if (gapRole_AdvertOffTime != 0) //restart advertising if param is set { if ((gapRole_AdvEnabled) || (gapRole_AdvNonConnEnabled)) { Util_restartClock(&startAdvClock, gapRole_AdvertOffTime); } } else { // Since gapRole_AdvertOffTime is set to 0, the device should not // automatically become discoverable again after a period of time. // Set enabler to FALSE; device will become discoverable again when // this value gets set to TRUE if (gapRole_AdvEnabled == TRUE) { gapRole_AdvEnabled = FALSE; } } } notify = TRUE; } else if (pPkt->hdr.status == LL_STATUS_ERROR_COMMAND_DISALLOWED) //we're already advertising { notify = FALSE; } else { gapRole_abort(); } } break; case GAP_LINK_ESTABLISHED_EVENT: { gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg; uint8_t advertEnable = TRUE; if (pPkt->hdr.status == SUCCESS) { // Notify the Bond Manager to the connection VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, pPkt->connRole); //advertising will stop after connection formed as slave if ((pPkt->connRole) == GAP_PROFILE_PERIPHERAL) { gapRole_AdvEnabled = FALSE; //reenable advertising GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnable, NULL); } } else if (pPkt->hdr.status == bleGAPConnNotAcceptable) { // Set enabler to FALSE; device will become discoverable again when // this value gets set to TRUE gapRole_AdvEnabled = FALSE; } else { gapRole_abort(); } notify = TRUE; } break; case GAP_LINK_TERMINATED_EVENT: { gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg; linkDBInfo_t pInfo; linkDB_GetInfo(pPkt->connectionHandle, &pInfo); // notify bond manager GAPBondMgr_LinkTerm(pPkt->connectionHandle); notify = TRUE; } break; case GAP_SLAVE_REQUESTED_SECURITY_EVENT: { uint16_t connHandle = ((gapSlaveSecurityReqEvent_t *)pMsg)->connectionHandle; uint8_t authReq = ((gapSlaveSecurityReqEvent_t *)pMsg)->authReq; GAPBondMgr_SlaveReqSecurity(connHandle, authReq); } break; case GAP_LINK_PARAM_UPDATE_EVENT: { gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; // Cancel connection param update timeout timer (if active) Util_stopClock(&updateTimeoutClock); if (pPkt->hdr.status == SUCCESS) { notify = TRUE; } } break; default: notify = TRUE; break; } if (notify == TRUE) //app needs to take further action { if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnPassThrough) { return (pGapRoles_AppCGs->pfnPassThrough((gapMultiRoleEvent_t *)pMsg)); } } return TRUE; }
/********************************************************************* * @brief Get a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_GetParameter(uint16_t param, void *pValue, uint8_t connHandle) { bStatus_t ret = SUCCESS; linkDBInfo_t pInfo; switch (param) { case GAPROLE_PROFILEROLE: *((uint8_t*)pValue) = gapRole_profileRole; break; case GAPROLE_IRK: VOID memcpy(pValue, gapRole_IRK, KEYLEN) ; break; case GAPROLE_SRK: VOID memcpy(pValue, gapRole_SRK, KEYLEN) ; break; case GAPROLE_SIGNCOUNTER: *((uint32_t*)pValue) = gapRole_signCounter; break; case GAPROLE_BD_ADDR: VOID memcpy(pValue, gapRole_bdAddr, B_ADDR_LEN) ; break; case GAPROLE_ADVERT_ENABLED: *((uint8_t*)pValue) = gapRole_AdvEnabled; break; case GAPROLE_ADV_NONCONN_ENABLED: *((uint8_t*)pValue) = gapRole_AdvNonConnEnabled; break; case GAPROLE_ADVERT_OFF_TIME: *((uint16_t*)pValue) = gapRole_AdvertOffTime; break; case GAPROLE_ADVERT_DATA: VOID memcpy(pValue , gapRole_AdvertData, gapRole_AdvertDataLen); break; case GAPROLE_SCAN_RSP_DATA: VOID memcpy(pValue, gapRole_ScanRspData, gapRole_ScanRspDataLen) ; break; case GAPROLE_ADV_EVENT_TYPE: *((uint8_t*)pValue) = gapRole_AdvEventType; break; case GAPROLE_ADV_DIRECT_TYPE: *((uint8_t*)pValue) = gapRole_AdvDirectType; break; case GAPROLE_ADV_DIRECT_ADDR: VOID memcpy(pValue, gapRole_AdvDirectAddr, B_ADDR_LEN) ; break; case GAPROLE_ADV_CHANNEL_MAP: *((uint8_t*)pValue) = gapRole_AdvChanMap; break; case GAPROLE_ADV_FILTER_POLICY: *((uint8_t*)pValue) = gapRole_AdvFilterPolicy; break; case GAPROLE_CONN_BD_ADDR: linkDB_GetInfo(connHandle, &pInfo); VOID memcpy(pValue, pInfo.addr, B_ADDR_LEN) ; break; case GAPROLE_CONN_INTERVAL: linkDB_GetInfo(connHandle, &pInfo); *((uint16_t*)pValue) = pInfo.connInterval; case GAPROLE_CONN_LATENCY: //wait for linkdb update // linkDB_GetInfo(connHandle, &pInfo); // *((uint16_t*)pValue) = pInfo.connLatency; break; case GAPROLE_CONN_TIMEOUT: //wait for linkdb update // linkDB_GetInfo(connHandle, &pInfo); // *((uint16_t*)pValue) = pInfo.connTimeout; break; case GAPROLE_MAX_SCAN_RES: *((uint8_t*)pValue) = gapRoleMaxScanRes; break; default: // The param value isn't part of this profile, try the GAP. if (param < TGAP_PARAMID_MAX) { *((uint16_t*)pValue) = GAP_GetParamValue(param); } else { ret = INVALIDPARAMETER; } break; } return (ret); }
/********************************************************************* * @fn SimplePropBeacon_processStateChangeEvt * * @brief Process a pending GAP Role state change event. * * @param newState - new state * * @return None. */ static void SimplePropBeacon_processStateChangeEvt(gaprole_States_t newState) { switch ( newState ) { case GAPROLE_STARTED: { uint8_t ownAddress[B_ADDR_LEN]; uint8_t systemId[DEVINFO_SYSTEM_ID_LEN]; GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress); // use 6 bytes of device address for 8 bytes of system ID value systemId[0] = ownAddress[0]; systemId[1] = ownAddress[1]; systemId[2] = ownAddress[2]; // set middle bytes to zero systemId[4] = 0x00; systemId[3] = 0x00; // shift three bytes up systemId[7] = ownAddress[5]; systemId[6] = ownAddress[4]; systemId[5] = ownAddress[3]; DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId); // Display device address Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(ownAddress)); Display_print0(dispHandle, 2, 0, "Initialized"); // Start advertising SimplePropBeacon_startRegularAdv(); } break; case GAPROLE_ADVERTISING: Display_print0(dispHandle, 2, 0, "Config Mode"); break; case GAPROLE_ADVERTISING_NONCONN: { SimplePropBeacon_freeAttRsp(bleNotConnected); Display_print0(dispHandle, 2, 0, "Advertising Proprietary Beacon"); Display_print0(dispHandle, 3, 0, ""); break; } case GAPROLE_CONNECTED: { linkDBInfo_t linkInfo; uint8_t numActive = 0; numActive = linkDB_NumActive(); // Use numActive to determine the connection handle of the last // connection if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS ) { Display_print1(dispHandle, 2, 0, "Num Conns: %d", (uint16_t)numActive); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(linkInfo.addr)); } else { uint8_t peerAddress[B_ADDR_LEN]; GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); Display_print0(dispHandle, 2, 0, "Connected"); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddress)); } } break; case GAPROLE_WAITING: case GAPROLE_WAITING_AFTER_TIMEOUT: SimplePropBeacon_freeAttRsp(bleNotConnected); SimplePropBeacon_startRegularAdv(); break; case GAPROLE_ERROR: Display_print0(dispHandle, 2, 0, "Error"); break; default: Display_clearLine(dispHandle, 2); break; } }
/********************************************************************* * @fn SimpleBLEPeripheral_processStateChangeEvt * * @brief Process a pending GAP Role state change event. * * @param newState - new state * * @return None. */ static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState) { #ifdef PLUS_BROADCASTER static bool firstConnFlag = false; #endif // PLUS_BROADCASTER switch ( newState ) { case GAPROLE_STARTED: { uint8_t ownAddress[B_ADDR_LEN]; uint8_t systemId[DEVINFO_SYSTEM_ID_LEN]; GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress); // use 6 bytes of device address for 8 bytes of system ID value systemId[0] = ownAddress[0]; systemId[1] = ownAddress[1]; systemId[2] = ownAddress[2]; // set middle bytes to zero systemId[4] = 0x00; systemId[3] = 0x00; // shift three bytes up systemId[7] = ownAddress[5]; systemId[6] = ownAddress[4]; systemId[5] = ownAddress[3]; DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId); // Display device address Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(ownAddress)); Display_print0(dispHandle, 2, 0, "Initialized"); } break; case GAPROLE_ADVERTISING: Display_print0(dispHandle, 2, 0, "Advertising"); break; #ifdef PLUS_BROADCASTER /* After a connection is dropped a device in PLUS_BROADCASTER will continue * sending non-connectable advertisements and shall sending this change of * state to the application. These are then disabled here so that sending * connectable advertisements can resume. */ case GAPROLE_ADVERTISING_NONCONN: { uint8_t advertEnabled = FALSE; // Disable non-connectable advertising. GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t), &advertEnabled); advertEnabled = TRUE; // Enabled connectable advertising. GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnabled); // Reset flag for next connection. firstConnFlag = false; SimpleBLEPeripheral_freeAttRsp(bleNotConnected); } break; #endif //PLUS_BROADCASTER case GAPROLE_CONNECTED: { linkDBInfo_t linkInfo; uint8_t numActive = 0; Util_startClock(&periodicClock); numActive = linkDB_NumActive(); // Use numActive to determine the connection handle of the last // connection if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS ) { Display_print1(dispHandle, 2, 0, "Num Conns: %d", (uint16_t)numActive); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(linkInfo.addr)); } else { uint8_t peerAddress[B_ADDR_LEN]; GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); Display_print0(dispHandle, 2, 0, "Connected"); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddress)); } #ifdef PLUS_BROADCASTER // Only turn advertising on for this state when we first connect // otherwise, when we go from connected_advertising back to this state // we will be turning advertising back on. if (firstConnFlag == false) { uint8_t advertEnabled = FALSE; // Turn on Advertising // Disable connectable advertising. GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnabled); // Set to true for non-connectabel advertising. advertEnabled = TRUE; // Enable non-connectable advertising. GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t), &advertEnabled); firstConnFlag = true; } #endif // PLUS_BROADCASTER } break; case GAPROLE_CONNECTED_ADV: Display_print0(dispHandle, 2, 0, "Connected Advertising"); break; case GAPROLE_WAITING: Util_stopClock(&periodicClock); SimpleBLEPeripheral_freeAttRsp(bleNotConnected); Display_print0(dispHandle, 2, 0, "Disconnected"); // Clear remaining lines Display_clearLines(dispHandle, 3, 5); break; case GAPROLE_WAITING_AFTER_TIMEOUT: SimpleBLEPeripheral_freeAttRsp(bleNotConnected); Display_print0(dispHandle, 2, 0, "Timed Out"); // Clear remaining lines Display_clearLines(dispHandle, 3, 5); #ifdef PLUS_BROADCASTER // Reset flag for next connection. firstConnFlag = false; #endif //#ifdef (PLUS_BROADCASTER) break; case GAPROLE_ERROR: Display_print0(dispHandle, 2, 0, "Error"); break; default: Display_clearLine(dispHandle, 2); break; } // Update the state //gapProfileState = newState; }