/*********************************************************************
 * @fn      simpleTopology_processRoleEvent
 *
 * @brief   Multi role event processing function.
 *
 * @param   pEvent - pointer to event structure
 *
 * @return  none
 */
static void simpleTopology_processRoleEvent(gapMultiRoleEvent_t *pEvent)
{
	switch (pEvent->gap.opcode)
	{
	/*case GAP_MAKE_DISCOVERABLE_DONE_EVENT:
	{
		if (gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) > 0)
		{
			LCD_WRITE_STRING("Advertising", LCD_PAGE2);
		}
		else
		{
			LCD_WRITE_STRING("Advertising", LCD_PAGE2);
		}
	}
	break;*/
	case GAP_END_DISCOVERABLE_DONE_EVENT:
	{
		if (gapRoleNumLinks(GAPROLE_AVAILABLE_LINKS) > 0)
		{
			LCD_WRITE_STRING("Ready to Advertise", LCD_PAGE2);
		}
		else
		{
			LCD_WRITE_STRING("Can't Adv : No links", LCD_PAGE2);
		}
	}
	break;

	case GAP_DEVICE_DISCOVERY_EVENT:
	{
		// discovery complete
		scanningStarted = FALSE;

		advertising_enabled = TRUE;
		GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertising_enabled, NULL);

	}
	break;


	default:
		break;
	}
}
/*********************************************************************
 * @fn      simpleTopology_processRoleEvent
 *
 * @brief   Multi role event processing function.
 *
 * @param   pEvent - pointer to event structure
 *
 * @return  none
 */
