/*
* Copyright (c) 2005-2006 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: BT RFComm socket
*
*/
#include <badesca.h>
#include "btmrfcommsock.h"
#include "btmsockobserver.h"
#include "debug.h"
// Constant for listening queue size
const TInt KListenQueSize = 1;
// ======== MEMBER FUNCTIONS ========
CBtmRfcommSock* CBtmRfcommSock::NewL(MBtmSockObserver& aObserver, RSocketServ& aServer)
{
CBtmRfcommSock* self = new (ELeave) CBtmRfcommSock(aObserver, aServer);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CBtmRfcommSock::~CBtmRfcommSock()
{
TRACE_FUNC_ENTRY
iAda.Close();
delete iDataSocket;
delete iListenSocket;
iInData.Close();
iOutData.Close();
delete iOutDataQueue;
TRACE_FUNC_EXIT
}
// ---------------------------------------------------------
// CBtmRfcommSock::Connect
// ---------------------------------------------------------
//
void CBtmRfcommSock::ConnectL(TBTSockAddr& aAddr, TUint aService)
{
TRACE_FUNC_ENTRY
TProtocolDesc pInfo;
LEAVE_IF_ERROR(iServer.FindProtocol(TProtocolName(KRFCOMMDesC), pInfo));
if (!iDataSocket)
{
iDataSocket = CBluetoothSocket::NewL(*this, iServer, pInfo.iSockType, pInfo.iProtocol);
}
LEAVE_IF_ERROR(iDataSocket->Connect(aAddr));
iService = aService;
iRemote = TBTDevAddr();
iRemoteHasConnected = EFalse;
TRACE_FUNC_EXIT
}
// ---------------------------------------------------------
// CBtmRfcommSock::CancelActiveConnectSocket
// ---------------------------------------------------------
//
void CBtmRfcommSock::CancelConnect()
{
if (iDataSocket)
{
TRACE_FUNC_ENTRY
iDataSocket->CancelConnect();
TRACE_FUNC_EXIT
}
}
TBool CBtmRfcommSock::AccessoryInitiatedConnection()
{
return iRemoteHasConnected;
}
TUint CBtmRfcommSock::ListenL(TUint aService, const TBTServiceSecurity& aSec, TUint aLastUsedPort)
{
TRACE_FUNC_ENTRY
TRACE_ASSERT(!iListenSocket, EBTPanicRfcommAlreadyListen)
TRACE_ASSERT(!iDataSocket, EBTPanicRfcommSockInuse)
TProtocolDesc pInfo;
LEAVE_IF_ERROR(iServer.FindProtocol(TProtocolName(KRFCOMMDesC), pInfo));
iListenSocket = CBluetoothSocket::NewL(*this, iServer, pInfo.iSockType, pInfo.iProtocol);
TRfcommSockAddr addr;
addr.SetSecurity(aSec);
TRACE_INFO((_L("Trying lastused port %d"), aLastUsedPort))
addr.SetPort(aLastUsedPort);
TInt error = iListenSocket->Bind(addr);
if ( error )
{
TRACE_INFO((_L("Trying KRfcommPassiveAutoBind")))
addr.SetPort(KRfcommPassiveAutoBind);
LEAVE_IF_ERROR(iListenSocket->Bind(addr));
}
LEAVE_IF_ERROR(iListenSocket->Listen(KListenQueSize));
iDataSocket = CBluetoothSocket::NewL(*this, iServer);
LEAVE_IF_ERROR(iListenSocket->Accept(*iDataSocket));
iService = aService;
TRACE_FUNC_EXIT
iRemote = TBTDevAddr();
return iListenSocket->LocalPort();
}
void CBtmRfcommSock::CancelListen()
{
if (iListenSocket)
{
TRACE_FUNC_ENTRY
iListenSocket->CancelAccept();
TRACE_FUNC_EXIT
}
}
void CBtmRfcommSock::Disconnect(RSocket::TShutdown aHow)
{
TRACE_FUNC_ENTRY
if (iDataSocket)
{
iAda.ActivateActiveRequester();
iDataSocket->CancelWrite();
iDataSocket->CancelRecv();
iDataSocket->CancelIoctl();
iDataSocket->Shutdown(aHow);
}
iRemote = TBTDevAddr();
TRACE_FUNC_EXIT
}
void CBtmRfcommSock::WriteL(const TDesC8& aData)
{
TRACE_FUNC_ENTRY
TRACE_ASSERT(iDataSocket != NULL, EBTPanicObjectUninitialized)
if (!iOutDataQueue)
{
iOutDataQueue = new (ELeave) CDesC8ArrayFlat(1);
}
iOutDataQueue->AppendL(aData);
SendPacketL();
TRACE_FUNC_EXIT
}
void CBtmRfcommSock::CancelWrite()
{
if (iDataSocket)
{
TRACE_FUNC_ENTRY
iDataSocket->CancelWrite();
iOutDataQueue->Reset();
TRACE_FUNC_EXIT
}
}
const TBTDevAddr& CBtmRfcommSock::Remote() const
{
return iRemote;
}
TBool CBtmRfcommSock::IsInSniff() const
{
return iInSniff;
}
TInt CBtmRfcommSock::ActivateBasebandEventNotification(TInt aNotification)
{
TRACE_FUNC
TRACE_ASSERT(iDataSocket, EBTPanicNullPointer)
iBBNotificationMode = aNotification;
return iDataSocket->ActivateBasebandEventNotifier(aNotification);
}
void CBtmRfcommSock::SetObserver(MBtmSockObserver& aObserver)
{
TRACE_FUNC
iObserver = &aObserver;
}
TUint CBtmRfcommSock::Service() const
{
return iService;
}
TInt CBtmRfcommSock::ActivateSniffRequester()
{
if (iDataSocket)
return iAda.ActivateSniffRequester();
else
return KErrGeneral;
}
void CBtmRfcommSock::RequestLinkToActiveMode()
{
if (iDataSocket)
{
TInt err = iAda.ActivateActiveRequester();
TRACE_INFO((_L("ada.ActivateActiveRequester err %d"), err))
}
TRACE_FUNC
}
void CBtmRfcommSock::HandleConnectCompleteL(TInt aErr)
{
TRACE_FUNC_ENTRY
TRACE_INFO((_L("err %d"), aErr))
if (aErr == KErrNone)
{
TBTSockAddr sockAddr;
iDataSocket->RemoteName(sockAddr);
iRemote = sockAddr.BTAddr();
}
// Process the connect complete before issuing a receive request to ensure that
// we are ready to process the data when it is received.
iObserver->RfcommConnectCompletedL(aErr);
if (aErr == KErrNone)
{
iInData.ReAllocL(256);
// Previously a request to become piconet master was made here, for IOP reasons this
// was removed (as theoretically being a piconet master is not required for HFP/HSP AG).
TInt err = iAda.Open(iServer, iRemote);
TRACE_INFO((_L("ada.Open err %d"), err))
iDataSocket->ActivateBasebandEventNotifier(ENotifyAnyPowerMode | ENotifyAnyRole |
ENotifySCOLinkUp | ENotifySCOLinkDown |
ENotifySCOLinkError | ENotifyPhysicalLinkUp |
ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError);
ReceiveL();
}
TRACE_FUNC_EXIT
}
void CBtmRfcommSock::HandleAcceptCompleteL(TInt aErr)
{
TRACE_FUNC_ENTRY
if (aErr == KErrNone)
{
iRemoteHasConnected = ETrue;
TBTSockAddr sockAddr;
iDataSocket->RemoteName(sockAddr);
iRemote = sockAddr.BTAddr();
}
// Process the accept complete before issuing a receive request to ensure that
// we are ready to process the data when it is received.
iObserver->RfcommAcceptCompletedL(aErr, iService);
if (aErr == KErrNone)
{
iInData.ReAllocL(256);
// Previously a request to become piconet master was made here, for IOP reasons this
// was removed (as theoretically being a piconet master is not required for HFP/HSP AG).
TInt err = iAda.Open(iServer, iRemote);
TRACE_INFO((_L("ada.Open err %d"), err))
iDataSocket->ActivateBasebandEventNotifier(ENotifyAnyPowerMode | ENotifyAnyRole |
ENotifySCOLinkUp | ENotifySCOLinkDown |
ENotifySCOLinkError | ENotifyPhysicalLinkUp |
ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError);
ReceiveL();
}
TRACE_FUNC_EXIT
}
void CBtmRfcommSock::HandleShutdownCompleteL(TInt aErr)
{
TRACE_FUNC
iObserver->RfcommShutdownCompletedL(aErr);
}
void CBtmRfcommSock::HandleSendCompleteL(TInt aErr)
{
TRACE_FUNC
TRACE_INFO((_L("err %d"), aErr))
iWriting = EFalse;
if (!aErr)
{
SendPacketL();
}
else
{
iObserver->RfcommSendCompletedL(aErr);
}
}
void CBtmRfcommSock::HandleReceiveCompleteL(TInt aErr)
{
TRACE_FUNC
TRACE_INFO((_L("err %d"), aErr))
iObserver->RfcommReceiveCompletedL(aErr, iInData);
if (!aErr)
{
ReceiveL();
}
}
void CBtmRfcommSock::HandleIoctlCompleteL(TInt aErr)
{
TRACE_FUNC
TRACE_INFO((_L("KL2CAPEchoRequestIoctl callback code: %d"), aErr ))
if (aErr)
{
iObserver->RfcommSendCompletedL(aErr);
}
}
void CBtmRfcommSock::HandleActivateBasebandEventNotifierCompleteL(
TInt aErr, TBTBasebandEventNotification& aEventNotification)
{
TRACE_FUNC_ENTRY
if (!aErr)
{
switch(aEventNotification.EventType())
{
case ENotifyActiveMode:
{
TRACE_INFO(_L( "BB Notif: Active mode" ))
iInSniff = EFalse;
break;
}
case ENotifySniffMode:
{
TRACE_INFO(_L( "BB Notif: Sniff mode" ))
break;
}
case ENotifyMaster:
{
TRACE_INFO(_L( "BB Notif: Master role"))
break;
}
case ENotifySlave:
{
TRACE_INFO(_L("BB Notif: Slave role"))
break;
}
case ENotifySCOLinkUp:
{
TRACE_INFO(_L("BB Notif: SCO up"))
break;
}
case ENotifySCOLinkDown:
{
TRACE_INFO(_L("BB Notif: SCO down"))
TInt err = iDataSocket->Ioctl( KL2CAPEchoRequestIoctl, NULL, KSolBtL2CAP );
TRACE_INFO((_L("KL2CAPEchoRequestIoctl return code: %d"), err ))
break;
}
case ENotifySCOLinkError:
{
TRACE_INFO(_L("BB Notif: SCO error"))
break;
}
case ENotifyPhysicalLinkUp:
{
TRACE_INFO(_L("BB Notif: Physical link up"))
break;
}
case ENotifyPhysicalLinkDown:
{
TRACE_INFO(_L("BB Notif: Physical link down"))
break;
}
case ENotifyPhysicalLinkError:
{
TRACE_INFO(_L("BB Notif: Physical link error"))
break;
}
default:
{
TRACE_INFO((_L( "BB Notif: Uninteresting event (0x%08X)"), aEventNotification.EventType()))
}
};
}
TRACE_FUNC_EXIT
}
void CBtmRfcommSock::ConstructL()
{
}
CBtmRfcommSock::CBtmRfcommSock(MBtmSockObserver& aObserver, RSocketServ& aServer)
: iObserver(&aObserver), iServer(aServer), iInSniff(EFalse)
{
TRACE_FUNC
}
// -----------------------------------------------------------------------------
// CBtmAtPipe::HandleAccessoryDataEventL
// -----------------------------------------------------------------------------
//
void CBtmRfcommSock::SendPacketL()
{
if (!iWriting && iOutDataQueue && iOutDataQueue->MdcaCount() > 0)
{
if (iOutData.MaxLength() < iOutDataQueue->MdcaPoint(0).Length())
{
iOutData.ReAllocL(iOutDataQueue->MdcaPoint(0).Length());
}
iOutData.Copy(iOutDataQueue->MdcaPoint(0));
iDataSocket->Write(iOutData);
iOutDataQueue->Delete(0);
TRACE_INFO((_L8("[HFP] [O] %S"), &iOutData))
iWriting = ETrue;
}
}
void CBtmRfcommSock::ReceiveL()
{
TRACE_FUNC
TRACE_ASSERT(iDataSocket != NULL, EBTPanicObjectUninitialized)
iInData.Zero();
LEAVE_IF_ERROR(iDataSocket->RecvOneOrMore(iInData, 0, iXfrLength));
}
void CBtmRfcommSock::CancelReceive()
{
if (iDataSocket)
{
TRACE_FUNC_ENTRY
iDataSocket->CancelRecv();
TRACE_FUNC_EXIT
}
}
void CBtmRfcommSock::SetService(TUint aService)
{
iService = aService;
}