dbgagents/trkagent/engine/TrkBtSocketCommPort.cpp
author ravikurupati
Tue, 02 Mar 2010 10:33:16 +0530
changeset 0 c6b0df440bee
permissions -rw-r--r--
Initial contribution of EPL licensed sources

/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include <e32cons.h>
#include <f32file.h>
// Notifier to select a device
#include <btextnotifiers.h>

#ifdef __UIQ_BUILD__
#include <QBTselectdlg.h>
#include <btsdp.h>          // CSdpAgent
#endif

#include "TrkBtSocketCommPort.h"
#include "TrkFramingLayer.h"
#include "TrkConnData.h"


//
// Static helper functions
//

//
//
// CTrkBtSocketCommPort implementation
//
//

//
// CTrkBtSocketCommPort constructor
//
CTrkBtSocketCommPort::CTrkBtSocketCommPort()
	: CTrkCommPort(CActive::EPriorityStandard, ETrkNotConnected),
	  iServerStarted(EFalse),
	  iConnected(EFalse),
	  iListening(EFalse),
	  iCurrUUID(0),
	  iPortValid(EFalse),
	  iDiscovering(EFalse),
	  iSearchPattern(NULL),
	  iAgent(NULL),
	  iConnectionListener(NULL)
{
   iAddr.Reset();
}

//
// CTrkBtSocketCommPort::ConstructL
//
void CTrkBtSocketCommPort::ConstructL(TTrkConnData aTrkConnData, TDes& /*aErrorMessage*/, MTrkConnectionListener* aCallback)
{
	iUnitNumber = aTrkConnData.iPortNumber;
	iUpdatedPort = iUnitNumber;

	CActiveScheduler::Add(this);		
	
	iConnectionListener = aCallback;
	
}

//
// CTrkBtSocketCommPort destructor
//
CTrkBtSocketCommPort::~CTrkBtSocketCommPort()
{
	// make sure we cancel the request for data before shutting down
	Cancel();
	StopDiscovery();
	
	if (iConnected)
	{
		iSock.Close();
		iConnected = EFalse;
	}
	
	if (iServerStarted)
	{
		iSocketServ.Close();
		iServerStarted = EFalse;
	}	
	

}

//
// CTrkBtSocketCommPort::NewL
//
CTrkBtSocketCommPort* CTrkBtSocketCommPort::NewL(TTrkConnData aTrkConnData, TDes& aErrorMessage, MTrkConnectionListener* aCallback)
{
	CTrkBtSocketCommPort* self = new(ELeave) CTrkBtSocketCommPort;
	CleanupStack::PushL(self);
	self->ConstructL(aTrkConnData, aErrorMessage, aCallback);
	CleanupStack::Pop(self);
	return self;
}

