0
|
1 |
/*
|
|
2 |
* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
* All rights reserved.
|
|
4 |
* This component and the accompanying materials are made available
|
|
5 |
* under the terms of "Eclipse Public License v1.0"
|
|
6 |
* which accompanies this distribution, and is available
|
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
*
|
|
9 |
* Initial Contributors:
|
|
10 |
* Nokia Corporation - initial contribution.
|
|
11 |
*
|
|
12 |
* Contributors:
|
|
13 |
*
|
|
14 |
* Description:
|
|
15 |
* Local Includes
|
|
16 |
*
|
|
17 |
*/
|
|
18 |
|
|
19 |
|
|
20 |
|
|
21 |
#include "assert.h"
|
|
22 |
#include "CSerialTransport.h"
|
|
23 |
|
|
24 |
/**************************************************************************************
|
|
25 |
*
|
|
26 |
* Definitions
|
|
27 |
*
|
|
28 |
*************************************************************************************/
|
|
29 |
_LIT(LDD_NAME,"ECOMM");
|
|
30 |
#ifdef __WINS__
|
|
31 |
_LIT(PDD_NAME,"ECDRV");
|
|
32 |
#else
|
|
33 |
_LIT(PDD_NAME,"EUART1");
|
|
34 |
#endif
|
|
35 |
|
|
36 |
#define KMaxTimeoutRetries (0x0FFFFFFF)
|
|
37 |
#define KWriteTimeout 50000000
|
|
38 |
|
|
39 |
/********************************************************************************
|
|
40 |
*
|
|
41 |
* Macro functions
|
|
42 |
*
|
|
43 |
********************************************************************************/
|
|
44 |
|
|
45 |
/**************************************************************************************
|
|
46 |
*
|
|
47 |
* CSerialTransport - Construction
|
|
48 |
*
|
|
49 |
*************************************************************************************/
|
|
50 |
CSerialTransport* CSerialTransport::NewL( TPtrC16 aModule )
|
|
51 |
{
|
|
52 |
CSerialTransport *self = new (ELeave) CSerialTransport();
|
|
53 |
CleanupStack::PushL(self);
|
|
54 |
self->ConstructL( aModule );
|
|
55 |
CleanupStack::Pop();
|
|
56 |
return self;
|
|
57 |
}
|
|
58 |
|
|
59 |
CSerialTransport::CSerialTransport()
|
|
60 |
{
|
|
61 |
}
|
|
62 |
|
|
63 |
CSerialTransport::~CSerialTransport()
|
|
64 |
{
|
|
65 |
iCommPort.Close();
|
|
66 |
iCommServer.Close();
|
|
67 |
}
|
|
68 |
|
|
69 |
void CSerialTransport::ConstructL( TPtrC16 aModule )
|
|
70 |
{
|
|
71 |
// set parameters
|
|
72 |
assert( aModule.Length() <= KModuleSize );
|
|
73 |
iModule.Copy( aModule );
|
|
74 |
iSerialStatus = EIdle;
|
|
75 |
iRetries = 0;
|
|
76 |
iCommPortOpen = 0;
|
|
77 |
iCommOldSettingsValid = 0;
|
|
78 |
}
|
|
79 |
|
|
80 |
/**************************************************************************************
|
|
81 |
*
|
|
82 |
* CSerialTransport - Initialise and Release
|
|
83 |
*
|
|
84 |
*************************************************************************************/
|
|
85 |
TInt CSerialTransport::InitialiseL()
|
|
86 |
{
|
|
87 |
TInt r;
|
|
88 |
|
|
89 |
// set the state
|
|
90 |
SetStatus( EInitialising );
|
|
91 |
|
|
92 |
// Under WINS we must force a link to the file server so that we're sure we'll be
|
|
93 |
// able to load the device drivers. On a MARM implementation, this code would not
|
|
94 |
// be required because higher level components (EIKON) will automatically have started
|
|
95 |
// the services. NOTE: this is now no longer required since we are an app and so even
|
|
96 |
// on WINS everything else should have started up by now.
|
|
97 |
|
|
98 |
// Load up the physical and the logical device drivers. If they are already loaded
|
|
99 |
// then it won't make any difference.
|
|
100 |
r = User::LoadPhysicalDevice( PDD_NAME );
|
|
101 |
if( (r != KErrNone) && (r != KErrAlreadyExists) ) {
|
|
102 |
User::Leave( r );
|
|
103 |
}
|
|
104 |
r = User::LoadLogicalDevice( LDD_NAME );
|
|
105 |
if( (r != KErrNone) && (r != KErrAlreadyExists) ) {
|
|
106 |
User::Leave( r );
|
|
107 |
}
|
|
108 |
|
|
109 |
// Both WINS and EIKON will have started the comms server process.
|
|
110 |
// (this is only really needed for ARM hardware development racks)
|
|
111 |
#ifndef __WINS__
|
|
112 |
r = StartC32();
|
|
113 |
if( (r != KErrNone) && (r != KErrAlreadyExists) )
|
|
114 |
User::Leave( r );
|
|
115 |
#endif
|
|
116 |
|
|
117 |
// Now connect to the comm server
|
|
118 |
User::LeaveIfError( iCommServer.Connect() );
|
|
119 |
|
|
120 |
// Load the CSY module
|
|
121 |
r = iCommServer.LoadCommModule( iModule );
|
|
122 |
User::LeaveIfError( r );
|
|
123 |
|
|
124 |
// check we loaded correctly
|
|
125 |
TInt numPorts;
|
|
126 |
r = iCommServer.NumPorts( numPorts );
|
|
127 |
User::LeaveIfError( r );
|
|
128 |
|
|
129 |
// set the state
|
|
130 |
SetStatus( EInitialised );
|
|
131 |
return KErrNone;
|
|
132 |
}
|
|
133 |
|
|
134 |
TInt CSerialTransport::Release(void)
|
|
135 |
{
|
|
136 |
// make sure the status is as expected
|
|
137 |
assert( (iSerialStatus == EInitialising) || (iSerialStatus == EInitialised) || (iSerialStatus == EDisconnected) );
|
|
138 |
SetStatus( EReleasing );
|
|
139 |
|
|
140 |
// disconnect from the comms server
|
|
141 |
iCommServer.Close();
|
|
142 |
|
|
143 |
// update state and finish
|
|
144 |
SetStatus( EIdle );
|
|
145 |
return KErrNone;
|
|
146 |
}
|
|
147 |
|
|
148 |
/**************************************************************************************
|
|
149 |
*
|
|
150 |
* CSerialTransport - Connect and Close
|
|
151 |
*
|
|
152 |
*************************************************************************************/
|
|
153 |
static int atoi( const short *str )
|
|
154 |
{
|
|
155 |
int ret = 0;
|
|
156 |
for( int i = 0; str[i] != NULL; i++ ) {
|
|
157 |
ret *= 10;
|
|
158 |
ret += str[i] - '0';
|
|
159 |
}
|
|
160 |
return ret;
|
|
161 |
}
|
|
162 |
|
|
163 |
void CSerialTransport::ExtractOptions( TDesC *aRemoteHost, TInt& aPortNumber, TInt& aBaudCap, TBps& aBaudRate )
|
|
164 |
{
|
|
165 |
TInt baud;
|
|
166 |
short *delim;
|
|
167 |
|
|
168 |
// get the character array for the remote host (note that this is in unicode)
|
|
169 |
short *opt = (short*)aRemoteHost->Ptr();
|
|
170 |
|
|
171 |
// extract the portnumber
|
|
172 |
aPortNumber = opt[0] - '0';
|
|
173 |
|
|
174 |
// make sure the next char is a delimiter
|
|
175 |
assert( opt[1] == OPT_DELIMITER );
|
|
176 |
|
|
177 |
// now search for the next delimiter and NULL it
|
|
178 |
for( delim = &opt[2]; (*delim != NULL) && (*delim != OPT_DELIMITER); delim++ )
|
|
179 |
;
|
|
180 |
|
|
181 |
// if this is a delim then NULL it
|
|
182 |
if( *delim == OPT_DELIMITER ) {
|
|
183 |
*delim = NULL;
|
|
184 |
}
|
|
185 |
|
|
186 |
// extract the baud -- and set the correct constants for the given baud
|
|
187 |
baud = atoi( &(opt[2]) );
|
|
188 |
switch( baud ) {
|
|
189 |
case 115200:
|
|
190 |
aBaudRate = EBps115200;
|
|
191 |
aBaudCap = KCapsBps115200;
|
|
192 |
break;
|
|
193 |
case 38400:
|
|
194 |
aBaudRate = EBps38400;
|
|
195 |
aBaudCap = KCapsBps38400;
|
|
196 |
break;
|
|
197 |
case 19200:
|
|
198 |
aBaudRate = EBps19200;
|
|
199 |
aBaudCap = KCapsBps19200;
|
|
200 |
break;
|
|
201 |
case 9600:
|
|
202 |
aBaudRate = EBps9600;
|
|
203 |
aBaudCap = KCapsBps9600;
|
|
204 |
break;
|
|
205 |
default:
|
|
206 |
assert( !"Unsupported baud rate" );
|
|
207 |
break;
|
|
208 |
}
|
|
209 |
}
|
|
210 |
|
|
211 |
TInt CSerialTransport::ConnectL( TDesC *aRemoteHost )
|
|
212 |
{
|
|
213 |
TInt portNumber;
|
|
214 |
TInt baudCap;
|
|
215 |
TBps baudRate;
|
|
216 |
|
|
217 |
TBuf8<1> iDummyBuffer;
|
|
218 |
|
|
219 |
// verify state
|
|
220 |
assert( iSerialStatus == EInitialised );
|
|
221 |
SetStatus( EConnecting );
|
|
222 |
|
|
223 |
// extract the options from the string
|
|
224 |
ExtractOptions( aRemoteHost, portNumber, baudCap, baudRate );
|
|
225 |
|
|
226 |
// construct the address -- aRemoteHost should provide the COM port number
|
|
227 |
TBuf16<KMaxPortName + 4> portName;
|
|
228 |
portName.Num( portNumber );
|
|
229 |
portName.Insert( 0, _L("::") );
|
|
230 |
if( iModule == _L("IrCOMM") )
|
|
231 |
portName.Insert( 0, _L("IrCOMM") );
|
|
232 |
else if( iModule == _L("ECUART") )
|
|
233 |
portName.Insert( 0, _L("COMM") );
|
|
234 |
|
|
235 |
// open the serial port
|
|
236 |
TInt r = iCommPort.Open( iCommServer, portName, ECommExclusive );
|
|
237 |
User::LeaveIfError( r );
|
|
238 |
iCommPortOpen = 1;
|
|
239 |
|
|
240 |
// check our configuration is supported
|
|
241 |
TCommCaps ourCapabilities;
|
|
242 |
iCommPort.Caps( ourCapabilities );
|
|
243 |
if (((ourCapabilities ().iRate & baudCap) == 0) ||
|
|
244 |
((ourCapabilities ().iDataBits & KCapsData8) == 0) ||
|
|
245 |
((ourCapabilities ().iStopBits & KCapsStop1) == 0) ||
|
|
246 |
((ourCapabilities ().iParity & KCapsParityNone) == 0))
|
|
247 |
{
|
|
248 |
User::Leave( KErrNotSupported );
|
|
249 |
}
|
|
250 |
|
|
251 |
|
|
252 |
// save port settings for restoring later
|
|
253 |
iCommPort.Config( iOldPortSettings );
|
|
254 |
iCommOldSettingsValid = 1;
|
|
255 |
|
|
256 |
// set new port settings
|
|
257 |
iCommPort.Config( iPortSettings );
|
|
258 |
iPortSettings().iRate = baudRate;
|
|
259 |
iPortSettings().iParity = EParityNone;
|
|
260 |
iPortSettings().iDataBits = EData8;
|
|
261 |
iPortSettings().iStopBits = EStop1;
|
|
262 |
iPortSettings().iFifo = EFifoEnable;
|
|
263 |
iPortSettings().iHandshake = KConfigObeyCTS;
|
|
264 |
iPortSettings().iTerminatorCount = 0;
|
|
265 |
|
|
266 |
// cancel any pending reads / writes to be safe and set the config
|
|
267 |
iCommPort.Cancel();
|
|
268 |
r = iCommPort.SetConfig( iPortSettings );
|
|
269 |
if( r != KErrNone ) {
|
|
270 |
User::Leave(r);
|
|
271 |
}
|
|
272 |
|
|
273 |
// set the receive buffer length then check it did it ok
|
|
274 |
iCommPort.SetReceiveBufferLength( 2*KMaxPacketSize );
|
|
275 |
if( iCommPort.ReceiveBufferLength() != 2*KMaxPacketSize ) {
|
|
276 |
User::Leave( KErrTooBig );
|
|
277 |
}
|
|
278 |
|
|
279 |
// power up the serial port by doing a null read on the port
|
|
280 |
if( iModule != _L("IrCOMM") ) {
|
|
281 |
iCommPort.Read(iStatus, iDummyBuffer,0);
|
|
282 |
User::WaitForRequest(iStatus);
|
|
283 |
if(iStatus.Int() != KErrNone){
|
|
284 |
Disconnect();
|
|
285 |
Release();
|
|
286 |
User::Leave(iStatus.Int());
|
|
287 |
|
|
288 |
}
|
|
289 |
} else {
|
|
290 |
iCommPort.Write(iStatus, iDummyBuffer,0);
|
|
291 |
User::WaitForRequest(iStatus);
|
|
292 |
if(iStatus.Int() != KErrNone){
|
|
293 |
Disconnect();
|
|
294 |
Release();
|
|
295 |
User::Leave(iStatus.Int());
|
|
296 |
|
|
297 |
}
|
|
298 |
}
|
|
299 |
|
|
300 |
SetStatus(EConnected);
|
|
301 |
return KErrNone;
|
|
302 |
}
|
|
303 |
|
|
304 |
TInt CSerialTransport::Disconnect(void)
|
|
305 |
{
|
|
306 |
// verify the status
|
|
307 |
assert( (iSerialStatus == EConnected) || (iSerialStatus == EConnecting) );
|
|
308 |
SetStatus( EDisconnecting );
|
|
309 |
|
|
310 |
// clean up the port
|
|
311 |
if( iCommPortOpen )
|
|
312 |
iCommPort.Cancel();
|
|
313 |
if( iCommOldSettingsValid )
|
|
314 |
iCommPort.SetConfig( iOldPortSettings );
|
|
315 |
if( iCommPortOpen )
|
|
316 |
iCommPort.Close();
|
|
317 |
iCommPortOpen = 0;
|
|
318 |
iCommOldSettingsValid = 0;
|
|
319 |
|
|
320 |
// done
|
|
321 |
SetStatus( EDisconnected );
|
|
322 |
return KErrNone;
|
|
323 |
}
|
|
324 |
|
|
325 |
/**************************************************************************************
|
|
326 |
*
|
|
327 |
* CSerialTransport - Receive and Send. The ID / Length / Data nonsense
|
|
328 |
* is handled by the packetisation layer. All serial has to do here is send data --
|
|
329 |
* serial is also assuming that the upper layer will keep the data until the response
|
|
330 |
*
|
|
331 |
*************************************************************************************/
|
|
332 |
TInt CSerialTransport::RequestSend( TDesC8 *aData, const TUint aDataLength )
|
|
333 |
{
|
|
334 |
|
|
335 |
// make sure we are in the appropriate state
|
|
336 |
assert( iSerialStatus == EConnected );
|
|
337 |
|
|
338 |
// do the send
|
|
339 |
assert( (unsigned)aData->Length() == aDataLength );
|
|
340 |
iCommPort.Write( iStatus, (*aData), aDataLength );
|
|
341 |
User::WaitForRequest(iStatus);
|
|
342 |
return iStatus.Int();
|
|
343 |
}
|
|
344 |
|
|
345 |
TInt CSerialTransport::RequestReceive( TPtr8 *recvBufferPtr,TUint aByteCount )
|
|
346 |
{
|
|
347 |
// make sure we are in the appropriate state
|
|
348 |
assert( iSerialStatus == EConnected );
|
|
349 |
|
|
350 |
// allocate a buffer for the read
|
|
351 |
assert( aByteCount <= KMaxPacketSize );
|
|
352 |
recvBufferPtr->SetLength( 0 );
|
|
353 |
iCommPort.ReadCancel();
|
|
354 |
iCommPort.Read( iStatus, *recvBufferPtr, aByteCount );
|
|
355 |
User::WaitForRequest(iStatus);
|
|
356 |
return iStatus.Int();
|
|
357 |
}
|
|
358 |
|
|
359 |
TText8 *CSerialTransport::Error( void )
|
|
360 |
{
|
|
361 |
return NULL;
|
|
362 |
}
|
|
363 |
|
|
364 |
/**************************************************************************************
|
|
365 |
*
|
|
366 |
* CSerialTransport - Private Functions
|
|
367 |
*
|
|
368 |
*************************************************************************************/
|
|
369 |
void CSerialTransport::SetStatus( TCommStatus aNewStatus )
|
|
370 |
{
|
|
371 |
iSerialStatus = aNewStatus;
|
|
372 |
}
|