bluetoothmgmt/bluetoothclientlib/avctpservices/avctpreceiver.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 13:05:56 +0200
changeset 3 4e39398d58ed
parent 0 29b1cd4cb562
permissions -rw-r--r--
Revision: 201001 Kit: 201004

// Copyright (c) 2005-2009 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:
//

/**
 @file
 @internalTechnology
*/

#include <bluetooth/logger.h>
#include "avctpreceiver.h"
#include "avctpcommon.h"
#include "avctpbody.h"
#include "avctpPriorities.h"
#include "avctpserviceutils.h"

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_AVCTP_SERVICES);
#endif

using namespace SymbianAvctp;

/**
two-phase constructor
@param aAvctpBody The class that provides access to the AVCTP client
@leave systemwide reason
@return pointer to newly created object
@internalTechnology
*/
CAvctpReceiver* CAvctpReceiver::NewL(MAvctpEventNotify& aNotify, RSocket& aAvctpSocket, TPid aPid)
	{
	LOG_STATIC_FUNC

	CAvctpReceiver* self = CAvctpReceiver::NewLC(aNotify, aAvctpSocket, aPid);
	CleanupStack::Pop(self);
	return self;
	}

/**
two-phase constructor, leaves object on cleanupstack
@param aAvctpBody The class that provides access to the AVCTP client
@leave systemwide reason
@return pointer to newly created object
@internalTechnology
*/
CAvctpReceiver* CAvctpReceiver::NewLC(MAvctpEventNotify& aNotify, RSocket& aAvctpSocket, TPid aPid)
	{
	LOG_STATIC_FUNC

	CAvctpReceiver* self = new(ELeave) CAvctpReceiver(aNotify, aAvctpSocket, aPid);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

/**
c'tor
*/
CAvctpReceiver::CAvctpReceiver(MAvctpEventNotify& aNotify, RSocket& aAvctpSocket, TPid aPid) : 
	CActive(KDataPlanePriority), 
	iNotify(aNotify),
	iAvctpSocket(aAvctpSocket),
	iRecvState(EWaitingForPktHeader),
	iRecvPtr(NULL, 0),
	iPid(aPid)
	{
	LOG_FUNC
	}

void CAvctpReceiver::ConstructL()
	{
	LOG_FUNC
	iRecvBuf = HBufC8::NewMaxL(ENormalHeaderLength);
	iRecvBuf->Des().SetMax();
	CActiveScheduler::Add(this);
	ReceiveL(EWaitingForPktHeader);
	}

/**
d'tor
*/
CAvctpReceiver::~CAvctpReceiver()
	{
	LOG_FUNC

	Cancel();
	delete iRecvBuf;
	}

inline void CAvctpReceiver::NotifyMessageReceived(const TBTDevAddr& aBTDevice,
									   		  SymbianAvctp::TTransactionLabel aTransactionLabel,
									   		  SymbianAvctp::TMessageType aType,
									   		  TBool aIpidBitSet,
							 		   		  const TDesC8& aMessageInformation)
	{
	LOG_FUNC
	__ASSERT_BTADDR(aBTDevice);
	SymbianAvctp::AssertValidTransactionLabel(aTransactionLabel);
	__ASSERT_DEBUG(aType == SymbianAvctp::ECommand || aType == SymbianAvctp::EResponse, Panic(::EAvctpInvalidMessageType));
	
	iNotify.MaenMessageReceivedIndicate(aBTDevice, aTransactionLabel, aType, aIpidBitSet, aMessageInformation);
	}
	
//
// Function that issues RecvFrom 

/**
Requests data from the Avctp Sap
When the async Recv completes, iXfrLength will contain the remaining amount of data
in the same packet that we've not yet got.
*/
void CAvctpReceiver::ReceiveL(TRecvState aNextState, TInt aBufLen)
	{
	LOG_FUNC
	//Make sure iRecvBuf isn't NULL before using it
	if((!iRecvBuf) || (iRecvBuf->Des().MaxLength() < aBufLen)) 
		{
		// Don't ReAlloc cause that copies across the old data which we don't want
		delete iRecvBuf; // free previous data
		iRecvBuf = NULL;
		iRecvBuf = HBufC8::NewMaxL(aBufLen);
		iRecvBuf->Des().SetMax();
		}
	iRecvPtr.Set(iRecvBuf->Des().MidTPtr(0, aBufLen));
	iAvctpSocket.RecvFrom(iRecvPtr, iAddr, KSockReadContinuation, iStatus, iXfrLength);	
	ChangeState(aNextState);
	}

//
// Functions From CActive
	
void CAvctpReceiver::DoCancel()
	{
	LOG_FUNC

	iAvctpSocket.CancelRecv();
	}

void CAvctpReceiver::RunL()
	{
	LOG_FUNC
	LOG1(_L("iStatus.Int(): %d"), iStatus.Int())
	
	if (iStatus.Int() == KErrNone)
		{
		switch (iRecvState)
			{
			case EWaitingForPktHeader:
				SetPacketInfo(iRecvPtr);
				if (iXfrLength())
					{
					ReceiveL(EWaitingForMsgInfo, iXfrLength());												 
					}
				else // there was no message data
					{
					NotifyMessageReceived(TAvctpSockAddr::Cast(iAddr).BTAddr(), 
													 iTransactionLabel, 
													 iMessageType, 
													 iIpidBitSet, 
													 KNullDesC8);
					ReceiveL(EWaitingForPktHeader);	
					}
				break;
				
			case EWaitingForMsgInfo:
				NotifyMessageReceived(TAvctpSockAddr::Cast(iAddr).BTAddr(), 
												 iTransactionLabel, 
												 iMessageType, 
												 iIpidBitSet, 
												 iRecvPtr);
				ReceiveL(EWaitingForPktHeader);
				break;		
					
			default:
				__ASSERT_ALWAYS(NULL, Panic(EAvctpUnrecognisedState));
				break;
			}
		}
	else if (iStatus.Int() != KErrCancel)
		{
		iNotify.MaenErrorNotify(TAvctpSockAddr::Cast(iAddr).BTAddr(), iStatus.Int());
		}
	// else ignore the KErrCancel since the cancelled request wasn't directly asked for by the client of RAvctp
	}
	
TInt CAvctpReceiver::RunError(TInt aError)
	{
	LOG_FUNC

	iNotify.MaenErrorNotify(TAvctpSockAddr::Cast(iAddr).BTAddr(), aError);
	return KErrNone;	
	}

//
// Other Functions

void CAvctpReceiver::ChangeState(TRecvState aNextState)
	{
	LOG_FUNC
	LOG2(_L("current State: %d, aNextState: %d"), iRecvState, aNextState)
	
	__ASSERT_DEBUG((iRecvState == EWaitingForPktHeader && aNextState == EWaitingForMsgInfo)   ||
				   (iRecvState == EWaitingForPktHeader && aNextState == EWaitingForPktHeader) ||
				   (iRecvState == EWaitingForMsgInfo &&   aNextState == EWaitingForPktHeader),
				   Panic(EAvctpRecvBadStateTransition));
	__ASSERT_ALWAYS(!IsActive(), Panic(EAvctpRecvBadStateTransition));
	iRecvState = aNextState;
	SetActive();
	}
    
void CAvctpReceiver::SetPacketInfo(TDes8& aHeader)
	{
	LOG_FUNC

	__ASSERT_DEBUG(Pid(aHeader) == iPid, Panic(EAvctpIncorrectPid));
	__ASSERT_DEBUG(PacketType(aHeader) == ENormalPkt, Panic(EAvctpPacketTypeNotNormal));
				
	iTransactionLabel = TransactionLabel(aHeader);
	iMessageType = MessageType(aHeader);
	iIpidBitSet = !IsValidPid(aHeader);
	
  __DEBUG_ONLY
  		(
  		TBuf<KBTAddressLength> address;
  		TAvctpSockAddr::Cast(iAddr).BTAddr().GetReadable(address);
  		)
  	
  	LOG1(_L("BT Device 0x%S"), &address);
	
	LOG3(_L("iTransactionLabel: %d, iMessageType: %d, iIpidBitSet: %d"), iTransactionLabel, iMessageType, iIpidBitSet)
	}
        	
// EOF