00001 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). 00002 // All rights reserved. 00003 // This component and the accompanying materials are made available 00004 // under the terms of "Eclipse Public License v1.0" 00005 // which accompanies this distribution, and is available 00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". 00007 // 00008 // Initial Contributors: 00009 // Nokia Corporation - initial contribution. 00010 // 00011 // Contributors: 00012 // 00013 // Description: 00014 // Purpose: Glass Term : read/Write from keyboard/serial port : example code for SDK 00015 // This uses the first serial port on the system, and offers a choice between different 00016 // handshaking modes. All control characters apart from carriage returns and line feeds are 00017 // displayed on the screen with ^ carets in from of the the ASCII equivalent (so tab = ^I) 00018 // The ESC key is used to end the program 00019 // Note : 00020 // In order for this program to do anything, the serial port should be connected to something. 00021 // A modem is of course quite suitable. In the absence of a modem, a loopback plug with the 00022 // receive and transmit lines connected will echo all serial port output to the screen. In 00023 // the absence of a loopback plug, a bent paper clip or somethings similar connecting pins 2 and 3 00024 // on any 25 or 9 way serial connector will do exactly the same thing. This last suggestion 00025 // is something that is carried out entirely at your own risk, and you should be very careful 00026 // neither to connect any other pins nor to push the paper clip in too far ! 00027 // If using the bent paper clip, you'll find that in order for the hardware handshaking option 00028 // to work, a second bent paper clip connecting pins 4 and 5 on a 25-way connector or pin 7 and 8 00029 // on a 9-way connector will also be needed - this second paper clip is needed to connect RTS to CTS 00030 // Note: this sample program now shows how to support infra-red as well 00031 // as RS232 and also systems with multiple serial ports and multiple 00032 // possible CSYs. 00033 // 00034 00035 #include <e32base.h> 00036 #include <e32test.h> 00037 #include <e32svr.h> 00038 #include <c32comm.h> 00039 #include <f32file.h> 00040 00041 #include "CommonFiles.h" 00042 00043 // first define our device driver names 00044 00045 _LIT(LDD_NAME,"ECOMM"); 00046 00047 #if defined (__WINS__) 00048 _LIT(PDD_NAME,"ECDRV"); 00049 #else 00050 _LIT(PDD_NAME,"EUART"); 00051 #endif 00052 00053 // next define an arbitrary buffer size and Hundred seconds in microseconds 00054 00055 const TInt KBufSize (512); 00056 const TInt KOneHundredSecond (100000000); 00057 00058 // short literals for use in doExampleL() declared at file scope 00059 _LIT(KMessage2,"%c\n"); 00060 _LIT(KMessage14,"^%c"); 00061 _LIT(KMessage15,"%c"); 00062 _LIT(KColons,"::"); 00063 00064 // utility function to print received text 00065 void printReceivedText(TDes8& localInputBuffer,TInt numberRead); 00066 00067 LOCAL_C void doExampleL () 00068 { 00069 _LIT(KMessage0,"Select S for RS232 Serial or R for InfraRed port : "); 00070 _LIT(KMessage1,"Select 0 for no handshaking, 1 for CTS/RTS and 2 for XON/XOFF :"); 00071 _LIT(KMessage4,"Loading device drivers\n"); 00072 _LIT(KMessage5,"Starting comms server\n"); 00073 _LIT(KMessage6,"Connecting to comms server\n"); 00074 _LIT(KMessage7,"Loading %S.CSY module\n"); 00075 _LIT(KMessage8,"%S has %S available as %S::%u to %S::%u\n"); 00076 _LIT(KMessage9,"Opened %S\n"); 00077 _LIT(KMessage10,"Configuring Serial port for 115200 bps 8 bits no parity 1 stop\n"); 00078 _LIT(KMessage11,"Powering up port\n"); 00079 _LIT(KMessage12,"\nDisconnecting\n"); 00080 _LIT(KMessage13,"\nWrite Failed %d\n"); 00081 _LIT(KMessage16,"\nRead failed %d\n"); 00082 _LIT(KMessage17,"Closed %S\n"); 00083 _LIT(KMessage18,"Closing server connection\n"); 00084 _LIT(KMessage19,"Comms server reports we have %u comms modules loaded\n"); 00085 _LIT(KMessage20,"Using the lowest %S out of %S::%u to %S::%u\n"); 00086 00087 _LIT(KPanic,"StraySignal"); 00088 _LIT(RS232,"ECUART"); 00089 _LIT(IRCOMM,"IRCOMM"); 00090 00091 TBuf16 < 6 > csyName; 00092 00093 TUint8 csyMode; 00094 const TUint8 mask=0xdf; // this mask 0xdf turns lower to upper case 00095 00096 console->Printf (KMessage0); 00097 do 00098 csyMode = STATIC_CAST(TUint8,console->Getch () & mask); 00099 while ((csyMode < 'R') || (csyMode > 'S')); 00100 console->Printf (KMessage2, csyMode); 00101 00102 if (csyMode=='S') 00103 csyName.Copy(RS232); 00104 else 00105 csyName.Copy(IRCOMM); 00106 00107 00108 00109 TKeyCode handshakingMode; 00110 console->Printf (KMessage1); 00111 do 00112 handshakingMode = console->Getch (); 00113 while ((handshakingMode < '0') || (handshakingMode > '2')); 00114 console->Printf (KMessage2, handshakingMode); 00115 00116 00117 // Under WINS we must force a link to the file server 00118 // so that we're sure we'll be able to load the device drivers. 00119 // On a MARM implementation, this code would not 00120 // be required because higher level components 00121 // will automatically have started the services. 00122 00123 #if defined (__WINS__) 00124 _LIT(KMessage3,"Connect to file server\n"); 00125 console->Printf (KMessage3); 00126 RFs fileServer; 00127 User::LeaveIfError (fileServer.Connect ()); 00128 fileServer.Close (); 00129 #endif 00130 00131 00132 // Load the physical and logical device drivers 00133 // The Symbian platform will automatically append .PDD and .LDD and 00134 // search /System/Libs on all drives starting from C: 00135 // If EIKON has done this, they'll already exist - 00136 // no harm will have been done 00137 00138 console->Printf (KMessage4); 00139 TInt r = User::LoadPhysicalDevice (PDD_NAME); 00140 if (r != KErrNone && r != KErrAlreadyExists) 00141 User::Leave (r); 00142 r = User::LoadLogicalDevice (LDD_NAME); 00143 if (r != KErrNone && r != KErrAlreadyExists) 00144 User::Leave (r); 00145 00146 // Both WINS and EIKON will have started the comms server process. 00147 // (this is only really needed for ARM hardware development racks) 00148 00149 #if !defined (__WINS__) 00150 console->Printf (KMessage5); 00151 r = StartC32 (); 00152 if (r != KErrNone && r != KErrAlreadyExists) 00153 User::Leave (r); 00154 #endif 00155 00156 // Now (at last) we can actually connect to the comm server 00157 00158 console->Printf (KMessage6); 00159 RCommServ server; 00160 User::LeaveIfError (server.Connect ()); 00161 00162 // Load the CSY module 00163 // The Symbian platform will automatically search \System\Libs 00164 // on all drives starting from C: 00165 00166 console->Printf (KMessage7,&csyName); 00167 r = server.LoadCommModule (csyName); 00168 User::LeaveIfError (r); 00169 00170 // if we know our machine architecture we can just go ahead and open (say) COMM::0 00171 // however, for machine independence we are better off looking up that information 00172 00173 // the oddly-named NumPorts function actually tells us how many CSYs are loaded 00174 // this isn't 0 since we've just loaded one ... 00175 00176 TInt numPorts; 00177 r = server.NumPorts (numPorts); 00178 User::LeaveIfError (r); 00179 console->Printf (KMessage19,numPorts); 00180 00181 // we can get port information for each loaded CSY in turn (note we 00182 // index them from 0) - we can find out the number of ports supported 00183 // together with their names, and their description. The information is 00184 // returned in a TSerialInfo structure together with the name of the 00185 // CSY that we've indexed 00186 00187 TSerialInfo portInfo; 00188 TBuf16 < 12 > moduleName; 00189 00190 for (TInt index=0 ; index < numPorts ; index++) 00191 { 00192 r = server.GetPortInfo (index, moduleName, portInfo); 00193 User::LeaveIfError (r); 00194 console->Printf (KMessage8, 00195 &moduleName, 00196 &portInfo.iDescription, 00197 &portInfo.iName, 00198 portInfo.iLowUnit, 00199 &portInfo.iName, 00200 portInfo.iHighUnit); 00201 } 00202 00203 // However, we are really only interested in using the CSY that we've 00204 // just loaded up ourselves. We could find out its portInfo by 00205 // comparing the moduleName returned by the version of GetPortInfo we 00206 // just used to the name of the CSY we loaded, but there's a better 00207 // version of GetPortInfo we can use, which just takes the name of a CSY 00208 // as a parameter. We'd expect to find this informtion is an exact 00209 // duplicate of the indexed portInfo for the last loaded CSY 00210 // Our example code will use the lowest possible port (why not?) 00211 00212 r = server.GetPortInfo (csyName, portInfo); 00213 console->Printf (KMessage20, 00214 &portInfo.iDescription, 00215 &portInfo.iName, 00216 portInfo.iLowUnit, 00217 &portInfo.iName, 00218 portInfo.iHighUnit); 00219 00220 // Now let's use a few Symbian platform functions to construct a descriptor for the 00221 // name of the lowest port our CSY supports - 00222 // The name can be as long as a TSerialInfo.iName plus a 00223 // couple of colons and digits 00224 00225 TBuf16 < KMaxPortName + 4 > portName; // declare an empty descriptor buffer 00226 portName.Num (portInfo.iLowUnit); // put in the port number in ASCII 00227 portName.Insert (0, KColons); // stick in a couple of colons 00228 portName.Insert (0, portInfo.iName); // and lead off with the iName 00229 00230 // and at last we can open the first serial port,which we do here in exclusive mode 00231 00232 RComm commPort; 00233 console->Printf (KMessage9, &portName); 00234 r = commPort.Open (server, portName, ECommExclusive); 00235 User::LeaveIfError (r); 00236 00237 // Now we can configure our serial port 00238 // we want to run it at 115200 bps 8 bits no parity (why not?) 00239 // so maybe we ought to get of its capabilities and check it can 00240 // do what we want before going ahead 00241 00242 TCommCaps ourCapabilities; 00243 commPort.Caps (ourCapabilities); 00244 00245 if (((ourCapabilities ().iRate & KCapsBps115200) == 0) || 00246 ((ourCapabilities ().iDataBits & KCapsData8) == 0) || 00247 ((ourCapabilities ().iStopBits & KCapsStop1) == 0) || 00248 ((ourCapabilities ().iParity & KCapsParityNone) == 0)) 00249 User::Leave (KErrNotSupported); 00250 00251 console->Printf (KMessage10); 00252 00253 TCommConfig portSettings; 00254 commPort.Config (portSettings); 00255 portSettings ().iRate = EBps115200; 00256 portSettings ().iParity = EParityNone; 00257 portSettings ().iDataBits = EData8; 00258 portSettings ().iStopBits = EStop1; 00259 00260 // as well as the physical characteristics, we need to set various logical ones 00261 // to do with handshaking, behaviour of reads and writes and so so 00262 00263 portSettings ().iFifo = EFifoEnable; 00264 if (handshakingMode == '2') 00265 portSettings ().iHandshake = (KConfigObeyXoff | KConfigSendXoff); // for xon/xoff 00266 else if (handshakingMode == '1') 00267 portSettings ().iHandshake = (KConfigObeyCTS | KConfigFreeRTS); // for cts/rts 00268 else 00269 portSettings ().iHandshake = KConfigFailDSR; // for no handshaking 00270 00271 portSettings ().iTerminator[0] = 10; 00272 portSettings ().iTerminatorCount = 1; // so that we terminate a read on each line feed arrives 00273 00274 r = commPort.SetConfig (portSettings); 00275 User::LeaveIfError (r); 00276 00277 // now turn on DTR and RTS, and set our buffer size 00278 00279 commPort.SetSignals (KSignalDTR, 0); 00280 commPort.SetSignals (KSignalRTS, 0); 00281 TInt curlenth = commPort.ReceiveBufferLength (); 00282 commPort.SetReceiveBufferLength (4096); 00283 curlenth = commPort.ReceiveBufferLength (); 00284 00285 // now we can start using the port 00286 00287 TKeyCode key; 00288 TPtrC8 outputByte ((TUint8 *) & key, 1); 00289 TBuf8 < KBufSize > localInputBuffer; 00290 TRequestStatus readStat, keyStat; 00291 00292 // a null read or write powers up the port 00293 00294 console->Printf (KMessage11); 00295 commPort.Read (readStat, localInputBuffer, 0); 00296 User::WaitForRequest(readStat); 00297 r = readStat.Int (); 00298 User::LeaveIfError (r); 00299 00300 // now the main glass terminal 00301 // this could be either an active object 00302 // or, as in this case, an asynchronous loop 00303 00304 // note that we use Read() with a timeout - we have configured the port so that 00305 // line feeds trigger early completion of reads, which optimizes text based reception. 00306 00307 // if we'd used the request commPort.ReadOneOrMore (readStat, localInputBuffer) we 00308 // could well have ended up calling the server once per character (up to 2000 times 00309 // per second!) so a regular re-issuing of the read request once in every 100 second is no 00310 // big deal (to retain echoing of keyboard characters) 00311 00312 00313 console->Read (keyStat); 00314 commPort.Read (readStat, KOneHundredSecond, localInputBuffer); 00315 for (;;) 00316 { 00317 User::WaitForRequest (readStat, keyStat); 00318 00319 // From keyboard 00320 00321 if (keyStat != KRequestPending) 00322 { 00323 key = console->KeyCode (); 00324 00325 if (key == 0x1b) // ESCAPE - Disconnect 00326 { 00327 console->Printf (KMessage12); 00328 commPort.ReadCancel (); // Cancel Read 00329 User::WaitForRequest (readStat); 00330 break; 00331 } 00332 00333 if (key < 256) // ASCII - Write to serial port 00334 { 00335 TRequestStatus stat; 00336 commPort.Write (stat, outputByte); 00337 User::WaitForRequest (stat); 00338 r = stat.Int (); 00339 if (r != KErrNone) // Write has failed for some reason 00340 console->Printf (KMessage13, r); 00341 } 00342 00343 console->Read (keyStat); // When complete, read again 00344 } 00345 00346 // From serial port - we display printable characters, line feeds and carriage returns 00347 // but control characters are displayed as a caret ^ followed by the printable equivalent 00348 00349 // timeout errors are OK here, but we do need to check that there really is data in the 00350 // buffer before printing it to the screen as we might have timed out with no data 00351 00352 else if (readStat != KRequestPending) 00353 { 00354 if (readStat == KErrNone || readStat == KErrTimedOut) 00355 { 00356 // check descriptor and print any characters 00357 TInt numberRead = localInputBuffer.Length (); 00358 if (numberRead != 0) 00359 printReceivedText(localInputBuffer,numberRead); 00360 else 00361 // else check the input buffer and print any characters 00362 { 00363 numberRead = commPort.QueryReceiveBuffer(); 00364 if (numberRead != 0) 00365 { 00366 commPort.ReadOneOrMore(readStat, localInputBuffer); 00367 User::WaitForRequest (readStat); 00368 if (readStat == KErrNone) printReceivedText(localInputBuffer,numberRead); 00369 } 00370 } 00371 } 00372 else // An error occured on reading 00373 console->Printf (KMessage16, readStat.Int ()); 00374 commPort.Read (readStat, KOneHundredSecond, localInputBuffer); 00375 } 00376 00377 // help !! a request we can't cater for 00378 00379 else 00380 { 00381 User::Panic (KPanic, 0); 00382 } 00383 00384 } 00385 00386 // Close port 00387 00388 commPort.Close (); 00389 console->Printf (KMessage17, &portName); 00390 console->Printf (KMessage18); 00391 server.Close (); 00392 } 00393 00394 void printReceivedText(TDes8& localInputBuffer,TInt numberRead) 00395 { 00396 TUint8 *nextByte = &localInputBuffer[0]; 00397 for (int i = 0; i < numberRead; i++, nextByte++) 00398 { 00399 if ((*nextByte < 32) && (*nextByte != 10) && (*nextByte != 13)) 00400 console->Printf (KMessage14, (*nextByte) + 64); 00401 else 00402 console->Printf (KMessage15, *nextByte); 00403 } 00404 }
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.