dbgagents/trkagent/dbgtrccomm/server/ostbaserouter.cpp
author bdonegan
Thu, 30 Sep 2010 16:15:48 +0100
changeset 3 b667e5204120
parent 0 c6b0df440bee
permissions -rw-r--r--
Remove reference to cinidata in order to allow TrkEngine to build

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


#include <e32debug.h>
#include <e32base.h>
#include <e32cons.h>

#include "logging.h"
#include "dbgtrcportmgr.h"
#include "ostprotregistry.h"
#include "portreader.h"
#include "portwriter.h"
#include "dbgtrcsrvsession.h"
#include "ostmessage.h"
#include "ostbaserouter.h"

// Static functions

//
// Swap2
//
// Byte-swaps a 2-byte value.  Used to convert to/from little/big endian.
//
static TUint16 Swap2(TUint16 aSource)
{
	TUint16 dest = 0;
	for (TInt i=0; i<2; i++)
	{
		dest <<= 8;
		dest |= aSource & 0xFF;
		aSource >>= 8;
	}
	
	return dest;
} 

COstWriteMsgEntry* COstWriteMsgEntry::NewL(TDesC8& aMsg, CDbgTrcSrvSession* aMsgListener)
{
	LOG_MSG("COstWriteMsgEntry::NewL");

	COstWriteMsgEntry* self = new(ELeave) COstWriteMsgEntry(aMsgListener);
	CleanupStack::PushL(self);
	self->ConstructL(aMsg);
	CleanupStack::Pop(self);
	return self;
}

COstWriteMsgEntry::COstWriteMsgEntry(CDbgTrcSrvSession* aMsgListener)
: iMessage(NULL),
  iWriteMsgListener(aMsgListener)
{
	LOG_MSG("COstWriteMsgEntry::COstWriteMsgEntry");


}

COstWriteMsgEntry::~COstWriteMsgEntry()
{
	LOG_MSG("COstWriteMsgEntry::~COstWriteMsgEntry");

	SafeDelete(iMessage);
	iWriteMsgListener = NULL; //don't delete the listener since we don't really own it.
}

void COstWriteMsgEntry::ConstructL(TDesC8& aMsg)
{
	LOG_MSG("COstWriteMsgEntry::ConstructL");

	iMessage = COstMessage::NewL(aMsg);
}


COstBaseRouter*	COstBaseRouter::NewL()
{
	LOG_MSG("COstWriteMsgEntry::NewL");

	COstBaseRouter* self = new(ELeave) COstBaseRouter;
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
}

COstBaseRouter::COstBaseRouter()
: iPortManager(NULL),
  iProtRegistry(NULL),
  iWriteMsgListener(NULL),
  iWriteMsgQueue(1)  
{
	LOG_MSG("COstBaseRouter::COstBaseRouter");

}

COstBaseRouter::~COstBaseRouter()
{	
	LOG_MSG("COstBaseRouter::~COstBaseRouter");

	SafeDelete(iPortManager);
	SafeDelete(iProtRegistry);
	
	iWriteMsgQueue.ResetAndDestroy();	
	iWriteMsgQueue.Close();
}

void COstBaseRouter::ConstructL()
{
	LOG_MSG("COstBaseRouter::ConstructL");

	iPortManager = CDbgTrcPortMgr::NewL();	
	iProtRegistry = COstProtRegistry::NewL();
	
	// check the target endianness
	TUint32	test;
	TUint8 *byte_alias = (TUint8 *)&test;
	
	// Write a specific 4-byte sequence and then read it as
	// a 32-bit word.  Big-endian systems yield one value and
	// little-endian systems yield another.
	
	byte_alias[ 0 ] = 0x12;
	byte_alias[ 1 ] = 0x34;
	byte_alias[ 2 ] = 0x56;
	byte_alias[ 3 ] = 0x78;
	
	if (test == 0x12345678)
		iIsBigEndian = ETrue;
	else
		iIsBigEndian = EFalse;			
	
	iSendMsgBuffer.Zero();
	iRecvMsgBuffer.Zero();
	
	iWriteMsgQueue.Reset();
}

void COstBaseRouter::RegisterProtocol(const TOstProtIds aProtId, CDbgTrcSrvSession* aProtMsgListener, TBool aNeedHeader)
{
	LOG_MSG("COstBaseRouter::RegisterProtocol");

	iProtRegistry->RegisterProtocol(aProtId, aProtMsgListener, aNeedHeader);
	
	// Initiate the reads once someone registers a protocol.
	//ReadMessage();
}

