bluetooth/btstack/test/util/hcemulator/hcemulator.cpp
changeset 0 29b1cd4cb562
child 47 a1b8f5cc021e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/test/util/hcemulator/hcemulator.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1883 @@
+// 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:
+// BT test code to emulate certain aspects of host controller over null modem
+// for testing stack behaviour on invalid events etc from HC
+// 
+//
+
+#include <e32test.h>
+#include <es_sock.h>
+#include <f32file.h>
+#include <e32test.h>
+#include <c32comm.h>
+//#include <log.h>
+
+#include "hcemulator.h"
+
+#if defined (__WINS__)
+#define PDD_NAME _L("ECDRV")
+#define LDD_NAME _L("ECOMM")
+#else  // __GCC32__
+#define PDD_NAME _L("EUART1")
+#define LDD_NAME _L("ECOMM")
+// #define ETNA_PDD_NAME _L("EUART2") // for debugging over Com2
+#endif
+
+#define _EMULATOR_HWFC
+#undef  _EMULATOR_HWFC
+
+//The #define below was introduced for DEF074193. 
+//This defect was subsumed by INC075303.
+//#define DISCONNECT_ON_ACCEPT //Tweak HCEmulator to disconnect instead of completing an Accept_Connection_Request cmd
+
+
+GLDEF_D RTest test(_L("Host Controller Emulator"));
+
+
+
+CHCEmulator* CHCEmulator::NewL(CConsoleBase& aConsole)
+	{
+	CHCEmulator* e = new (ELeave) CHCEmulator(aConsole);
+	CleanupStack::PushL(e);
+	e->ConstructL(aConsole);
+	CleanupStack::Pop(e);
+	return e;
+	}
+
+
+CHCEmulator::CHCEmulator(CConsoleBase& aConsole) : iConsole(aConsole), iPacket(NULL,0), iHCAddress(KEmulatedHCAddress)
+	{
+	}
+
+
+CHCEmulator::~CHCEmulator()
+	{
+	delete iReader;
+	delete iWriter;
+	delete iInquiryTimer;
+	delete iActiveConsole;
+	delete iConnectionsConsole;
+	delete iPacketBuffer;
+	
+	iLocalName.Close();
+
+	iConnections.Close();
+
+	iPort.Close();
+	iCommServer.Close();
+	}
+
+
+void CHCEmulator::ConstructL(CConsoleBase& aConsole)
+	{
+	User::LeaveIfError(iCommServer.Connect());
+	User::LeaveIfError(iCommServer.LoadCommModule(_L("ECUART")));
+	
+	iConsole.Printf(_L("Select COM port that NULL modem lead is connected to (0/1/2/3/4/5/6/7/8/9):"));
+
+	TChar port;
+	
+	do
+		{
+		port = iConsole.Getch();
+		}
+	while (port != '0' && 
+		   port != '1' && 
+		   port != '2' && 
+		   port != '3' && 
+		   port != '4' && 
+		   port != '5' && 
+		   port != '6' && 
+		   port != '7' && 
+		   port != '8' && 
+		   port != '9');
+
+	TBuf<7> portName;
+
+	portName = _L("COMM::");
+	portName.Append(port);
+
+	TInt ret=iPort.Open(iCommServer,portName,ECommExclusive);
+	
+	if (ret!=KErrNone)
+		User::Leave(ret);
+
+	iPort.ResetBuffers();
+
+	TCommConfig config;
+	iPort.Config(config);
+	config().iRate=EBps115200;					// 115200 for CSR, 57600 for EBDK builds of stack
+	config().iDataBits=EData8;
+	config().iParity=EParityNone;			    // no parity
+	config().iStopBits=EStop1;                 // 1 stop bit
+#ifdef _EMULATOR_HWFC
+	config().iHandshake=KConfigObeyCTS | KConfigFreeRTS | KConfigFreeDTR;        // no handshaking;
+#else
+	config().iHandshake=0;
+#endif
+	User::LeaveIfError(iPort.SetConfig(config));
+
+//	iPort.SetSignals(KSignalDTEInputs,0);			// allow other side to send
+#ifdef _EMULATOR_HWFC
+	iPort.SetSignals(KSignalRTS,KSignalDTR);
+#endif
+
+	iReader = CActiveReader::NewL(aConsole, *this, iPort);
+	iWriter = CActiveWriter::NewL(aConsole, *this, iPort);
+	iInquiryTimer = CInquiryTimer::NewL(*this);
+
+	iActiveConsole = CActiveConsole::NewL(aConsole, *this);
+	iConnectionsConsole = AutoSizeNewL(_L("Emulated Connections"), TSize(60,20));
+
+	iPacketBuffer = HBufC8::NewL(KWriteBufSize);
+	iPacket.Set(iPacketBuffer->Des());
+
+	iInquiryAddresses.Copy(&KDeviceAddresses[0], KEmulatedInquiryNumberDevicesFound);
+	iInquiryNames.Copy(&KDeviceNames[0], KEmulatedInquiryNumberDevicesFound);
+	
+	iLocalName.Create(248);
+	iLocalName.Append(KDefaultLocalName);
+	}
+
+
+CConsoleBase* CHCEmulator::AutoSizeNewL(const TDesC& aTitle, TSize aSize)
+	{
+	// Try to create a console of our preferred size, otherwise we
+	// guess the screen is too small and use its entirety.
+	CConsoleBase* console = NULL;
+	TRAPD(err, console = Console::NewL(aTitle, aSize));
+	if (err != KErrNone)
+		{
+		// If we leave now it is not because of offscreen drawing.
+		console = Console::NewL(aTitle, TSize(KConsFullScreen, KConsFullScreen));
+		}
+	return console;
+	}
+
+
+void CHCEmulator::Start()
+	{
+	CActiveScheduler::Start();
+	}
+
+
+void CHCEmulator::Stop()
+	{
+	CActiveScheduler::Stop();
+	}
+
+
+void CHCEmulator::CommandStatusEvent(TUint16 aOpcode, TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.S.E (opcode 0x%04x, error 0x%02x)...\n"), aOpcode, aError);
+	BuildAndWriteCommandPacket(ECommandStatusEvent, aOpcode, aError);
+	}
+
+
+void CHCEmulator::InquiryStartEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Starting inquiry...")); //FIXME IAC
+
+	iCurrentInquiryResponse = 0;
+	iInquiryTimer->Start();
+	
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KInquiryOpcode, aError);
+	}
+
+
+void CHCEmulator::DefaultCommandCompleteEvent(TUint16 aOpcode, TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode 0x%04x, error 0x%02x)...\n"), aOpcode, aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, aOpcode, aError);
+	}
+
+
+void CHCEmulator::ReadBufferSizeCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadBufSize, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadBufferSizeOpcode, aError);
+	}
+
+
+void CHCEmulator::ReadBDAddrCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadBDAddr, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadBdaddrOpcode, aError);
+	}
+	
+
+void CHCEmulator::ReadLocalNameCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadLocalName, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadLocalNameOpcode, aError);
+	}
+
+
+void CHCEmulator::InquiryCompleteEvent(TUint8 aError)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending InquiryComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIInquiryCompleteEventCode);
+	PutBytes(KHCIInquiryCompleteEventLength);
+	PutBytes(aError);
+	
+	WritePacket();
+	}
+
+
+void CHCEmulator::InquiryResultEvent()
+	{
+	TInt resultsInPacket = Min(((iCurrentInquiryResponse % 5) + 1) , (KEmulatedInquiryNumberDevicesFound - iCurrentInquiryResponse));
+	
+	ClearPacket();
+
+	TInt error = KHCIOK;
+
+	iConsole.Printf(_L("Sending InquiryResult Event (error 0x%02x)...\n"), error);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIInquiryResultEventCode);
+	PutBytes(1 + (14 * resultsInPacket));
+	PutBytes(resultsInPacket);
+	
+	for (TInt i = 0; i < resultsInPacket; i++)
+		{
+		// stick them all in one event!
+		
+		PutAddress(iInquiryAddresses[iCurrentInquiryResponse + i]);
+		PutBytes(KEmulatedInquiryPageScanRepetionMode);
+		PutBytes(KEmulatedInquiryPageScanPeriodMode);
+		PutBytes(KEmulatedInquiryPageScanMode);
+		PutBytes(KEmulatedInquiryClassOfDevice,3);
+		PutBytes(KEmulatedInquiryClockOffset,2);
+		}
+
+	WritePacket();
+	
+	iCurrentInquiryResponse += resultsInPacket;
+	
+	// Wait for another result if we've not done them all, else complete inquiry
+	if(iCurrentInquiryResponse < KEmulatedInquiryNumberDevicesFound)
+		{
+		iInquiryTimer->Start();
+		}
+	else
+		{
+		InquiryCompleteEvent(KHCIOK);
+		}
+	}
+
+
+void CHCEmulator::ConnectionCompleteEvent(TUint8 aError, TLinkType /*aType*/)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending ConnectionComplete Event (error 0x%02x)...\n"), aError);
+
+	const TBTConnect& newConnection = iConnections[iConnections.Count()-1];
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIConnectionCompleteEventCode);
+	PutBytes(KHCIConnectionCompleteEventLength);
+
+	// test for what happens if we createconnection while inquiry is active
+	if (iInquiryTimer->IsActive())
+		PutBytes(KHCICommandDisallowed);
+	else
+		PutBytes(aError);
+
+	PutBytes(newConnection.iConnH,2);
+	PutAddress(newConnection.iBdaddr); // <-- test signaller by changing this address
+	PutBytes(newConnection.iLinkType);
+	PutBytes(newConnection.iEncryptMode);
+	
+	WritePacket();
+	}
+
+
+void CHCEmulator::InquiryCancelCompleteEvent(TUint8 aError)
+	{
+	iInquiryTimer->Cancel();
+
+	DefaultCommandCompleteEvent(KInquiryCancelOpcode, aError); 
+	}
+
+
+void CHCEmulator::ConnectionRequestEvent(const TBTDevAddr& aAddr, TUint aCoD, TLinkType aType)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending Connection Request event...\n"));
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIConnectionRequestEventCode);
+	PutBytes(KHCIConnectionRequestEventLength);
+	PutAddress(aAddr);
+	PutBytes(aCoD,3);
+	PutBytes(aType);
+	
+	WritePacket();
+	}
+
+
+void CHCEmulator::DisconnectionCompleteEvent(TUint8 aError, THCIConnHandle aConnH, TUint8 aReason)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending DisconnectComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIDisconnectionCompleteEventCode);
+	PutBytes(KHCIDisconnectionCompleteEventLength);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+	PutBytes(aReason);
+	
+	WritePacket();
+	}
+
+
+void CHCEmulator::WriteLinkPolicySettingsCompleteEvent(TUint8 aError, THCIConnHandle aConnH)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending WriteLinkPolicySettingsComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCICommandCompleteEventCode);
+	PutBytes(KHCIWriteLinkPolicySettingsCompleteLength);
+	PutBytes(1); //1 command token
+	PutBytes(KWriteLinkPolicySettingsOpcode,2);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+
+	WritePacket();	
+	}
+
+
+void CHCEmulator::ReadClockOffsetCompleteEvent(TUint8 aError, THCIConnHandle aConnH)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending ReadClockOffsetComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIReadClockOffsetCompleteEventCode);
+	PutBytes(KHCIReadClockOffsetCompleteLength);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+	PutBytes(KEmulatedClockOffset,2);
+
+	WritePacket();	
+	}
+
+
+void CHCEmulator::ConnectionPacketTypeChangedEvent(TUint8 aError, THCIConnHandle aConnH)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending ConnectionPacketTypeChanged Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIConnectionPacketTypeChangedCode);
+	PutBytes(KHCIConnectionPacketTypeChangedLength);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+	PutBytes(KEmulatedChangedPacketType,2);
+
+	WritePacket();	
+	}
+
+
+void CHCEmulator::ReadRemoteSupportedFeaturesCompleteEvent(TUint8 aError, THCIConnHandle aConnH)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending ReadRemoteSupportedFeaturesComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIReadRemoteSupportedFeaturesCode);
+	PutBytes(KHCIReadRemoteSupportedFeaturesLength);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+	PutBytes(KEmulatedRemoteSupportedFeatures1,4);
+	PutBytes(KEmulatedRemoteSupportedFeatures2,4);
+
+	WritePacket();	
+	}
+
+
+void CHCEmulator::ReadRemoteVersionInfoCompleteEvent(TUint8 aError, THCIConnHandle aConnH)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending ReadRemoteVersionInfoComplete Event (error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIReadRemoteVersionInfoCode);
+	PutBytes(KHCIReadRemoteVersionInfoLength);
+	PutBytes(aError);
+	PutBytes(aConnH, 2);
+	PutBytes(KEmulatedRemoteVersionInfo1,4);
+	PutBytes(KEmulatedRemoteVersionInfo2,1);
+
+	WritePacket();	
+	}
+
+	
+void CHCEmulator::ReadRemoteNameCompleteEvent(TUint8 aError, const TBTDevAddr& aAddr, const TDesC8& aName)
+	{
+	ClearPacket();
+	
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadRemoteName, error 0x%02x)...\n"), aError);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIRemoteNameRequestCompleteEventCode);
+	PutBytes(KHCIRemoteNameReqCompleteEventPacketLength);
+	PutBytes(aError);
+	PutAddress(aAddr);
+	PutName(aName);
+	
+	WritePacket();
+	}
+
+
+void CHCEmulator::ReadLocalSupportedFeaturesCompleteEvent(TUint8 aError)
+	{	
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadLocalSupportedFeatures, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadLocalSupportedFeaturesOpcode, aError);
+	}
+
+
+void CHCEmulator::ReadLocalVersionInfoCompleteEvent(TUint8 aError)
+	{	
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadLocalVersionInformation, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadLocalVersionInfoOpcode, aError);
+	}
+
+
+void CHCEmulator::WriteVoiceSettingCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode WriteVoiceSetting, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KWriteVoiceSettingOpcode, aError);	
+	}
+
+
+void CHCEmulator::WriteCurrentIACLAPCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode WriteVoiceSetting, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KWriteCurrentIACLAPOpcode, aError);	
+	}
+
+	
+void CHCEmulator::ReadClassOfDeviceCompleteEvent(TUint8 aError)
+	{
+	iConsole.Printf(_L("Sending C.C.E (opcode ReadClassOfDevice, error 0x%02x)...\n"), aError);
+	BuildAndWriteCommandPacket(ECommandCompleteEvent, KReadClassOfDeviceOpcode, aError);	
+	}
+
+
+void CHCEmulator::VendorSpecificDebugCompleteEvent(TUint16 aOpCode, const TDesC8& aRemainderBuf)
+	{
+	ClearPacket();
+	
+	//  Just send back the payload we got in Vendor Specific Command. This is used by
+	//  the tproxy HCIProxy test program, to be found in HCIProxy's directory.
+
+	const TUint KFixedParamSize = 3;
+	const TUint KMaxUserParamSize  = 255 - KFixedParamSize;
+	TUint userParamSize = (aRemainderBuf.Length() < KMaxUserParamSize) ?
+						   aRemainderBuf.Length() : KMaxUserParamSize;
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCICommandCompleteEventCode);
+	PutBytes(KFixedParamSize + userParamSize);
+	PutBytes(1);	// numPackets
+	PutBytes(aOpCode, 2);
+	for (int i = 0; i < userParamSize; i++)
+		PutBytes(aRemainderBuf[i]);
+
+	iConsole.Printf(_L("Sending C.C.E (opcode VendorSpecificDebug), user param size %d...\n"),
+					userParamSize);
+	WritePacket();
+	}
+
+
+void CHCEmulator::ACLDataReceived(const TDesC8& aConnHandleFlagsBuf, const TDesC8& aRemainderBuf)
+	{
+	// send it back!
+	// RFCOMM might need to tweak the data to allow SC n to connect to (say) SC (n+1)
+	BuildAndWriteDataPacket(aConnHandleFlagsBuf, aRemainderBuf);
+
+	// send ACL completed packets event
+
+	// test link manager by varying this (e.g. comment it out!)
+
+	THCIConnHandle connh;
+	GetConnHandle(connh, aConnHandleFlagsBuf.Ptr());
+
+//	NumberCompletedPacketsEvent(connh+0x0f00, 1, KHCIOK);	//invalid behvaiour
+	NumberCompletedPacketsEvent(connh, 1, KHCIOK);	//valid behvaiour
+	}
+
+
+void CHCEmulator::NumberCompletedPacketsEvent(/*const TDesC8& aConnHandleFlagsBuf*/THCIConnHandle aConnH, TUint8 aNumPackets, TUint8 aError)
+	{
+	ClearPacket();
+
+	iConsole.Printf(_L("Sending NumPacketsComplete Event (error 0x%02x)...\n"), aError);
+	
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCINumCompletedPacketsEventCode);
+	PutBytes(KHCINumCompletedPacketsEventLength);
+	PutBytes(0x01);				// FIXME we'll do one at a time for the moment
+	PutBytes(aConnH,2);
+//	iPacket.Append(aConnHandleFlagsBuf);
+	PutBytes(aNumPackets,2);				// FIXME we'll do one at a time for the moment
+	
+	WritePacket();
+	}
+
+	
+void CHCEmulator::HardwareErrorEvent()
+	{
+	ClearPacket();
+
+	TUint8 error = KHCIOK;
+
+	iConsole.Printf(_L("Sending HardwareError Event (error 0x%02x)...\n"), error);
+
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCIHardwareErrorEventCode);
+	PutBytes(KHCIHardwareErrorEventLength);	
+	PutBytes(error);
+
+	WritePacket();
+	}
+
+
+void CHCEmulator::SpecificVendorDebugEvent()
+	{
+	TInputManager manager(iConsole);
+	
+	iConsole.Printf(_L("Data length (0-99): "));
+	
+	TBuf8<255> str;
+	manager.ReadString(str);
+	TUint count;
+	
+	if (manager.String2Uint(str, count) != KErrNone)
+		{
+		iConsole.Printf(_L("Invalid data length\n"), count);
+		return;
+		}
+	
+	iConsole.Printf(_L("Fill in %d bytes\n"), count);
+	
+	TBuf8<255> data(count);
+	TUint value;
+	
+	for(TUint index=0;index<count;index++)
+		{
+		iConsole.Printf(_L("byte %d: 0x"), index);
+		// TUint value = manager.ReadInt(ETrue);
+		manager.ReadString(str);
+		if (manager.String2Uint(str, value, ETrue) != KErrNone)
+			{
+			iConsole.Printf(_L("Invalid byte value (must be hex)\n"), count);
+			return;
+			}
+		data[index] = value;
+		}
+	
+	ClearPacket();
+	PutBytes(KHCIUARTEventHeader);
+	PutBytes(KHCISpecificVendorDebugEvent);
+	PutBytes(count);
+	for(TUint index=0;index<count;index++)
+		{
+		PutBytes(data[index]);
+		}
+	
+	TRAPD(error,iWriter->WriteL(iPacket));
+
+	if (error)
+		iConsole.Printf(_L("ERROR - Write failed\n"));
+	}
+
+
+void CHCEmulator::BuildAndWriteDataPacket(const TDesC8& aConnHandleBuf /* THCIConnHandle aConnH*/, const TDesC8& aRemainderBuf)
+	{
+	ClearPacket();
+
+	PutBytes(KHCIUARTACLDataHeader);
+//	PutBytes(aConnH,2);
+
+	iPacket.Append(aConnHandleBuf);
+	PutBytes(aRemainderBuf.Length(), 2);
+	iPacket.Append(aRemainderBuf);
+
+	TRAPD(error,iWriter->WriteL(iPacket));
+
+	if (error)
+		iConsole.Printf(_L("ERROR - Write failed\n"));
+	}
+
+
+void CHCEmulator::BuildAndWriteCommandPacket(TPacketType aType, TUint16 aOpcode, TUint8 aError)
+/**
+	For 'easy' packets
+**/
+	{
+	iPacket.Zero();
+
+	TUint8 numpackets = 1;					// <--- adjustable
+
+	switch (aType)
+		{
+		case ECommandStatusEvent:
+			{
+			PutBytes(KHCIUARTEventHeader);
+			PutBytes(KHCICommandStatusEventCode);
+			PutBytes(KHCICommandStatusEventLength);
+			PutBytes(aError);
+			PutBytes(numpackets);
+			PutBytes(aOpcode,2);
+			break;
+			}
+		case ECommandCompleteEvent:
+			{
+			switch (aOpcode)
+				{
+				case KReadBufferSizeOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadBufferSizeCommandCompleteEventLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutBytes(KEmulatedHCSizeACLBuffers,2);
+					PutBytes(KEmulatedHCSizeSCOBuffers,1);
+					PutBytes(KEmulatedHCNumberACLBuffers,2);
+					PutBytes(KEmulatedHCNumberSCOBuffers,2);
+					break;
+					}
+				case KReadBdaddrOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadBdaddrCommandCompleteEventLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutAddress(KEmulatedHCAddress);
+					break;
+					}
+				case KReadLocalNameOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadLocalNameCommandCompleteEventLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutName(iLocalName);
+					break;
+					}
+				case KResetOpcode:
+				case KSetHostControllerToHostFlowOpcode:
+				case KWritePageTimeoutOpcode:
+				case KHostBufferSizeOpcode:
+				case KWriteScanEnableOpcode:
+				case KWriteConnectionAcceptTimeoutOpcode:
+				case KChangeLocalNameOpcode:
+				case KInquiryCancelOpcode:
+				case KWriteVoiceSettingOpcode:
+				case KWriteCurrentIACLAPOpcode:
+				case KSetEventMaskOpcode:
+				case KNopOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIDefaultCommandCompleteEventLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					}
+					break;
+					
+				case KReadLocalSupportedFeaturesOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadLocalSupportedFeaturesLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutBytes(KEmulatedLocalSupportedFeatures1,4);
+					PutBytes(KEmulatedLocalSupportedFeatures2,4);
+					}
+					break;
+					
+				case KReadLocalVersionInfoOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadLocalVersionInformationLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutBytes(KEmulatedLocalVersion1,4);
+					PutBytes(KEmulatedLocalVersion2,4);
+					}
+					break;
+					
+				case KReadClassOfDeviceOpcode:
+					{
+					PutBytes(KHCIUARTEventHeader);
+					PutBytes(KHCICommandCompleteEventCode);
+					PutBytes(KHCIReadCoDLength);
+					PutBytes(numpackets);
+					PutBytes(aOpcode,2);
+					PutBytes(aError);
+					PutBytes(KEmulatedCoD,3);	
+					}
+					break;
+					
+				}
+			break;
+			}
+		}
+	WritePacket();
+	}
+
+
+void CHCEmulator::ClearPacket()
+	{
+	iPacket.Zero();
+	}
+
+
+void CHCEmulator::WritePacket()
+	{
+	TRAPD(error, iWriter->WriteL(iPacket));
+	if (error)
+		iConsole.Printf(_L("ERROR - Write failed\n"));
+	}
+
+
+void CHCEmulator::CommandReceived(const TDesC8& aOpcodeBuf, const TDesC8& aRemainderBuf)
+	{
+	iParsePtr = 0;
+	Decode(aOpcodeBuf, aRemainderBuf);
+	}
+
+
+void CHCEmulator::ResetEmulator()
+	{
+	iConnections.Reset();
+	}
+
+
+TBool CHCEmulator::Decode(const TDesC8& aOpcodeBuf, const TDesC8& aRemainderBuf)
+	{
+	TUint16 opcode = static_cast<TUint16>((aOpcodeBuf[1] << 8) + aOpcodeBuf[0]);
+
+	TBuf<60> command;
+	
+	// Separate if to catch all Vendor Specific opcodes.
+	if ((opcode & KOGFMask) == KVendorDebugOGF)
+		{
+		command = _L("VendorSpecificDebug");
+		const TUint16 KOCFMask = KMaxTUint16 & ~KOGFMask;
+		if((opcode &  KOCFMask) != 0) //OCF = 0 is used by tproxy to indicate that we do not want a reply
+			{
+			VendorSpecificDebugCompleteEvent(opcode, aRemainderBuf);
+			}
+		else
+			{
+			DefaultCommandCompleteEvent(KNopOpcode, KHCIOK);
+			}
+		}
+	else
+		{
+		switch (opcode)
+			{
+			case KResetOpcode:
+				command = _L("Reset");
+	
+				ResetEmulator();
+	
+				DefaultCommandCompleteEvent(KResetOpcode, KHCIOK);
+				CommandStatusEvent(KNoOpcode, KHCIOK);	// for CSR
+				break;
+			case KSetHostControllerToHostFlowOpcode:
+				command = _L("SetHostControllerToHostFlow");
+				DefaultCommandCompleteEvent(KSetHostControllerToHostFlowOpcode, KHCIOK);
+				break;
+			case KWritePageTimeoutOpcode:
+				command = _L("WritePageTimeout");
+				DefaultCommandCompleteEvent(KWritePageTimeoutOpcode, KHCIOK);
+				break;
+			case KHostBufferSizeOpcode:
+				command = _L("HostBufferSize");
+				DefaultCommandCompleteEvent(KHostBufferSizeOpcode, KHCIOK);
+				break;
+			case KWriteScanEnableOpcode:
+				command = _L("WriteScanEnable");
+				DefaultCommandCompleteEvent(KWriteScanEnableOpcode, KHCIOK);
+				break;
+			case KWriteConnectionAcceptTimeoutOpcode:
+				command = _L("WriteConnectionAcceptTimeout");
+				DefaultCommandCompleteEvent(KWriteConnectionAcceptTimeoutOpcode, KHCIOK);
+				break;
+			case KChangeLocalNameOpcode:
+				command = _L("ChangeLocalName");
+				iLocalName.SetLength(248);
+				iLocalName.Replace(0, aRemainderBuf.Length(), aRemainderBuf);
+				DefaultCommandCompleteEvent(KChangeLocalNameOpcode, KHCIOK);
+				break;
+			case KReadBdaddrOpcode:
+				command = _L("ReadBDAddr");
+				ReadBDAddrCompleteEvent(KHCIOK);
+				break;
+			case KReadLocalNameOpcode:
+				command = _L("ReadLocalName");
+				ReadLocalNameCompleteEvent(KHCIOK);
+				break;
+			case KReadBufferSizeOpcode:
+				command = _L("ReadBufferSize");
+				ReadBufferSizeCompleteEvent(KHCIOK);
+				break;
+			case KCreateACLConnectionOpcode:
+				{
+				// decode this and store in emulated connections
+				command = _L("CreateConnection");
+				CommandStatusEvent(KCreateACLConnectionOpcode, KHCIOK);
+	
+				TBTDevAddr remoteaddr;
+				GetBigEndianDevAddr(remoteaddr, aRemainderBuf.Ptr());
+	#ifdef _CONNECT_TYPE_1
+				ConnectionRequestEvent(remoteaddr, KEmulatedInquiryClassOfDevice, EACLLink);
+	#else
+				TBTConnect newConnection;
+				
+				//GetBigEndianDevAddr(newConnection.iBdaddr, aRemainderBuf.Ptr());
+	
+				newConnection.iBdaddr=remoteaddr;
+				newConnection.iLinkType=EACLLink;
+				newConnection.iEncryptMode=KEmulatedEncryptMode;
+				newConnection.iConnH = static_cast<TUint16>(KEmulatedBaseConnectionHandle + iConnections.Count());
+	
+				//update connection model - stick in separate class that wraps RArray/Console
+				iConnections.Append(newConnection);
+				TBuf<30> readableaddr;
+				newConnection.iBdaddr.GetReadable(readableaddr);
+				iConnectionsConsole->Printf(_L("Connection added: Handle 0x%04x, Remote address %S, Type ACL\n"), newConnection.iConnH, &readableaddr);
+	
+				ConnectionCompleteEvent(KHCIOK, EACLLink);
+	#endif
+				// CommandStatusEvent(KCreateACLConnectionOpcode, KHCICommandDisallowed); 
+				}
+				break;
+	
+			case KAcceptConnectionRequestOpcode:
+				{
+				TBTConnect newConnection;
+				
+				//GetBigEndianDevAddr(newConnection.iBdaddr, aRemainderBuf.Ptr());
+	
+				newConnection.iLinkType=EACLLink;
+				newConnection.iEncryptMode=KEmulatedEncryptMode;
+				newConnection.iConnH = static_cast<TUint16>(KEmulatedBaseConnectionHandle + iConnections.Count());
+	
+				//update connection model - stick in separate class that wraps RArray/Console
+				iConnections.Append(newConnection);
+				TBuf<30> readableaddr;
+				newConnection.iBdaddr.GetReadable(readableaddr);
+				iConnectionsConsole->Printf(_L("Connection added: Handle 0x%04x, Remote address %S, Type ACL\n"), newConnection.iConnH, &readableaddr);
+	
+	#ifdef DISCONNECT_ON_ACCEPT
+				//This was first used for reproducing DEF074193 
+				//we need to send a disconnect to a SCO socket
+				//that is in state TSCOLinkStateAccepting.
+				DisconnectionCompleteEvent(KHCIOK, 1, KHCINoConnection);
+	#else
+				ConnectionCompleteEvent(KHCIOK, EACLLink);
+	#endif
+				}
+				break;
+	
+			case KDisconnectOpcode:
+				{
+				command = _L("Disconnect");
+				CommandStatusEvent(KDisconnectOpcode, KHCIOK);
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+				
+				TUint8 reason;
+				GetByte(reason, aRemainderBuf.Ptr()+2); //+2 or else first byte of connection handle will be read
+	
+				TInt index = FindConnection(connh);
+				if (index!=KErrNotFound)
+					{
+					iConnections.Remove(index);				// delete from emulator's connections
+					iConnectionsConsole->Printf(_L("Connection removed: Handle 0x%04x\n"), connh);
+					DisconnectionCompleteEvent(KHCIOK, connh, reason);
+					}
+				else
+					DisconnectionCompleteEvent(KHCIOK, connh, KHCINoConnection);
+	
+	
+				}
+				break;
+	
+			case KInquiryOpcode:
+				command = _L("Inquiry");
+				CommandStatusEvent(KInquiryOpcode, KHCIOK);
+				InquiryStartEvent(KHCIOK);
+				break;
+	
+			case KInquiryCancelOpcode:
+				command = _L("InquiryCancel");
+				InquiryCancelCompleteEvent(KHCIOK);
+				break;
+				
+			case KRemoteNameRequestOpcode:
+				{
+				command = _L("RemoteNameRequest");
+				CommandStatusEvent(KRemoteNameRequestOpcode, KHCIOK);
+				
+				TBTDevAddr remoteAddr;
+				GetBigEndianDevAddr(remoteAddr, aRemainderBuf.Ptr());
+				
+				TPtrC8 namePtr;
+				TInt err = GetRemoteName(remoteAddr, namePtr);
+				
+				ReadRemoteNameCompleteEvent(err, remoteAddr, namePtr);
+				break;
+				}
+	
+			case KReadLocalSupportedFeaturesOpcode:
+				{
+				command = _L("ReadLocalSupportedFeatures");			
+				ReadLocalSupportedFeaturesCompleteEvent(KHCIOK);
+				break;
+				}
+				
+			case KReadLocalVersionInfoOpcode:
+				{
+				command = _L("ReadLocalVersionInformation");
+				ReadLocalVersionInfoCompleteEvent(KHCIOK);
+				break;		
+				}
+				
+			case KWriteVoiceSettingOpcode:
+				{
+				command = _L("WriteVoiceSetting");	
+				WriteVoiceSettingCompleteEvent(KHCIOK);
+				break;
+				}
+			
+			case KWriteCurrentIACLAPOpcode:
+				{
+				command = _L("WriteCurrentIACLAP");	
+				WriteCurrentIACLAPCompleteEvent(KHCIOK);
+				break;	
+				}
+				
+			case KReadClassOfDeviceOpcode:
+				{
+				command = _L("ReadClassOfDevice");	
+				ReadClassOfDeviceCompleteEvent(KHCIOK);
+				break;	
+				}
+		
+			case KWriteLinkPolicySettingsOpcode:
+				{
+				command = _L("WriteLinkPolicySettings");
+				CommandStatusEvent(KWriteLinkPolicySettingsOpcode, KHCIOK);
+				
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+	
+				WriteLinkPolicySettingsCompleteEvent(KHCIOK, connh);
+				}
+				break;
+				
+			case KReadClockOffsetOpcode:
+				{
+				command = _L("ReadClockOffset");
+				CommandStatusEvent(KReadClockOffsetOpcode, KHCIOK);
+						
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+	
+				ReadClockOffsetCompleteEvent(KHCIOK, connh);		
+				}
+				break;
+			
+			case KReadRemoteSupportedFeaturesOpcode:
+				{
+				command = _L("ReadRemoteSupportedFeatures");
+				CommandStatusEvent(KReadRemoteSupportedFeaturesOpcode, KHCIOK);
+						
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+	
+				ReadRemoteSupportedFeaturesCompleteEvent(KHCIOK, connh);	
+				}
+				break;
+			
+			case KReadRemoteVersionInfoOpcode:
+				{
+				command = _L("ReadRemoteVersionInfo");
+				CommandStatusEvent(KReadRemoteVersionInfoOpcode, KHCIOK);
+						
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+	
+				ReadRemoteVersionInfoCompleteEvent(KHCIOK, connh);				
+				}
+				break;
+			
+			case KChangeConnectionPacketTypeOpcode:
+				{
+				command = _L("ChangeConnectPacketType");
+				CommandStatusEvent(KChangeConnectionPacketTypeOpcode, KHCIOK);
+						
+				THCIConnHandle connh;
+				GetConnHandle(connh, aRemainderBuf.Ptr());
+	
+				ConnectionPacketTypeChangedEvent(KHCIOK, connh);		
+				}
+				break;
+			case KNopOpcode:
+				{
+				command = _L("NoOperationOpcode");
+				DefaultCommandCompleteEvent(KNopOpcode, KHCIOK);
+				}
+				break;
+			case KSetEventMaskOpcode:
+				{
+				command = _L("SetEventMaskOpcode");
+				DefaultCommandCompleteEvent(KSetEventMaskOpcode, KHCIOK);
+				}
+				break;
+			default:
+				command = _L("Unknown");
+				break;
+			} // switch
+		} // opcode OGF is not Vendor Debug
+	iConsole.Printf(_L("%S command received - opcode 0x%x\n"), &command, opcode); //FIXME
+
+	return ETrue;
+	}
+
+
+TInt CHCEmulator::GetRemoteName(const TBTDevAddr& aAddr, TPtrC8& aName) const
+	{
+	TInt index = 0;
+	while(index < iInquiryAddresses.Count())
+		{
+		if (iInquiryAddresses[index] == aAddr)
+			{
+			aName.Set(iInquiryNames[index]);
+			return KHCIOK;
+			}
+		index++;
+		}
+		
+	aName.Set(KNullDesC8);
+	return KHCIPageTimeout;
+	}
+
+
+TInt CHCEmulator::FindConnection(THCIConnHandle aConnH)
+	{
+	TInt index = 0;
+	while (index<iConnections.Count())
+		{
+		if (iConnections[index].iConnH == aConnH)
+			return index;
+		else
+			++index;
+		}
+	return KErrNotFound;
+	}
+
+
+void CHCEmulator::PutBytes(TUint aNum, TUint8 aNumOfBytes)
+	{
+	TInt length = iPacket.Length();
+	iPacket.SetLength(length+aNumOfBytes);
+
+    switch (aNumOfBytes)
+        {
+		// deliberate fallthroughs...
+    case 4:
+        iPacket[length+3]=TUint8(aNum>>24);
+    case 3:
+        iPacket[length+2]=TUint8(aNum>>16 & 0xff);
+    case 2:
+		iPacket[length+1]=TUint8(aNum>>8 & 0xff);
+    case 1:
+        iPacket[length]=TUint8(aNum & 0xff);
+        break;
+		}
+	}
+
+
+void CHCEmulator::PutAddress(const TBTDevAddr& aAddress)
+	{
+	TInt currentLength = iPacket.Length();
+	
+	iPacket.SetLength(currentLength + KBTMaxDevAddrSize);
+
+    for (TInt i=0;i<KBTMaxDevAddrSize;i++)
+		{
+        iPacket[currentLength+i]=aAddress[KBTMaxDevAddrSize-1-i];  // little endian-ify
+		}
+	}
+
+
+void CHCEmulator::PutName(const TDesC8& aName)
+	{
+	// The length of a name parameter is 248.  Any bytes not used by
+	// the name should be set to zero.
+	TInt padding = 248 - aName.Length();
+	
+	iPacket.Append(aName);
+	
+	while(padding--)
+		{
+		iPacket.Append(0x0);
+		}
+	}
+
+
+//FIXME make static
+
+void CHCEmulator::GetBigEndianDevAddr(TBTDevAddr& aAddress, const TUint8* aPacket)
+// big endian get of dev addr
+    {
+    TUint8* ptr=const_cast<TUint8*>(aPacket);
+
+    for (TInt i=0; i<KBTMaxDevAddrSize; i++)
+        aAddress[KBTMaxDevAddrSize-1-i]=*ptr++;  // reading bdaddr from iEventBufPtr
+    
+	iParsePtr+=6;
+	}
+
+
+void CHCEmulator::GetByte(TUint8& aByte, const TUint8* aPacket)
+	{
+//	aByte = const_cast<TUint8>(aPacket[iParsePtr++]);
+	aByte = aPacket[iParsePtr++];
+	}
+
+
+void CHCEmulator::GetConnHandle(THCIConnHandle& aConnH, const TUint8* aPacket)
+	{
+	// ignore the ACL flags
+    aConnH = TUint16(((aPacket[1]&~KPacketDataFlagMask)<<8) | aPacket[0]);
+//	iParsePtr+=2;
+	}
+
+
+// -------------------------------------------
+
+CInquiryTimer* CInquiryTimer::NewL(CHCEmulator& aEmulator)
+	{
+	CInquiryTimer* t = new (ELeave) CInquiryTimer(aEmulator);
+	CleanupStack::PushL(t);
+	t->ConstructL();
+	CleanupStack::Pop(t);
+	return t;
+	}
+
+
+CInquiryTimer::CInquiryTimer(CHCEmulator& aEmulator) : CTimer(EPriorityStandard), iEmulator(aEmulator)
+	{
+	}
+
+
+void CInquiryTimer::Start()
+	{
+	After(KEmulatedInterDeviceInquiryTime.Int() * 1000000);
+	}
+
+
+void CInquiryTimer::ConstructL()
+	{
+	CTimer::ConstructL();
+	CActiveScheduler::Add(this);
+	}
+
+
+void CInquiryTimer::RunL()
+	{
+	iEmulator.InquiryResultEvent();
+	}
+
+
+// -------------------------------------------
+
+CActiveReader* CActiveReader::NewL(CConsoleBase& aConsole, CHCEmulator& aEmulator, RComm& aPort)
+	{
+	CActiveReader* r = new (ELeave) CActiveReader(aConsole, aEmulator, aPort);
+	CleanupStack::PushL(r);
+	r->ConstructL();
+	CleanupStack::Pop(r);
+	return r;
+	}
+
+
+CActiveReader::CActiveReader(CConsoleBase& aConsole, CHCEmulator& aEmulator, RComm& aPort)
+: CActive(EPriorityHigh), iConsole(aConsole), iEmulator(aEmulator),
+  iPort(aPort), iAuto(ETrue), iReadState(EReadHeader)
+	{
+	}
+
+
+CActiveReader::~CActiveReader()
+	{
+	Cancel();
+	delete iReaderOutputConsole;
+	}
+
+
+void CActiveReader::ConstructL()
+	{
+	User::LeaveIfNull(iReaderOutputConsole = CHCEmulator::AutoSizeNewL(_L("Input"), TSize(60,20)));
+
+	CActiveScheduler::Add(this);
+	
+	// start reading
+	DoRead();
+	}
+
+
+void CActiveReader::DoRead()
+	{
+#ifdef _EMULATOR_HWFC
+	iPort.SetSignals(KSignalRTS,KSignalDTR);		//FIXME
+#endif
+	switch (iReadState)
+		{
+		case EReadHeader:
+			iPort.Read(iStatus,iHeaderBuf, 1);
+			break;
+
+		case EReadOpcode:
+			iPort.Read(iStatus,iOpcodeBuf, 2);
+			break;
+
+		case EReadCommandLength:
+			iPort.Read(iStatus,iCommandLengthBuf, 1);
+			break;
+
+		case EReadDataLength:
+			iPort.Read(iStatus,iDataLengthBuf, 2);
+			break;
+
+		case EReadConnectionHandleFlags:
+			iPort.Read(iStatus,iConnectionHandleFlagsBuf, 2);
+			break;
+
+		case EReadCommandRemainder:
+			{
+			const TInt len = iCommandLengthBuf[0];
+			iPort.Read(iStatus,iRemainderBuf, len);
+			}
+			break;
+
+		case EReadDataRemainder:
+			{
+			const TUint16 len = static_cast<TUint16>((iDataLengthBuf[1] << 8) + iDataLengthBuf[0]);
+			iPort.Read(iStatus,iRemainderBuf, len);
+			}
+			break;
+
+		default:
+			__DEBUGGER();
+		}
+
+
+	SetActive();
+	}
+
+
+void CActiveReader::RunL()
+	{
+	// the read has completed - for the moment we are not really interested at the moment
+
+	if (iAuto)
+		{
+		switch (iReadState)
+			{
+			case EReadHeader:
+				iReaderOutputConsole->Printf(_L("Header byte recvd\n"));
+				iReadState = (DecodeHeader() == KHCIUARTCommandHeader ? EReadOpcode : EReadConnectionHandleFlags);
+				break;
+			case EReadOpcode:
+				{
+				iReaderOutputConsole->Printf(_L("Opcode bytes recvd\n"));
+				TInt opcode = DecodeOpcode();
+				if (opcode == 0)
+					//NoOpCommand has no more parameters
+					{
+					iReadComplete = ETrue;
+					iReadState = EReadHeader; // start again
+					}
+				else
+					{
+					iReadState = EReadCommandLength;
+					}
+				}
+				break;
+			case EReadCommandLength:
+				iReaderOutputConsole->Printf(_L("Length byte recvd\n"));
+				iReadState = EReadCommandRemainder;
+				break;
+			case EReadDataLength:
+				iReaderOutputConsole->Printf(_L("Length byte recvd\n"));
+				iReadState = EReadDataRemainder;
+				break;
+			case EReadConnectionHandleFlags:
+				iReaderOutputConsole->Printf(_L("ConnectionHandle bytes recvd\n"));
+				iReadState = EReadDataLength;
+				break;
+			case EReadCommandRemainder:
+			case EReadDataRemainder:
+				iReaderOutputConsole->Printf(_L("Remainder bytes recvd\n"));
+				iReadComplete = ETrue;
+				iReadState = EReadHeader; // start again
+				break;
+
+			default:
+				__DEBUGGER();
+			}
+		
+		if (iReadComplete)
+			{
+			iReaderOutputConsole->Printf(_L("Decoding...\n"));
+
+			if (DecodeHeader() == KHCIUARTCommandHeader)
+				{
+				iReaderOutputConsole->Printf(_L("Decode: Command\n"));
+				iEmulator.CommandReceived(iOpcodeBuf, iRemainderBuf);
+				}
+			else
+				{
+				iReaderOutputConsole->Printf(_L("Decode: ACL Data\n"));
+				iEmulator.ACLDataReceived(iConnectionHandleFlagsBuf, iRemainderBuf);
+				}
+			iReadComplete = EFalse;
+			}
+				
+
+		}
+
+	// queue another one
+	DoRead();
+	}
+
+
+TInt CActiveReader::DecodeHeader()
+	{
+	TUint8 header = iHeaderBuf[0];
+	return header;
+	}
+
+
+TInt CActiveReader::DecodeOpcode()
+	{
+	TUint16 opcode = static_cast<TUint16>((iOpcodeBuf[1] << 8) + iOpcodeBuf[0]);
+	return opcode;
+	}
+
+
+void CActiveReader::DoCancel()
+	{
+	iPort.ReadCancel();
+	}
+
+
+// -------------------------------------------
+
+CActiveWriter* CActiveWriter::NewL(CConsoleBase& aConsole, CHCEmulator& aEmulator, RComm& aPort)
+	{
+	CActiveWriter* w = new (ELeave) CActiveWriter(aConsole, aEmulator, aPort);
+	CleanupStack::PushL(w);
+	w->ConstructL();
+	CleanupStack::Pop(w);
+	return w;
+	}
+
+
+CActiveWriter::CActiveWriter(CConsoleBase& aConsole, CHCEmulator& aEmulator, RComm& aPort)
+: CActive(EPriorityStandard), iConsole(aConsole), iEmulator(aEmulator), iPort(aPort)
+	{
+	}
+
+
+CActiveWriter::~CActiveWriter()
+	{
+	Cancel();
+
+	iWriteBuffers.ResetAndDestroy();
+	iWriteBuffers.Close();
+	}
+
+
+void CActiveWriter::ConstructL()
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+void CActiveWriter::DoWrite()
+	{
+	TPtr8 currentbuffer = (iWriteBuffers[0])->Des();
+
+	iPort.Write(iStatus,currentbuffer);
+	SetActive();
+
+	// let other side try to send - this handshaking is a pain!
+#ifdef _EMULATOR_HWFC
+	iPort.SetSignals(KSignalCTS,KSignalDSR);		//FIXME
+#endif
+	}
+
+
+void CActiveWriter::WriteL(const TDesC8& aPacket)
+	{
+	HBufC8* newbuf = HBufC8::NewL(KWriteBufSize);
+	newbuf->Des() = aPacket;
+	iWriteBuffers.Append(newbuf);
+	if (IsActive())
+		return; //try again later
+
+	DoWrite();
+	}
+
+
+void CActiveWriter::RunL()
+	{
+	TPtr8 currentbuffer = (iWriteBuffers[0])->Des();
+
+	iConsole.Printf(_L("Write of %d bytes (including header) returned result %d.\n"), currentbuffer.Length(), iStatus.Int());
+	
+	// the write has completed - clear up the buffer
+	delete iWriteBuffers[0];
+	iWriteBuffers.Remove(0);
+
+	if (iWriteBuffers.Count())
+		// more to send
+		DoWrite();
+	}
+
+
+void CActiveWriter::DoCancel()
+	{
+	iPort.WriteCancel();
+	}
+
+
+
+// ----------------------------------------------------------------------------
+//							Active Console
+// ----------------------------------------------------------------------------
+
+
+CActiveConsole::CActiveConsole(CConsoleBase& aConsole, CHCEmulator& aEmulator)
+: CActive(EPriorityStandard), iConsole(aConsole), iEmulator(aEmulator)
+	{
+	}
+
+
+CActiveConsole::~CActiveConsole()
+	{
+	// must cancel
+	Cancel();
+	}
+
+
+CActiveConsole* CActiveConsole::NewL(CConsoleBase& aConsole, CHCEmulator& aEmulator)
+	{
+	CActiveConsole* console = new (ELeave) CActiveConsole(aConsole, aEmulator);
+	CleanupStack::PushL(console);
+	console->ConstructL();
+	CleanupStack::Pop();
+	return console;
+	}
+
+
+void CActiveConsole::ConstructL()
+	{
+	CActiveScheduler::Add(this);
+	TestMenu();
+	}
+
+
+void CActiveConsole::DoCancel()
+	{
+	iConsole.ReadCancel();
+	}
+
+
+void CActiveConsole::RequestKey()
+	{
+	DrawCursor();
+	iConsole.Read(iStatus);
+	SetActive();
+	}
+
+
+void CActiveConsole::DrawCursor()
+	{
+	iConsole.Printf(_L(">>"));
+	}
+
+
+void CActiveConsole::TestMenu()
+	{
+	iConsole.Printf(_L("Choose action...\n\n"));
+	iConsole.Printf(_L("s.\t\tCommand status event (connect, error)\n"));
+	iConsole.Printf(_L("n.\t\tCommand Status event (NOP, no error) - CSR-reset\n"));
+	iConsole.Printf(_L("p.\t\tWritePageTimeout complete vent (no error)\n"));
+	iConsole.Printf(_L("r.\t\tReset Complete event (no error)\n"));
+	iConsole.Printf(_L("b.\t\tReadBufferSize Complete event (no error)\n"));
+	iConsole.Printf(_L("B.\t\tHostBufferSize Complete event (no error)\n"));
+	iConsole.Printf(_L("a.\t\tReadBdAddr Complete event (no error)\n"));
+	iConsole.Printf(_L("A.\t\tReadLocalName Complete event (no error)\n"));
+	iConsole.Printf(_L("e.\t\tWriteScanEnable Complete event (no error)\n"));
+	iConsole.Printf(_L("c.\t\tWriteConnectionAcceptTimeout complete event (no error)\n"));
+	iConsole.Printf(_L("h.\t\tHostToHostControllerFC Complete Event (no error)\n"));
+	iConsole.Printf(_L("l.\t\tSetLocalName Complete Event (no error)\n"));
+	iConsole.Printf(_L("i.\t\tStartInquiry Complete Event (no error)\n"));
+	iConsole.Printf(_L("I.\t\tInquiryComplete Event (no error)\n"));
+	iConsole.Printf(_L("@.\t\tInquiryResultComplete Event (no error)\n"));
+	iConsole.Printf(_L("C.\t\tConnectionCompleteEvent (no error)\n"));
+	iConsole.Printf(_L("d.\t\tDisconnectionCompleteEvent (no error)\n"));
+	iConsole.Printf(_L("k.\t\tConnectionRequestEvent (no error)\n"));
+	iConsole.Printf(_L("K.\t\tConnectionRequestEvent (NULL CoD, no error)\n"));
+	iConsole.Printf(_L("X.\t\tHardware Error Event (error 0)\n"));
+	iConsole.Printf(_L("V.\t\tVendor Specific Debug Event\n"));
+	iConsole.Printf(_L("Esc.\tStop\n"));
+	RequestKey();
+	}
+
+
+void CActiveConsole::RunL()
+	{
+	// key has been pressed
+	TChar ch = iConsole.KeyCode();
+
+	TUint8 error = KHCIOK;
+	TUint16 opcode;
+
+	TBTDevAddr remoteaddr(MAKE_TINT64(0x0002, 0x5bff0a1e)); // an example addr
+	TBTDevAddr remoteaddr2(MAKE_TINT64(0x0002, 0x5bff0a1e)); // an example addr
+
+	// Change the errors for interesting tests of stack behaviour
+
+	switch (ch)
+		{
+	case 's':
+		error = KHCICommandDisallowed;
+		opcode = KCreateACLConnectionOpcode;
+		iEmulator.CommandStatusEvent(opcode, error);
+		break;
+
+	case 'n':									
+		opcode = KNoOpcode;
+		iEmulator.CommandStatusEvent(opcode, error);
+		break;
+
+	case 'a':
+		opcode = KReadBdaddrOpcode;
+		iEmulator.ReadBDAddrCompleteEvent(error);
+		break;
+		
+	case 'A':
+		opcode = KReadLocalNameOpcode;
+		iEmulator.ReadLocalNameCompleteEvent(error);
+		break;
+
+	case 'b':
+		opcode = KReadBufferSizeOpcode;
+		iEmulator.ReadBufferSizeCompleteEvent(error);
+		break;
+
+	case 'B':
+		opcode = KHostBufferSizeOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'p':
+		opcode = KWritePageTimeoutOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'e':
+		opcode = KWriteScanEnableOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'h':
+		opcode = KSetHostControllerToHostFlowOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'c':
+		opcode = KWriteConnectionAcceptTimeoutOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'r':
+		opcode = KResetOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'l':
+		opcode = KChangeLocalNameOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'i':
+		opcode = KInquiryOpcode;
+		iEmulator.DefaultCommandCompleteEvent(opcode, error);
+		break;
+
+	case 'I':
+		iEmulator.InquiryCompleteEvent(error);
+		break;
+
+	case 'C':
+		iEmulator.ConnectionCompleteEvent(error, EACLLink);
+		break;
+
+	case 'd':
+		iEmulator.DisconnectionCompleteEvent(error, KEmulatedBaseConnectionHandle, KHCIEmulatedDisconnectionReason);
+		break;
+	case 'k':
+		iEmulator.ConnectionRequestEvent(remoteaddr, KEmulatedInquiryClassOfDevice, EACLLink);
+		break;
+
+	case 'K':
+		iEmulator.ConnectionRequestEvent(remoteaddr2, KEmulatedInquiryNullClassOfDevice, EACLLink);
+		break;		
+	
+	case 'x':
+	case 'X':
+		iEmulator.HardwareErrorEvent();
+		break;
+
+	case 'V':
+	case 'v':
+		iEmulator.SpecificVendorDebugEvent();
+		break;
+	case '1':
+		//First used for reproducing DEF074193
+		//Sends a SCO connection request. A DisconnectComplete event will 
+		//be sent in response to the resulting 
+		//HCI_Accept_Connection_Request command.
+		iEmulator.ConnectionRequestEvent(KDeviceAddresses[0], KEmulatedInquiryNullClassOfDevice, ESCOLink);
+		break;		
+		
+	case EKeyEscape:
+		{
+		iEmulator.Stop();
+		goto end;
+		}
+
+
+	default:
+		iConsole.Printf(_L("Unknown command\r\n"));
+		}
+
+	// schedule another key press
+	RequestKey();
+
+end:
+	return;
+	}
+
+
+// -----------------------------------------------
+
+TInputManager::TInputManager(CConsoleBase& aConsole) : 
+	iConsole(aConsole)
+	{
+	}
+
+
+void TInputManager::ConsoleBackspace(TUint aNumberOfChars)
+	{
+	TPoint cur = iConsole.CursorPos();
+	cur.iX -= aNumberOfChars;
+	iConsole.SetCursorPosAbs(cur);
+	iConsole.ClearToEndOfLine();
+	}
+
+
+TUint TInputManager::ReadString(TDes8& aStr)
+	{
+	TKeyCode key;
+	
+	aStr.Zero();
+	
+	while( (key = iConsole.Getch()) != EKeyEnter)
+		{
+		if (aStr.Length() == aStr.MaxLength())
+			return aStr.MaxLength();
+		
+		if (key == EKeyBackspace)
+			{
+			if (aStr.Length() > 0)
+				{
+				aStr.Delete(aStr.Length()-1, 1);
+				ConsoleBackspace(1);
+				}
+			}
+		else
+			{
+			TUint8 keyChar(key);
+			aStr.Append(keyChar);
+			iConsole.Printf(_L("%c"), keyChar);
+			}
+		}
+	iConsole.Printf(_L("\n"));
+	return aStr.Length();
+	}
+
+
+TUint TInputManager::GetCipher(TChar aChar)
+	{
+	TUint value;
+	switch(aChar)
+		{
+		case 'a': value = 10; break;
+		case 'b': value = 11; break;
+		case 'c': value = 12; break;
+		case 'd': value = 13; break;
+		case 'e': value = 14; break;
+		case 'f': value = 15; break;
+		default: value = aChar.GetNumericValue(); 
+		}
+	return value;
+	}
+
+
+TInt TInputManager::String2Uint(TDes8& aStr, TUint& aResult, TBool aHex)
+	{
+		TInt result = 0;
+		for(TUint index=0;index<aStr.Length();index++)
+			{
+			TChar keyChar(aStr[index]);
+			TBool isDigit = (aHex ? keyChar.IsHexDigit() : keyChar.IsDigit());
+			if (!isDigit)
+				return KErrArgument;
+			TUint mult = aHex ? 16 : 10;
+			result = result * mult + GetCipher(keyChar);
+			}
+		aResult = result;
+		return KErrNone;
+	}
+
+
+// -----------------------------------------------
+
+void StartL()
+	{
+	CHCEmulator* emulator= CHCEmulator::NewL(*test.Console());
+
+	emulator->Start();
+
+	delete emulator;
+	//finished
+	}
+
+
+void LoadLDD_PDD()
+	{
+	TInt r;
+	r=StartC32();
+	if (r!=KErrNone && r!=KErrAlreadyExists)
+		{
+		test.Printf(_L("Failed %d!\n\r"),r);
+		test(r==KErrNone);
+		}
+	else
+		test.Printf(_L("Started C32\n"));
+	test.Printf(_L("Loading PDD\n"));
+	r=User::LoadPhysicalDevice(PDD_NAME);
+	if (r!=KErrNone && r!=KErrAlreadyExists)
+		{
+		test.Printf(_L("Failed %d!\n\r"),r);
+		test(r==KErrNone);
+		}
+	else 
+		test.Printf(_L("Loaded LDD\n"));
+	test.Printf(_L("Loading LDD\n"));
+	r=User::LoadLogicalDevice(LDD_NAME);
+	if (r!=KErrNone && r!=KErrAlreadyExists)
+		{
+		test.Printf(_L("Failed %d!\n\r"),r);
+		test(r==KErrNone);
+		}
+	else
+		test.Printf(_L("Loaded PDD\n"));
+	}
+
+
+TInt E32Main()
+	{
+	test.SetLogged(EFalse);
+	test.Title();
+
+// For some reason, you have to do the following to
+// ensure that the file server behaves properly.
+	RFs fs;
+	fs.Connect();
+	fs.Close();
+
+	LoadLDD_PDD();
+
+	__UHEAP_MARK;
+	CTrapCleanup* cleanupStack=CTrapCleanup::New();	// Get CleanupStack
+
+	CActiveScheduler* activescheduler=new CActiveScheduler;
+	CActiveScheduler::Install(activescheduler);
+
+	TRAPD(err, StartL());
+	if (err)
+		{
+		test.Printf(_L("StartL failed with error: %d!\n"), err);
+		}
+		
+	delete activescheduler;
+	delete cleanupStack;
+
+	__UHEAP_MARKEND;
+
+	return 0; // and return
+	}
+