/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void *pValue ) { bStatus_t ret = SUCCESS; switch ( param ) { case GAPROLE_IRK: if ( len == KEYLEN ) { VOID osal_memcpy( gapRole_IRK, pValue, KEYLEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SRK: if ( len == KEYLEN ) { VOID osal_memcpy( gapRole_SRK, pValue, KEYLEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SIGNCOUNTER: if ( len == sizeof ( uint32 ) ) { gapRole_signCounter = *((uint32*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_ENABLED: if ( len == sizeof( uint8 ) ) { if ( (gapRole_state == GAPROLE_CONNECTED) || (gapRole_state == GAPROLE_CONNECTED_ADV) ) { uint8 advEnabled = *((uint8*)pValue); if ( (gapRole_state == GAPROLE_CONNECTED) && (advEnabled == TRUE) ) { // Turn on advertising osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } else if ( (gapRole_state == GAPROLE_CONNECTED_ADV) && (advEnabled == FALSE) ) { // Turn off Advertising GAP_EndDiscoverable( gapRole_TaskID ); } } else { uint8 oldAdvEnabled = gapRole_AdvEnabled; gapRole_AdvEnabled = *((uint8*)pValue); if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) { // Turn off Advertising VOID GAP_EndDiscoverable( gapRole_TaskID ); } else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) { // Turn on Advertising if ( (gapRole_state == GAPROLE_STARTED) || (gapRole_state == GAPROLE_WAITING ) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) ) { VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } } } } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_OFF_TIME: if ( len == sizeof ( uint16 ) ) { gapRole_AdvertOffTime = *((uint16*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_AdvertData, pValue, len ); gapRole_AdvertDataLen = len; } else { ret = bleInvalidRange; } break; case GAPROLE_SCAN_RSP_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); gapRole_ScanRspDataLen = len; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_EVENT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) { gapRole_AdvEventType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) { gapRole_AdvDirectType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_ADDR: if ( len == B_ADDR_LEN ) { VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_CHANNEL_MAP: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) { gapRole_AdvChanMap = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_FILTER_POLICY: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) { gapRole_AdvFilterPolicy = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_RSSI_READ_RATE: if ( len == sizeof ( uint16 ) ) { gapRole_RSSIReadRate = *((uint16*)pValue); if ( (gapRole_RSSIReadRate) && (gapRole_state == GAPROLE_CONNECTED) ) { // Start the RSSI Reads VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); } } else { ret = bleInvalidRange; } break; case GAPROLE_PARAM_UPDATE_ENABLE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) { gapRole_ParamUpdateEnable = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_MIN_CONN_INTERVAL: { uint16 newInterval = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && ( newInterval >= MIN_CONN_INTERVAL ) && ( newInterval <= MAX_CONN_INTERVAL ) ) { gapRole_MinConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_MAX_CONN_INTERVAL: { uint16 newInterval = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && ( newInterval >= MIN_CONN_INTERVAL) && ( newInterval <= MAX_CONN_INTERVAL) ) { gapRole_MaxConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_SLAVE_LATENCY: { uint16 latency = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && (latency < MAX_SLAVE_LATENCY) ) { gapRole_SlaveLatency = latency; } else { ret = bleInvalidRange; } } break; case GAPROLE_TIMEOUT_MULTIPLIER: { uint16 newTimeout = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER) ) { gapRole_TimeoutMultiplier = newTimeout; } 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 )) ) { ret = GAP_SetParamValue( param, *((uint16*)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 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 osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN ); gapRole_state = GAPROLE_STARTED; // Update the advertising data stat = GAP_UpdateAdvertisingData( gapRole_TaskID, 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( gapRole_TaskID, FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); } else { // Start advertising VOID osal_set_event( gapRole_TaskID, 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 { gapRole_state = GAPROLE_ADVERTISING; } } else // GAP_END_DISCOVERABLE_DONE_EVENT { if ( gapRole_AdvertOffTime != 0 ) { if ( ( gapRole_AdvEnabled ) ) { VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, 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 gapRole_AdvEnabled = FALSE; } // 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 osal_memcpy( gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN ); gapRole_ConnectionHandle = pPkt->connectionHandle; gapRole_state = GAPROLE_CONNECTED; if ( gapRole_RSSIReadRate ) { // Start the RSSI Reads VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); } // Check whether update parameter request is enabled, and check the connection parameters if ( ( gapRole_ParamUpdateEnable == TRUE ) && ( (pPkt->connInterval < gapRole_MinConnInterval) || (pPkt->connInterval > gapRole_MaxConnInterval) || (pPkt->connLatency != gapRole_SlaveLatency) || (pPkt->connTimeout != gapRole_TimeoutMultiplier) )) { gapRole_SendUpdateParam( pPkt->connInterval, pPkt->connLatency ); } // Notify the Bond Manager to the connection VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL ); } else { gapRole_state = GAPROLE_ERROR; } notify = TRUE; } break; case GAP_LINK_TERMINATED_EVENT: { VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t *)pMsg ); osal_memset( gapRole_ConnectedDevAddr, 0, B_ADDR_LEN ); if ( gapRole_state == GAPROLE_CONNECTED_ADV ) { // End the non-connectable advertising GAP_EndDiscoverable( gapRole_TaskID ); gapRole_state = GAPROLE_CONNECTED; } else { gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg; if( pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM ) { gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; } else { gapRole_state = GAPROLE_WAITING; } notify = TRUE; VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } gapRole_ConnectionHandle = INVALID_CONNHANDLE; } break; case GAP_LINK_PARAM_UPDATE_EVENT: { gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; if ( (pPkt->hdr.status != SUCCESS) || (pPkt->connInterval < gapRole_MinConnInterval) || (pPkt->connInterval > gapRole_MaxConnInterval) ) { // Ask to change the interval gapRole_SendUpdateParam( pPkt->connInterval, pPkt->connLatency ); } else { // All is good stop Update Parameters timeout VOID osal_stop_timerEx( gapRole_TaskID, UPDATE_PARAMS_TIMEOUT_EVT ); } } break; default: break; } if ( notify == TRUE ) { // Notify the application if ( pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange ) { pGapRoles_AppCGs->pfnStateChange( gapRole_state ); } } }
/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in broadcaster.h. */ bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void *pValue ) { bStatus_t ret = SUCCESS; switch ( param ) { case GAPROLE_ADVERT_ENABLED: if ( len == sizeof( uint8 ) ) { uint8 oldAdvEnabled = gapRole_AdvEnabled; gapRole_AdvEnabled = *((uint8*)pValue); if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) { // Turn off Advertising if ( gapRole_state == GAPROLE_ADVERTISING ) { VOID GAP_EndDiscoverable( gapRole_TaskID ); } } else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) { // Turn on Advertising if ( (gapRole_state == GAPROLE_STARTED) || (gapRole_state == GAPROLE_WAITING) ) { VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } } } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_OFF_TIME: if ( len == sizeof ( uint16 ) ) { gapRole_AdvertOffTime = *((uint16*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_AdvertData, pValue, len ); gapRole_AdvertDataLen = len; } else { ret = bleInvalidRange; } break; case GAPROLE_SCAN_RSP_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); gapRole_ScanRspDataLen = len; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_EVENT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) { gapRole_AdvEventType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) { gapRole_AdvDirectType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_ADDR: if ( len == B_ADDR_LEN ) { VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_CHANNEL_MAP: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) { gapRole_AdvChanMap = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_FILTER_POLICY: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) { gapRole_AdvFilterPolicy = *((uint8*)pValue); } 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 )) ) { ret = GAP_SetParamValue( param, *((uint16*)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 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 osal_memcpy( gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN ); gapRole_state = GAPROLE_STARTED; // Update the advertising data stat = GAP_UpdateAdvertisingData( gapRole_TaskID, 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( gapRole_TaskID, FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); } else if ( ( gapRole_state != GAPROLE_ADVERTISING ) && ( osal_get_timeoutEx( gapRole_TaskID, START_ADVERTISING_EVT ) == 0 ) ) { // Start advertising VOID osal_set_event( gapRole_TaskID, 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 { gapRole_state = GAPROLE_ADVERTISING; } } else // GAP_END_DISCOVERABLE_DONE_EVENT { if ( gapRole_AdvertOffTime != 0 ) { if ( ( gapRole_AdvEnabled ) ) { VOID osal_start_timerEx( gapRole_TaskID, START_ADVERTISING_EVT, 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 gapRole_AdvEnabled = FALSE; } if (gapRole_state == GAPROLE_CONNECTED_ADV) { // In the Advertising Off period gapRole_state = GAPROLE_CONNECTED; } else if (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) { // Advertising was just turned off after the link disconnected so begin // advertising again. gapRole_AdvEnabled = TRUE; // Turn advertising back on. VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } 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 osal_memcpy( gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN ); gapRole_ConnectionHandle = pPkt->connectionHandle; gapRole_state = GAPROLE_CONNECTED; if ( gapRole_RSSIReadRate ) { // Start the RSSI Reads VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); } // Store connection information gapRole_ConnInterval = pPkt->connInterval; gapRole_ConnSlaveLatency = pPkt->connLatency; gapRole_ConnTimeout = pPkt->connTimeout; // 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 timeout = GAP_GetParamValue( TGAP_CONN_PAUSE_PERIPHERAL ); osal_start_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT, timeout*1000 ); } // Notify the Bond Manager to the connection VOID GAPBondMgr_LinkEst( pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL ); // Set enabler to FALSE; device will become discoverable again when // this value gets set to TRUE gapRole_AdvEnabled = FALSE; } 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; VOID GAPBondMgr_ProcessGAPMsg( (gapEventHdr_t *)pMsg ); osal_memset( gapRole_ConnectedDevAddr, 0, B_ADDR_LEN ); // Erase connection information gapRole_ConnInterval = 0; gapRole_ConnSlaveLatency = 0; gapRole_ConnTimeout = 0; // Cancel all connection parameter update timers (if any active) VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); // Go to WAITING state, and then start advertising if( pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM ) { gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT; } else { gapRole_state = GAPROLE_WAITING; } notify = TRUE; // Check if still advertising from within last connection. if ( gapRole_AdvEnabled) { // End advertising so we can restart advertising in order // to change to connectable advertising from nonconnectable. VOID GAP_EndDiscoverable( gapRole_TaskID ); } else // Turn advertising back on. { gapRole_AdvEnabled = TRUE; VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT); } gapRole_ConnectionHandle = INVALID_CONNHANDLE; } break; case GAP_LINK_PARAM_UPDATE_EVENT: { gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg; // Cancel connection param update timeout timer (if active) VOID osal_stop_timerEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ); 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 ( osal_get_timeoutEx( gapRole_TaskID, START_CONN_UPDATE_EVT ) == 0 ) { // Notify the application with the new connection parameters if ( pGapRoles_ParamUpdateCB != NULL ) { (*pGapRoles_ParamUpdateCB)( gapRole_ConnInterval, gapRole_ConnSlaveLatency, gapRole_ConnTimeout ); } } } } 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 ); } } }
/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_SetParameter( uint16 param, uint8 len, void *pValue ) { bStatus_t ret = SUCCESS; switch ( param ) { case GAPROLE_IRK: if ( len == KEYLEN ) { VOID osal_memcpy( gapRole_IRK, pValue, KEYLEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SRK: if ( len == KEYLEN ) { VOID osal_memcpy( gapRole_SRK, pValue, KEYLEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_SIGNCOUNTER: if ( len == sizeof ( uint32 ) ) { gapRole_signCounter = *((uint32*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_ENABLED: if ( len == sizeof( uint8 ) ) { uint8 oldAdvEnabled = gapRole_AdvEnabled; gapRole_AdvEnabled = *((uint8*)pValue); if ( (oldAdvEnabled) && (gapRole_AdvEnabled == FALSE) ) { // Turn off Advertising if ( ( gapRole_state == GAPROLE_ADVERTISING ) || ( gapRole_state == GAPROLE_CONNECTED_ADV ) || ( gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT ) ) { VOID GAP_EndDiscoverable( gapRole_TaskID ); } } else if ( (oldAdvEnabled == FALSE) && (gapRole_AdvEnabled) ) { // Turn on Advertising if ( (gapRole_state == GAPROLE_STARTED) || (gapRole_state == GAPROLE_WAITING) || (gapRole_state == GAPROLE_CONNECTED) || (gapRole_state == GAPROLE_WAITING_AFTER_TIMEOUT) ) { VOID osal_set_event( gapRole_TaskID, START_ADVERTISING_EVT ); } } } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_OFF_TIME: if ( len == sizeof ( uint16 ) ) { gapRole_AdvertOffTime = *((uint16*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADVERT_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_AdvertData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_AdvertData, pValue, len ); gapRole_AdvertDataLen = len; // Update the advertising data ret = GAP_UpdateAdvertisingData( gapRole_TaskID, TRUE, gapRole_AdvertDataLen, gapRole_AdvertData ); } else { ret = bleInvalidRange; } break; case GAPROLE_SCAN_RSP_DATA: if ( len <= B_MAX_ADV_LEN ) { VOID osal_memset( gapRole_ScanRspData, 0, B_MAX_ADV_LEN ); VOID osal_memcpy( gapRole_ScanRspData, pValue, len ); gapRole_ScanRspDataLen = len; // Update the Response Data ret = GAP_UpdateAdvertisingData( gapRole_TaskID, FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData ); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_EVENT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND) ) { gapRole_AdvEventType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_TYPE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= ADDRTYPE_PRIVATE_RESOLVE) ) { gapRole_AdvDirectType = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_DIRECT_ADDR: if ( len == B_ADDR_LEN ) { VOID osal_memcpy( gapRole_AdvDirectAddr, pValue, B_ADDR_LEN ) ; } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_CHANNEL_MAP: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= 0x07) ) { gapRole_AdvChanMap = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_ADV_FILTER_POLICY: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= GAP_FILTER_POLICY_WHITE) ) { gapRole_AdvFilterPolicy = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_RSSI_READ_RATE: if ( len == sizeof ( uint16 ) ) { gapRole_RSSIReadRate = *((uint16*)pValue); if ( (gapRole_RSSIReadRate) && (gapRole_state == GAPROLE_CONNECTED) ) { // Start the RSSI Reads VOID osal_start_timerEx( gapRole_TaskID, RSSI_READ_EVT, gapRole_RSSIReadRate ); } } else { ret = bleInvalidRange; } break; case GAPROLE_PARAM_UPDATE_ENABLE: if ( (len == sizeof ( uint8 )) && (*((uint8*)pValue) <= TRUE) ) { gapRole_ParamUpdateEnable = *((uint8*)pValue); } else { ret = bleInvalidRange; } break; case GAPROLE_MIN_CONN_INTERVAL: { uint16 newInterval = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && ( newInterval >= MIN_CONN_INTERVAL ) && ( newInterval <= MAX_CONN_INTERVAL ) ) { gapRole_MinConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_MAX_CONN_INTERVAL: { uint16 newInterval = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && ( newInterval >= MIN_CONN_INTERVAL) && ( newInterval <= MAX_CONN_INTERVAL) ) { gapRole_MaxConnInterval = newInterval; } else { ret = bleInvalidRange; } } break; case GAPROLE_SLAVE_LATENCY: { uint16 latency = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && (latency < MAX_SLAVE_LATENCY) ) { gapRole_SlaveLatency = latency; } else { ret = bleInvalidRange; } } break; case GAPROLE_TIMEOUT_MULTIPLIER: { uint16 newTimeout = *((uint16*)pValue); if ( len == sizeof ( uint16 ) && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER) ) { gapRole_TimeoutMultiplier = newTimeout; } else { ret = bleInvalidRange; } } break; case GAPROLE_PARAM_UPDATE_REQ: { uint8 req = *((uint8*)pValue); if ( len == sizeof ( uint8 ) && (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 ( osal_get_timeoutEx( gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT ) == 0 ) { // Start connection update procedure gapRole_startConnUpdate( GAPROLE_NO_ACTION ); // Connection update requested by app, cancel such pending procedure (if active) VOID osal_stop_timerEx( gapRole_TaskID, START_CONN_UPDATE_EVT ); } 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 )) ) { ret = GAP_SetParamValue( param, *((uint16*)pValue) ); } else { ret = INVALIDPARAMETER; } break; } return ( ret ); }
/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_SetParameter(uint16_t param, uint8_t len, void *pValue, uint8 connHandle) { 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: //connectable advertising 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)) { return GAP_EndDiscoverable(selfEntity); } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvEnabled)) { // Turn on advertising. if (linkDB_NumActive() >= MAX_NUM_BLE_CONNS) //don't do conn adv if we don't have any avilable links { return bleNoResources; // no more available links } else { 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)) { VOID GAP_EndDiscoverable(selfEntity); } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvNonConnEnabled)) { //turnon advertising 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) <= ADDRMODE_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_MAX_SCAN_RES: if (len == sizeof (uint8_t)) { gapRoleMaxScanRes = *((uint8_t*)pValue); } 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); }
/********************************************************************* * @brief Set a GAP Role parameter. * * Public function defined in peripheral.h. */ bStatus_t GAPRole_SetParameter(uint16_t param, uint8_t len, void *pValue, uint8 connHandle) { 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: //connectable advertising 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_peripheralState == GAPROLE_ADVERTISING) || (gapRole_peripheralState == GAPROLE_WAITING_AFTER_TIMEOUT)) { VOID GAP_EndDiscoverable(selfEntity); //} } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvEnabled)) { // Turn on advertising. if (gapRoleNumLinks(GAPROLE_AVAILABLE_LINKS)) //don't do conn adv if we don't have any avilable links { // Turn on advertising. //if ((gapRole_peripheralState == GAPROLE_STARTED) || (gapRole_peripheralState == GAPROLE_WAITING) || (gapRole_peripheralState == GAPROLE_WAITING_AFTER_TIMEOUT)) { gapRole_setEvent(START_ADVERTISING_EVT); //} //gapRole_setEvent(START_ADVERTISING_EVT); } else { return bleNoResources; // no more available links } } } 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_peripheralState == GAPROLE_ADVERTISING_NONCONN) || (gapRole_peripheralState == GAPROLE_CONNECTED_ADV) || (gapRole_peripheralState == GAPROLE_WAITING_AFTER_TIMEOUT)) { VOID GAP_EndDiscoverable(selfEntity); //} } else if ((oldAdvEnabled == FALSE) && (gapRole_AdvNonConnEnabled)) { // Turn on advertising. //if ((gapRole_peripheralState == GAPROLE_STARTED) || (gapRole_peripheralState == GAPROLE_WAITING) || (gapRole_peripheralState == GAPROLE_CONNECTED) // || (gapRole_peripheralState == 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) <= ADDRMODE_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 uint8 index = 0; while (index < MAX_NUM_BLE_CONNS && multiConnInfo[index].gapRole_ConnRole != GAP_PROFILE_PERIPHERAL && multiConnInfo[index].gapRole_ConnectionHandle != GAPROLE_CONN_JUST_TERMINATED) { index++; } if (index >= MAX_NUM_BLE_CONNS) { //no connection as peripheral found ret = INVALIDPARAMETER; //Util_stopClock(&startUpdateClock); } else { ret = gapRole_startConnUpdate(GAPROLE_NO_ACTION, multiConnInfo[index].gapRole_ConnectionHandle); } if (ret == SUCCESS) { // Connection update requested by app, cancel such pending procedure (if active) Util_stopClock(&startUpdateClock); } } else { ret = blePending; } } else { ret = bleInvalidRange; } } break; case GAPROLE_MAX_SCAN_RES: if (len == sizeof(uint8_t)) { gapRoleMaxScanRes = *((uint8_t*) pValue); } 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); }