void COstBaseRouter::UnRegisterProtocol(const TOstProtIds aProtId)
{
	LOG_MSG("COstBaseRouter::UnRegisterProtocol");

	iProtRegistry->UnRegisterProtocol(aProtId);
	
	// if listener count is 0, cancel the reads as well.
	if (!iProtRegistry->GetProtListenerCount())
	{
		CPortReader* reader = iPortManager->GetPortReader();
		if (reader)
		{
			reader->Cancel();
		}
	}	
}


void COstBaseRouter::ReadMessage()
{	
	LOG_MSG("COstBaseRouter::ReadMessage");

	CPortReader* reader = iPortManager->GetPortReader();
	
	if (reader)
		reader->StartRead(this);
}


void COstBaseRouter::WriteMessageL(TDesC8& aMsg, CDbgTrcSrvSession* aProtMsgListener)
{
	LOG_MSG("COstBaseRouter::WriteMessage");
	
	iSendMsgBuffer.Zero();
	iSendMsgBuffer.Append(aMsg);
			
	DoWriteMessageL(aProtMsgListener);
}

void COstBaseRouter::WriteMessageL(TDesC8& aMsg, CDbgTrcSrvSession* aProtMsgListener, TOstProtIds aProtId)
{
	LOG_MSG("COstBaseRouter::WriteMessage");	
	
	// write now, we use a fixed size array for the write message,
	// look below for the commented implementation if necessary in the future.
	iSendMsgBuffer.Zero();

	TUint16 msgLength = aMsg.Length();
	
	TUint8 version = OST_PROTOCOL_VERSION;		
	
	iSendMsgBuffer.Append(&version, sizeof(TUint8));
	iSendMsgBuffer.Append((TUint8*)&aProtId, sizeof(TUint8));
	
	TUint16 temp = msgLength; 
	if (!iIsBigEndian)
		temp = Swap2(msgLength);
		
	iSendMsgBuffer.Append((TUint8*)&temp, sizeof(TUint16));
			
	// now append the msg data
	iSendMsgBuffer.Append(aMsg);
		
	DoWriteMessageL(aProtMsgListener);
}


/*
TInt COstBaseRouter::WriteMessage(TDesC8& aMsg, CDbgTrcSrvSession* aProtMsgListener, TOstProtIds aProtId)
{	
	HBufC8* msgBuffer = HBufC8::New(aMsg.Length() + OST_HEADER_LENGTH);
	
	TUint16 msgLength = aMsg.Length();
	
	TUint8 version = OST_PROTOCOL_VERSION;		
	
	msgBuffer->Des().Append(&version, sizeof(TUint8));
	msgBuffer->Des().Append((TUint8*)&aProtId, sizeof(TUint8));
	
	TUint16 temp = msgLength; 
	if (!iIsBigEndian)
		temp = Swap2(msgLength);
		
	msgBuffer->Des().Append((TUint8*)&temp, sizeof(TUint16));
			
	// now append the msg data
	msgBuffer->Des().Append(aMsg);
	
	
}
*/

void COstBaseRouter::DoWriteMessageL(CDbgTrcSrvSession* aProtMsgListener)
{
	LOG_MSG("COstBaseRouter::DoWriteMessage");

	CPortWriter* writer = iPortManager->GetPortWriter();
	
	if(writer)
	{
		if (writer->IsBusy())
		{
			LOG_MSG("Writer busy, queuing up the write message");

			// we are already writing a message
			// so queue up this one, we only have to queue up one message for each connected client for writing.
			COstWriteMsgEntry* writeMsgEntry = COstWriteMsgEntry::NewL(iSendMsgBuffer, aProtMsgListener);
			iWriteMsgQueue.Append(writeMsgEntry);
		}
		else
		{
			// set the write listener for completing the request when the write is done
			iWriteMsgListener = aProtMsgListener;	
			writer->StartWrite(iSendMsgBuffer, this);
		}
	}
}

