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