/********************************************************************* * @fn SensorTagKeys_clockHandler * * @brief Handler function for clock time-outs. * * @param arg - event type * * @return none */ static void SensorTagKeys_clockHandler(UArg arg) { // Are both keys pressed? if (keys & SK_KEY_RIGHT) { keyTimer++; } else { keyTimer = 0; } // Both keys have been pressed for 6 seconds -> restore factory image if (keyTimer >= RESET_PRESS_PERIOD ) { // Stop the clock if (Util_isActive(&periodicClock)) { Util_stopClock(&periodicClock); keyTimer = 0; // set event flag and wake up the application thread event |= SK_EVT_FACTORY_RESET; Semaphore_post(sem); } } // // Right key (POWER) pressed for three seconds, disconnect if connected // else if (keyRightTimer >= POWER_PRESS_PERIOD && keyLeftTimer == 0) // { // // Stop the clock // if (Util_isActive(&periodicClock)) // { // Util_stopClock(&periodicClock); // keyRightTimer = 0; // // // set event flag and wake up the application thread // event |= SK_EVT_DISCONNECT; // Semaphore_post(sem); // } // } else if (keyTimer == 0) { // Stop the clock if (Util_isActive(&periodicClock)) { Util_stopClock(&periodicClock); } } }
static void rightKeyEvent_Handler(void) { if (PIN_getInputValue(Board_KEY_RIGHT) == 0) { longPressedButtonCheck |= KEY_RIGHT_EVT; longPressNotiSent = 0; if(Util_isActive(&longPressCheckClock)){ Util_startClock(&longPressCheckClock); }else{ Util_startClock(&longPressCheckClock); } } else { longPressedButtonCheck &= ~KEY_RIGHT_EVT; if(longPressedButtonCheck == 0){ Util_stopClock(&longPressCheckClock); } if (Keys_AppCGs && longPressNotiSent == 0) { Keys_AppCGs->pfnKeysNotification(RIGHT_SHORT); } } }
/******************************************************************** * @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 SensorTag_processStateChangeEvt * * @brief Process a pending GAP Role state change event. * * @param newState - new state * * @return none */ static void SensorTag_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]; SensorTag_blinkLed(Board_LED2, 5); 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); LCD_WRITES_STATUS("Initialized"); } break; case GAPROLE_ADVERTISING: // Start the clock if (!Util_isActive(&periodicClock)) { Util_startClock(&periodicClock); } // Make sure key presses are not stuck sensorTag_updateAdvertisingData(0); LCD_WRITES_STATUS("Advertising"); break; case GAPROLE_CONNECTED: { // Start the clock if (!Util_isActive(&periodicClock)) { Util_startClock(&periodicClock); } // Turn of LEDs and buzzer PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF); PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF); PIN_setOutputValue(hGpioPin, Board_BUZZER, Board_BUZZER_OFF); #ifdef FEATURE_OAD SensorTagConnectionControl_update(); #endif #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 = TRUE; // Turn on Advertising GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnabled); firstConnFlag = true; } #endif // PLUS_BROADCASTER } LCD_WRITES_STATUS("Connected"); break; case GAPROLE_CONNECTED_ADV: break; case GAPROLE_WAITING: case GAPROLE_WAITING_AFTER_TIMEOUT: SensorTag_resetAllSensors(); LCD_WRITES_STATUS("Waiting..."); break; case GAPROLE_ERROR: SensorTag_resetAllSensors(); PIN_setOutputValue(hGpioPin,Board_LED1, Board_LED_ON); LCD_WRITES_STATUS("Error"); break; default: break; } gapProfileState = newState; }
/********************************************************************* * @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; }
/********************************************************************* * @fn SensorTagKeys_processEvent * * @brief SensorTag Keys event processor. * * @param none * * @return none */ void SensorTagKeys_processEvent(void) { static uint8_t current_keys = 0; // Factory reset by six second simultaneous key press if (event & SK_EVT_FACTORY_RESET) { event &= ~SK_EVT_FACTORY_RESET; // Indicate that we're entering factory reset SensorTagIO_blinkLed(IOID_RED_LED, 10); // Apply factory image and reboot SensorTagFactoryReset_applyFactoryImage(); } // Disconnect on three seconds press on the power switch (right key) if (event & SK_EVT_DISCONNECT) { event &= ~SK_EVT_DISCONNECT; if (gapProfileState == GAPROLE_CONNECTED) { processGapStateChange(); } } // Set the value of the keys state to the Simple Keys Profile; // This will send out a notification of the keys state if enabled if (current_keys != keys) { SK_SetParameter(SK_KEY_ATTR, sizeof(uint8_t), &keys); // Insert key state into advertising data if (gapProfileState == GAPROLE_ADVERTISING) { SensorTag_updateAdvertisingData(keys); } // Check if right key was pressed if ((current_keys & SK_KEY_RIGHT)!=0 && (keys & SK_KEY_RIGHT)==0) { if (gapProfileState != GAPROLE_CONNECTED) { // Not connected; change state immediately (power/right button) processGapStateChange(); } } // Has a key been pressed ? if ((keys & SK_PUSH_KEYS) && (current_keys == 0)) { if (!Util_isActive(&periodicClock)) { Util_startClock(&periodicClock); keyTimer = 0; } } } current_keys = keys; }
/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_SetParameter(uint16_t param, uint8_t len, void *pValue) { bStatus_t ret = SUCCESS; switch (param) { case GAPROLE_IRK: if (len == KEYLEN) { VOID memcpy(gapRole_IRK, pValue, KEYLEN) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SRK: if (len == KEYLEN) { VOID memcpy(gapRole_SRK, pValue, KEYLEN) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SIGNCOUNTER: if (len == sizeof (uint32_t)) { gapRole_signCounter = *((uint32_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_ENABLED: if (len == sizeof(uint8_t)) { // Non-connectable advertising must be disabled. if (gapRole_AdvNonConnEnabled != TRUE) { uint8_t oldAdvEnabled = gapRole_AdvEnabled; gapRole_AdvEnabled = *((uint8_t*)pValue); if ((oldAdvEnabled) && (gapRole_AdvEnabled == FALSE)) { // Turn off advertising. if ((gapRole_state == GAPROLE_ADVERTISING) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT)) { VOID GAP_EndDiscoverable(selfEntity); } } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvEnabled)) { // Turn on advertising. if ((gapRole_state == GAPROLE_STARTED) || (gapRole_state == GAPROLE_WAITING) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT)) { gapRole_setEvent(START_ADVERTISING_EVT); } } } else { ret = bleIncorrectMode; } } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_NONCONN_ENABLED: if (len == sizeof(uint8_t)) { // Connectable advertising must be disabled. if (gapRole_AdvEnabled != TRUE) { uint8_t oldAdvEnabled = gapRole_AdvNonConnEnabled; gapRole_AdvNonConnEnabled = *((uint8_t*)pValue); if ((oldAdvEnabled) && (gapRole_AdvNonConnEnabled == FALSE)) { if ((gapRole_state == GAPROLE_ADVERTISING_NONCONN) || (gapRole_state == GAPROLE_CONNECTED_ADV) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT)) { VOID GAP_EndDiscoverable(selfEntity); } } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvNonConnEnabled)) { // Turn on advertising. if ((gapRole_state == GAPROLE_STARTED) || (gapRole_state == GAPROLE_WAITING) || (gapRole_state == GAPROLE_CONNECTED) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT)) { gapRole_setEvent(START_ADVERTISING_EVT); } } } else { ret = bleIncorrectMode; } } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_OFF_TIME: if (len == sizeof (uint16_t)) { gapRole_AdvertOffTime = *((uint16_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_DATA: if (len <= B_MAX_ADV_LEN) { VOID memset(gapRole_AdvertData, 0, B_MAX_ADV_LEN); VOID memcpy(gapRole_AdvertData, pValue, len); gapRole_AdvertDataLen = len; // Update the advertising data ret = GAP_UpdateAdvertisingData(selfEntity, TRUE, gapRole_AdvertDataLen, gapRole_AdvertData); } else { ret = bleInvalidRange; } break; case GAPROLE_SCAN_RSP_DATA: if (len <= B_MAX_ADV_LEN) { VOID memset(gapRole_ScanRspData, 0, B_MAX_ADV_LEN); VOID memcpy(gapRole_ScanRspData, pValue, len); gapRole_ScanRspDataLen = len; // Update the Response Data ret = GAP_UpdateAdvertisingData(selfEntity, FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_EVENT_TYPE: if ((len == sizeof (uint8_t)) && (*((uint8_t*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND)) { gapRole_AdvEventType = *((uint8_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_TYPE: if ((len == sizeof (uint8_t)) && (*((uint8_t*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE)) { gapRole_AdvDirectType = *((uint8_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_ADDR: if (len == B_ADDR_LEN) { VOID memcpy(gapRole_AdvDirectAddr, pValue, B_ADDR_LEN) ; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_CHANNEL_MAP: if ((len == sizeof (uint8_t)) && (*((uint8_t*)pValue) <= 0x07)) { gapRole_AdvChanMap = *((uint8_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_FILTER_POLICY: if ((len == sizeof (uint8_t)) && (*((uint8_t*)pValue) <= GAP_FILTER_POLICY_WHITE)) { gapRole_AdvFilterPolicy = *((uint8_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_PARAM_UPDATE_ENABLE: if ((len == sizeof (uint8_t)) && (*((uint8_t*)pValue) <= TRUE)) { gapRole_ParamUpdateEnable = *((uint8_t*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_MIN_CONN_INTERVAL: { uint16_t newInterval = *((uint16_t*)pValue); if ( len == sizeof (uint16_t) && (newInterval >= MIN_CONN_INTERVAL) && (newInterval <= MAX_CONN_INTERVAL)) { gapRole_MinConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_MAX_CONN_INTERVAL: { uint16_t newInterval = *((uint16_t*)pValue); if ( len == sizeof (uint16_t) && (newInterval >= MIN_CONN_INTERVAL) && (newInterval <= MAX_CONN_INTERVAL)) { gapRole_MaxConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_SLAVE_LATENCY: { uint16_t latency = *((uint16_t*)pValue); if (len == sizeof (uint16_t) && (latency < MAX_SLAVE_LATENCY)) { gapRole_SlaveLatency = latency; } else { ret = bleInvalidRange; } } break; case GAPROLE_TIMEOUT_MULTIPLIER: { uint16_t newTimeout = *((uint16_t*)pValue); if (len == sizeof (uint16_t) && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER)) { gapRole_TimeoutMultiplier = newTimeout; } else { ret = bleInvalidRange; } } break; case GAPROLE_PARAM_UPDATE_REQ: { uint8_t req = *((uint8_t*)pValue); if (len == sizeof (uint8_t) && (req == TRUE)) { // 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) { // Start connection update procedure ret = gapRole_startConnUpdate(GAPROLE_NO_ACTION); if (ret == SUCCESS) { // Connection update requested by app, cancel such pending procedure (if active) Util_stopClock(&startUpdateClock); } } else { ret = blePending; } } else { ret = bleInvalidRange; } } break; default: // The param value isn't part of this profile, try the GAP. if ((param < TGAP_PARAMID_MAX) && (len == sizeof (uint16_t))) { ret = GAP_SetParamValue(param, *((uint16_t*)pValue)); } else { ret = INVALIDPARAMETER; } break; } return (ret); }
/********************************************************************* * @fn gapRole_processGAPMsg * * @brief Process an incoming task message. * * @param pMsg - message to process * * @return none */ static void 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); gapRole_state = GAPROLE_STARTED; // Update the advertising data stat = GAP_UpdateAdvertisingData(selfEntity, TRUE, gapRole_AdvertDataLen, gapRole_AdvertData); } if (stat != SUCCESS) { gapRole_state = GAPROLE_ERROR; } 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 ((gapRole_state != GAPROLE_ADVERTISING) && (gapRole_state != GAPROLE_CONNECTED_ADV) && (gapRole_state != GAPROLE_CONNECTED || gapRole_AdvNonConnEnabled == TRUE) && (Util_isActive(&startAdvClock) == FALSE)) { // Start advertising gapRole_setEvent(START_ADVERTISING_EVT); } } if (pPkt->hdr.status != SUCCESS) { // Set into Error state gapRole_state = GAPROLE_ERROR; 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) { if (gapRole_state == GAPROLE_CONNECTED) { gapRole_state = GAPROLE_CONNECTED_ADV; } else if (gapRole_AdvEnabled) { gapRole_state = GAPROLE_ADVERTISING; } else { gapRole_state = GAPROLE_ADVERTISING_NONCONN; } } else // GAP_END_DISCOVERABLE_DONE_EVENT { if (gapRole_AdvertOffTime != 0) { 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; } else { gapRole_AdvNonConnEnabled = FALSE; } } // Update state. if (gapRole_state == GAPROLE_CONNECTED_ADV) { // In the Advertising Off period gapRole_state = GAPROLE_CONNECTED; } else { // In the Advertising Off period gapRole_state = GAPROLE_WAITING; } } } else { gapRole_state = GAPROLE_ERROR; } notify = TRUE; } break; case GAP_LINK_ESTABLISHED_EVENT: { gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg; if (pPkt->hdr.status == SUCCESS) { VOID memcpy(gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN); gapRole_ConnectionHandle = pPkt->connectionHandle; gapRole_state = GAPROLE_CONNECTED; // Store connection information gapRole_ConnInterval = pPkt->connInterval; gapRole_ConnSlaveLatency = pPkt->connLatency; gapRole_ConnTimeout = pPkt->connTimeout; gapRole_ConnectedDevAddrType = pPkt->devAddrType; // Check whether update parameter request is enabled if (gapRole_ParamUpdateEnable == TRUE) { // Get the minimum time upon connection establishment before the // peripheral can start a connection update procedure. uint16_t timeout = GAP_GetParamValue(TGAP_CONN_PAUSE_PERIPHERAL); Util_restartClock(&startUpdateClock, timeout*1000); } // Notify the Bond Manager to the connection VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL); } 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; // Go to WAITING state, and then start advertising gapRole_state = GAPROLE_WAITING; } else { gapRole_state = GAPROLE_ERROR; } notify = TRUE; } break; case GAP_LINK_TERMINATED_EVENT: { gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg; GAPBondMgr_LinkTerm(pPkt->connectionHandle); memset(gapRole_ConnectedDevAddr, 0, B_ADDR_LEN); // Erase connection information gapRole_ConnInterval = 0; gapRole_ConnSlaveLatency = 0; gapRole_ConnTimeout = 0; gapRole_ConnTermReason = pPkt->reason; // Cancel all connection parameter update timers (if any active) Util_stopClock(&startUpdateClock); Util_stopClock(&updateTimeoutClock); notify = TRUE; gapRole_ConnectionHandle = INVALID_CONNHANDLE; // If device was advertising when connection dropped if (gapRole_AdvNonConnEnabled) { // Continue advertising. gapRole_state = GAPROLE_ADVERTISING_NONCONN; } // Else go to WAITING state. else { if(pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM) { gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; } else { gapRole_state = GAPROLE_WAITING; } // Start advertising, if enabled. gapRole_setEvent(START_ADVERTISING_EVT); } } 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) { // Store new connection parameters gapRole_ConnInterval = pPkt->connInterval; gapRole_ConnSlaveLatency = pPkt->connLatency; gapRole_ConnTimeout = pPkt->connTimeout; // Make sure there's no pending connection update procedure if(Util_isActive(&startUpdateClock) == FALSE) { // Notify the application with the new connection parameters if (pGapRoles_ParamUpdateCB != NULL) { (*pGapRoles_ParamUpdateCB)(gapRole_ConnInterval, gapRole_ConnSlaveLatency, gapRole_ConnTimeout); } } } } break; case GAP_PAIRING_REQ_EVENT: { gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg; // Send Pairing Failed Response VOID GAP_TerminateAuth(pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED); } break; default: break; } if (notify == TRUE) { // Notify the application with the new state change if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange) { pGapRoles_AppCGs->pfnStateChange(gapRole_state); } } }
/********************************************************************* * @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); gapRole_peripheralState = GAPROLE_STARTED; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); // Update the advertising data stat = GAP_UpdateAdvertisingData(selfEntity, TRUE, gapRole_AdvertDataLen, gapRole_AdvertData); } if (stat != SUCCESS) { gapRole_peripheralState = GAPROLE_ERROR; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); //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 ((gapRole_peripheralState != GAPROLE_ADVERTISING) && (gapRole_peripheralState != GAPROLE_CONNECTED_ADV) && (gapRole_peripheralState != GAPROLE_CONNECTED || gapRole_AdvNonConnEnabled == TRUE) && (Util_isActive(&startAdvClock) == FALSE)) { // Start advertising gapRole_setEvent(START_ADVERTISING_EVT); } notify = FALSE; }else { // Set into Error state gapRole_peripheralState = GAPROLE_ERROR; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); //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) { if (gapRole_peripheralState == GAPROLE_CONNECTED) { gapRole_peripheralState = GAPROLE_CONNECTED_ADV; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } else if (gapRole_AdvEnabled) { gapRole_peripheralState = GAPROLE_ADVERTISING; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } else { gapRole_peripheralState = GAPROLE_ADVERTISING_NONCONN; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } } 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; } else { gapRole_AdvNonConnEnabled = FALSE; } } // Update state. if (gapRole_peripheralState == GAPROLE_CONNECTED_ADV) { // In the Advertising Off period gapRole_peripheralState = GAPROLE_CONNECTED; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } else { // In the Advertising Off period gapRole_peripheralState = GAPROLE_WAITING; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } } notify = TRUE; } else if (pPkt->hdr.status == LL_STATUS_ERROR_COMMAND_DISALLOWED) //we're already advertising { notify = FALSE; } else { gapRole_peripheralState = GAPROLE_ERROR; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); //gapRole_abort(); } } break; case GAP_LINK_ESTABLISHED_EVENT: { gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *) pMsg; if (pPkt->hdr.status == SUCCESS) { //add to database gapRoleInfo_Add(pPkt); // advertising will stop when a connection forms in the peripheral role if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) { gapRole_peripheralState = GAPROLE_CONNECTED; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); // Check whether update parameter request is enabled if (gapRole_ParamUpdateEnable == TRUE) { // Get the minimum time upon connection establishment before the // peripheral can start a connection update procedure. uint16_t timeout = GAP_GetParamValue( TGAP_CONN_PAUSE_PERIPHERAL); Util_restartClock(&startUpdateClock, timeout * 1000); } } // Notify the Bond Manager to the connection VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, pPkt->connRole); } 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; // Go to WAITING state, and then start advertising if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) { gapRole_peripheralState = GAPROLE_WAITING; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } } else { if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) { gapRole_peripheralState = GAPROLE_ERROR; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } else { gapRole_abort(); } } notify = TRUE; } break; case GAP_LINK_TERMINATED_EVENT: { gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *) pMsg; // notify bond manager GAPBondMgr_LinkTerm(pPkt->connectionHandle); // Erase connection information (maybe make this a function) uint8 connHandleIndex = gapRoleInfo_Find(pPkt->connectionHandle); multiConnInfo[connHandleIndex].gapRole_ConnectionHandle = INVALID_CONNHANDLE; multiConnInfo[connHandleIndex].gapRole_ConnInterval = 0; multiConnInfo[connHandleIndex].gapRole_ConnSlaveLatency = 0; multiConnInfo[connHandleIndex].gapRole_ConnTimeout = 0; // Cancel all connection parameter update timers (if any active) Util_stopClock(&startUpdateClock); Util_stopClock(&updateTimeoutClock); notify = TRUE; if (multiConnInfo[connHandleIndex].gapRole_ConnRole == GAP_PROFILE_PERIPHERAL) { // If device was advertising when connection dropped if (gapRole_AdvNonConnEnabled) { // Continue advertising. gapRole_peripheralState = GAPROLE_ADVERTISING_NONCONN; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } // Else go to WAITING state. else { if (pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM) { gapRole_peripheralState = GAPROLE_WAITING_AFTER_TIMEOUT; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } else { gapRole_peripheralState = GAPROLE_WAITING; gapRole_peripheralStateChangeHandler(gapRole_peripheralState); } // Start advertising, if enabled. gapRole_setEvent(START_ADVERTISING_EVT); } } } 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) { // Store new connection parameters // gapRole_ConnInterval = pPkt->connInterval; // gapRole_ConnSlaveLatency = pPkt->connLatency; // gapRole_ConnTimeout = pPkt->connTimeout; // Make sure there's no pending connection update procedure if (Util_isActive(&startUpdateClock) == FALSE) { // // Notify the application with the new connection parameters // if (pGapRoles_ParamUpdateCB != NULL) // { // (*pGapRoles_ParamUpdateCB)(gapRole_ConnInterval, // gapRole_ConnSlaveLatency, // gapRole_ConnTimeout); // } } } notify = TRUE; } break; case GAP_PAIRING_REQ_EVENT: { gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *) pMsg; // Send Pairing Failed Response VOID GAP_TerminateAuth(pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED); } 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_DEVICE_INFO_EVENT: case GAP_DEVICE_DISCOVERY_EVENT: notify = TRUE; break; default: notify = FALSE; 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; }
/********************************************************************* * @fn RunningSensor_processServiceEvt * * @brief Handler RSC service callback. * * @param event - service event * @param newCummVal - new total distance data if specified by event. * 0 otherwise. * * @return SUCCESS if operation successful. FAILURE, otherwise. */ static bStatus_t RunningSensor_processServiceEvt(uint8_t event, uint32_t newCummVal) { bStatus_t status = SUCCESS; switch (event) { case RSC_CMD_SET_CUMM_VAL: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT // Update total distance. totalDistance = newCummVal; break; case RSC_CMD_START_SENS_CALIB: // Do nothing for now break; case RSC_CMD_UPDATE_SENS_LOC: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT // Get updated sensor location. RunningService_getParameter(RSC_SENS_LOC, &sensorLocation); break; case RSC_MEAS_NOTI_ENABLED: #if (USING_NEGLECT_TIMEOUT) // Stop neglect timer. Util_stopClock(&neglectClock); #endif //USING_NEGLECT_TIMEOUT // If connected start periodic measurement for notifications. if (gapProfileState == GAPROLE_CONNECTED) { Util_startClock(&periodicClock); } break; case RSC_MEAS_NOTI_DISABLED: // Stop periodic measurement. Util_stopClock(&periodicClock); #if USING_NEGLECT_TIMEOUT // Start neglect timer. Util_startClock(&neglectClock); #endif //USING_NEGLECT_TIMEOUT break; case RSC_READ_ATTR: case RSC_WRITE_ATTR: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT break; default: // Do nothing. break; } return (status); }
/********************************************************************* * @fn CyclingSensor_processServiceEvt * * @brief Handler function for CSC service callback. * * @param event - service event * @param newCummVal - new wheel revolution data if specified by event. * * @return none */ static void CyclingSensor_processServiceEvt(uint8_t event, uint32_t newCummVal) { switch (event) { case CSC_CMD_SET_CUMM_VAL: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT cummWheelRevs = newCummVal; break; case CSC_CMD_UPDATE_SENS_LOC: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT // Get updated sensor location. CyclingService_getParameter(CSC_SENS_LOC, &sensorLocation); break; case CSC_MEAS_NOTI_ENABLED: #if (USING_NEGLECT_TIMEOUT) // Stop neglect timer. Util_stopClock(&neglectClock); #endif //USING_NEGLECT_TIMEOUT // If connected start periodic measurement. if (gapProfileState == GAPROLE_CONNECTED) { Util_startClock(&periodicClock); } break; case CSC_MEAS_NOTI_DISABLED: // Stop periodic measurement. Util_stopClock(&periodicClock); #if USING_NEGLECT_TIMEOUT // Start neglect timer. Util_startClock(&neglectClock); #endif //USING_NEGLECT_TIMEOUT break; case CSC_READ_ATTR: case CSC_WRITE_ATTR: #if USING_NEGLECT_TIMEOUT // If notifications aren't enabled if (!Util_isActive(&periodicClock)) { // Restart neglect timer. Util_startClock(&neglectClock); } #endif //USING_NEGLECT_TIMEOUT break; default: // Do nothing. break; } }