//
// CTrkBtSocketCommPort::OpenPortL
//
// Open the bluetooth selection dialog and connect to the selected device.
//
void CTrkBtSocketCommPort::OpenPortL()
{
	if (!iServerStarted)
	{
		StartC32();
		ReportAndLeaveIfErrorL(iSocketServ.Connect(), _L("Failed to connect to socketserver."));
		iServerStarted = ETrue;
	}

#ifdef __UIQ_BUILD__
	CBTDeviceArray* aSelectedDeviceArray = new (ELeave) CArrayPtrFlat<CBTDevice>(4); 
	CleanupStack::PushL(aSelectedDeviceArray); 
	CQBTUISelectDialog* dialog = CQBTUISelectDialog::NewL(aSelectedDeviceArray); 
	TInt err = dialog->RunDlgLD(KQBTUISelectDlgFlagNone);
	if (err == KErrNone)
	{ 
		CBTDevice* ptrBTDev = aSelectedDeviceArray->operator[](0); 

	  	TBTDeviceResponseParamsPckg devRespParamsPckg;
		devRespParamsPckg().SetDeviceAddress(ptrBTDev->BDAddr()); 
		devRespParamsPckg().SetDeviceName(ptrBTDev->FriendlyName()); 
		devRespParamsPckg().SetDeviceClass(ptrBTDev->DeviceClass()); 

		TBuf8<100> tmpName = ptrBTDev->DeviceName();
		iName.Copy(tmpName);
		iAddr = devRespParamsPckg().BDAddr();
	}
	else
	{ 
		ReportAndLeaveIfErrorL(err, _L("Failed to get device list."));
	}
	CleanupStack::Pop(aSelectedDeviceArray); 
#else
	// Try to open bluetooth selection dialog to get the name and address of the device
	TBTDeviceResponseParamsPckg aResponse;
    
    RNotifier notifier;
    User::LeaveIfError(notifier.Connect());
  
    TBTDeviceSelectionParamsPckg selectionFilter;

    TRequestStatus status;
    notifier.StartNotifierAndGetResponse(
        status,
        KDeviceSelectionNotifierUid,
        selectionFilter,
        aResponse
    );

    User::WaitForRequest(status);

    if (status.Int() != KErrNone)
    {
        notifier.CancelNotifier(KDeviceSelectionNotifierUid);
	    notifier.Close();
	
     	ReportAndLeaveIfErrorL(status.Int(), _L("Failed to get device list."));
    }

    notifier.CancelNotifier(KDeviceSelectionNotifierUid);
    notifier.Close();
    
    iName = aResponse().DeviceName();
    iAddr = aResponse().BDAddr();
#endif

	// load protocol, RFCOMM
	TProtocolDesc pdesc;
	ReportAndLeaveIfErrorL(iSocketServ.FindProtocol(_L("RFCOMM"), pdesc),_L("Unable to find protocol."));

	// open socket
	ReportAndLeaveIfErrorL(iSock.Open(iSocketServ, _L("RFCOMM")),_L("Unable to open socket."));
	// set address and port
    iState = EDiscovering;
    DiscoverPortL();
    iConnectionStatus = ETrkConnecting;
}

/*
 * To connect to BT socket after getting appropriate port
 * 
 */
void CTrkBtSocketCommPort::ConnectToPortL()
{
	TBTSockAddr addr;
	addr.SetBTAddr(iAddr);
    addr.SetPort(iUpdatedPort);

	TRequestStatus cstatus;
	iSock.Connect(addr, cstatus);
	User::WaitForRequest(cstatus);

    TInt err = cstatus.Int();    
    if (err != KErrNone)
    {
        iErrorMessage.Format(_L("Error connecting socket\r\nError Code: %d\r\n"),err);
        iConnectionStatus = ETrkConnectionError;
        iConnectionListener->AsyncConnectionFailed();
        return;
	}
		
	iConnected = ETrue;
    iConnectionMessage.Format(_L("BT Dev Name: %S\r\nBT Port number: %d\r\n"), &iName, iUpdatedPort);
		
    iConnectionStatus = ETrkConnected;
    iConnectionListener->AsyncConnectionSuccessfulL();    
}

//
// CTrkBtSocketCommPort::ClosePort
//
// Close the communications port
//
void CTrkBtSocketCommPort::ClosePort()
{
	Cancel();
	
	if (iConnected)
	{
		iSock.Close();
		iConnected = EFalse;
	}

	if (iServerStarted)
	{
		iSocketServ.Close();
		iServerStarted = EFalse;
	}
}

//
// CTrkBtSocketCommPort::SendDataL
//
// Write data to the serial type port
//
void CTrkBtSocketCommPort::SendDataL(const TDesC8& aBuffer)
{
	iSock.CancelRead();
	iState = ESending;

	iSock.Write(aBuffer, iStatus);
	User::WaitForRequest(iStatus);
	
	if (iStatus!=KErrNone)
	{
		ReportAndLeaveIfErrorL(iStatus.Int(), _L("Error sending data."));
	}	
}

//
// CTrkBtSocketCommPort::Listen
//
// Start listening for data coming into the serial type communications port
//
void CTrkBtSocketCommPort::Listen(CTrkFramingLayer *aFramingLayer)
{
	iFramingLayer = aFramingLayer;
	iListening = ETrue;
}