void COstBaseRouter::DataAvailable(TDesC8& aMsgData, TUint aLength)
{
	LOG_MSG("COstBaseRouter::DataAvailable");
	LOG_MSG2("Received bytes : %d", aLength);	

	TInt remainingBytes = aMsgData.Length();
	const TUint8* recvMsgDataPtr = aMsgData.Ptr();
	while (remainingBytes > 0)
	{	
		TInt bytesToCopy = remainingBytes;
		TInt spaceAvailable = MAX_BUF_SIZE-iRecvMsgBuffer.Length();
		if (spaceAvailable == 0) //should never happen, if this happens, then we will loose messages.
			return;
			
		if (remainingBytes > spaceAvailable)
		{
			bytesToCopy = spaceAvailable;
		}
		
		remainingBytes -= bytesToCopy;		
		iRecvMsgBuffer.Append(recvMsgDataPtr, bytesToCopy);
		recvMsgDataPtr += bytesToCopy;
							
		LOG_MSG2("Bytes copied: %d", bytesToCopy);
		LOG_MSG2("Remaining bytes : %d", remainingBytes);
					
		//
		// We could possibly get more than one message at a time, 
		// so check until we have atleast as many bytes as the OST header.
		//
		LOG_MSG2("Total bytes in the buffer : %d", iRecvMsgBuffer.Length());
		while (iRecvMsgBuffer.Length() > OST_HEADER_LENGTH)
		{
			LOG_MSG("No of received bytes > OST header length");

			const TUint8* ptr = iRecvMsgBuffer.Ptr();

			TUint8 version = ptr[VERS_FIELD_INDEX];
			TUint8 protId  = ptr[PROTID_FIELD_INDEX];
			
			// There could be some junk bytes in the data.
			// With the latest PCSuite/USB cable drivers, there seems to be some 
			// junk bytes in the USB channel. Also we can only do this simple check 
			// only at the beginning of the packet. The only check we have right now 
			// for the OST base protocol is to check for the version and the protocol id	
			if ( !( (version == OST_PROTOCOL_VERSION || version == OST_VERSION_PROTOCOL_VERSION) &&
				 (protId == EOstProtTrk || protId == EOstProtTraceCore || protId == EOstProtOstSystem || protId == EOstProtTrcActivation) ) )
			{
				LOG_MSG2("Invalid version byte: %x", version);
				LOG_MSG2("Invalid protocol byte: %x", protId);
				RemoveNonOstBytes(iRecvMsgBuffer);
			}
				
			LOG_MSG2("Total bytes in the buffer after removing non ost : %d", iRecvMsgBuffer.Length());					
			if (iRecvMsgBuffer.Length()>OST_HEADER_LENGTH)
			{
				// reset ptr just incase if we have deleted some junk bytes
				ptr = iRecvMsgBuffer.Ptr();
				TUint16 packetLength = 0;
				SwapBytes((TUint8*)&packetLength, &ptr[LENGTH_FIELD_INDEX], 2);
			
				LOG_MSG2("packet length is %d", packetLength);			

				if (iRecvMsgBuffer.Length() >= (packetLength+OST_HEADER_LENGTH))
				{
					LOG_MSG("Got one complete message");

					// got one complete message, complete the message if someone is listening for this message.
					TBool needHeader;
					CDbgTrcSrvSession* protMsgListener = iProtRegistry->GetProtListenerForProtId((TOstProtIds)protId, needHeader);
					
					if (protMsgListener)
					{
						LOG_MSG("Found a listener");

						TPtrC8 completeMessage;
						// check to see if we need to strip the header or not.
						if (needHeader)				
							completeMessage.Set(iRecvMsgBuffer.Ptr(), packetLength+OST_HEADER_LENGTH);
						else
							completeMessage.Set(iRecvMsgBuffer.Ptr()+OST_HEADER_LENGTH, packetLength);
							
						TRAPD(err, protMsgListener->MessageAvailableL(completeMessage));
						if (err != KErrNone)
						    LOG_MSG2("Failed to deliver the message: %d", err);
					}	
				
					LOG_MSG2("Deleting bytes in the recieve buffer: %d", packetLength+OST_HEADER_LENGTH);

					// now remove this message from our buffer as its already given to the listener				
					iRecvMsgBuffer.Delete(0, packetLength+OST_HEADER_LENGTH);
					
					LOG_MSG2("Remaining bytes in the recieve buffer: %d", iRecvMsgBuffer.Length());				
				}
				else
				{
					// We have more bytes than the header but we have an incomplete message.
					// So we break out here.
					break; 
				}
			}	
		}
	}
}

void COstBaseRouter::DataWriteComplete(TInt aErrCode)
{		
	LOG_MSG("COstBaseRouter::DataWriteComplete");

	if (iWriteMsgListener != NULL)
	{
		iWriteMsgListener->WriteComplete(aErrCode);
		iWriteMsgListener = NULL;
	}
	else
	{
		LOG_MSG("Invalid write message listener, should never happen");
	}	
	
	if (iWriteMsgQueue.Count() > 0)
	{
		LOG_MSG("Message found in write queue");
		
		COstMessage* ostMsg = iWriteMsgQueue[0]->iMessage;
		iWriteMsgListener = iWriteMsgQueue[0]->iWriteMsgListener;
		HBufC8* msg = ostMsg->iMsgBuffer;
		
		CPortWriter* writer = iPortManager->GetPortWriter();
		if(writer)
			writer->StartWrite(*msg, this);
		
		// now remove the message from the queue
		SafeDelete(iWriteMsgQueue[0]);			
		iWriteMsgQueue.Remove(0);		
	}
}

