emulator/emulatorbsp/test/exdriver/exdriver_pio/src/d_expio_emul.cpp
changeset 0 cec860690d41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emulator/emulatorbsp/test/exdriver/exdriver_pio/src/d_expio_emul.cpp	Tue Feb 02 01:39:10 2010 +0200
@@ -0,0 +1,621 @@
+// Copyright (c) 2007-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:
+// This file implements the DExUartPhysicalChannelEmul class functions. 
+// This is the implementation os serila port driver for emulator
+// target, i.e serial port of windows PC. This pdd is actually an
+// application for windows serial driver and therefore uses windows
+// API to access windows serial driver functionality
+// 
+//
+
+// include h4 specific header file
+#include "d_expio_emul.h"
+
+/** 
+ PDD entry point
+ This function is called when the PDD is loaded. This creates a factory
+ object for PDD. DECLARE_STANDARD_PDD macro defines the first export to
+ represent the DLL factory function, that will be called first by loader
+ after loading the PDD. 
+ */
+DECLARE_STANDARD_PDD()
+	{	
+	// Create a PDD factory object, i.e instance of DPhysicalDevice derived 
+	// class. This is the first step that is done after loading the driver.
+	// Physical device constructor inturn creates a Physical Channel.
+	//		
+	DExEmulPhysicalDevice* pD = new DExEmulPhysicalDevice;
+	if(pD)
+		{
+		// TDynamicDfcQue is used for creating and destroying a DFC as needed
+		// This extends TDfcQue with destroy method. This ensures there is
+		// no memory leak done while using DFC queue 
+		//
+		TDynamicDfcQue* pDfcQ;
+		// Create a new DFC queue using kernel API, Kern::DynamicDfcQCreate(). It 
+		// allocates a TDynamicDfcQue object on the heap and initializes it with 
+		// provided parameters like thread priority for the queue. Thread priority
+		// has to be chosen carefully, as priority higher than the kernel threads 
+		// used for timers may adversely effect the system performance, nano 
+		// kernel ticks.
+		//
+		TInt r = Kern::DynamicDfcQCreate(pDfcQ,KExEmulUartDfcPriority,
+														KExEmulUartDfcName);
+		if (KErrNone==r)
+			{
+			// Store the DFC thread pointer to return when required
+			pD->iDfcQueue = pDfcQ;
+			// Success return point
+			return pD;
+			}
+		// if DFCQ creation failed, then fail the PDD loading, hence asynchronously close	
+		// the LDD factory object created.
+		//
+		pD->AsyncClose();
+		}
+	// Failure exit point	
+	return NULL;
+	}
+
+/**
+ PDD factory constructor. This is called while creating the PDD factory
+ object as a part of the driver (PDD) loading. This is called after the
+ base class constructor, i.e DExUartPhysicalDevice()
+ */
+DExEmulPhysicalDevice::DExEmulPhysicalDevice()	
+	{	
+	// if multiple units are supported, then iUnitsMask is set here
+	// to indicate the units being supported by the driver.	
+	}
+
+/**
+ Physical device destructor. This is called whicle unloading the PDD
+ */
+DExEmulPhysicalDevice::~DExEmulPhysicalDevice()	
+	{	
+	// If a Dynamic Dfc Queue is created, delete it to ensure there is no
+	// memory leak.
+	//
+	if (iDfcQueue)
+		{
+		// Destroys the DFC queue.The function destroys the DFC queue, killing
+		// the DFC thread and deleting the TDynamicDfcQue object itself
+		//
+		iDfcQueue->Destroy();
+		}
+	}
+
+/** 
+ PDD factory object (physical device) create. This is called by framework
+ to create a physical channel. It is called in the context of the client 
+ user-side thread that requested the creation of the logical channel. 
+ This is a result of a user-side call to RBusLogicalChannel::DoCreate().
+ 
+ @param 	aChannel
+ 			reference to the physical channel object created
+ 
+ @return	KErrNone for success or KErrNoMemory for failure
+ */ 
+TInt DExEmulPhysicalDevice::Create(DBase*& aChannel,TInt aUnit, const TDesC8* aInfo, 
+								const TVersion& aVer)
+	{		
+	// Create the Physical channel		
+	DExUartPhysicalChannelEmul *device = new DExUartPhysicalChannelEmul;
+	if (!device)
+		return KErrNoMemory;
+	
+	aChannel = device;
+	
+	// Call the second stage contructor of physical channel
+	return device->DoCreate(aUnit,aInfo,aVer);	
+	}		
+		
+/**
+ Constructor for physical channel. Called after the base class constructor
+ */
+DExUartPhysicalChannelEmul::DExUartPhysicalChannelEmul()
+:iConfigured(EFalse),
+iBytesRead(0),
+ iRxPollTimer(RxPollTimerCallback,this)	// Timer to poll Rx data
+	{	
+	}
+
+/**
+ Hardware peripheral class (uart) Destructor
+ */
+DExUartPhysicalChannelEmul::~DExUartPhysicalChannelEmul()
+	{
+	// Cancel the Rx poll timer. NTimer.Cancel() Cancel a nanokernel 
+	// timer. Removes this timer from the nanokernel timer queue. 
+	// Does nothing if the timer is inactive or has already expired. 
+	// If the timer was queued and DFC callback requested it is possible 
+	// for the expiry handler to run even after Cancel() has been called.
+	//
+	if (iTimerStatus==KTimerStarted)
+		iRxPollTimer.Cancel();
+
+	// close the port if the handle is invalid
+	if (hCommPort!=INVALID_HANDLE_VALUE)
+	{
+		// Close the Serial Port after reading data
+		CloseHandle(hCommPort);
+		KEXDEBUG(Kern::Printf("Emulator::Serial Port Closed"));
+	}
+	}
+
+/**
+ Physical channel second stage constructor. This is called from the DPhysicalDevice::Create()
+ after creating the physical channel. Any further initializations as a part of the physical
+ channel creation are done here.
+ 
+ @param	aUnit
+ 		device unit number
+ @param	aInfo
+ 		device related information
+ @param	aVer
+ 		version number
+ @return
+ */
+TInt DExUartPhysicalChannelEmul::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
+    { 
+    TInt r;
+     
+    // We are not using these parameters here, and therefore making them void to avoid any
+    // warning messages during build. If multiple units are supported, creating the channel
+    // w.r.t unit can be controlled here
+    //
+    (void)aUnit;     
+    (void)aInfo;
+    (void)aVer;
+    
+    // TCommConfigV01 structure defined in d32comm.h is used
+ 	// to hold the configuration details like baudrate, parity,
+ 	// databits etc for serial
+ 	//
+    TCommConfigV01 cfg;
+    // Configure the channel by default, (9600 baud rate)
+    cfg.iRate = EBps9600;
+    r = Configure(cfg);
+    if (r!=KErrNone)
+    	{
+    	// Configuration failed, still continue by updating device state
+    	iConfigured=EFalse;
+    	}
+    else
+    	{
+    	// Device configured successfully
+        iConfigured=ETrue;		    
+    	}
+    
+    // Physical channel creation is successful
+    return KErrNone;    
+    }
+    
+/**   
+ DfcQ - Creates a DFC queue dedicated for the tutorial driver. By default
+ logical channel derived from DLogicalChannel has a DFCQ, and DFC thread 0
+ is generally used. However, driver can choose o create it's own DFC and
+ use it for queuing it's messages to this queue. In this case, PDD can 
+ implement this function, DfcQ(), which is called by LDD to initialize it's
+ messgage queue with this DFC.
+ 
+ @return	refernce to the created TDynamicDfcQue object
+ */
+TDynamicDfcQue* DExUartPhysicalChannelEmul::DfcQ()    
+	{
+	// return the dfc thread created for this driver. one per uint/device
+	return ((DExEmulPhysicalDevice*)iLdd->iPhysicalDevice)->iDfcQueue;		
+	}
+
+/** 
+ Get the capabilities of the channel. This can be used by the user to get
+ the capabilities for the channel from PSL.
+ 
+ @param	aCaps
+ 		descriptor returned after filling with capabilities 
+ */ 
+void DExUartPhysicalChannelEmul:: Caps(TDes8& aCaps)
+	{
+	// Package buffer of TCommCapsV03. This creates a descriptor
+	// for the commcaps structure, and provide compatibility
+	// to use with API using descriptors
+	//
+	TCommCaps3 capsBuf;    
+	  
+	// Retrieves the data structure from the package buffer. TCommCapsV03
+	// holds the uart capabilities information.
+    //
+	TCommCapsV03 &caps=capsBuf();
+	
+	caps.iRate=KCapsBps9600;	// baudrate
+	caps.iDataBits=KCapsData8;	// data size
+	caps.iFifo=KCapsHasFifo;	// fifo enabled
+	caps.iBreakSupported=EFalse;// no braek support	
+
+	// [TDes8::MaxLength()] - Get the descriptor's length.
+	TInt len = aCaps.MaxLength();
+	
+	// [TDes8::FillZ(len)] -Fill the descriptor's data area with binary 
+	// zeroes, replacing any existing data and change its length. 
+	aCaps.FillZ(len);
+	
+    TInt size = sizeof(caps);
+    if (size>len)
+    	size=len;
+    
+    // [TDes8::Copy()] - Copy the data of length (size) into aDes descriptor
+    //  replacing any existing data in the descriptor.
+    aCaps.Copy((TUint8*)&caps, size);
+        	
+	aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
+	}
+		
+/**
+ Configure the hardware device (Uart). This is device specific API, that 
+ provides functionality to configure the uart. Uart configuration settings are 
+ passed to this function by user. User calls this by using 
+ RBusLogicalChannel::DoControl() to LDD and ldd inturn calls this PDD function
+ to do the actual operation on the device.
+  
+ @param	aConfig
+ 		configuration settings for the device
+ 
+ @return	KErrNone or standard error code
+ */
+TInt DExUartPhysicalChannelEmul::Configure(const TCommConfigV01& aConfig)
+	{
+
+	// if channel is already configured to same baud rate, then no need to 
+	// repeat the configuration
+	//
+	if (iConfigured!=EFalse)
+	{
+		if(iBaudRate==aConfig.iRate)
+			return KErrNone;
+	}
+	
+	iBaudRate = aConfig.iRate;
+
+	// variables used with the com port
+	BOOL     bPortReady;
+	DCB      dcb;
+	COMMTIMEOUTS commTimeouts;
+
+	bPortReady = TRUE; // everything is OK so far
+	
+	// Open a serial port device using the CreateFile() function by specifying
+	// a filename that refers to the specific port, such as COM1 or COM2.
+	// 
+	// When you open a serial port, it is opened automatically for exclusive access,
+	// so you should pass a zero for the CreateFile()'s third parameter and OPEN_EXISTING
+	// for the open mode (fifth parameter). You can add a combination of the special file
+	// mode flags to indicate overlapped I/O or any special buffering requirements, as normal.
+	// 
+	// If the serial port opens successfully, a Win32 file object handle is returned.
+	// Otherwise, INVALID_HANDLE_VALUE is returned.
+	//
+	hCommPort=CreateFileA((LPCSTR)"\\\\.\\com1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+	
+	if (hCommPort==INVALID_HANDLE_VALUE)	
+	{	
+		Kern::Printf("Emulator::Configure: FAILED");
+		
+		bPortReady = FALSE;
+
+		DWORD winErr=GetLastError();
+		switch (winErr)
+		{
+			case ERROR_INVALID_USER_BUFFER:
+			case ERROR_NOT_ENOUGH_MEMORY:
+			case ERROR_INSUFFICIENT_BUFFER:
+				return(KErrNoMemory);
+			case ERROR_ACCESS_DENIED:
+				return(KErrAccessDenied);
+			case ERROR_FILE_NOT_FOUND:		//	Reflects value returned by
+				return(KErrNotSupported);	//	corresponding MARM Pdd  
+			case ERROR_NOT_SUPPORTED:
+				return(KErrNotSupported);
+			default:
+				return(KErrGeneral);
+		}
+	}
+	
+	if (bPortReady)
+	{
+		bPortReady = SetupComm(hCommPort, 256, 256); // set buffer sizes
+		if (!bPortReady)
+		{
+			return(KErrNoMemory);
+		}
+	}
+	
+    
+    // After you open a serial port, you must set the many flags required to configure
+    // the device. These flags are held in a device control block (DCB) structure.
+    // You can either fill in the entire DCB structure or use one of the helper functions
+    // to fill in some of the details. The GetCommState() function fills in a DCB structure
+    // with the current settings from the hardware, and you can use a corresponding
+    // SetCommState() function to specify the new settings from a DCB structure.
+	//
+	if (bPortReady)
+	{
+		bPortReady = GetCommState(hCommPort, &dcb);
+		if (!bPortReady)
+		{
+			return(KErrGeneral);
+		}
+	}
+	
+	if (bPortReady)
+	{
+		//baud rate
+		switch (aConfig.iRate)
+			{
+		case EBps9600:
+			dcb.BaudRate=9600;
+			break;
+		case EBps38400:
+			dcb.BaudRate=38400;
+			break;
+		case EBps115200:
+			dcb.BaudRate=115200;
+			break;
+		default:
+			dcb.BaudRate=9600;
+			break;
+			}
+			
+	   	//data bits
+	   	switch(aConfig.iDataBits)
+			{
+		case EData7:
+			dcb.ByteSize=7;
+			break;
+		case EData8:
+			dcb.ByteSize=8;
+			break;
+		default:
+			dcb.ByteSize=8;
+			break;
+			}
+
+		//stop bits
+		switch(aConfig.iStopBits)
+			{
+		case EStop1:
+			dcb.StopBits=ONESTOPBIT;
+			break;
+		case EStop2:
+			dcb.StopBits=TWOSTOPBITS;
+			break;
+		default:
+			dcb.StopBits = ONESTOPBIT;
+			break;	
+			}
+		
+		dcb.Parity = NOPARITY;
+
+		bPortReady = SetCommState(hCommPort, &dcb);
+		if (!bPortReady)
+		{
+			return(KErrGeneral);
+		}
+	}
+
+	if (bPortReady)
+	{		
+		// You can find the current timeout settings using the GetCommTimeout()
+		// function, which fills a passed COMMTIMEOUTS structure.	
+		//
+		bPortReady = GetCommTimeouts (hCommPort, &commTimeouts);
+		if (bPortReady)
+		{
+			// You can set ReadIntervalTimeout to MAXDWORD and set the
+			// ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members
+			// to zero to indicate that the ReadFile() should return immediately.
+			//
+		    commTimeouts.ReadIntervalTimeout = MAXDWORD;
+		    commTimeouts.ReadTotalTimeoutConstant = 0;
+		    commTimeouts.ReadTotalTimeoutMultiplier = 0;
+		}
+		else
+		{
+			return(KErrGeneral);
+		}
+		if(!SetCommTimeouts(hCommPort, &commTimeouts))
+			return(KErrGeneral);
+		
+	}
+	return KErrNone;
+	}
+
+// After configuring the serial port, you can start transferring data via ReadFile()
+// and WriteFile() functions. However, you should remember that if you haven't specified
+// the FILE_FLAG_OVERLAPPED flag in the CreateFile() flags parameter,
+// ReadFile() will block waiting for input. This probably is good if your program spawns
+// another thread that specifically waits for incoming serial port characters, but not
+// if you want to issue a ReadFile() and periodically check to see whether any characters
+// have arrived.
+// 
+
+/**
+ Transmit data over uart for emulator targte, i.e serial port for pc
+ Transmit data buffer is filled and passed by user to the driver
+ 
+ @param	aData
+ 			buffer for transmit data
+ 
+ @return	KErrNone or standard error code
+ */
+TInt DExUartPhysicalChannelEmul::TransmitData(const TDesC8& aData)
+	{
+	TInt r;
+	TInt count;
+	TInt size;
+	TInt offset=0;
+		
+	// if the device is not configured, try to configure the device again
+	if (iConfigured==EFalse)
+		{
+		// Configure the channel by default
+    	TCommConfigV01 cfg;
+    	cfg.iRate = EBps9600; // 9600 baudrate
+    	r = Configure(cfg);
+    	if (r!=KErrNone)
+    		{
+    		// configure failed again, abort the request
+    		iConfigured=EFalse;
+    		return KErrAbort;
+    		}
+    	// configured successfully, continue with Tx	
+    	iConfigured=ETrue;	
+		}	
+	
+	// Size of the data to be transmitted is obtained from the descriptor. 
+	// TDesC8::Size() gets the size of the data interms of number of bytes occupied 
+	// by the data represented by the descriptor
+	//
+	count= aData.Size();
+	if (count<=0)
+		return KErrAbort;
+	
+	// Loop till all the data sent from LDD is transmitted in blocks of KTxFifoSize
+ 	while (count>0)
+ 		{
+ 		// Each block size can be max KTxFifoSize or less
+ 		size=(count<KTxFifoSize)?count:KTxFifoSize;
+		
+		BOOL bWriteRC;
+		DWORD iBytesWritten;
+
+		iBytesWritten = 0;
+		bWriteRC = WriteFile(hCommPort, aData.Ptr(), size, &iBytesWritten, NULL);
+
+		if (!bWriteRC || iBytesWritten == 0)
+			{
+			return(KErrGeneral);
+			}
+		
+ 		// calculate the offset
+		offset+=iBytesWritten;			
+		// calculate the remaining buffer size
+		count-=iBytesWritten;			
+		}
+		
+	return KErrNone;
+	}
+
+/**
+ Receive data over uart for emulator target, i.e uart of pc
+ Receive data buffer is filled and passed by driver to the user
+ 
+ @param	aData
+ 			buffer for received data
+ 
+ @return	KErrNone or standard error code
+ */
+TInt DExUartPhysicalChannelEmul::ReceiveData(TDes8& aData,TInt aLen)
+	{	
+	TInt ret;
+	TInt size;
+	TInt count;
+	TInt bytesRcvd=0;
+	
+	// Size of the data to be transmitted is obtained from the descriptor. 
+	// TDesC8::Size() gets the size of the data interms of number of bytes occupied 
+	// by the data represented by the descriptor
+	//
+	size= aLen;
+	if (size<=0)
+		return KErrAbort; // Zero length request, exit and fail
+	
+	// Keep track of the requested size
+	count=size;	
+
+ 	// Loop till the requested amount of data from LDD is filled or a timeout
+  	while (count>0)
+ 		{ 		
+ 		BOOL bReadRC;
+		char sBuffer[256];
+	
+		memset(sBuffer,0,sizeof(sBuffer));
+ 		// if no data and timer expired
+ 		while ((bReadRC=ReadFile(hCommPort, sBuffer, sizeof(sBuffer), &iBytesRead, NULL)) == 0
+ 				|| (iBytesRead==0)) 		
+ 			{
+ 			if (iTimerStatus==KTimerExpired)
+ 				{
+ 				aData.SetLength(bytesRcvd);
+ 				return KErrTimedOut;
+ 				}
+ 			}
+ 				 			
+ 		if (iTimerStatus==KTimerStarted)
+			{
+			// Cancel the Rx poll timer. NTimer.Cancel() Cancel a nanokernel 
+			// timer. Removes this timer from the nanokernel timer queue. 
+			// Does nothing if the timer is inactive or has already expired. 
+			// If the timer was queued and DFC callback requested it is possible 
+			// for the expiry handler to run even after Cancel() has been called.
+			//
+			iRxPollTimer.Cancel();
+			// Update status as Cancelled
+			iTimerStatus=KTimerCancelled;
+			}
+			
+		if (bReadRC && (iBytesRead>0))
+			{
+			if (iBytesRead>=static_cast<TUint>(size))			
+				iBytesRead=size;
+			aData.Append(TPtrC8((const TText8*)sBuffer,iBytesRead));		
+			bytesRcvd+=iBytesRead;
+			iBytesRead=0;
+			}
+		else
+			{
+			iTimerStatus = KTimerStarted;			 			
+			// Start a nanokernel timer in one-shot mode with ISR callback
+			// Queues the timer to expire in the specified number of nanokernel
+			// ticks. The actual wait time will be at least that much and 
+			// may be up to one tick more. The expiry handler will be called in
+			// ISR context.
+			//		 			
+    		ret=iRxPollTimer.OneShot(KRxPollTimeout); 			
+			if(ret!=KErrNone) // timer creation failed
+				return ret;
+			}	
+
+		// If we have received the requested number of bytes, return
+		if (bytesRcvd>=size)
+			{					
+			if (iTimerStatus == KTimerStarted)
+				iRxPollTimer.Cancel();			
+			return KErrNone;
+			}
+						
+		// remaining bytes to be received	
+		count -= bytesRcvd;		 		 		
+		}		
+
+	return KErrNone;
+	}
+
+void DExUartPhysicalChannelEmul::RxPollTimerCallback(TAny* aPtr)
+    {
+    KEXDEBUG(Kern::Printf("EMUL UART::Rx Timer Expired, Data Flow Stopped"));
+    ((DExUartPhysicalChannelEmul*)aPtr)->iTimerStatus=KTimerExpired;        
+    }
+	
+//
+// End of d_expio_emul.cpp