//
// CTrkBtSocketCommPort::StopListening
//
// Stop listening for data coming into the serial type communications port
//
void CTrkBtSocketCommPort::StopListening()
{
	if (iListening)
	{
		iSock.CancelRead();
		Cancel();
		Deque();
	}
	
	iListening = EFalse;
}

//
// CTrkBtSocketCommPort::ReportAndLeaveIfErrorL
//
// If an error occurred, print the error information to the screen and bail out
//
void CTrkBtSocketCommPort::ReportAndLeaveIfErrorL(TInt aError, const TDesC& aDesc)
{
	if (KErrNone != aError)
	{
		iErrorMessage.Format(_L("%S\r\nError Code: %d\r\n"), &aDesc, aError);
		User::Leave(aError);
	}
}


//
// CTrkBtSocketCommPort::IssueReadRequest
//
// Wait for data to come into the communications port
//
void CTrkBtSocketCommPort::IssueReadRequest()
{
	iSock.CancelRead();
	iNextReadChar = 0;
	iState = EWaiting;
	iReceivedChars.Zero();
	iSock.RecvOneOrMore(iReceivedChars, 0, iStatus, iLen);
	SetActive();
}

//
// CTrkBtSocketCommPort::DoCancel
//
// Cancel the request for data from the communications port
//
void CTrkBtSocketCommPort::DoCancel()
{
	//iSock.CancelRead();
	//iPort.ReadCancel();
}

//
// CTrkBtSocketCommPort::RunL
//
// Called when data comes into the communications port
//
void CTrkBtSocketCommPort::RunL()
{
	if (iStatus != KErrNone)
	{
		switch(iState)
		{
		   case EDiscovering:
		   {
		       iConnectionListener->AsyncConnectionFailed();
		       break;	       
		   }	       
		   default:
		 	  break;
		}
	}
	else
	{
		switch (iState)
		{
	
			case EWaiting:
			{
				if (iStatus.Int() == KErrNone)
				{
					while (iNextReadChar < iReceivedChars.Length())
						iFramingLayer->HandleByte(iReceivedChars[iNextReadChar++]);
				}
				break;
			}
			case ESending:
			{
				break;
			}
			case EDiscovering:
			{
				ConnectToPortL();
				break;
			}
			case EConnecting:
			{
				break;
			}
			default:
				break;
		}
		IssueReadRequest();
	}

}

//
// CTrkBtSocketCommPort::DiscoverPortL
//
// Called to figure out the port number for serial profile
//
void CTrkBtSocketCommPort::DiscoverPortL()
{
    StopDiscovery(); // to avoid conflicts if called several times before the old discovery is finished
   
    const TInt BT_UUID_SPP_SP = 0x1101; // SPP (Serial Port) UUID
    
    // Init new service discovery agent
    iAgent = CSdpAgent::NewL( *this, iAddr);
    
    // Set search properties for agent (use SPP service-UUID to filter the services discovered)
    iSearchPattern = CSdpSearchPattern::NewL();
    
    iSearchPattern->AddL(BT_UUID_SPP_SP);
    iAgent->SetRecordFilterL(*iSearchPattern);
    iDiscovering = ETrue;
   
    // Initiate search, result will be received with call of NextRecordRequestComplete()
    iAgent->NextRecordRequestL();
    iStatus = KRequestPending;
    SetActive();       
}

//
//CTrkBtSocketCommPort::StopDiscovery()
//
//Called to stop the discovery services
//
void CTrkBtSocketCommPort::StopDiscovery()
{
    iDiscovering = EFalse;
    
    if (iAgent)
    {
        iAgent->Cancel();
        delete iAgent;
        iAgent = NULL;
    }
    
    if (iSearchPattern)
    {
        iSearchPattern->Reset();
        delete iSearchPattern;
        iSearchPattern = NULL;
    }
}