static void simpleTopology_processRoleEvent(gapMultiRoleEvent_t *pEvent)
{
  switch (pEvent->gap.opcode)
  {
    case GAP_DEVICE_INIT_DONE_EVENT:  
      {
        maxPduSize = pEvent->initDone.dataPktLen;
        
        LCD_WRITE_STRING("Connected to 0", LCD_PAGE0);
        LCD_WRITE_STRING(Util_convertBdAddr2Str(pEvent->initDone.devAddr),
                         LCD_PAGE1);
        LCD_WRITE_STRING("Initialized", LCD_PAGE2);

        DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, pEvent->initDone.devAddr);    
      }
      break;

      case GAP_MAKE_DISCOVERABLE_DONE_EVENT:
        {
          if (gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) > 0)
          {
            LCD_WRITE_STRING("Advertising", LCD_PAGE2);
          }
          else
          {
            LCD_WRITE_STRING("Advertising", LCD_PAGE2);
          }
        }
      break;

      case GAP_END_DISCOVERABLE_DONE_EVENT:
        {
          if (gapRoleNumLinks(GAPROLE_AVAILABLE_LINKS) > 0)
          {
            LCD_WRITE_STRING("Ready to Advertise", LCD_PAGE2);
          }
          else
          {
            LCD_WRITE_STRING("Can't Adv : No links", LCD_PAGE2);
          }
        }
      break;      
      
    case GAP_DEVICE_INFO_EVENT:
      {
        // if filtering device discovery results based on service UUID
        if (DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE)
        {
          if (simpleTopology_findSvcUuid(SIMPLEPROFILE_SERV_UUID,
                                           pEvent->deviceInfo.pEvtData,
                                           pEvent->deviceInfo.dataLen))
          {
            simpleTopology_addDeviceInfo(pEvent->deviceInfo.addr,
                                           pEvent->deviceInfo.addrType);
          }
        }
      }
      break;
      
    case GAP_DEVICE_DISCOVERY_EVENT:
      {
        // discovery complete
        scanningStarted = FALSE;

        // if not filtering device discovery results based on service UUID
        if (DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE)
        {
          // Copy results
          scanRes = pEvent->discCmpl.numDevs;
          memcpy(devList, pEvent->discCmpl.pDevList,
                 (sizeof(gapDevRec_t) * scanRes));
        }
        
        LCD_WRITE_STRING_VALUE("Devices Found", scanRes, 10, LCD_PAGE3);
        
        if (scanRes > 0)
        {
          LCD_WRITE_STRING("<- To Select", LCD_PAGE4);
        }

        // initialize scan index to last device
        scanIdx = scanRes;
      }
      break;

    case GAP_LINK_ESTABLISHED_EVENT:
      {
        if (pEvent->gap.hdr.status == SUCCESS)
        {
          LCD_WRITE_STRING("Connected!", LCD_PAGE3);
          LCD_WRITE_STRING_VALUE("Connected to ", gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) ,10, LCD_PAGE0);
          
          //update state
          connecting_state = 0;
          //store connection handle
          connHandle = pEvent->linkCmpl.connectionHandle;

          //if we're not advertising, attempt to turn advertising back on
          uint8_t adv;
          GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, &adv, NULL);
          if (adv == 1) //connected and advertising
          {
            if (gapRoleNumLinks(GAPROLE_AVAILABLE_LINKS) > 0)
            {
              LCD_WRITE_STRING("Advertising", LCD_PAGE2);
            }
            else //no available links
            {
              LCD_WRITE_STRING("Can't adv: no links", LCD_PAGE2);
            }
          }
          else //not currently advertising
          {
            LCD_WRITE_STRING("Ready to Advertise", LCD_PAGE2);
            //attempt to turn advertising back o
            uint8_t advertEnabled = TRUE;        
            uint8_t stat = GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &advertEnabled, NULL);
            if (stat == bleNoResources) //no more links
            {
              LCD_WRITE_STRING("Can't adv: no links", LCD_PAGE2);
            }
            else if (stat == SUCCESS) //turning advertising back on
            {
              LCD_WRITE_STRING("Advertising", LCD_PAGE2);
            }
            else
            {
              while(1);
            }
          }
          
          // Print last connected device
          LCD_WRITE_STRING("", LCD_PAGE4);
          LCD_WRITE_STRING(Util_convertBdAddr2Str(pEvent->linkCmpl.devAddr), LCD_PAGE5 );                         

          // initiate service discovery
          Util_startClock(&startDiscClock);
        }
        else
        {
          connHandle = GAP_CONNHANDLE_INIT;        
          discState = BLE_DISC_STATE_IDLE;
          
          LCD_WRITE_STRING("Connect Failed", LCD_PAGE4);
          LCD_WRITE_STRING_VALUE("Reason:", pEvent->gap.hdr.status, 10, 
                                 LCD_PAGE3);
        }
      }
      break;

    case GAP_LINK_TERMINATED_EVENT:
      {
        connHandle = GAP_CONNHANDLE_INIT;      
        discState = BLE_DISC_STATE_IDLE;
  
        uint8_t i;
        for (i=0; i < MAX_NUM_BLE_CONNS; i++)
        {
          if (multiConnInfo[i].gapRole_ConnectionHandle == GAPROLE_CONN_JUST_TERMINATED)
          {
            //clear screen, reset discovery info, and return to main menu
            multiConnInfo[i].gapRole_ConnectionHandle = INVALID_CONNHANDLE;
            charHdl[i] = 0;
            LCD_WRITE_STRING_VALUE("Connected to ", gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) ,10, LCD_PAGE0);
            LCD_WRITE_STRING("Disconnected!", LCD_PAGE5);
            LCD_WRITE_STRING("Main Menu", LCD_PAGE3);
            LCDmenu = MAIN_MENU;
          }
          if ((gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) == (MAX_NUM_BLE_CONNS-1))) //now we can advertise again
          {
            LCD_WRITE_STRING("Ready to Advertise", LCD_PAGE2);
          }
        }        
      }
      break;

    case GAP_LINK_PARAM_UPDATE_EVENT:
      {
        LCD_WRITE_STRING_VALUE("Param Update:", pEvent->linkUpdate.status,
                                10, LCD_PAGE2);
      }
      break;
      
    default:
      break;
  }
}
/*********************************************************************
 * @fn      simpleTopology_processGATTMsg
 *
 * @brief   Process GATT messages and events.
 *
 * @return  TRUE if safe to deallocate incoming message, FALSE otherwise.
 */
