/****************************************************************************
NAME	
    connectionHandleReadInquiryTx

DESCRIPTION
    This function will initiate a read of the inquiry tx power of the device

RETURNS
    void
*/
void connectionHandleReadInquiryTx(connectionReadInfoState* infoState, connectionInquiryState *state, const CL_INTERNAL_DM_READ_INQUIRY_TX_REQ_T *req)
{
	/* Check command supported by firmware */
	if(infoState->version != bluetooth_unknown)
	{
		/* Check the state of the task lock before doing anything */
		if (!state->inquiryLock)
		{
			/* One request at a time */
			state->inquiryLock = req->theAppTask;
		
			/* Issue request to read the inquiry tx */
			{
				MAKE_PRIM_C(DM_HCI_READ_INQUIRY_RESPONSE_TX_POWER_LEVEL_REQ);
				VmSendDmPrim(prim);
			}
		}
		else
		{
			/* Remote name request currently being performed, queue up the request */
			MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_INQUIRY_TX_REQ);
			COPY_CL_MESSAGE(req, message);
			MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_INQUIRY_TX_REQ, message, &state->inquiryLock);
		}
	}
	else
	{
		/* Tell the app this is unsupported */
		MAKE_CL_MESSAGE(CL_DM_READ_INQUIRY_TX_CFM);
		message->status = hci_error_unsupported_feature;
		message->tx_power = 0;
		MessageSend(req->theAppTask, CL_DM_READ_INQUIRY_TX_CFM, message);
	}
}
/****************************************************************************
NAME
    connectionHandleReadEirDataRequest

DESCRIPTION
    Handles request for Reading the Extended Inquiry Data.

RETURNS
    void
*/
void connectionHandleReadEirDataRequest(connectionReadInfoState *infoState, connectionInquiryState *state, const CL_INTERNAL_DM_READ_EIR_DATA_REQ_T *req)
{
    if(infoState->version >= bluetooth2_1)
	{
		/* Check the state of the task lock before doing anything */
		if (!state->inquiryLock)
		{
			state->inquiryLock = req->task;
			{
                MAKE_PRIM_C(DM_HCI_READ_EXTENDED_INQUIRY_RESPONSE_DATA_REQ);
				VmSendDmPrim(prim);
			}
		}
		else
		{
			/* Inquiry currently being performed, queue up the request */
			MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_EIR_DATA_REQ);
			COPY_CL_MESSAGE(req, message);
			MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_EIR_DATA_REQ, message, &state->inquiryLock);
		}
	}
	else
	{
		/* Not supported, tell the app */
		MAKE_CL_MESSAGE(CL_DM_READ_EIR_DATA_CFM);
		message->status = hci_error_unsupported_feature;
		message->fec_required = FALSE;
		message->size_eir_data = 0;
		message->eir_data[0] = 0;
    	MessageSend(state->inquiryLock, CL_DM_READ_EIR_DATA_CFM, message);
	}
}
/****************************************************************************
NAME	
	connectionHandleSdpOpenSearchRequest

DESCRIPTION
	Send a request to BlueSTack to open an SDP search session

RETURNS
	void	
*/
void connectionHandleSdpOpenSearchRequest(connectionSdpState *state, const CL_INTERNAL_SDP_OPEN_SEARCH_REQ_T *req)
{
	/* Check the state of the resource lock */
	if (!state->sdpLock)
	{
		/* Resource free, set the lock */
		state->sdpLock = req->theAppTask;

		/* Store the address of the device we're opening the search to */
		state->sdpServerAddr = req->bd_addr;

		/* Send the request to BlueStack */
		{
			MAKE_PRIM_T(SDC_OPEN_SEARCH_REQ);
			connectionConvertBdaddr_t(&prim->bd_addr, &req->bd_addr);
			VmSendSdpPrim(prim);
		}
	}
	else if(req->theAppTask != connectionGetCmTask())
	{
		/* Resource busy so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_SDP_OPEN_SEARCH_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_SDP_OPEN_SEARCH_REQ, message, &state->sdpLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleReadRemoteSupportedFeaturesRequest

DESCRIPTION
    Request to read the supported features of a remote device.

RETURNS
    void
*/
void connectionHandleReadRemoteSupportedFeaturesRequest(connectionReadInfoState *state, const CL_INTERNAL_DM_READ_REMOTE_SUPP_FEAT_REQ_T *req)
{
	/* Check the resource lock */
	if (!state->stateInfoLock)
	{
		bdaddr addr;

		/* Check we got a valid addr */
		if (!SinkGetBdAddr(req->sink, &addr))
		{
			/* Send an error to the app as it didn't pass in a valid sink */
			sendRemoteSupportedFeaturesCfm(req->theAppTask, hci_error_no_connection, 0, req->sink);		
		}
		else
		{
			/* Response not outstanding so issue request */
			MAKE_PRIM_C(DM_HCI_READ_REMOTE_FEATURES);
			connectionConvertBdaddr_t(&prim->bd_addr, &addr);
			VmSendDmPrim(prim);

			/* Set the lock */
			state->stateInfoLock = req->theAppTask;
			state->sink = req->sink;
		}		
	}
	else
	{
		/* Lock set so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_REMOTE_SUPP_FEAT_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_REMOTE_SUPP_FEAT_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME	
	connectionHandleSdpServiceSearchAttrRequest

DESCRIPTION
	Handle a request to perfor a service/ attribute search. If allowed, send
	request to BlueStack otherwise queue it up until it can be sent.

RETURNS
	void	
*/
void connectionHandleSdpServiceSearchAttrRequest(connectionSdpState *state, const CL_INTERNAL_SDP_SERVICE_SEARCH_ATTRIBUTE_REQ_T *req)
{
	sdp_search_req res = sendSearchRequest(req->theAppTask, state, &req->bd_addr);
	
	if (res == sdp_start_search)
	{
		/* Send the request to BlueStack */
		MAKE_PRIM_T(SDC_SERVICE_SEARCH_ATTRIBUTE_REQ);
		prim->phandle = 0;
        connectionConvertBdaddr_t(&prim->bd_addr, &req->bd_addr);
		prim->size_srch_pttrn = req->size_search_pattern;

		if (req->size_search_pattern)
			prim->srch_pttrn = VmGetHandleFromPointer(req->search_pattern);
		else
			prim->srch_pttrn = 0;

        prim->size_attr_list = req->size_attribute_list;
        
		if (req->size_attribute_list)
			prim->attr_list = VmGetHandleFromPointer(req->attribute_list);
		else
			prim->attr_list = 0;

        prim->max_num_attr = req->max_num_attributes;
		VmSendSdpPrim(prim);

		/* Lock the resource */
		state->sdpSearchLock = req->theAppTask;
	}
	else
	{
		Task *c = 0;

		/* Queue up the search request */
		MAKE_CL_MESSAGE(CL_INTERNAL_SDP_SERVICE_SEARCH_ATTRIBUTE_REQ);
		COPY_CL_MESSAGE(req, message);

		/* Use the return value from searchRequest function to decide which resource to wait on */
		if (res == sdp_lock_set)
			c = &state->sdpLock;
		else if (res == sdp_search_lock_set)
			c = &state->sdpSearchLock;
		else if (res == sdp_session_open_other_dev)
			c = &state->sdpLock;
		else
			/* Should not get here but if we do panic */
			Panic();

		/* Queus up message with condition determined above */
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_SDP_SERVICE_SEARCH_ATTRIBUTE_REQ, message, c);
	}
}
/****************************************************************************
NAME	
    connectionHandleSetBtVersionReq

DESCRIPTION
    Handle setting BT Version

RETURNS
    void
*/
void connectionHandleSetBtVersionReq(connectionReadInfoState *state, const CL_INTERNAL_DM_SET_BT_VERSION_REQ_T *req)
{
	if(!state->stateInfoLock)
	{
		state->stateInfoLock = req->theAppTask;
		{
		MAKE_PRIM_T(DM_SET_BT_VERSION_REQ);
		prim->version = req->version;
		VmSendDmPrim(prim);
		}
	}
	else
	{
		/* Lock set so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_SET_BT_VERSION_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_SET_BT_VERSION_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleReadInquiryModeRequest

DESCRIPTION
    Read inquiry mode

RETURNS
    void
*/
void connectionHandleReadInquiryModeRequest(connectionInquiryState *state, const CL_INTERNAL_DM_READ_INQUIRY_MODE_REQ_T *req)
{
	/* Check the state of the task lock before doing anything */
	if (!state->inquiryLock)
	{
		state->inquiryLock = req->theAppTask;

	    {   /* Issue inquiry mode read */
            MAKE_PRIM_C(DM_HCI_READ_INQUIRY_MODE_REQ);
			VmSendDmPrim(prim);
		}
	}
	else
	{
		/* Inquiry currently being performed, queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_INQUIRY_MODE_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_INQUIRY_MODE_REQ, message, &state->inquiryLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleReadLocalVersionRequest

DESCRIPTION
    Request to read the version information of the local device.
  
RETURNS
    void
*/
void connectionHandleReadLocalVersionRequest(connectionReadInfoState *state, const CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ_T *req)
{
 	/* Check the resource lock */
 	if (!state->stateInfoLock)
 	{
		/* Response not outstanding so issue request */
 		MAKE_PRIM_C(DM_HCI_READ_LOCAL_VERSION);
 		VmSendDmPrim(prim);
 
 		/* Set the lock */
 		state->stateInfoLock = req->theAppTask;
 	}
 	else
 	{
 		/* Lock set so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_LOCAL_VERSION_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleWriteInquiryModeRequest

DESCRIPTION
    Write inquiry mode

RETURNS
    void
*/
void connectionHandleWriteInquiryModeRequest(connectionInquiryState *state, const CL_INTERNAL_DM_WRITE_INQUIRY_MODE_REQ_T *req)
{
	/* Check the state of the task lock before doing anything */
	if (!state->inquiryLock)
	{
		state->inquiryLock = req->theAppTask;

	    {   /* Issue inquiry mode change with the supplied parameter */
            MAKE_PRIM_C(DM_HCI_WRITE_INQUIRY_MODE_REQ);
			prim->mode = connectionConvertInquiryMode_t(req->mode);
			VmSendDmPrim(prim);
		}
	}
	else
	{
		/* Inquiry currently being performed, queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_WRITE_INQUIRY_MODE_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_WRITE_INQUIRY_MODE_REQ, message, &state->inquiryLock);
	}
}
/****************************************************************************
NAME	
	connectionHandleSdpClientConfigMtu

DESCRIPTION
	Send a request to BlueStack to configure the SDP client MTU size

RETURNS
	void	
*/
void connectionHandleSdpClientConfigMtu(const connectionSdpState *state, const CL_INTERNAL_SDP_CONFIG_CLIENT_MTU_REQ_T *req)
{
	/* 
		We don't get a response from this so send it without setting the lock. 
		Still have to make sure the lock isn't set though so check it before 
		sending the prim 
	*/
	if (!state->sdpLock)
	{
		MAKE_PRIM_T(SDC_CONFIG_REQ);
		prim->mtu = req->mtu;
		VmSendSdpPrim(prim);
	}
	else
	{
		/* Resource is locked, queue up the request for later */
		MAKE_CL_MESSAGE(CL_INTERNAL_SDP_CONFIG_CLIENT_MTU_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_SDP_CONFIG_CLIENT_MTU_REQ, message, &state->sdpLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleReadAddrRequest

DESCRIPTION
    Handle an internal request to read the local bluetooth address

RETURNS
    void
*/
void connectionHandleReadAddrRequest(connectionReadInfoState *state, const CL_INTERNAL_DM_READ_BD_ADDR_REQ_T *req)
{
	if (!state->stateInfoLock)
	{
		/* Set the lock */
		state->stateInfoLock = req->theAppTask;
        state->sink = 0;

		/* Response not outstanding so issue request */
		{
			MAKE_PRIM_C(DM_HCI_READ_BD_ADDR);
			VmSendDmPrim(prim);
		}
	}
	else
	{
		/* Lock set so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_BD_ADDR_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_BD_ADDR_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME    
    connectionHandleReadLocalName

DESCRIPTION
    This function will initiate a read of the local name of the device

RETURNS
    void
*/
void connectionHandleReadLocalName(connectionInquiryState *state, const CL_INTERNAL_DM_READ_LOCAL_NAME_REQ_T *req)
{
    /* Check the state of the task lock before doing anything */
    if (!state->nameLock)
    {
        /* One request at a time */
        state->nameLock = req->theAppTask;
        
        /* Issue request to read the remote name */
        {
            MAKE_PRIM_C(DM_HCI_READ_LOCAL_NAME_REQ);
            VmSendDmPrim(prim);
        }
    }
    else
    {
        /* Remote name request currently being performed, queue up the request */
        MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_LOCAL_NAME_REQ);
        COPY_CL_MESSAGE(req, message);
        MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_LOCAL_NAME_REQ, message, &state->nameLock);
    }
}
/****************************************************************************
NAME	
    connectionHandleReadRemoteVersionRequest

DESCRIPTION
    Request to read the version information of a remote device.
  
RETURNS
    void
*/
void connectionHandleReadRemoteVersionRequest(connectionReadInfoState *state, const CL_INTERNAL_DM_READ_REMOTE_VERSION_REQ_T *req)
{
 	/* Check the resource lock */
 	if (!state->stateInfoLock)
 	{
		bdaddr addr;
		
		/* Check we got a valid addr */
		if (!SinkGetBdAddr(req->sink, &addr))
		{
			/* Create and send the message */
			MAKE_CL_MESSAGE(CL_DM_REMOTE_VERSION_CFM);
			message->status = hci_error_no_connection;	
			message->lmpVersion       = 0;
			message->manufacturerName = 0;
			message->lmpSubVersion    = 0;
         
			MessageSend(req->theAppTask, CL_DM_REMOTE_VERSION_CFM, message);	
		}
		else
		{
 			/* Response not outstanding so issue request */
 			MAKE_PRIM_C(DM_HCI_READ_REMOTE_VERSION);
 			connectionConvertBdaddr_t(&prim->bd_addr, &addr);
 			VmSendDmPrim(prim);
 
 			/* Set the lock */
 			state->stateInfoLock = req->theAppTask;
		}
 	}
 	else
 	{
 		/* Lock set so queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_REMOTE_VERSION_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_REMOTE_VERSION_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME	
    connectionHandleReadClassOfDeviceRequest

DESCRIPTION
    Handles the internal message that initiates the read class of device

RETURNS
    void
*/
void connectionHandleReadClassOfDeviceRequest(connectionReadInfoState *state, const CL_INTERNAL_DM_READ_CLASS_OF_DEVICE_REQ_T *req)
{
	/* Check the lock */
	if (!state->stateInfoLock)
	{
		/* Not currently processing one of these so set the lock */
		state->stateInfoLock = req->theAppTask;
        state->sink = 0;

		{
			/* Issue the request to BlueStack */
			MAKE_PRIM_C(DM_HCI_READ_CLASS_OF_DEVICE_REQ);
			VmSendDmPrim(prim);
		}
	}
	else
	{
		/* Currently busy processing a read cod request so queue this up */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_READ_CLASS_OF_DEVICE_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_READ_CLASS_OF_DEVICE_REQ, message, &state->stateInfoLock);
	}
}
/****************************************************************************
NAME	
	connectionHandleSdpUnregisterRequest

DESCRIPTION
	Handle the request to unregister a particular service record

RETURNS
	void	
*/
void connectionHandleSdpUnregisterRequest(connectionSdpState *state, const CL_INTERNAL_SDP_UNREGISTER_RECORD_REQ_T *req)
{
	/* Check the resource lock */
	if (!state->sdpLock)
	{
		/* Set lock */
		state->sdpLock = req->theAppTask;

		/* Resource free so send request down to BlueStack */
		{
			MAKE_PRIM_T(SDS_UNREGISTER_REQ);
			prim->phandle = 0;
			prim->svc_rec_hndl = req->service_handle;
			VmSendSdpPrim(prim);
		}
	}
	else
	{
		/* Resource is locked, queue up the request for later */
		MAKE_CL_MESSAGE(CL_INTERNAL_SDP_UNREGISTER_RECORD_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_SDP_UNREGISTER_RECORD_REQ, message, &state->sdpLock);
	}
}
/****************************************************************************
NAME	
	connectionHandleSdpRegisterRequest

DESCRIPTION
	Sends a register request to the SDP server

RETURNS
	void	
*/
void connectionHandleSdpRegisterRequest(connectionSdpState *state, const CL_INTERNAL_SDP_REGISTER_RECORD_REQ_T *req)
{
	/* If the resource is not locked, send downt he request */
	if (!state->sdpLock)
	{
		/* Set the lock */
		state->sdpLock = req->theAppTask;

		{
			MAKE_PRIM_T(SDS_REGISTER_REQ);
			prim->phandle = 0;
			prim->num_rec_bytes = req->record_length;
			prim->service_rec = VmGetHandleFromPointer(req->record);
			VmSendSdpPrim(prim);
		}
	}
	else
	{
		/* Resource locked, queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_SDP_REGISTER_RECORD_REQ);
		COPY_CL_MESSAGE(req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_SDP_REGISTER_RECORD_REQ, message, &state->sdpLock);
	}
}
/****************************************************************************
  NAME	
      connectionStartInquiry
  
  DESCRIPTION
      This function actually kicks off an inquiry message to BlueStack.
  
  RETURNS
      void
*/
void connectionHandleInquiryStart(connectionInquiryState *state, const CL_INTERNAL_DM_INQUIRY_REQ_T *inquiry_req)
{
	/* Check the state of the task lock before doing anything */
	if (!state->inquiryLock)
	{
		state->inquiryLock = inquiry_req->theAppTask;

		/* 
			If the class of device field is set, set an event filter so we 
			only receive inquiry results with devices with this class of 
			device. By default we filter in all devices so if class of 
			device mask set to zero we don't have to set the event filter.
		*/
		if (inquiry_req->class_of_device)
		{
            MAKE_PRIM_C(DM_HCI_SET_EVENT_FILTER_REQ);
			prim->filter_type = INQUIRY_RESULT_FILTER;
			prim->filter_condition_type = CLASS_OF_DEVICE_RESPONDED;
			prim->condition.class_mask.class_of_device = inquiry_req->class_of_device;

	        /* 
				We don't care what the bits other than the specific class 
				of device are set to so set them to zero 
			*/
			prim->condition.class_mask.mask = inquiry_req->class_of_device;
			VmSendDmPrim(prim);
		}

	    {
    if (inquiry_req->min_period)
    {
        /* Start an periodic inquiry with the supplied parameters */
        MAKE_PRIM_C(DM_HCI_PERIODIC_INQUIRY_MODE_REQ);
        prim->lap = inquiry_req->inquiry_lap;
        prim->inquiry_length = inquiry_req->timeout;
        prim->num_responses = inquiry_req->max_responses;
        prim->max_period_length = inquiry_req->max_period;
        prim->min_period_length = inquiry_req->min_period;                
        VmSendDmPrim(prim);
        state->periodic_inquiry = TRUE;
    }
    else
    {
		    /* Start an inquiry with the supplied parameters */
            MAKE_PRIM_C(DM_HCI_INQUIRY_REQ);
			prim->lap = inquiry_req->inquiry_lap;
			prim->inquiry_length = inquiry_req->timeout;
			prim->num_responses = inquiry_req->max_responses;
			VmSendDmPrim(prim);
        state->periodic_inquiry = FALSE;
		}
	}
    }
	else
	{
		/* Inquiry currently being performed, queue up the request */
		MAKE_CL_MESSAGE(CL_INTERNAL_DM_INQUIRY_REQ);
		COPY_CL_MESSAGE(inquiry_req, message);
		MessageSendConditionallyOnTask(connectionGetCmTask(), CL_INTERNAL_DM_INQUIRY_REQ, message, &state->inquiryLock);
	}
}