examples/SerialComms/ServerClientSide/GlassTerm/GlassTerm.cpp

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         }

Generated by  doxygen 1.6.2