//
// CTrkBtSocketCommPort::NextRecordRequestComplete
//
// called when the service discovery agent has completed discovering services on device (i.e. if next service found or not)
//
void CTrkBtSocketCommPort::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount)
{
    if ( (KErrNone == aError) && (0 < aTotalRecordsCount) )
    {
        // We got next service record, request protocol descriptor to retrieve remote port
        // (it calls later the AttributeRequestResult() when the answer is ready)
        TRAPD(err, iAgent->AttributeRequestL(aHandle, KSdpAttrIdProtocolDescriptorList));
        if( err )
        {
	        iErrorMessage.Format(_L("Error in finding the serial port record\r\nError Code: %d\r\n"),err);
	        iConnectionStatus = ETrkConnectionError;
	        StopDiscovery();
	        TRequestStatus *status = &iStatus;
	        User::RequestComplete(status, aError);
        }
    }
    else
    {
	    // no any services found or error occures (probably the device is not present or SPP service is not present)
	    iErrorMessage.Format(_L("Error in finding the serial port record\r\nError Code: %d\r\n"),aError);
	    iConnectionStatus = ETrkConnectionError;
	    StopDiscovery();
	    TRequestStatus *status = &iStatus;
	    User::RequestComplete(status, aError);  
    }    

}


//
//CTrkBtSocketCommPort::AttributeRequestResult
//
// Called when the service attributes for the service record have been retrieved.
//
void CTrkBtSocketCommPort::AttributeRequestResult(TSdpServRecordHandle, TSdpAttributeID, CSdpAttrValue* aAttrValue)
{
    // can't ignore the call of this function because we need take care about aAttrValue
    // Parse attributes, it will return results by several calls of VisitAttributeValue()
    TRAPD(err, aAttrValue->AcceptVisitorL(*this));
    if( err )
    {   
	    iErrorMessage.Format(_L("Error in finding the serial port record \r\nError Code: %d"),err);
	    iConnectionStatus = ETrkConnectionError;
	    StopDiscovery();
	    TRequestStatus *status = &iStatus;
	    User::RequestComplete(status, err);
    }
    delete aAttrValue;
}

//
// CTrkBtSocketCommPort::AttributeRequestComplete
//
// Called when the request to resolve the service attributes for the service record completes.
//
void CTrkBtSocketCommPort::AttributeRequestComplete(TSdpServRecordHandle, TInt aError)
{
    // if KErrNone ==aError and we need not just the first SPP service but check several services,
    // can call for iAgent->NextRecordRequestL() here (and add corresponded processing in
    // NextRecordRequestComplete() )
    if (KErrNone != aError)
    {
        iErrorMessage.Format(_L("Error in finding the serial port record\r\nError Code: %d"),aError);
        iConnectionStatus = ETrkConnectionError;
        StopDiscovery();
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, aError);
    }
    else
    {
        StopDiscovery();
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);  
    }
}
    
//
// CTrkBtSocketCommPort::VisitAttributeValueL
//    
// Called for processing of each service attribute.
//
void CTrkBtSocketCommPort::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType)
{
    if (!iDiscovering)
    {
        return; // ignore calls to that function if not discovering currently
    }
    
    // Check for attributes of UUID type. 
    // If the UUID is RFCOMM UUID, resolve the value for this attribute,
    // which will be the channel number.
    switch (aType)
    {
        case ETypeUUID: // UUID of attribute, store it 
        {
            TPtrC8 uuid(aValue.UUID().ShortestForm());
            iCurrUUID.SetL(uuid);
            break;
        }
        case ETypeUint: // uint value, check if the current attribute type is KRFCOMM, store the port value if "yes"
        {
            if (iCurrUUID == KRFCOMM)
            {
                iUpdatedPort = aValue.Uint();
                iPortValid = TRUE;
                iDiscovering = EFalse;
            }
            break;
        }
        default:
            // other attributes are not interesting for processing...
            break;
    }   
}

/*
 * This method should be overridden
 */
void CTrkBtSocketCommPort::StartListL(CSdpAttrValueList&)
{
}

/*
 * This method should be overridden 
 * 
 */
void CTrkBtSocketCommPort::EndListL()
{
}