void COstBaseRouter::GetPortConfig(TDes8& aConfigDes)
{
	LOG_MSG("COstBaseRouter::GetPortConfig");

	iPortManager->GetPortConfig(aConfigDes);
}

TInt COstBaseRouter::SetPortConfig(TDesC8& aConfigDes)
{
	LOG_MSG("COstBaseRouter::SetPortConfig");

	return iPortManager->SetPortConfig(aConfigDes);
}

TInt COstBaseRouter::OpenCommPortL()
{
	LOG_MSG("COstBaseRouter::OpenCommPort");

	return iPortManager->OpenPortL();
}

TInt COstBaseRouter::CloseCommPort()
{
	LOG_MSG("COstBaseRouter::CloseCommPort");
	
	return iPortManager->ClosePort();
}


void COstBaseRouter::SwapBytes(TUint8* aTrgtData, const TUint8* aSrcData, TInt aLength)
{	
	LOG_MSG("COstBaseRouter::SwapBytes");
	
	if (iIsBigEndian)
	{
		Mem::Copy(aTrgtData, aSrcData, aLength);
	}
	else
	{
		for (int i=aLength-1, j=0; i>=0; i--, j++)
			aTrgtData[j] = aSrcData[i];
	}		
}


void COstBaseRouter::RemoveNonOstBytes(TDes8& aMsgBuffer)
{
	LOG_MSG("COstBaseRouter::RemoveNonOstBytes");	
	// We need to check for non OST bytes only in the beginning of the packet.
	// The only check we have right now for the OST base protocol
	// is to check for the version and the protocol id	
	const TUint8* msgDataPtr = aMsgBuffer.Ptr(); 				
	// look for the version byte..
	// if found, bail out and check for protocol byte
	TUint length = aMsgBuffer.Length();
	LOG_MSG2("Total bytes in the buffer: %d", length);
	for (TInt i=VERS_FIELD_INDEX; i<length; i++)
	{			
		if (msgDataPtr[VERS_FIELD_INDEX] == OST_PROTOCOL_VERSION ||
			msgDataPtr[VERS_FIELD_INDEX] == OST_VERSION_PROTOCOL_VERSION)	
		{
			// If we have more than one byte and the first byte seems to be the version byte
			// then check to see whether the second byte is the protocol byte or not.
			// if not, then delete the two bytes and start looking for version byte in the remaining bytes
			if (aMsgBuffer.Length()>1)
			{
				if (msgDataPtr[PROTID_FIELD_INDEX] == EOstProtTrk || 
					msgDataPtr[PROTID_FIELD_INDEX] == EOstProtTraceCore  ||
					msgDataPtr[PROTID_FIELD_INDEX] == EOstProtOstSystem ||
					msgDataPtr[PROTID_FIELD_INDEX] == EOstProtTrcActivation)				
				{
					LOG_MSG("Found a valid packet");
					break;					
				}					
				else
				{
					// we didn't find the version byte and the protocol byte together
					// so delete the two bytes
					LOG_MSG2("Deleting junk bytes, unexpected version: %x", msgDataPtr[VERS_FIELD_INDEX]);
					LOG_MSG2("Deleting junk bytes, unexpected protocol id: %x", msgDataPtr[PROTID_FIELD_INDEX]);

					aMsgBuffer.Delete(VERS_FIELD_INDEX, 2);
					i++; //deleting more than one byte, so increment one more time here.
				}					
			}
			else
			{
				// Special case handling when there is only one remaining byte 
				// and that byte happens to be the version byte
				// This could be an invalid byte from out of protocol data, just happens to be the version byte.
				// So delete this byte as well just so that we don't treat this byte as the version byte by mistake.
				LOG_MSG2("Deleting one remaining byte, unexpected version: %x", msgDataPtr[VERS_FIELD_INDEX]);
				aMsgBuffer.Delete(VERS_FIELD_INDEX, 1);			
			}
		}
		else
		{
			// if the first byte is not the version byte, delete it
			// it could be out of protocol data, we just need throw away
			LOG_MSG2("Deleting junk byte, unexpected version: %x", msgDataPtr[VERS_FIELD_INDEX]);
			aMsgBuffer.Delete(VERS_FIELD_INDEX, 1);
		}
	}		
}