examples/SerialComms/ServerClientSide/GlassTerm/GlassTerm.cpp

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

Generated by  doxygen 1.6.2