os/boardsupport/emulator/emulatorbsp/test/exdriver/exdriver_pio/src/d_expio_emul.cpp
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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
22 // include h4 specific header file
23 #include "d_expio_emul.h"
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.
32 DECLARE_STANDARD_PDD()
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.
38 DExEmulPhysicalDevice* pD = new DExEmulPhysicalDevice;
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
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
53 TInt r = Kern::DynamicDfcQCreate(pDfcQ,KExEmulUartDfcPriority,
57 // Store the DFC thread pointer to return when required
58 pD->iDfcQueue = pDfcQ;
59 // Success return point
62 // if DFCQ creation failed, then fail the PDD loading, hence asynchronously close
63 // the LDD factory object created.
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()
76 DExEmulPhysicalDevice::DExEmulPhysicalDevice()
78 // if multiple units are supported, then iUnitsMask is set here
79 // to indicate the units being supported by the driver.
83 Physical device destructor. This is called whicle unloading the PDD
85 DExEmulPhysicalDevice::~DExEmulPhysicalDevice()
87 // If a Dynamic Dfc Queue is created, delete it to ensure there is no
92 // Destroys the DFC queue.The function destroys the DFC queue, killing
93 // the DFC thread and deleting the TDynamicDfcQue object itself
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().
106 reference to the physical channel object created
108 @return KErrNone for success or KErrNoMemory for failure
110 TInt DExEmulPhysicalDevice::Create(DBase*& aChannel,TInt aUnit, const TDesC8* aInfo,
111 const TVersion& aVer)
113 // Create the Physical channel
114 DExUartPhysicalChannelEmul *device = new DExUartPhysicalChannelEmul;
120 // Call the second stage contructor of physical channel
121 return device->DoCreate(aUnit,aInfo,aVer);
125 Constructor for physical channel. Called after the base class constructor
127 DExUartPhysicalChannelEmul::DExUartPhysicalChannelEmul()
128 :iConfigured(EFalse),
130 iRxPollTimer(RxPollTimerCallback,this) // Timer to poll Rx data
135 Hardware peripheral class (uart) Destructor
137 DExUartPhysicalChannelEmul::~DExUartPhysicalChannelEmul()
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.
145 if (iTimerStatus==KTimerStarted)
146 iRxPollTimer.Cancel();
148 // close the port if the handle is invalid
149 if (hCommPort!=INVALID_HANDLE_VALUE)
151 // Close the Serial Port after reading data
152 CloseHandle(hCommPort);
153 KEXDEBUG(Kern::Printf("Emulator::Serial Port Closed"));
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.
165 device related information
170 TInt DExUartPhysicalChannelEmul::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
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
182 // TCommConfigV01 structure defined in d32comm.h is used
183 // to hold the configuration details like baudrate, parity,
184 // databits etc for serial
187 // Configure the channel by default, (9600 baud rate)
188 cfg.iRate = EBps9600;
192 // Configuration failed, still continue by updating device state
197 // Device configured successfully
201 // Physical channel creation is successful
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.
213 @return refernce to the created TDynamicDfcQue object
215 TDynamicDfcQue* DExUartPhysicalChannelEmul::DfcQ()
217 // return the dfc thread created for this driver. one per uint/device
218 return ((DExEmulPhysicalDevice*)iLdd->iPhysicalDevice)->iDfcQueue;
222 Get the capabilities of the channel. This can be used by the user to get
223 the capabilities for the channel from PSL.
226 descriptor returned after filling with capabilities
228 void DExUartPhysicalChannelEmul:: Caps(TDes8& aCaps)
230 // Package buffer of TCommCapsV03. This creates a descriptor
231 // for the commcaps structure, and provide compatibility
232 // to use with API using descriptors
236 // Retrieves the data structure from the package buffer. TCommCapsV03
237 // holds the uart capabilities information.
239 TCommCapsV03 &caps=capsBuf();
241 caps.iRate=KCapsBps9600; // baudrate
242 caps.iDataBits=KCapsData8; // data size
243 caps.iFifo=KCapsHasFifo; // fifo enabled
244 caps.iBreakSupported=EFalse;// no braek support
246 // [TDes8::MaxLength()] - Get the descriptor's length.
247 TInt len = aCaps.MaxLength();
249 // [TDes8::FillZ(len)] -Fill the descriptor's data area with binary
250 // zeroes, replacing any existing data and change its length.
253 TInt size = sizeof(caps);
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);
261 aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
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.
272 configuration settings for the device
274 @return KErrNone or standard error code
276 TInt DExUartPhysicalChannelEmul::Configure(const TCommConfigV01& aConfig)
279 // if channel is already configured to same baud rate, then no need to
280 // repeat the configuration
282 if (iConfigured!=EFalse)
284 if(iBaudRate==aConfig.iRate)
288 iBaudRate = aConfig.iRate;
290 // variables used with the com port
293 COMMTIMEOUTS commTimeouts;
295 bPortReady = TRUE; // everything is OK so far
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.
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.
305 // If the serial port opens successfully, a Win32 file object handle is returned.
306 // Otherwise, INVALID_HANDLE_VALUE is returned.
308 hCommPort=CreateFileA((LPCSTR)"\\\\.\\com1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
310 if (hCommPort==INVALID_HANDLE_VALUE)
312 Kern::Printf("Emulator::Configure: FAILED");
316 DWORD winErr=GetLastError();
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);
336 bPortReady = SetupComm(hCommPort, 256, 256); // set buffer sizes
339 return(KErrNoMemory);
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.
353 bPortReady = GetCommState(hCommPort, &dcb);
363 switch (aConfig.iRate)
380 switch(aConfig.iDataBits)
394 switch(aConfig.iStopBits)
397 dcb.StopBits=ONESTOPBIT;
400 dcb.StopBits=TWOSTOPBITS;
403 dcb.StopBits = ONESTOPBIT;
407 dcb.Parity = NOPARITY;
409 bPortReady = SetCommState(hCommPort, &dcb);
418 // You can find the current timeout settings using the GetCommTimeout()
419 // function, which fills a passed COMMTIMEOUTS structure.
421 bPortReady = GetCommTimeouts (hCommPort, &commTimeouts);
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.
428 commTimeouts.ReadIntervalTimeout = MAXDWORD;
429 commTimeouts.ReadTotalTimeoutConstant = 0;
430 commTimeouts.ReadTotalTimeoutMultiplier = 0;
436 if(!SetCommTimeouts(hCommPort, &commTimeouts))
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
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
457 buffer for transmit data
459 @return KErrNone or standard error code
461 TInt DExUartPhysicalChannelEmul::TransmitData(const TDesC8& aData)
468 // if the device is not configured, try to configure the device again
469 if (iConfigured==EFalse)
471 // Configure the channel by default
473 cfg.iRate = EBps9600; // 9600 baudrate
477 // configure failed again, abort the request
481 // configured successfully, continue with Tx
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
493 // Loop till all the data sent from LDD is transmitted in blocks of KTxFifoSize
496 // Each block size can be max KTxFifoSize or less
497 size=(count<KTxFifoSize)?count:KTxFifoSize;
503 bWriteRC = WriteFile(hCommPort, aData.Ptr(), size, &iBytesWritten, NULL);
505 if (!bWriteRC || iBytesWritten == 0)
510 // calculate the offset
511 offset+=iBytesWritten;
512 // calculate the remaining buffer size
513 count-=iBytesWritten;
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
524 buffer for received data
526 @return KErrNone or standard error code
528 TInt DExUartPhysicalChannelEmul::ReceiveData(TDes8& aData,TInt aLen)
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
541 return KErrAbort; // Zero length request, exit and fail
543 // Keep track of the requested size
546 // Loop till the requested amount of data from LDD is filled or a timeout
552 memset(sBuffer,0,sizeof(sBuffer));
553 // if no data and timer expired
554 while ((bReadRC=ReadFile(hCommPort, sBuffer, sizeof(sBuffer), &iBytesRead, NULL)) == 0
557 if (iTimerStatus==KTimerExpired)
559 aData.SetLength(bytesRcvd);
564 if (iTimerStatus==KTimerStarted)
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.
572 iRxPollTimer.Cancel();
573 // Update status as Cancelled
574 iTimerStatus=KTimerCancelled;
577 if (bReadRC && (iBytesRead>0))
579 if (iBytesRead>=static_cast<TUint>(size))
581 aData.Append(TPtrC8((const TText8*)sBuffer,iBytesRead));
582 bytesRcvd+=iBytesRead;
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
594 ret=iRxPollTimer.OneShot(KRxPollTimeout);
595 if(ret!=KErrNone) // timer creation failed
599 // If we have received the requested number of bytes, return
602 if (iTimerStatus == KTimerStarted)
603 iRxPollTimer.Cancel();
607 // remaining bytes to be received
614 void DExUartPhysicalChannelEmul::RxPollTimerCallback(TAny* aPtr)
616 KEXDEBUG(Kern::Printf("EMUL UART::Rx Timer Expired, Data Flow Stopped"));
617 ((DExUartPhysicalChannelEmul*)aPtr)->iTimerStatus=KTimerExpired;
621 // End of d_expio_emul.cpp