traceservices/commsdebugutility/SSVR/comsdbgwriter.cpp
changeset 0 08ec8eefde2f
child 1 c084286672be
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/traceservices/commsdebugutility/SSVR/comsdbgwriter.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1045 @@
+// Copyright (c) 1997-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:
+// Implements the Flogger server side data writing
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "comsdbgwriter.h"
+#include "comsdbgmessages.h"
+
+
+const TInt KHeapBufSize = 50000;   // Maximum that the file buffer can grow to limit its impact somewhat
+
+
+// RDebug will truncate strings longer than the limit below
+const TInt KRDebugLimit = 0x100;
+
+
+// source strings, lengths and offsets
+_LIT8(KLogStartedString, "#Logging started on dd/mm/yyyy. Output version 2\r\n");	///< Format specifier for the very first line written. The output version is printed so tools processing the log output can determine the expected format of the output.
+_LIT8(KDateChangedString,"#      Date is now: dd/mm/yyyy.\r\n");	///< Format specifier for subsequent date changes
+const TInt KLogStartedStringLength = 50;
+const TInt KLogStartedDayOffset = 20;
+const TInt KLogStartedMonthOffset = 23;
+const TInt KLogStartedYearOffset = 26;
+
+_LIT8(KUnableToLog, "#Logs lost since log file couldn't be written to");
+
+_LIT8(KClearLogString, "#Clear Log called by ");
+const TInt KClearLogStringLength = 21;
+
+_LIT8(KEolCharacters, "\r\n");
+const TInt KEolCharactersLength = 2;
+
+_LIT8(KLogPathTree,"\\");	
+_LIT8(KLogFileExt,".");
+
+//Below const is... log string + 2 tags + 8 for the thread id + 3 tabs + EOL characters.
+const TInt KMaxFinalLogStringLength = KLogBufferSize+2*KMaxTagLength+8+3+KEolCharactersLength;
+
+_LIT8(KBadMediaString, "#Bad media setting in ini file.\r\n");
+_LIT8(KUnableToUpdateMedia, "#Unable to update logging media. Err code: %d\r\n");
+_LIT8(KUnableToLoadSerialDevices, "#Unable to load the LDD or PDD required for serial. Err code: %d\r\n");
+_LIT8(KUnableToOpenSerial, "#Unable to open the serial port. Err code: %d\r\n");
+_LIT8(KUnableToSetSerialConfig, "#Could not set serial port configuration after opening port. Err code: %d\r\n");
+
+// source characters
+_LIT8(KTabCharacter, "\t");
+_LIT8(KTypeIdentifierAscii, "a");
+_LIT8(KTypeIdentifierBinary, "b");
+
+// serial specs
+const TBps KFloggerSerialRate = EBps115200;
+const TInt KSerialRetryCount = 50;
+const TInt KSerialTimeoutInMicroSecs = 100000;
+
+// serial ports
+const TInt KSerialPort1 = 0;
+#if defined (__WINS__)
+const TInt KSerialPort2OnEmulator = 1;
+#else
+const TInt KSerialPort2OnTarget = 2;
+#endif
+
+#if defined (__WINS__)
+#define PDD_NAME _L("ECDRV.PDD")
+#define LDD_NAME _L("ECOMM.LDD")
+#else
+#define PDD_NAME _L("EUART1")
+#define LDD_NAME _L("ECOMM")
+#endif
+
+
+// log file specs
+_LIT(KLogFileName, "log.txt");
+_LIT(KLogDefaultFilePath, "C:\\logs\\");
+
+
+const TUint KZeroDate = 0;  ///< The day to count forward from when determining date roll.
+const TUint KSecondsToWriteTimestampOnNoActivity = 5;
+
+#if defined (__WINS__)
+const TInt Win32DisplayStringLengthMax = 1024; 
+#endif
+
+
+
+
+CLogManager* CLogManager::NewL(MLogArrayAccess& aArrayAccess)
+	{
+	CLogManager* self = new(ELeave) CLogManager(aArrayAccess);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CLogManager::CLogManager(MLogArrayAccess& aArrayAccess)
+: iArrayAccess(aArrayAccess), iTimeString(KTimeFormat)
+{}
+
+CLogManager::~CLogManager()
+	{
+	delete iLogger;
+	}
+
+void CLogManager::ConstructL()
+/*
+ * Set the initial media to file and write there until the server has told us
+ * which media is in the ini file.
+ * Write the log started and date message. 
+ */
+	{
+	iLogger = CFileWriter::NewL();	//File writer by default
+	iCurrentMediaSetting = KFileMedia;
+	iLoggingEnabled = EFalse;
+	}
+
+TInt CLogManager::ThreadEntryPoint(TAny* aPtr)
+	{
+	__UHEAP_MARK;
+
+	MLogArrayAccess* arrayAccess = static_cast<MLogArrayAccess*> (aPtr);
+
+	CTrapCleanup* cleanupStack = CTrapCleanup::New();
+	if (cleanupStack==NULL)
+		{
+		return KErrNoMemory;
+		}
+
+	TRAPD(err, CLogManager::DoRunThreadL(*arrayAccess));
+
+	delete cleanupStack;
+
+	__UHEAP_MARKEND;
+
+	return err;
+	}
+
+void CLogManager::DoRunThreadL(MLogArrayAccess& aArrayAccess)
+	{
+	CLogManager* self = CLogManager::NewL(aArrayAccess);
+	self->DoStart();
+	delete self;
+	}
+
+void CLogManager::DoStart()
+/**
+ * Second/consumer/slave/draining/dequeuer thread main loop.
+ * @note Continuously takes the log queue top message and processes it. Blocks on the "Get" if no messages.
+ * @note Completes when a shutdown message is processed from the queue. This message sets "iShutDown".
+ */
+	{
+	CLogMessageBase * message = NULL;
+
+	TInt ret = KErrNone;
+	RThread::Rendezvous(ret);
+
+	FOREVER
+		{
+		iArrayAccess.GetFirstMessageAndTakeOwnership(message);
+		__ASSERT_ALWAYS(message, User::Panic(KFloggerServerPanic, ENullMessageInArray));
+		message->Invoke(*this);
+		delete message;
+        // GetFirstMessage waits on the request semaphore, so to balance these each 
+		// time a message is processed we must then signal the completion semaphore
+		// when in synchronous mode
+		iArrayAccess.SignalCompletionSemaphore();
+		if (iShutDown)
+			{
+			break;
+			}
+		}
+	}
+
+void CLogManager::WriteDateIntoLog(TBool firstTime)
+/**
+ * Write the date straight to the log output
+ * @param firstTime If ETrue then write a "log started" otherwise write a "date change" msg
+ */
+	{
+	if (!iLoggingEnabled) 
+	   {
+	   return;
+	   }
+	//Put a date stamp for when we've started logging
+	//Can't use TTime::FormatL since it gives unicode and we want narrow.
+	TTime time;
+	TBuf8<KLogStartedStringLength> logDateString;
+	time.HomeTime();
+	TDateTime dateTime(time.DateTime());
+	if (firstTime)
+		{
+		logDateString.Copy(KLogStartedString);
+		}
+	else
+		{
+		logDateString.Copy(KDateChangedString);
+		}
+	TBuf8<2> holdingBuf;
+	holdingBuf.NumFixedWidth(dateTime.Day()+1, EDecimal, 2);
+	logDateString.Replace(KLogStartedDayOffset,2,holdingBuf);
+	holdingBuf.NumFixedWidth(dateTime.Month()+1, EDecimal, 2);
+	logDateString.Replace(KLogStartedMonthOffset,2,holdingBuf);
+	TBuf8<4> holdingBuf2;
+	holdingBuf2.NumFixedWidth(dateTime.Year(), EDecimal, 4);
+	logDateString.Replace(KLogStartedYearOffset,4,holdingBuf2);
+	iLogger->LogString(logDateString);
+	}
+
+void CLogManager::ClearLog(const TFullName& aName)
+	{
+	if (!iLoggingEnabled) 
+	   {
+	   return;
+	   }
+	TRAP_IGNORE(iLogger->ClearLogL());	//if there is an error there is nothing we can do.
+	TBuf8<KMaxFullName+KClearLogStringLength+KEolCharactersLength> buf(KClearLogString);
+	buf.Append(aName);
+	buf.Append(KEolCharacters);
+	iLogger->LogString(buf);
+	WriteDateIntoLog(ETrue);
+	iTicksSinceLastLog=0;
+	}
+
+void CLogManager::SetTimeL(const TTime& aTime)
+	{
+	if (!iLoggingEnabled) 
+	   {
+	   return;
+	   }
+	//check whether date has rolled and write it to log if necessary
+	TTime currentMicrosecs;
+	TTimeIntervalDays newDate;
+	currentMicrosecs.HomeTime();
+	TTime zeroDate = TTime(TInt64(KZeroDate));
+	newDate = currentMicrosecs.DaysFrom(zeroDate);
+	if (newDate > iCurrentDate)
+		{
+		WriteDateIntoLog(EFalse);
+		iCurrentDate = newDate;
+		}
+	
+	//Print the time to the log
+	//Have to do this stuff manually since TTime only provides Unicode formating
+	//which is not what we want.
+	// We format this each second regardless of whether it is used so that it is ready for use
+	// if a client logs since in normal use it would be rare for flogger not to log something each second.
+	TDateTime dateTime(aTime.DateTime());
+	TBuf8<2> holdingBuf;
+	holdingBuf.NumFixedWidth(dateTime.Hour(), EDecimal, 2);
+	iTimeString.Replace(KHourOffset,2,holdingBuf);
+	holdingBuf.NumFixedWidth(dateTime.Minute(), EDecimal, 2);
+	iTimeString.Replace(KMinuteOffset,2,holdingBuf);
+	holdingBuf.NumFixedWidth(dateTime.Second(), EDecimal, 2);
+	iTimeString.Replace(KSecondOffset,2,holdingBuf);
+	if (iTicksSinceLastLog++ < KSecondsToWriteTimestampOnNoActivity)
+		{
+		iLogger->LogString(iTimeString);
+		iLogger->FlushLogL();
+		}
+		
+	}
+
+void CLogManager::LogString(const TDesC8& aLogString, const TDesC8& aSubSystem, const TDesC8& aComponent, const TThreadId& aThreadId)
+	{
+	if (!iLoggingEnabled) 
+	   {
+	   return;
+	   }
+	if (iTicksSinceLastLog > KSecondsToWriteTimestampOnNoActivity)
+		{
+		iLogger->LogString(iTimeString);
+		}
+	iTicksSinceLastLog=0;
+
+	TBuf8<KMaxFinalLogStringLength> buf;
+	buf.Append(aSubSystem);
+	buf.Append(KTabCharacter);
+	buf.Append(aComponent);
+	buf.Append(KTabCharacter);
+	buf.Append(KTypeIdentifierAscii);
+	buf.Append(KTabCharacter);
+	buf.AppendNum(aThreadId, EHex);
+	buf.Append(KTabCharacter);
+	buf.Append(aLogString);
+	// check whether last two bytes of string are eol chars, since some lines have cr/lf, some don't
+	TPtr8 ptr(&buf[buf.Length()-2], 2, 2);
+	if (ptr.Compare(KEolCharacters)!=0)
+		{
+		buf.Append(KEolCharacters);
+		}
+	iLogger->LogString(buf);
+	}
+
+void CLogManager::LogBinaryDump(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+	{
+	iLogger->LogBinaryDump(aBinaryString, aSubSystem, aComponent);
+	}
+
+void CLogManager::LogComment(const TDesC8& aComment)
+	{
+	if (iTicksSinceLastLog > KSecondsToWriteTimestampOnNoActivity)
+		{
+		iLogger->LogString(iTimeString);
+		}
+	iTicksSinceLastLog=0;
+
+	iLogger->LogString(aComment);
+	}
+
+void CLogManager::MediaUpdate(const TDesC8& aMediaSetting, const TBool aForceFlush, const TDesC8& aLogPathSetting)
+	{
+	TRAPD(err, DoMediaUpdateL(aMediaSetting,aForceFlush, aLogPathSetting));
+	if (err!=KErrNone)
+		{
+		TBuf8<KMaxFinalLogStringLength> buf;
+		buf.Format(KUnableToUpdateMedia,err);
+		iLogger->LogString(buf);
+		}
+	}
+
+void CLogManager::DoMediaUpdateL(const TDesC8& aMediaSetting,const TBool aForceFlush, const TDesC8& aLogPathSetting)
+	{
+	//We should NEVER have no media selected, media is set on construction
+	//and there should always be something set up.
+	__ASSERT_ALWAYS(iLogger, User::Panic(KFloggerServerPanic, ENoLoggingMediaSetUp));
+
+	if (aMediaSetting.Length() == 0)
+		{
+		return;
+		}
+		
+	// if the ini file has been opened, the media setting will be either the default
+	// or some other string so we can allow logging. If we are only opening media now, output extra info.
+	TTime currentMicrosecs;
+	currentMicrosecs.HomeTime();
+	iCurrentDate = currentMicrosecs.DaysFrom(TTime(TInt64(KZeroDate)));
+	
+	if (!iLoggingEnabled)
+		{
+		iLoggingEnabled = ETrue;
+		WriteDateIntoLog(ETrue);
+		}
+	
+	//Media update is a best effort, if it fails we keep
+	//logging to the old media
+	//If bad media in ini file, carry on with old media and post message in log
+
+	if (aMediaSetting.CompareF(iCurrentMediaSetting)==0 && aLogPathSetting.CompareF(iLogPath) == 0)
+		{
+		//Media hasn't changed, so update flush status only
+		// ForceFlushing as far as media is concerned only applies to file since 
+		// serial has no such buffer which needs flushing.
+		iLogger->SetForceFlush(aForceFlush);
+		return;
+		}
+	if (!aMediaSetting.CompareF(KFileMedia))
+		{
+		CLoggerMediaBase* media = CFileWriter::NewL();
+		delete iLogger;
+		iLogger = media;
+		// ForceFlushing only applies to file since serial has no such buffer
+		iLogger->SetForceFlush(aForceFlush);
+		if(aLogPathSetting.Length() != 0)
+			{
+			(static_cast<CFileWriter*>(iLogger))->SetLogPath(aLogPathSetting);
+			WriteDateIntoLog(ETrue);
+			}
+		}
+	else if (!aMediaSetting.CompareF(KSerial1Media))
+		{
+		// lots of things can go wrong when constructing the serial, so
+		// we set it up in stages, and log here if an error
+		// If we get an error in NewL - just let generic error given by
+		// SetMedia cover it
+		//CLoggerMediaBase* media = CSerialWriter::NewL();
+		CSerialWriter* serial = CSerialWriter::NewL();
+
+		TInt res = serial->LoadDevices();
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToLoadSerialDevices,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+		res = serial->OpenPort(KSerialPort1);
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToOpenSerial,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+
+		res = serial->SetPortConfig();
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToSetSerialConfig,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+		CLoggerMediaBase* media = serial;
+		delete iLogger;
+		iLogger = media;
+		WriteDateIntoLog(ETrue);
+		}
+	else if (!aMediaSetting.CompareF(KSerial2Media))
+		{
+		// lots of things can go wrong when constructing the serial, so
+		// we set it up in stages, and log here if an error.
+		// If we get an error in NewL - just let generic error given by
+		// SetMedia cover it
+
+		CSerialWriter* serial = CSerialWriter::NewL();
+
+		TInt res = serial->LoadDevices();
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToLoadSerialDevices,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+
+		#if defined (__WINS__)
+		res = serial->OpenPort(KSerialPort2OnEmulator);
+		#else
+		res = serial->OpenPort(KSerialPort2OnTarget);
+		#endif
+
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToOpenSerial,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+
+		res = serial->SetPortConfig();
+		if (res != KErrNone)
+			{
+			TBuf8<KMaxFinalLogStringLength> buf;
+			buf.Format(KUnableToSetSerialConfig,res);
+			iLogger->LogString(buf);
+			delete serial;
+			User::Leave(res);
+			}
+		CLoggerMediaBase* media = serial;
+		delete iLogger;
+		iLogger = media;
+		WriteDateIntoLog(ETrue);
+		}
+	else if (!aMediaSetting.CompareF(KRDebugMedia))
+		{
+		CLoggerMediaBase* media = CRDebugWriter::NewL();;
+		delete iLogger;
+		iLogger = media;
+		WriteDateIntoLog(ETrue);
+		}
+	else if (!aMediaSetting.CompareF(KOSTv2Media))
+		{
+		CLoggerMediaBase* media = COstv2Writer::NewL();;
+		delete iLogger;
+		iLogger = media;
+		WriteDateIntoLog(ETrue);
+		}
+	else	//Bad setting in the media file, leave media as is and return.
+		{
+		iLogger->LogString(KBadMediaString);
+		return;	
+		}
+	iCurrentMediaSetting = aMediaSetting;
+	iLogPath = aLogPathSetting;
+	}
+
+void CLogManager::ShutDown()
+	{
+	iShutDown = ETrue;
+	}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void CFileWriter::LogString(const TDesC8& aString)
+	{
+	TPtr8 ptr(iHBuf->Des());
+	if (ptr.Length()+aString.Length() <=KHeapBufSize)
+		{
+		ptr.Append(aString);
+		}
+	else
+		{
+		TRAPD(err, DoFlushBufferToFileL());
+		if (err==KErrNone)
+			{
+			ptr.Zero();
+			ptr.Append(aString);
+			}
+		else
+			{
+			ptr.Zero();
+			ptr.Append(KUnableToLog);
+			ptr.Append(aString);
+			}
+		}
+	if (iForceBufferFlushAlways)
+		{
+		TRAPD(err, DoFlushBufferToFileL());
+		ptr.Zero();
+		if (err!=KErrNone)
+			{
+			ptr.Append(KUnableToLog);
+			}
+		}
+
+	}
+
+void CFileWriter::LogBinaryDump(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+	{
+	TRAPD(err, DoLogBinaryDumpL(aBinaryString, aSubSystem, aComponent));
+	if (err!=KErrNone)
+		{
+		LogString(KUnableToLog);
+		}
+	}
+
+void CFileWriter::DoLogBinaryDumpL(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+/**
+ * Place a chunk of raw binary into the log file
+ * @post Opens the output file, flushes the write buffer and then places some tags before writing
+ *   the binary data.
+ */
+	{
+	RFile logFile;
+	TInt err = logFile.Open(iFs, iLogFileName, EFileWrite|EFileShareAny);
+	if(err == KErrPathNotFound)
+		{
+		TName filePath;
+		filePath.Copy(iLogPath);
+		User::LeaveIfError(iFs.MkDirAll(filePath));
+		}
+	if(err == KErrNotFound || err == KErrPathNotFound)
+		{
+		err = logFile.Create(iFs, iLogFileName, EFileWrite|EFileShareAny);
+		}
+	User::LeaveIfError(err);
+	
+	CleanupClosePushL(logFile);
+	TInt filePos = 0;
+	User::LeaveIfError(logFile.Seek(ESeekEnd,filePos));
+	User::LeaveIfError(logFile.Write(*iHBuf));
+	TPtr8 ptr(iHBuf->Des());
+	ptr.Zero();
+
+	TUint32 length = static_cast<TUint32>(aBinaryString.Length());
+	TBuf8<sizeof(TUint32)> lengthString(4);
+	lengthString[0] = static_cast<TUint8>((length & 0x000000ff) >> 0);
+	lengthString[1] = static_cast<TUint8>((length & 0x0000ff00) >> 8);
+	lengthString[2] = static_cast<TUint8>((length & 0x00ff0000) >> 16);
+	lengthString[3] = static_cast<TUint8>((length & 0xff000000) >> 24);
+
+	User::LeaveIfError(logFile.Write(aSubSystem));
+	User::LeaveIfError(logFile.Write(KTabCharacter));
+	User::LeaveIfError(logFile.Write(aComponent));
+	User::LeaveIfError(logFile.Write(KTabCharacter));
+	User::LeaveIfError(logFile.Write(KTypeIdentifierBinary));
+	User::LeaveIfError(logFile.Write(KTabCharacter));
+	User::LeaveIfError(logFile.Write(lengthString));
+	User::LeaveIfError(logFile.Write(KTabCharacter));
+	User::LeaveIfError(logFile.Write(aBinaryString));
+	User::LeaveIfError(logFile.Write(KEolCharacters));
+	
+	CleanupStack::PopAndDestroy();	//logFile
+	//LogString(KEolCharacters);
+	}
+
+void CFileWriter::ClearLogL()
+	{
+	User::LeaveIfError(iFs.Delete(iLogFileName));
+	RFile logFile;
+	User::LeaveIfError(logFile.Create(iFs, iLogFileName, EFileWrite|EFileShareAny));
+	logFile.Close();
+	TPtr8 ptr(iHBuf->Des());
+	ptr.Zero();
+	}
+
+void CFileWriter::DoFlushBufferToFileL()
+	{
+	//Check that the log file exists, if not create a blank one.
+	RFile logFile;
+	TBool writePathErrorCode = KErrNone;
+	TInt err = logFile.Open(iFs, iLogFileName, EFileWrite|EFileShareAny);
+	if (err==KErrPathNotFound)
+		{
+		TName filePath;
+		filePath.Copy(iLogPath);
+		User::LeaveIfError(iFs.MkDirAll(filePath));
+		}
+	else if (err == KErrBadName || err == KErrNotReady)
+		{
+		writePathErrorCode = err;			
+		// duff pathspec in ini file
+		TName filePath;
+		filePath.Copy(KLogDefaultFilePath);
+		err = iFs.MkDirAll(filePath);
+		iLogFileName.Copy(KLogDefaultFilePath);
+		iLogFileName.Append(KLogFileName);			
+		if (err == KErrAlreadyExists)
+			{
+			err = logFile.Open(iFs, iLogFileName, EFileWrite|EFileShareAny);
+			}
+		}
+		
+	if (err==KErrNotFound||err==KErrPathNotFound||err==KErrBadName||err == KErrNotReady)
+		{
+		err = logFile.Create(iFs, iLogFileName, EFileWrite|EFileShareAny);
+		}
+	User::LeaveIfError(err);
+	CleanupClosePushL(logFile);
+	TInt filePos = 0;
+	User::LeaveIfError(logFile.Seek(ESeekEnd,filePos));
+	if (writePathErrorCode != KErrNone)
+		{
+		TBuf8<KMaxFinalLogStringLength> tmpBuf;
+		tmpBuf.Format(KUnableToUpdateMedia,writePathErrorCode);
+		User::LeaveIfError(logFile.Write(tmpBuf));
+		}
+	if (iHBuf)
+		{
+		User::LeaveIfError(logFile.Write(*iHBuf));
+		}
+	CleanupStack::PopAndDestroy();	//logFile
+	}
+
+void CFileWriter::FlushLogL()
+	{
+	DoFlushBufferToFileL();
+	if (iHBuf)
+		{
+		TPtr8 ptr(iHBuf->Des());
+		ptr.Zero();
+		}
+	}
+
+void CFileWriter::SetForceFlush(TBool aOn)
+	{
+	iForceBufferFlushAlways = aOn;
+	}
+
+void CFileWriter::SetLogPath(const TDesC8& aLogPathSetting)
+	{
+	iLogPath.Copy(aLogPathSetting);
+	
+	//the path may be reconfigured, so check for '\' 
+	//as its assumed to be at the end already
+	TPtr8 iTempStr = iLogPath.RightTPtr(1);	//get last
+	TPtr8 iTempExt = iLogPath.RightTPtr(4);	//get last 4
+
+	if( iTempStr == KLogPathTree)
+		{
+			//ends with '\', so ok to copy
+			iLogFileName.Copy(iLogPath);
+			iLogFileName.Append(KLogFileName);
+		}	
+	else if(iTempExt.Find(KLogFileExt)==KErrNotFound)
+		{
+			//no file extension already set, so its just path
+			iLogPath.Append(KLogPathTree);
+			iLogFileName.Copy(iLogPath);
+			iLogFileName.Append(KLogFileName);
+		}
+	else
+		{
+			//already has all we need
+			iLogFileName.Copy(iLogPath);
+		}
+	}
+
+CFileWriter* CFileWriter::NewL()
+	{
+	CFileWriter* self = new(ELeave) CFileWriter;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CFileWriter::ConstructL()
+	{
+	User::LeaveIfError(iFs.Connect());
+	//Create our buffer for logging into, at zero length but specify a maximum.
+	iHBuf = HBufC8::NewL(KHeapBufSize);
+	iForceBufferFlushAlways = EFalse;
+	iLogPath.Copy(KLogDefaultFilePath);
+	iLogFileName.Copy(iLogPath);
+	iLogFileName.Append(KLogFileName);
+	}
+
+CFileWriter::~CFileWriter()
+	{
+	// Don't attempt flushing when it's an OOM leave from NewL()
+	if (iHBuf)
+		{
+		TRAP_IGNORE(CFileWriter::FlushLogL());	//Ignore error. Nothing we can do now.
+		delete iHBuf;
+		}
+	iFs.Close();
+	}
+
+///////////////////////////////////////////////////////////////////////
+
+CSerialWriter* CSerialWriter::NewL()
+	{
+	CSerialWriter* self = new(ELeave) CSerialWriter;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CSerialWriter::ConstructL()
+	{
+	User::LeaveIfError(iTimeoutTimer.CreateLocal());
+	}
+
+TInt CSerialWriter::LoadDevices()
+	{
+	// load the device drivers
+	TInt result = User::LoadPhysicalDevice(PDD_NAME);
+	if ((result != KErrNone) && (result != KErrAlreadyExists))
+		{
+		 return result;
+		}
+
+	result = User::LoadLogicalDevice(LDD_NAME);
+	if ((result != KErrNone) && (result != KErrAlreadyExists))
+		{
+		return result;
+		}
+
+	return KErrNone;
+	}
+
+
+TInt CSerialWriter::OpenPort(TInt aPort)
+	{
+	return iSerialPort.Open(aPort);
+	}
+
+TInt CSerialWriter::SetPortConfig()
+	{
+	TCommConfig tComConfig;
+	TCommConfigV01 &tComConfigV = tComConfig();
+	iSerialPort.Config(tComConfig);
+	tComConfigV.iRate=KFloggerSerialRate;
+	tComConfigV.iDataBits=EData8;
+	tComConfigV.iStopBits=EStop1;
+	tComConfigV.iParity=EParityNone;
+	tComConfigV.iHandshake=0;
+	tComConfigV.iFifo = EFifoEnable;
+	return iSerialPort.SetConfig(tComConfig);
+	}
+
+
+
+CSerialWriter::~CSerialWriter()
+	{
+	iTimeoutTimer.Close();
+	iSerialPort.Close();
+	}
+
+void CSerialWriter::ClearLogL()
+/**
+ * @note: Nothing to do for serial
+ */
+	{}
+
+void CSerialWriter::FlushLogL()
+/**
+ * @note: Nothing to do for serial
+ */
+	{}
+
+void CSerialWriter::SetForceFlush(TBool)
+/**
+ * @note: Nothing to do for serial.
+ */
+	{
+	}
+
+
+void CSerialWriter::LogString(const TDesC8& aString)
+	{
+	//iInvalidcounter is used to dump packets if we fail to get a write through before the
+	//timer expires. It stops us getting backed up too much if there's a problem.
+	if (iInvalidCounter==0)
+		{
+		TRequestStatus writeStatus(KRequestPending);
+		TRequestStatus timeoutStatus(KRequestPending);
+		iSerialPort.Write(writeStatus, aString, aString.Length());
+		iTimeoutTimer.After(timeoutStatus, 
+			TTimeIntervalMicroSeconds32(KSerialTimeoutInMicroSecs));
+		User::WaitForRequest(writeStatus, timeoutStatus);
+		if (writeStatus==KRequestPending)
+			{//OK, still not completed, better cancel send.
+			iSerialPort.WriteCancel();
+			iInvalidCounter=KSerialRetryCount;
+			}
+		else
+			{
+			iTimeoutTimer.Cancel();
+			}
+		User::WaitForAnyRequest();
+		}
+	else
+		--iInvalidCounter;
+	}
+
+void CSerialWriter::LogBinaryDump(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+	{
+	TUint32 length = static_cast<TUint32>(aBinaryString.Length());
+	TBuf8<sizeof(TUint32)> lengthString(4);
+	lengthString[0] = static_cast<TUint8>((length & 0x000000ff) >> 0);
+	lengthString[1] = static_cast<TUint8>((length & 0x0000ff00) >> 8);
+	lengthString[2] = static_cast<TUint8>((length & 0x00ff0000) >> 16);
+	lengthString[3] = static_cast<TUint8>((length & 0xff000000) >> 24);
+
+	LogString(aSubSystem);
+	LogString(KTabCharacter);
+	LogString(aComponent);
+	LogString(KTabCharacter);
+	LogString(KTypeIdentifierBinary);
+	LogString(KTabCharacter);
+	LogString(lengthString);
+	LogString(KTabCharacter);
+	LogString(aBinaryString);
+	LogString(KEolCharacters);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+//Don't strictly need a NewL. Doing it for consistency.
+CRDebugWriter* CRDebugWriter::NewL()
+	{
+	return new(ELeave) CRDebugWriter;
+	}
+
+CRDebugWriter::~CRDebugWriter()
+	{
+	}
+
+void CRDebugWriter::ClearLogL()
+/**
+ * @note: Nothing to do for RDebug
+ */
+	{}
+
+void CRDebugWriter::FlushLogL()
+/**
+ * @note: Nothing to do for RDebug
+ */
+	{}
+
+void CRDebugWriter::SetForceFlush(TBool)
+/**
+ * @note: Nothing to do for RDebug.
+ */
+	{
+	}
+
+
+void CRDebugWriter::LogString(const TDesC8& aString)
+	{
+	
+	//RDebug truncates strings longer than a certain size
+	//To work around this we chop our string into palatable chunks
+	//and log those individually
+	
+	const TUint8 *p = aString.Ptr();
+	TInt bytesSent(0);
+	TInt totalToSend = aString.Length();
+	TInt length(0);
+	
+	do
+		{
+		bytesSent += KRDebugLimit;
+		if (bytesSent < totalToSend)
+			{
+			length = KRDebugLimit;
+			}
+		else
+			{
+			length = totalToSend - bytesSent + KRDebugLimit;
+			}
+		
+		TPtrC8 ptr(p,length);
+		RDebug::RawPrint(ptr);		
+		p += KRDebugLimit;
+		}
+	while(bytesSent < totalToSend);
+	}
+
+
+void CRDebugWriter::LogBinaryDump(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+	{
+	TUint32 length = static_cast<TUint32>(aBinaryString.Length());
+	TBuf8<sizeof(TUint32)> lengthString(4);
+	lengthString[0] = static_cast<TUint8>((length & 0x000000ff) >> 0);
+	lengthString[1] = static_cast<TUint8>((length & 0x0000ff00) >> 8);
+	lengthString[2] = static_cast<TUint8>((length & 0x00ff0000) >> 16);
+	lengthString[3] = static_cast<TUint8>((length & 0xff000000) >> 24);
+
+	RDebug::RawPrint(aSubSystem);
+	RDebug::RawPrint(KTabCharacter);
+	RDebug::RawPrint(aComponent);
+	RDebug::RawPrint(KTabCharacter);
+	RDebug::RawPrint(KTypeIdentifierBinary);
+	RDebug::RawPrint(KTabCharacter);
+	RDebug::RawPrint(lengthString);
+	RDebug::RawPrint(KTabCharacter);
+	LogString(aBinaryString);	
+	RDebug::RawPrint(KEolCharacters);
+
+	}
+
+
+///////////////////////////////////////////////////////////////////////
+
+#if defined (__WINS__)
+#include <emulator.h>
+
+CDebugPortProtocol* CDebugPortProtocol::NewL()
+	{
+	CDebugPortProtocol* protocol = new(ELeave) CDebugPortProtocol;
+	CleanupStack::PushL(protocol);
+	protocol->ConstructL();
+	CleanupStack::Pop(protocol);
+	return protocol;
+	}
+	
+void CDebugPortProtocol::ConstructL()
+	{
+	iDebugWriter = CDebugPortWriter::NewL();
+	}
+	
+CDebugPortProtocol::~CDebugPortProtocol()
+	{
+	delete iDebugWriter;
+	}
+void CDebugPortProtocol::ClearLog(const TFullName& /*aName*/)
+	{
+	}
+void CDebugPortProtocol::SetTimeL(const TTime& /*aTime*/)
+	{
+	}
+void CDebugPortProtocol::LogString(const TDesC8& aLogString, const TDesC8& aSubSystem, const TDesC8& aComponent, const TThreadId& aThreadId)
+	{
+	TBuf8<KMaxFinalLogStringLength> buf;
+	buf.Append(aSubSystem);
+	buf.Append(KTabCharacter);
+	buf.Append(aComponent);
+	buf.Append(KTabCharacter);
+	buf.Append(KTypeIdentifierAscii);
+	buf.Append(KTabCharacter);
+	buf.AppendNum(aThreadId, EHex);
+	buf.Append(KTabCharacter);
+	buf.Append(aLogString);
+	// check whether last two bytes of string are eol chars, since some lines have cr/lf, some don't
+	TPtr8 ptr(&buf[buf.Length()-2], 2, 2);
+	if (ptr.Compare(KEolCharacters) !=0 )
+		{
+		buf.Append(KEolCharacters);
+		}
+	iDebugWriter->LogString(buf);
+	}
+void CDebugPortProtocol::LogBinaryDump(const TDesC8& aBinaryString, const TDesC8& aSubSystem, const TDesC8& aComponent)
+	{
+	iDebugWriter->LogBinaryDump(aBinaryString, aSubSystem, aComponent);
+	}
+void CDebugPortProtocol::LogComment(const TDesC8& aComment)
+	{
+	iDebugWriter->LogString(aComment);
+	}
+void CDebugPortProtocol::MediaUpdate(const TDesC8& /*aMediaSetting*/, const TBool /*aForceFlushOn*/, const TDesC8& /*aLogPathSetting*/)
+	{
+	}
+void CDebugPortProtocol::ShutDown()
+	{
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+CDebugPortWriter* CDebugPortWriter::NewL()
+	{
+	return new(ELeave) CDebugPortWriter;
+	}
+	
+
+void CDebugPortWriter::LogString(const TDesC8& aString)
+	{
+	char str[Win32DisplayStringLengthMax];
+	int len = Min(sizeof(str) - 1, aString.Length());
+	Mem::Copy(str, aString.Ptr(), len);
+	str[len] = '\0';
+	Emulator::Lock();
+	::OutputDebugStringA(str);
+	Emulator::Unlock();
+	}
+void CDebugPortWriter::ClearLogL()
+	{
+	}
+void CDebugPortWriter::FlushLogL()
+	{
+	}
+void CDebugPortWriter::LogBinaryDump(const TDesC8& /*aBinaryString*/, const TDesC8& /*aSubSystem*/, const TDesC8& /*aComponent*/)
+	{
+	}
+void CDebugPortWriter::SetForceFlush(const TBool /*aOn*/)
+	{
+	}
+
+#endif  //(__WINS__)