static uint8_t simpleTopology_processGATTMsg(gattMsgEvent_t *pMsg)
{
  // See if GATT server was unable to transmit an ATT response
  if (pMsg->hdr.status == blePending)
  {
    // No HCI buffer was available. Let's try to retransmit the response
    // on the next connection event.
    if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity,
                                   SBT_CONN_EVT_END_EVT) == SUCCESS)
    {
      // First free any pending response
      simpleTopology_freeAttRsp(FAILURE);
      
      // Hold on to the response message for retransmission
      pAttRsp = pMsg;
      
      // Don't free the response message yet
      return (FALSE);
    }
  }
  else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
  {
    // ATT request-response or indication-confirmation flow control is
    // violated. All subsequent ATT requests or indications will be dropped.
    // The app is informed in case it wants to drop the connection.
    
    // Display the opcode of the message that caused the violation.
    LCD_WRITE_STRING_VALUE("FC Violated:", pMsg->msg.flowCtrlEvt.opcode,
                           10, LCD_PAGE6);
  }    
  else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
  {
    // MTU size updated
    LCD_WRITE_STRING_VALUE("MTU Size:", pMsg->msg.mtuEvt.MTU, 10, LCD_PAGE6);
  }
  
  //messages from GATT server
  if ((gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) > 0))
  {
    if ((pMsg->method == ATT_READ_RSP)   ||
        ((pMsg->method == ATT_ERROR_RSP) &&
         (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
    {
      if (pMsg->method == ATT_ERROR_RSP)
      {      
        LCD_WRITE_STRING_VALUE("Read Error", pMsg->msg.errorRsp.errCode, 10,
                               LCD_PAGE6);
      }
      else
      {
        // After a successful read, display the read value
        LCD_WRITE_STRING_VALUE("Read rsp:", pMsg->msg.readRsp.pValue[0], 10,
                               LCD_PAGE6);
      }
      
    }
    else if ((pMsg->method == ATT_WRITE_RSP)  ||
             ((pMsg->method == ATT_ERROR_RSP) &&
              (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
    {
      
      if (pMsg->method == ATT_ERROR_RSP == ATT_ERROR_RSP)
      {     
        LCD_WRITE_STRING_VALUE("Write Error", pMsg->msg.errorRsp.errCode, 10,
                               LCD_PAGE6);
      }
      else
      {
        // After a succesful write, display the value that was written and
        // increment value
        LCD_WRITE_STRING_VALUE("Write sent:", charVal++, 10, LCD_PAGE6);
      }
    }
    else if (discState != BLE_DISC_STATE_IDLE)
    {
      simpleTopology_processGATTDiscEvent(pMsg);
    }
  } // else - in case a GATT message came after a connection has dropped, ignore it.  
  
  // Free message payload. Needed only for ATT Protocol messages
  GATT_bm_free(&pMsg->msg, pMsg->method);
  
  // It's safe to free the incoming message
  return (TRUE);
}
/*********************************************************************
 * @fn      simpleTopology_handleKeys
 *
 * @brief   Handles all key events for this device.
 *
 * @param   shift - true if in shift/alt.
 * @param   keys - bit field for key events. Valid entries:
 *                 HAL_KEY_SW_2
 *                 HAL_KEY_SW_1
 *
 * @return  none
 */
static void simpleTopology_handleKeys(uint8_t shift, uint8_t keys)
{
  (void)shift;  // Intentionally unreferenced parameter
  
  if (LCDmenu == MAIN_MENU)
  {
    if (keys & KEY_LEFT)  //show discovery results
    {
      selectKey = DISCOVERED_DEVICES;
      
      // If discovery has occurred and a device was found
      if (!scanningStarted && scanRes > 0)
      {
        // Increment index of current result (with wraparound)
        scanIdx++;
        if (scanIdx >= scanRes)
        {
          scanIdx = 0;
        }
        
        LCD_WRITE_STRING_VALUE("Device", (scanIdx + 1), 10, LCD_PAGE3);
        LCD_WRITE_STRING(Util_convertBdAddr2Str(devList[scanIdx].addr), LCD_PAGE4);
      }
      return;
    }
    if (keys & KEY_UP)  //Scan for devices
    {
      // Start or stop discovery
      if (gapRoleNumLinks(GAPROLE_AVAILABLE_LINKS) > 0) //if we can connect to another device
      {
        if (!scanningStarted) //if we're not already scanning
        {
          scanningStarted = TRUE;
          scanRes = 0;
          
          LCD_WRITE_STRING("Discovering...", LCD_PAGE3);
          LCD_WRITE_STRING("", LCD_PAGE4);
          LCD_WRITE_STRING("", LCD_PAGE6);
          
          GAPRole_StartDiscovery(DEFAULT_DISCOVERY_MODE,
                                 DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                 DEFAULT_DISCOVERY_WHITE_LIST);      
        }
        else //cancel scanning
        {
          LCD_WRITE_STRING("Discovery Cancelled", LCD_PAGE3);
          GAPRole_CancelDiscovery();
          scanningStarted = FALSE;
        }
      }
      else // can't add more links at this time
      {
        LCD_WRITE_STRING("Can't scan:no links ", LCD_PAGE3);
      }
      return;
    }
    if (keys & KEY_RIGHT)  // turn advertising on / off
    {
      uint8_t adv;
      uint8_t adv_status;
      GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, &adv_status, NULL);
      if (adv_status) //turn off
      {
        adv = FALSE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &adv, NULL);
      }
      else //turn on
      {
        adv = TRUE;
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &adv, NULL);
      }
      return;
    }
    
    if (keys & KEY_SELECT) //connect to a discovered device
    {
      if (selectKey == DISCOVERED_DEVICES)    // connect to a device  
      {
        uint8_t addrType;
        uint8_t *peerAddr;
        
        if (connecting_state == 1) // if already attempting to connect, cancel connection
        {
        	GAPRole_TerminateConnection(0xFFFE);
        	LCD_WRITE_STRING("Connecting stopped.", LCD_PAGE3);
        	connecting_state = 0;
        }
        else //establish new connection
        {
        	// if there is a scan result
        	if (scanRes > 0)
        	{
        		// connect to current device in scan result
        		peerAddr = devList[scanIdx].addr;
        		addrType = devList[scanIdx].addrType;

        		GAPRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
                                	DEFAULT_LINK_WHITE_LIST,
									addrType, peerAddr);
        		connecting_state = 1;

        		LCD_WRITE_STRING("Connecting", LCD_PAGE3);
        		LCD_WRITE_STRING(Util_convertBdAddr2Str(peerAddr), LCD_PAGE4);
        	}
        }
      }
      else if (selectKey == CONNECTED_DEVICES) //enter the device menu
      {
        if (multiConnInfo[connIdx].gapRole_ConnectionHandle != INVALID_CONNHANDLE)
        {
          LCDmenu = DEVICE_MENU;
          LCD_WRITE_STRING("Device Menu", LCD_PAGE3);
          LCD_WRITE_STRING(Util_convertBdAddr2Str(multiConnInfo[connIdx].gapRole_devAddr), LCD_PAGE4);
          if (multiConnInfo[connIdx].gapRole_ConnRole == GAP_PROFILE_CENTRAL)
          {
             LCD_WRITE_STRING("Connected as Central", LCD_PAGE5);
             LCD_WRITE_STRING("", LCD_PAGE6);
             LCD_WRITE_STRING("", LCD_PAGE7);
          }
          else //PERIPHERAL
          {
            LCD_WRITE_STRING("Connected as Periph", LCD_PAGE5);
            LCD_WRITE_STRING("", LCD_PAGE6);
            LCD_WRITE_STRING("", LCD_PAGE7);            
          }
          //use this connection for all functionality
          connHandle = multiConnInfo[connIdx].gapRole_ConnectionHandle;
        }
        else // no active connection here
        LCD_WRITE_STRING("No Connection here.", LCD_PAGE3);
      }
      return;
    }
    
    if (keys & KEY_DOWN) //browse connected devices
    {
      LCD_WRITE_STRING("Connected Device:", LCD_PAGE3);
      if (++connIdx >= MAX_NUM_BLE_CONNS) //increment connIdx
      {
        connIdx = 0;
      }   
      if (multiConnInfo[connIdx].gapRole_ConnectionHandle != INVALID_CONNHANDLE) //if there is a connection at this index
      {
        LCD_WRITE_STRING(Util_convertBdAddr2Str(multiConnInfo[connIdx].gapRole_devAddr), LCD_PAGE4);
      }
      else
      {
        LCD_WRITE_STRING("N/A", LCD_PAGE4);
      }
      selectKey = CONNECTED_DEVICES;
    } 
    return;
  }
  
  else if (LCDmenu == DEVICE_MENU)
  {
    if (keys & KEY_UP) //read/whrite char
    {
      if (charHdl[connIdx] != 0)
      {
        uint8_t status;
        
        // Do a read or write as long as no other read or write is in progress
        if (doWrite)
        {
          // Do a write
          attWriteReq_t req;
          
          req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, 1, NULL);
          if ( req.pValue != NULL )
          {
            req.handle = charHdl[connIdx];
            req.len = 1;
            req.pValue[0] = charVal;
            req.sig = 0;
            req.cmd = 0;
            
            status = GATT_WriteCharValue(connHandle, &req, selfEntity);
            if ( status != SUCCESS )
            {
              GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
            }
          }
        }
        else
        {
          // Do a read
          attReadReq_t req;
          
          req.handle = charHdl[connIdx];
          status = GATT_ReadCharValue(connHandle, &req, selfEntity);
        }
        
        if (status == SUCCESS)
        {
          doWrite = !doWrite;
        }
      }
      return;
    }
    
    if (keys & KEY_RIGHT) //connection update...eventually
    {
      asm("NOP");
      return;
    }
    
    if (keys & KEY_SELECT)
    {
      GAPRole_TerminateConnection(connHandle);
      
      LCD_WRITE_STRING("Disconnecting", LCD_PAGE5);
      LCD_WRITE_STRING("", LCD_PAGE6);
      
      return;
    }

    if (keys & KEY_DOWN) //back to main menu
    {
      LCDmenu = MAIN_MENU;
      LCD_WRITE_STRING("Main Menu", LCD_PAGE3);
      //clear screen
      LCD_WRITE_STRING("", LCD_PAGE4);
      LCD_WRITE_STRING("", LCD_PAGE5);
      LCD_WRITE_STRING("", LCD_PAGE6);
      LCD_WRITE_STRING("", LCD_PAGE7);
      LCD_WRITE_STRING_VALUE("Connected to ", gapRoleNumLinks(GAPROLE_ACTIVE_LINKS) ,10, LCD_PAGE0);
      
      connIdx = 0;
      
      return;
    }
  }
}
/*********************************************************************
 * @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);
}