glassterm.cpp
来自「symbian 操作系统下的如何进行串口编程」· C++ 代码 · 共 402 行
CPP
402 行
// GlassTerm.CPP
//
// Copyright (c) 1999 Symbian Ltd. All rights reserved.
//
// Purpose: Glass Term : read/Write from keyboard/serial port : example code for SDK
// This uses the first serial port on the system, and offers a choice between different
// handshaking modes. All control characters apart from carriage returns and line feeds are
// displayed on the screen with ^ carets in from of the the ASCII equivalent (so tab = ^I)
// The ESC key is used to end the program
// Note :
// In order for this program to do anything, the serial port should be connected to something.
// A modem is of course quite suitable. In the absence of a modem, a loopback plug with the
// receive and transmit lines connected will echo all serial port output to the screen. In
// the absence of a loopback plug, a bent paper clip or somethings similar connecting pins 2 and 3
// on any 25 or 9 way serial connector will do exactly the same thing. This last suggestion
// is something that is carried out entirely at your own risk, and you should be very careful
// neither to connect any other pins by mistake nor to push the paper clip in too far !
// If using the bent paper clip, you'll find that in order for the hardware handshaking option
// to work, a second bent paper clip connecting pins 4 and 5 on a 25-way connector or pin 7 and 8
// on a 9-way connector will also be needed - this second paper clip is needed to connect RTS to CTS
// Note: this sample program now shows how to support infra-red as well
// as RS232 and also systems with multiple serial ports and multiple
// possible CSYs.
#include <e32base.h>
#include <e32test.h>
#include <e32svr.h>
#include <c32comm.h>
#include <f32file.h>
#include "CommonFiles.h"
// first define our device driver names
_LIT(LDD_NAME,"ECOMM");
#if defined (__WINS__)
_LIT(PDD_NAME,"ECDRV");
#else
_LIT(PDD_NAME,"EUART1");
#endif
// next define an arbitrary buffer size and tenth of a second in microseconds
const TInt KBufSize (512);
const TInt KTenthSecond (100000);
// short literals for use in doExampleL() declared at file scope
_LIT(KMessage2,"%c\n");
_LIT(KMessage14,"^%c");
_LIT(KMessage15,"%c");
_LIT(KColons,"::");
// utility function to print received text
void printReceivedText(TDes8& localInputBuffer,TInt numberRead);
LOCAL_C void doExampleL ()
{
_LIT(KMessage0,"Select S for RS232 Serial or R for InfraRed port : ");
_LIT(KMessage1,"Select 0 for no handshaking, 1 for CTS/RTS and 2 for XON/XOFF :");
_LIT(KMessage4,"Loading device drivers\n");
_LIT(KMessage5,"Starting comms server\n");
_LIT(KMessage6,"Connecting to comms server\n");
_LIT(KMessage7,"Loading %S.CSY module\n");
_LIT(KMessage8,"%S has %S available as %S::%u to %S::%u\n");
_LIT(KMessage9,"Opened %S\n");
_LIT(KMessage10,"Configuring Serial port for 19200 bps 8 bits no parity 1 stop\n");
_LIT(KMessage11,"Powering up port\n");
_LIT(KMessage12,"\nDisconnecting\n");
_LIT(KMessage13,"\nWrite Failed %d\n");
_LIT(KMessage16,"\nRead failed %d\n");
_LIT(KMessage17,"Closed %S\n");
_LIT(KMessage18,"Closing server connection\n");
_LIT(KMessage19,"Comms server reports we have %u comms modules loaded\n");
_LIT(KMessage20,"Using the lowest %S out of %S::%u to %S::%u\n");
_LIT(KPanic,"StraySignal");
_LIT(RS232,"ECUART");
_LIT(IRCOMM,"IRCOMM");
TBuf16 < 6 > csyName;
TUint8 csyMode;
const TUint8 mask=0xdf; // this mask 0xdf turns lower to upper case
console->Printf (KMessage0);
do
csyMode = STATIC_CAST(TUint8,console->Getch () & mask);
while ((csyMode < 'R') || (csyMode > 'S'));
console->Printf (KMessage2, csyMode);
if (csyMode=='S')
csyName.Copy(RS232);
else
csyName.Copy(IRCOMM);
TKeyCode handshakingMode;
console->Printf (KMessage1);
do
handshakingMode = console->Getch ();
while ((handshakingMode < '0') || (handshakingMode > '2'));
console->Printf (KMessage2, handshakingMode);
// Under WINS we must force a link to the file server
// so that we're sure we'll be able to load the device drivers.
// On a MARM implementation, this code would not
// be required because higher level components
// will automatically have started the services.
#if defined (__WINS__)
_LIT(KMessage3,"Connect to file server\n");
console->Printf (KMessage3);
RFs fileServer;
User::LeaveIfError (fileServer.Connect ());
fileServer.Close ();
#endif
// Load the physical and logical device drivers
// Symbian OS will automatically append .PDD and .LDD and
// search /System/Libs on all drives starting from C:
// If EIKON has done this, they'll already exist -
// no harm will have been done
console->Printf (KMessage4);
TInt r = User::LoadPhysicalDevice (PDD_NAME);
if (r != KErrNone && r != KErrAlreadyExists)
User::Leave (r);
r = User::LoadLogicalDevice (LDD_NAME);
if (r != KErrNone && r != KErrAlreadyExists)
User::Leave (r);
// Both WINS and EIKON will have started the comms server process.
// (this is only really needed for ARM hardware development racks)
#if !defined (__WINS__)
console->Printf (KMessage5);
r = StartC32 ();
if (r != KErrNone && r != KErrAlreadyExists)
User::Leave (r);
#endif
// Now (at last) we can actually connect to the comm server
console->Printf (KMessage6);
RCommServ server;
User::LeaveIfError (server.Connect ());
// Load the CSY module
// Symbian OS will automatically search \System\Libs
// on all drives starting from C:
console->Printf (KMessage7,&csyName);
r = server.LoadCommModule (csyName);
User::LeaveIfError (r);
// if we know our machine architecture we can just go ahead and open (say) COMM::0
// however, for machine independence we are better off looking up that information
// the oddly-named NumPorts function actually tells us how many CSYs are loaded
// this isn't 0 since we've just loaded one ...
TInt numPorts;
r = server.NumPorts (numPorts);
User::LeaveIfError (r);
console->Printf (KMessage19,numPorts);
// we can get port information for each loaded CSY in turn (note we
// index them from 0) - we can find out the number of ports supported
// together with their names, and their description. The information is
// returned in a TSerialInfo structure together with the name of the
// CSY that we've indexed
TSerialInfo portInfo;
TBuf16 < 12 > moduleName;
for (TInt index=0 ; index < numPorts ; index++)
{
r = server.GetPortInfo (index, moduleName, portInfo);
User::LeaveIfError (r);
console->Printf (KMessage8,
&moduleName,
&portInfo.iDescription,
&portInfo.iName,
portInfo.iLowUnit,
&portInfo.iName,
portInfo.iHighUnit);
}
// However, we are really only interested in using the CSY that we've
// just loaded up ourselves. We could find out its portInfo by
// comparing the moduleName returned by the version of GetPortInfo we
// just used to the name of the CSY we loaded, but there's a better
// version of GetPortInfo we can use, which just takes the name of a CSY
// as a parameter. We'd expect to find this informtion is an exact
// duplicate of the indexed portInfo for the last loaded CSY
// Our example code will use the lowest possible port (why not?)
r = server.GetPortInfo (csyName, portInfo);
console->Printf (KMessage20,
&portInfo.iDescription,
&portInfo.iName,
portInfo.iLowUnit,
&portInfo.iName,
portInfo.iHighUnit);
// Now let's use a few Symbian OS functions to construct a descriptor for the
// name of the lowest port our CSY supports -
// The name can can be as long as a TSerialInfo.iName plus a
// couple of colons and digits
TBuf16 < KMaxPortName + 4 > portName; // declare an empty descriptor buffer
portName.Num (portInfo.iLowUnit); // put in the port number in ASCII
portName.Insert (0, KColons); // stick in a couple of colons
portName.Insert (0, portInfo.iName); // and lead off with the iName
// and at last we can open the first serial port,which we do here in exclusive mode
RComm commPort;
console->Printf (KMessage9, &portName);
r = commPort.Open (server, portName, ECommExclusive);
User::LeaveIfError (r);
// Now we can configure our serial port
// we want to run it at 19200 bps 8 bits no parity (why not?)
// so maybe we ought to get of its capabilities and check it can
// do what we want before going ahead
TCommCaps ourCapabilities;
commPort.Caps (ourCapabilities);
if (((ourCapabilities ().iRate & KCapsBps19200) == 0) ||
((ourCapabilities ().iDataBits & KCapsData8) == 0) ||
((ourCapabilities ().iStopBits & KCapsStop1) == 0) ||
((ourCapabilities ().iParity & KCapsParityNone) == 0))
User::Leave (KErrNotSupported);
console->Printf (KMessage10);
TCommConfig portSettings;
commPort.Config (portSettings);
portSettings ().iRate = EBps19200;
portSettings ().iParity = EParityNone;
portSettings ().iDataBits = EData8;
portSettings ().iStopBits = EStop1;
// as well as the physical characteristics, we need to set various logical ones
// to do with handshaking, behaviour of reads and writes and so so
portSettings ().iFifo = EFifoEnable;
if (handshakingMode == '2')
portSettings ().iHandshake = (KConfigObeyXoff | KConfigSendXoff); // for xon/xoff
else if (handshakingMode == '1')
portSettings ().iHandshake = (KConfigObeyCTS | KConfigFreeRTS); // for cts/rts
else
portSettings ().iHandshake = KConfigFailDSR; // for no handshaking
portSettings ().iTerminator[0] = 10;
portSettings ().iTerminatorCount = 1; // so that we terminate a read on each line feed arrives
r = commPort.SetConfig (portSettings);
User::LeaveIfError (r);
// now turn on DTR and RTS, and set our buffer size
commPort.SetSignals (KSignalDTR, 0);
commPort.SetSignals (KSignalRTS, 0);
TInt curlenth = commPort.ReceiveBufferLength ();
commPort.SetReceiveBufferLength (4096);
curlenth = commPort.ReceiveBufferLength ();
// now we can start using the port
TKeyCode key;
TPtrC8 outputByte ((TUint8 *) & key, 1);
TBuf8 < KBufSize > localInputBuffer;
TRequestStatus readStat, keyStat;
// a null read or write powers up the port
console->Printf (KMessage11);
commPort.Read (readStat, localInputBuffer, 0);
User::WaitForRequest(readStat);
r = readStat.Int ();
User::LeaveIfError (r);
// now the main glass terminal
// this could be either an active object
// or, as in this case, an asynchronous loop
// note that we use Read() with a timeout - we have configured the port so that
// line feeds trigger early completion of reads, which optimizes text based reception.
// if we'd used the request commPort.ReadOneOrMore (readStat, localInputBuffer) we
// could well have ended up calling the server once per character (up to 2000 times
// per second!) so a regular re-issuing of the read request 10 times per second is no
// big deal (to retain echoing of keyboard characters)
console->Read (keyStat);
commPort.Read (readStat, KTenthSecond, localInputBuffer);
for (;;)
{
User::WaitForRequest (readStat, keyStat);
// From keyboard
if (keyStat != KRequestPending)
{
key = console->KeyCode ();
if (key == 0x1b) // ESCAPE - Disconnect
{
console->Printf (KMessage12);
commPort.ReadCancel (); // Cancel Read
User::WaitForRequest (readStat);
break;
}
if (key < 256) // ASCII - Write to serial port
{
TRequestStatus stat;
commPort.Write (stat, outputByte);
User::WaitForRequest (stat);
r = stat.Int ();
if (r != KErrNone) // Write has failed for some reason
console->Printf (KMessage13, r);
}
console->Read (keyStat); // When complete, read again
}
// From serial port - we display printable characters, line feeds and carriage returns
// but control characters are displayed as a caret ^ followed by the printable equivalent
// timeout errors are OK here, but we do need to check that there really is data in the
// buffer before printing it to the screen as we might have timed out with no data
else if (readStat != KRequestPending)
{
if (readStat == KErrNone || readStat == KErrTimedOut)
{
// check descriptor and print any characters
TInt numberRead = localInputBuffer.Length ();
if (numberRead != 0)
printReceivedText(localInputBuffer,numberRead);
else
// else check the input buffer and print any characters
{
numberRead = commPort.QueryReceiveBuffer();
if (numberRead != 0)
{
commPort.ReadOneOrMore(readStat, localInputBuffer);
User::WaitForRequest (readStat);
if (readStat == KErrNone) printReceivedText(localInputBuffer,numberRead);
}
}
}
else // An error occured on reading
console->Printf (KMessage16, readStat.Int ());
commPort.Read (readStat, KTenthSecond, localInputBuffer);
}
// help !! a request we can't cater for
else
{
User::Panic (KPanic, 0);
}
}
// Close port
commPort.Close ();
console->Printf (KMessage17, &portName);
console->Printf (KMessage18);
server.Close ();
}
void printReceivedText(TDes8& localInputBuffer,TInt numberRead)
{
TUint8 *nextByte = &localInputBuffer[0];
for (int i = 0; i < numberRead; i++, nextByte++)
{
if ((*nextByte < 32) && (*nextByte != 10) && (*nextByte != 13))
console->Printf (KMessage14, (*nextByte) + 64);
else
console->Printf (KMessage15, *nextByte);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?