os/boardsupport/emulator/emulatorbsp/test/exdriver/exdriver_pio/src/d_expio_emul.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // This file implements the DExUartPhysicalChannelEmul class functions. 
    15 // This is the implementation os serila port driver for emulator
    16 // target, i.e serial port of windows PC. This pdd is actually an
    17 // application for windows serial driver and therefore uses windows
    18 // API to access windows serial driver functionality
    19 // 
    20 //
    21 
    22 // include h4 specific header file
    23 #include "d_expio_emul.h"
    24 
    25 /** 
    26  PDD entry point
    27  This function is called when the PDD is loaded. This creates a factory
    28  object for PDD. DECLARE_STANDARD_PDD macro defines the first export to
    29  represent the DLL factory function, that will be called first by loader
    30  after loading the PDD. 
    31  */
    32 DECLARE_STANDARD_PDD()
    33 	{	
    34 	// Create a PDD factory object, i.e instance of DPhysicalDevice derived 
    35 	// class. This is the first step that is done after loading the driver.
    36 	// Physical device constructor inturn creates a Physical Channel.
    37 	//		
    38 	DExEmulPhysicalDevice* pD = new DExEmulPhysicalDevice;
    39 	if(pD)
    40 		{
    41 		// TDynamicDfcQue is used for creating and destroying a DFC as needed
    42 		// This extends TDfcQue with destroy method. This ensures there is
    43 		// no memory leak done while using DFC queue 
    44 		//
    45 		TDynamicDfcQue* pDfcQ;
    46 		// Create a new DFC queue using kernel API, Kern::DynamicDfcQCreate(). It 
    47 		// allocates a TDynamicDfcQue object on the heap and initializes it with 
    48 		// provided parameters like thread priority for the queue. Thread priority
    49 		// has to be chosen carefully, as priority higher than the kernel threads 
    50 		// used for timers may adversely effect the system performance, nano 
    51 		// kernel ticks.
    52 		//
    53 		TInt r = Kern::DynamicDfcQCreate(pDfcQ,KExEmulUartDfcPriority,
    54 														KExEmulUartDfcName);
    55 		if (KErrNone==r)
    56 			{
    57 			// Store the DFC thread pointer to return when required
    58 			pD->iDfcQueue = pDfcQ;
    59 			// Success return point
    60 			return pD;
    61 			}
    62 		// if DFCQ creation failed, then fail the PDD loading, hence asynchronously close	
    63 		// the LDD factory object created.
    64 		//
    65 		pD->AsyncClose();
    66 		}
    67 	// Failure exit point	
    68 	return NULL;
    69 	}
    70 
    71 /**
    72  PDD factory constructor. This is called while creating the PDD factory
    73  object as a part of the driver (PDD) loading. This is called after the
    74  base class constructor, i.e DExUartPhysicalDevice()
    75  */
    76 DExEmulPhysicalDevice::DExEmulPhysicalDevice()	
    77 	{	
    78 	// if multiple units are supported, then iUnitsMask is set here
    79 	// to indicate the units being supported by the driver.	
    80 	}
    81 
    82 /**
    83  Physical device destructor. This is called whicle unloading the PDD
    84  */
    85 DExEmulPhysicalDevice::~DExEmulPhysicalDevice()	
    86 	{	
    87 	// If a Dynamic Dfc Queue is created, delete it to ensure there is no
    88 	// memory leak.
    89 	//
    90 	if (iDfcQueue)
    91 		{
    92 		// Destroys the DFC queue.The function destroys the DFC queue, killing
    93 		// the DFC thread and deleting the TDynamicDfcQue object itself
    94 		//
    95 		iDfcQueue->Destroy();
    96 		}
    97 	}
    98 
    99 /** 
   100  PDD factory object (physical device) create. This is called by framework
   101  to create a physical channel. It is called in the context of the client 
   102  user-side thread that requested the creation of the logical channel. 
   103  This is a result of a user-side call to RBusLogicalChannel::DoCreate().
   104  
   105  @param 	aChannel
   106  			reference to the physical channel object created
   107  
   108  @return	KErrNone for success or KErrNoMemory for failure
   109  */ 
   110 TInt DExEmulPhysicalDevice::Create(DBase*& aChannel,TInt aUnit, const TDesC8* aInfo, 
   111 								const TVersion& aVer)
   112 	{		
   113 	// Create the Physical channel		
   114 	DExUartPhysicalChannelEmul *device = new DExUartPhysicalChannelEmul;
   115 	if (!device)
   116 		return KErrNoMemory;
   117 	
   118 	aChannel = device;
   119 	
   120 	// Call the second stage contructor of physical channel
   121 	return device->DoCreate(aUnit,aInfo,aVer);	
   122 	}		
   123 		
   124 /**
   125  Constructor for physical channel. Called after the base class constructor
   126  */
   127 DExUartPhysicalChannelEmul::DExUartPhysicalChannelEmul()
   128 :iConfigured(EFalse),
   129 iBytesRead(0),
   130  iRxPollTimer(RxPollTimerCallback,this)	// Timer to poll Rx data
   131 	{	
   132 	}
   133 
   134 /**
   135  Hardware peripheral class (uart) Destructor
   136  */
   137 DExUartPhysicalChannelEmul::~DExUartPhysicalChannelEmul()
   138 	{
   139 	// Cancel the Rx poll timer. NTimer.Cancel() Cancel a nanokernel 
   140 	// timer. Removes this timer from the nanokernel timer queue. 
   141 	// Does nothing if the timer is inactive or has already expired. 
   142 	// If the timer was queued and DFC callback requested it is possible 
   143 	// for the expiry handler to run even after Cancel() has been called.
   144 	//
   145 	if (iTimerStatus==KTimerStarted)
   146 		iRxPollTimer.Cancel();
   147 
   148 	// close the port if the handle is invalid
   149 	if (hCommPort!=INVALID_HANDLE_VALUE)
   150 	{
   151 		// Close the Serial Port after reading data
   152 		CloseHandle(hCommPort);
   153 		KEXDEBUG(Kern::Printf("Emulator::Serial Port Closed"));
   154 	}
   155 	}
   156 
   157 /**
   158  Physical channel second stage constructor. This is called from the DPhysicalDevice::Create()
   159  after creating the physical channel. Any further initializations as a part of the physical
   160  channel creation are done here.
   161  
   162  @param	aUnit
   163  		device unit number
   164  @param	aInfo
   165  		device related information
   166  @param	aVer
   167  		version number
   168  @return
   169  */
   170 TInt DExUartPhysicalChannelEmul::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
   171     { 
   172     TInt r;
   173      
   174     // We are not using these parameters here, and therefore making them void to avoid any
   175     // warning messages during build. If multiple units are supported, creating the channel
   176     // w.r.t unit can be controlled here
   177     //
   178     (void)aUnit;     
   179     (void)aInfo;
   180     (void)aVer;
   181     
   182     // TCommConfigV01 structure defined in d32comm.h is used
   183  	// to hold the configuration details like baudrate, parity,
   184  	// databits etc for serial
   185  	//
   186     TCommConfigV01 cfg;
   187     // Configure the channel by default, (9600 baud rate)
   188     cfg.iRate = EBps9600;
   189     r = Configure(cfg);
   190     if (r!=KErrNone)
   191     	{
   192     	// Configuration failed, still continue by updating device state
   193     	iConfigured=EFalse;
   194     	}
   195     else
   196     	{
   197     	// Device configured successfully
   198         iConfigured=ETrue;		    
   199     	}
   200     
   201     // Physical channel creation is successful
   202     return KErrNone;    
   203     }
   204     
   205 /**   
   206  DfcQ - Creates a DFC queue dedicated for the tutorial driver. By default
   207  logical channel derived from DLogicalChannel has a DFCQ, and DFC thread 0
   208  is generally used. However, driver can choose o create it's own DFC and
   209  use it for queuing it's messages to this queue. In this case, PDD can 
   210  implement this function, DfcQ(), which is called by LDD to initialize it's
   211  messgage queue with this DFC.
   212  
   213  @return	refernce to the created TDynamicDfcQue object
   214  */
   215 TDynamicDfcQue* DExUartPhysicalChannelEmul::DfcQ()    
   216 	{
   217 	// return the dfc thread created for this driver. one per uint/device
   218 	return ((DExEmulPhysicalDevice*)iLdd->iPhysicalDevice)->iDfcQueue;		
   219 	}
   220 
   221 /** 
   222  Get the capabilities of the channel. This can be used by the user to get
   223  the capabilities for the channel from PSL.
   224  
   225  @param	aCaps
   226  		descriptor returned after filling with capabilities 
   227  */ 
   228 void DExUartPhysicalChannelEmul:: Caps(TDes8& aCaps)
   229 	{
   230 	// Package buffer of TCommCapsV03. This creates a descriptor
   231 	// for the commcaps structure, and provide compatibility
   232 	// to use with API using descriptors
   233 	//
   234 	TCommCaps3 capsBuf;    
   235 	  
   236 	// Retrieves the data structure from the package buffer. TCommCapsV03
   237 	// holds the uart capabilities information.
   238     //
   239 	TCommCapsV03 &caps=capsBuf();
   240 	
   241 	caps.iRate=KCapsBps9600;	// baudrate
   242 	caps.iDataBits=KCapsData8;	// data size
   243 	caps.iFifo=KCapsHasFifo;	// fifo enabled
   244 	caps.iBreakSupported=EFalse;// no braek support	
   245 
   246 	// [TDes8::MaxLength()] - Get the descriptor's length.
   247 	TInt len = aCaps.MaxLength();
   248 	
   249 	// [TDes8::FillZ(len)] -Fill the descriptor's data area with binary 
   250 	// zeroes, replacing any existing data and change its length. 
   251 	aCaps.FillZ(len);
   252 	
   253     TInt size = sizeof(caps);
   254     if (size>len)
   255     	size=len;
   256     
   257     // [TDes8::Copy()] - Copy the data of length (size) into aDes descriptor
   258     //  replacing any existing data in the descriptor.
   259     aCaps.Copy((TUint8*)&caps, size);
   260         	
   261 	aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
   262 	}
   263 		
   264 /**
   265  Configure the hardware device (Uart). This is device specific API, that 
   266  provides functionality to configure the uart. Uart configuration settings are 
   267  passed to this function by user. User calls this by using 
   268  RBusLogicalChannel::DoControl() to LDD and ldd inturn calls this PDD function
   269  to do the actual operation on the device.
   270   
   271  @param	aConfig
   272  		configuration settings for the device
   273  
   274  @return	KErrNone or standard error code
   275  */
   276 TInt DExUartPhysicalChannelEmul::Configure(const TCommConfigV01& aConfig)
   277 	{
   278 
   279 	// if channel is already configured to same baud rate, then no need to 
   280 	// repeat the configuration
   281 	//
   282 	if (iConfigured!=EFalse)
   283 	{
   284 		if(iBaudRate==aConfig.iRate)
   285 			return KErrNone;
   286 	}
   287 	
   288 	iBaudRate = aConfig.iRate;
   289 
   290 	// variables used with the com port
   291 	BOOL     bPortReady;
   292 	DCB      dcb;
   293 	COMMTIMEOUTS commTimeouts;
   294 
   295 	bPortReady = TRUE; // everything is OK so far
   296 	
   297 	// Open a serial port device using the CreateFile() function by specifying
   298 	// a filename that refers to the specific port, such as COM1 or COM2.
   299 	// 
   300 	// When you open a serial port, it is opened automatically for exclusive access,
   301 	// so you should pass a zero for the CreateFile()'s third parameter and OPEN_EXISTING
   302 	// for the open mode (fifth parameter). You can add a combination of the special file
   303 	// mode flags to indicate overlapped I/O or any special buffering requirements, as normal.
   304 	// 
   305 	// If the serial port opens successfully, a Win32 file object handle is returned.
   306 	// Otherwise, INVALID_HANDLE_VALUE is returned.
   307 	//
   308 	hCommPort=CreateFileA((LPCSTR)"\\\\.\\com1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
   309 	
   310 	if (hCommPort==INVALID_HANDLE_VALUE)	
   311 	{	
   312 		Kern::Printf("Emulator::Configure: FAILED");
   313 		
   314 		bPortReady = FALSE;
   315 
   316 		DWORD winErr=GetLastError();
   317 		switch (winErr)
   318 		{
   319 			case ERROR_INVALID_USER_BUFFER:
   320 			case ERROR_NOT_ENOUGH_MEMORY:
   321 			case ERROR_INSUFFICIENT_BUFFER:
   322 				return(KErrNoMemory);
   323 			case ERROR_ACCESS_DENIED:
   324 				return(KErrAccessDenied);
   325 			case ERROR_FILE_NOT_FOUND:		//	Reflects value returned by
   326 				return(KErrNotSupported);	//	corresponding MARM Pdd  
   327 			case ERROR_NOT_SUPPORTED:
   328 				return(KErrNotSupported);
   329 			default:
   330 				return(KErrGeneral);
   331 		}
   332 	}
   333 	
   334 	if (bPortReady)
   335 	{
   336 		bPortReady = SetupComm(hCommPort, 256, 256); // set buffer sizes
   337 		if (!bPortReady)
   338 		{
   339 			return(KErrNoMemory);
   340 		}
   341 	}
   342 	
   343     
   344     // After you open a serial port, you must set the many flags required to configure
   345     // the device. These flags are held in a device control block (DCB) structure.
   346     // You can either fill in the entire DCB structure or use one of the helper functions
   347     // to fill in some of the details. The GetCommState() function fills in a DCB structure
   348     // with the current settings from the hardware, and you can use a corresponding
   349     // SetCommState() function to specify the new settings from a DCB structure.
   350 	//
   351 	if (bPortReady)
   352 	{
   353 		bPortReady = GetCommState(hCommPort, &dcb);
   354 		if (!bPortReady)
   355 		{
   356 			return(KErrGeneral);
   357 		}
   358 	}
   359 	
   360 	if (bPortReady)
   361 	{
   362 		//baud rate
   363 		switch (aConfig.iRate)
   364 			{
   365 		case EBps9600:
   366 			dcb.BaudRate=9600;
   367 			break;
   368 		case EBps38400:
   369 			dcb.BaudRate=38400;
   370 			break;
   371 		case EBps115200:
   372 			dcb.BaudRate=115200;
   373 			break;
   374 		default:
   375 			dcb.BaudRate=9600;
   376 			break;
   377 			}
   378 			
   379 	   	//data bits
   380 	   	switch(aConfig.iDataBits)
   381 			{
   382 		case EData7:
   383 			dcb.ByteSize=7;
   384 			break;
   385 		case EData8:
   386 			dcb.ByteSize=8;
   387 			break;
   388 		default:
   389 			dcb.ByteSize=8;
   390 			break;
   391 			}
   392 
   393 		//stop bits
   394 		switch(aConfig.iStopBits)
   395 			{
   396 		case EStop1:
   397 			dcb.StopBits=ONESTOPBIT;
   398 			break;
   399 		case EStop2:
   400 			dcb.StopBits=TWOSTOPBITS;
   401 			break;
   402 		default:
   403 			dcb.StopBits = ONESTOPBIT;
   404 			break;	
   405 			}
   406 		
   407 		dcb.Parity = NOPARITY;
   408 
   409 		bPortReady = SetCommState(hCommPort, &dcb);
   410 		if (!bPortReady)
   411 		{
   412 			return(KErrGeneral);
   413 		}
   414 	}
   415 
   416 	if (bPortReady)
   417 	{		
   418 		// You can find the current timeout settings using the GetCommTimeout()
   419 		// function, which fills a passed COMMTIMEOUTS structure.	
   420 		//
   421 		bPortReady = GetCommTimeouts (hCommPort, &commTimeouts);
   422 		if (bPortReady)
   423 		{
   424 			// You can set ReadIntervalTimeout to MAXDWORD and set the
   425 			// ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members
   426 			// to zero to indicate that the ReadFile() should return immediately.
   427 			//
   428 		    commTimeouts.ReadIntervalTimeout = MAXDWORD;
   429 		    commTimeouts.ReadTotalTimeoutConstant = 0;
   430 		    commTimeouts.ReadTotalTimeoutMultiplier = 0;
   431 		}
   432 		else
   433 		{
   434 			return(KErrGeneral);
   435 		}
   436 		if(!SetCommTimeouts(hCommPort, &commTimeouts))
   437 			return(KErrGeneral);
   438 		
   439 	}
   440 	return KErrNone;
   441 	}
   442 
   443 // After configuring the serial port, you can start transferring data via ReadFile()
   444 // and WriteFile() functions. However, you should remember that if you haven't specified
   445 // the FILE_FLAG_OVERLAPPED flag in the CreateFile() flags parameter,
   446 // ReadFile() will block waiting for input. This probably is good if your program spawns
   447 // another thread that specifically waits for incoming serial port characters, but not
   448 // if you want to issue a ReadFile() and periodically check to see whether any characters
   449 // have arrived.
   450 // 
   451 
   452 /**
   453  Transmit data over uart for emulator targte, i.e serial port for pc
   454  Transmit data buffer is filled and passed by user to the driver
   455  
   456  @param	aData
   457  			buffer for transmit data
   458  
   459  @return	KErrNone or standard error code
   460  */
   461 TInt DExUartPhysicalChannelEmul::TransmitData(const TDesC8& aData)
   462 	{
   463 	TInt r;
   464 	TInt count;
   465 	TInt size;
   466 	TInt offset=0;
   467 		
   468 	// if the device is not configured, try to configure the device again
   469 	if (iConfigured==EFalse)
   470 		{
   471 		// Configure the channel by default
   472     	TCommConfigV01 cfg;
   473     	cfg.iRate = EBps9600; // 9600 baudrate
   474     	r = Configure(cfg);
   475     	if (r!=KErrNone)
   476     		{
   477     		// configure failed again, abort the request
   478     		iConfigured=EFalse;
   479     		return KErrAbort;
   480     		}
   481     	// configured successfully, continue with Tx	
   482     	iConfigured=ETrue;	
   483 		}	
   484 	
   485 	// Size of the data to be transmitted is obtained from the descriptor. 
   486 	// TDesC8::Size() gets the size of the data interms of number of bytes occupied 
   487 	// by the data represented by the descriptor
   488 	//
   489 	count= aData.Size();
   490 	if (count<=0)
   491 		return KErrAbort;
   492 	
   493 	// Loop till all the data sent from LDD is transmitted in blocks of KTxFifoSize
   494  	while (count>0)
   495  		{
   496  		// Each block size can be max KTxFifoSize or less
   497  		size=(count<KTxFifoSize)?count:KTxFifoSize;
   498 		
   499 		BOOL bWriteRC;
   500 		DWORD iBytesWritten;
   501 
   502 		iBytesWritten = 0;
   503 		bWriteRC = WriteFile(hCommPort, aData.Ptr(), size, &iBytesWritten, NULL);
   504 
   505 		if (!bWriteRC || iBytesWritten == 0)
   506 			{
   507 			return(KErrGeneral);
   508 			}
   509 		
   510  		// calculate the offset
   511 		offset+=iBytesWritten;			
   512 		// calculate the remaining buffer size
   513 		count-=iBytesWritten;			
   514 		}
   515 		
   516 	return KErrNone;
   517 	}
   518 
   519 /**
   520  Receive data over uart for emulator target, i.e uart of pc
   521  Receive data buffer is filled and passed by driver to the user
   522  
   523  @param	aData
   524  			buffer for received data
   525  
   526  @return	KErrNone or standard error code
   527  */
   528 TInt DExUartPhysicalChannelEmul::ReceiveData(TDes8& aData,TInt aLen)
   529 	{	
   530 	TInt ret;
   531 	TInt size;
   532 	TInt count;
   533 	TInt bytesRcvd=0;
   534 	
   535 	// Size of the data to be transmitted is obtained from the descriptor. 
   536 	// TDesC8::Size() gets the size of the data interms of number of bytes occupied 
   537 	// by the data represented by the descriptor
   538 	//
   539 	size= aLen;
   540 	if (size<=0)
   541 		return KErrAbort; // Zero length request, exit and fail
   542 	
   543 	// Keep track of the requested size
   544 	count=size;	
   545 
   546  	// Loop till the requested amount of data from LDD is filled or a timeout
   547   	while (count>0)
   548  		{ 		
   549  		BOOL bReadRC;
   550 		char sBuffer[256];
   551 	
   552 		memset(sBuffer,0,sizeof(sBuffer));
   553  		// if no data and timer expired
   554  		while ((bReadRC=ReadFile(hCommPort, sBuffer, sizeof(sBuffer), &iBytesRead, NULL)) == 0
   555  				|| (iBytesRead==0)) 		
   556  			{
   557  			if (iTimerStatus==KTimerExpired)
   558  				{
   559  				aData.SetLength(bytesRcvd);
   560  				return KErrTimedOut;
   561  				}
   562  			}
   563  				 			
   564  		if (iTimerStatus==KTimerStarted)
   565 			{
   566 			// Cancel the Rx poll timer. NTimer.Cancel() Cancel a nanokernel 
   567 			// timer. Removes this timer from the nanokernel timer queue. 
   568 			// Does nothing if the timer is inactive or has already expired. 
   569 			// If the timer was queued and DFC callback requested it is possible 
   570 			// for the expiry handler to run even after Cancel() has been called.
   571 			//
   572 			iRxPollTimer.Cancel();
   573 			// Update status as Cancelled
   574 			iTimerStatus=KTimerCancelled;
   575 			}
   576 			
   577 		if (bReadRC && (iBytesRead>0))
   578 			{
   579 			if (iBytesRead>=static_cast<TUint>(size))			
   580 				iBytesRead=size;
   581 			aData.Append(TPtrC8((const TText8*)sBuffer,iBytesRead));		
   582 			bytesRcvd+=iBytesRead;
   583 			iBytesRead=0;
   584 			}
   585 		else
   586 			{
   587 			iTimerStatus = KTimerStarted;			 			
   588 			// Start a nanokernel timer in one-shot mode with ISR callback
   589 			// Queues the timer to expire in the specified number of nanokernel
   590 			// ticks. The actual wait time will be at least that much and 
   591 			// may be up to one tick more. The expiry handler will be called in
   592 			// ISR context.
   593 			//		 			
   594     		ret=iRxPollTimer.OneShot(KRxPollTimeout); 			
   595 			if(ret!=KErrNone) // timer creation failed
   596 				return ret;
   597 			}	
   598 
   599 		// If we have received the requested number of bytes, return
   600 		if (bytesRcvd>=size)
   601 			{					
   602 			if (iTimerStatus == KTimerStarted)
   603 				iRxPollTimer.Cancel();			
   604 			return KErrNone;
   605 			}
   606 						
   607 		// remaining bytes to be received	
   608 		count -= bytesRcvd;		 		 		
   609 		}		
   610 
   611 	return KErrNone;
   612 	}
   613 
   614 void DExUartPhysicalChannelEmul::RxPollTimerCallback(TAny* aPtr)
   615     {
   616     KEXDEBUG(Kern::Printf("EMUL UART::Rx Timer Expired, Data Flow Stopped"));
   617     ((DExUartPhysicalChannelEmul*)aPtr)->iTimerStatus=KTimerExpired;        
   618     }
   619 	
   620 //
   621 // End of d_expio_emul.cpp