// FCATerm.CPP v0.1
// Really, really Beta version

// Purpose: FCATerm : read/Write from keyboard/serial port : example code from 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 <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(KMessageCaretC,"^%c");
_LIT(KMessageC,"%c");
_LIT(KColons,"::");
_LIT(KMessageRun,"rUN:");
_LIT(KMessageInt,"%i");
_LIT(KMessageStr,"%S");
_LIT(KMessage13,"\nWrite Failed %d\n");

// utility function to print received text
void out_byte(RComm commPort, int ikey)
{
	TRequestStatus stat;
	TKeyCode key=ikey;
	TPtrC8 outputByte ((TUint8 *) & key, 1);
	commPort.Write (stat, outputByte);
	User::WaitForRequest (stat);
}
TInt swapi(TInt aCommand)
	{
	TInt val=0;
	val= ((aCommand & 0xFF) <<24) | ((aCommand & 0xFF00) <<8) | ((aCommand & 0xFF0000) >>8) | ((aCommand & 0xFF000000)>>24);
	return val;
	}

TUint char8_to_TUint(char *p)
{
TUint		addr=0, addrx=0;
		for (int j = 0; j < 8; j++)
			{
			addr=addr*16;
			addrx=p[j];
			if(addrx>='a' && addrx<='f')	addrx=addrx-'a'+10;
			if(addrx>='A' && addrx<='F')	addrx=addrx-'A'+10;
			if(addrx>='0' && addrx<='9')	addrx=addrx-'0';
			addr=addr+addrx;
			}
return addr;
}

int printReceivedText(TDes8& localInputBuffer,TInt numberRead,
 char *command, int icommand, RDevice dev_read, RDevice dev_write,
 RComm commPort )
	{
	TBuf<256> textbuf;
	HBufC* data=HBufC::New(40);
	TPtr ptr=data->Des();
	TInt dira=0x50000000;
	static TUint must_echo=1;

	TUint8 *nextByte = &localInputBuffer[0];
	TInt addr, leng, tam;
	for (int i = 0; i < numberRead; i++, nextByte++)
		{
		// non-printable: print with KMessageCaretC format
		if ((*nextByte < 32) && (*nextByte != 10) && (*nextByte != 13))
			console->Printf (KMessageCaretC, (*nextByte) + 64);
		else
			{
			console->Printf (KMessageC, *nextByte);

			if(must_echo==1)	out_byte(commPort, *nextByte);	// echo

			command[icommand++]=*nextByte;
			if(*nextByte==10 || *nextByte==13)
				{
				console->Printf (KMessageC, '!');
				command[icommand]=0;
				console->Printf (KMessageRun);
				for (int j = 0; j < icommand; j++)
					console->Printf (KMessageC, command[j]);
				if(icommand<3 && command[0]=='A' && command[1]=='T' )
					{	// AT
					console->Printf (KMessageC, '1');
					out_byte(commPort, 0x0D);
					out_byte(commPort, 'O');
					out_byte(commPort, 'K');
					out_byte(commPort, 0x0D);
					return 0;
					}
				if(icommand<10 && command[0]=='A' && command[1]=='T'  && command[2]=='+'  && command[3]=='I'
				  && command[4]=='P'  && command[5]=='R' )
					{	// AT+IPR
					console->Printf (KMessageC, '2');
					out_byte(commPort, 0x0D);
					out_byte(commPort, 'O');
					out_byte(commPort, 'K');
					out_byte(commPort, 0x0D);
					return 0;
					}
				if(icommand<7 && command[0]=='A' && command[1]=='T'  && command[2]=='E' )
					{	// ATE. probably ATE0
					console->Printf (KMessageC, '3');
					out_byte(commPort, 0x0D);
					out_byte(commPort, 'O');
					out_byte(commPort, 'K');
					out_byte(commPort, 0x0D);
					must_echo=0;
					return 0;
					}
				if(icommand<8 && command[3]=='A' && command[4]=='T'  && command[5]=='E' )
					{	// ATxATE. probably ATE0
					console->Printf (KMessageC, '3');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					out_byte(commPort, 'O');
					out_byte(commPort, 'K');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					must_echo=0;
					return 0;
					}
				if(icommand<7 && command[2]=='A' && command[3]=='T'  && command[4]=='E' )
					{	// ATATE. probably ATE0
					console->Printf (KMessageC, '3');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					out_byte(commPort, 'O');
					out_byte(commPort, 'K');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					must_echo=0;
					return 0;
					}
				if(icommand<9 && command[4]=='G' && command[5]=='M'  && command[6]=='M' )
					{	// AT+CGMM	-> SX1
					console->Printf (KMessageC, ']');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					out_byte(commPort, 'S');
					out_byte(commPort, 'X');
					out_byte(commPort, '1');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					return 0;
					}
				if(icommand<9 && command[4]=='G' && command[5]=='M'  && command[6]=='R' )
					{	// AT+CGMR	-> 14
					console->Printf (KMessageC, '[');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					out_byte(commPort, '1');
					out_byte(commPort, '4');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					return 0;
					}
				if(icommand<9 && command[4]=='G' && command[5]=='M'  && command[6]=='I' )
					{	// AT+CGMI	-> SIEMENS
					console->Printf (KMessageC, '*');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					out_byte(commPort, 'S');
					out_byte(commPort, 'I');
					out_byte(commPort, 'E');
					out_byte(commPort, 'M');
					out_byte(commPort, 'E');
					out_byte(commPort, 'N');
					out_byte(commPort, 'S');
					out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
					return 0;
					}
				if(command[5] =='S' && (command[6]=='N' || command[6]=='n') )
					{	// AT+CGSN
					console->Printf (KMessageC, 'N');
					if(command[7]==':')	// AT+CGSN:50001D30,00000010 AT+CGSN:01234567,00000008
						{
						console->Printf (KMessageC, ':');
						addr=char8_to_TUint(&command[8]);
						console->Printf (KMessageInt, addr);

						leng=256;	// default, if missing parameter
						if(icommand>19 && command[16]==',')	// AT+CGSN:00000000,00000008 AT+CGSN:01234567,00000008
							{// AT+CGSN:50000200,00000010
							console->Printf (KMessageC, ',');
							leng=char8_to_TUint(&command[17]);
							console->Printf (KMessageC, '=');
							console->Printf (KMessageInt, leng);
							}
						addr=addr/4; addr=addr*4;	// never odd address
						leng=leng/4; leng=leng*4;	// never odd address

						out_byte(commPort, 0xA1);	// required by chaos. Expects 0xA1 in answer
						console->Printf (KMessageC, '!');
						if(addr==0)	{ addr=0x50000000; leng=8; }
						for (dira=addr; dira < addr+leng; dira+=4)
							{
							asm  ("MOV r7, %0" : : "r"(dira) : "r7" );
							dev_read.GetCaps((TDes8 &)ptr);
							// textbuf.Format(_L("x%i=%x %x %x %x "),0, ptr[0]%256, ptr[0]/256, ptr[1]%256, ptr[1]/256);
							// console->Printf ( textbuf );

							TInt o_bytes[8+1];
							o_bytes[0]=(ptr[0]%256)>>4;	if(o_bytes[0]>9) o_bytes[0]=o_bytes[0]+'A'-10; else o_bytes[0]+='0';
							o_bytes[1]=(ptr[0]%16 );	if(o_bytes[1]>9) o_bytes[1]=o_bytes[1]+'A'-10; else o_bytes[1]+='0';
							o_bytes[2]=(ptr[0]/256)>>4;	if(o_bytes[2]>9) o_bytes[2]=o_bytes[2]+'A'-10; else o_bytes[2]+='0';
							o_bytes[3]=((ptr[0]/256)%16);	if(o_bytes[3]>9) o_bytes[3]=o_bytes[3]+'A'-10; else o_bytes[3]+='0';
							o_bytes[4]=(ptr[1]%256)>>4;	if(o_bytes[4]>9) o_bytes[4]=o_bytes[4]+'A'-10; else o_bytes[4]+='0';
							o_bytes[5]=(ptr[1]%16 );	if(o_bytes[5]>9) o_bytes[5]=o_bytes[5]+'A'-10; else o_bytes[5]+='0';
							o_bytes[6]=(ptr[1]/256)>>4;	if(o_bytes[6]>9) o_bytes[6]=o_bytes[6]+'A'-10; else o_bytes[6]+='0';
							o_bytes[7]=((ptr[1]/256)%16);	if(o_bytes[7]>9) o_bytes[7]=o_bytes[7]+'A'-10; else o_bytes[7]+='0';
							for (int j = 0; j < 8; j++)
								{
								out_byte(commPort, o_bytes[j]);
								} // send 8 chars
							} // dump all addresses, until leng
						out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);

						} // command :
					if(command[7]=='*')	// AT+CGSN*800003FC,12345678
						{		// AT+CGSN:800003FC
						console->Printf (KMessageC, ':');
						addr=char8_to_TUint(&command[8]);
						addr=addr/4; addr=addr*4;	// never odd address
						console->Printf (KMessageInt, addr);

						out_byte(commPort, 0xA1);
						TInt iWrite=0;
						if(command[16]==',')	iWrite++;
						leng=(icommand+iWrite-17);
						if(addr==0)	addr=0x50000000;
						for (dira=addr; dira < addr+(leng/8); dira+=4)
							{
							tam=swapi(char8_to_TUint(&command[16+iWrite]));	iWrite+=8;
							console->Printf (KMessageInt, tam);
							asm  ("MOV r9, %0" : : "r"(tam) : "r9" );	// important: little-indian !!!!
							asm  ("MOV r7, %0" : : "r"(dira) : "r7" );
							dev_write.GetCaps((TDes8 &)ptr);
							}
						// I think no answer is expected
						out_byte(commPort, 0x0D); out_byte(commPort, 0x0A);
						} // command *
					} // command N
				icommand=0;
				}
			}
		}
	return icommand;
	}

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");
							  &moduleName,
							  &portInfo.iDescription,
							  &portInfo.iName,
							  portInfo.iLowUnit,
							  &portInfo.iName,
							  portInfo.iHighUnit);
	_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(KMessage0,"Select 3 for RS232 Serial or 2 for InfraRed port or 4 for USB: ");
	_LIT(KMessage1,"Select 0 for no handshaking, 1 for CTS/RTS and 2 for XON/XOFF :");
	_LIT(KMessage4,"L-dev ");
	_LIT(KMessage5,"S-c ");
	_LIT(KMessage6,"C-c ");
	_LIT(KMessage7,"L-%S.CSY/");
	_LIT(KMessage8,"A %S-%S %S::%u 2 %S::%u/");
	_LIT(KMessage9,"9 %S/");
	_LIT(KMessage10,"C/");
	_LIT(KMessage11,"P/");
	_LIT(KMessage12,"\nDisconnecting\n");
	_LIT(KMessage16,"R%d");
	_LIT(KMessage17,"Closed %S\n");
	_LIT(KMessage18,"Closing server connection\n");
	_LIT(KMessage19,"R-%u/");
	_LIT(KMessage20,"U-%S 2 %S::%u 2 %S::%u/");
	
	_LIT(KPanic,"StraySignal");
	_LIT(RS232,"ECUART");	// 	ECUART=-5
	_LIT(IRCOMM,"IRCOMM");
	_LIT(ECACM,"ECACM");	// BTCOMM	AMUX=-1	ECACM=-5	emux_k1=peta

/* read/write mem */
#define PDD_NAME1 _L("ECOMM")
#define PDD_NAME2 _L("EUART2")
#define PDD_NAME3 _L("EMUX_K1")

#define LDD_NAME_READ _L("PowerMeasLdd")
#define LDD_NAME_WRITE _L("edosyin")
	User::LoadPhysicalDevice (PDD_NAME1); // step 1 
	User::LoadPhysicalDevice (PDD_NAME2); // step 2 
	User::LoadPhysicalDevice (PDD_NAME3); // step 3 
	TInt r;
	r = User::LoadLogicalDevice (LDD_NAME_READ);
	r = User::LoadLogicalDevice (LDD_NAME_WRITE);
	RDevice dev_read, dev_write;
	r=dev_read.Open(_L("PowerMeas"),EOwnerProcess);
	r=dev_write.Open(_L("DosPlugInLdd"),EOwnerProcess);
	TBuf<256> textbuf;

	TInt dira=0x50000000;	// 86 00 00 EA

	HBufC* data=HBufC::New(40);
	TPtr ptr=data->Des();

	/* test read mem */
		asm  ("MOV r7, %0" : : "r"(dira) : "r7" );
		dev_read.GetCaps((TDes8 &)ptr);
		textbuf.Format(_L("x%i=%x %x %x %x "),0, ptr[0]%256, ptr[0]/256, ptr[1]%256, ptr[1]/256);
		console->Printf ( textbuf );
/*end read/write mem */

	TBuf16 < 8 > csyName;	// fca: extended to 8
	char command[200];
	int icommand=0;
	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 < 'A') || (csyMode > 'J'));
	console->Printf (KMessage2, csyMode);

	if (csyMode=='A')
		csyName.Copy(RS232);
	else if (csyMode=='G')
		csyName.Copy(ECACM);
	else
		csyName.Copy(IRCOMM);



	TKeyCode handshakingMode;
	console->Printf (KMessage1);
	do
		handshakingMode = console->Getch ();
	while ((handshakingMode < '0') || (handshakingMode > '2'));
	console->Printf (KMessage2, handshakingMode);

	// Load the physical and logical device drivers
	// EPOC32 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);
	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
	// EPOC/32 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 EPOC32 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

	console->Printf (KMessageC,'W');
	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
	console->Printf (KMessageC,'E');
	portName.Insert (0, portInfo.iName); // and lead off with the iName
	console->Printf (KMessageC,'Q');

	// and at last we can open the first serial port,which we do here in exclusive mode

	RComm commPort;
	console->Printf (KMessage9, &portName);
	console->Printf (KMessageC,'X');
	r = commPort.Open (server, portName, ECommExclusive);
	console->Printf (KMessageC,'Y');
	User::LeaveIfError (r);
	console->Printf (KMessageC,'Z');

	// 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;
	console->Printf (KMessageC,'x');
	commPort.Caps (ourCapabilities);
	console->Printf (KMessageC,'w');

	// fca: use higher available speed
	TUint supported=1;
	TUint speed=EBps9600;
	if (((ourCapabilities ().iRate & KCapsBps9600) != 0))
		speed=EBps9600;
	if (((ourCapabilities ().iRate & KCapsBps19200) != 0))
		speed=EBps19200;
	if (((ourCapabilities ().iRate & KCapsBps38400) != 0))
		speed=EBps38400;
	if (((ourCapabilities ().iRate & KCapsBps57600) != 0))
		speed=EBps57600;
	if (((ourCapabilities ().iRate & KCapsBps115200) != 0))
		speed=EBps115200;

	console->Printf (KMessageInt,ourCapabilities ().iRate);

	if (((ourCapabilities ().iDataBits & KCapsData8) == 0))
		{
		console->Printf (KMessageC,'y');
		supported=1;
		User::Leave (KErrNotSupported);
		}
	if (((ourCapabilities ().iStopBits & KCapsStop1) == 0))
		{
		console->Printf (KMessageC,'u');
		supported=1;
		User::Leave (KErrNotSupported);
		}
	if (((ourCapabilities ().iParity & KCapsParityNone) == 0))
		{
		console->Printf (KMessageC,'i');
		supported=1;
		User::Leave (KErrNotSupported);
		}
	console->Printf (KMessageC,'c');
	console->Printf (KMessage10);
	console->Printf (KMessageC,'b');

	TCommConfig portSettings;
	commPort.Config (portSettings);
	console->Printf (KMessageC,'n');
	if(supported==1)
		{
		portSettings ().iRate = speed;
		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
		}
	console->Printf (KMessageC,'m');
	r = commPort.SetConfig (portSettings);
	console->Printf (KMessageC,'g');
	User::LeaveIfError (r);

	// now turn on DTR and RTS, and set our buffer size
	console->Printf (KMessageC,'h');

	commPort.SetSignals (KSignalDTR, 0);
	commPort.SetSignals (KSignalRTS, 0);
	TInt curlenth = commPort.ReceiveBufferLength ();
	commPort.SetReceiveBufferLength (4096);
	curlenth = commPort.ReceiveBufferLength ();
	console->Printf (KMessageC,'i');

	// 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 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 ();	// only gets numbers, C , and trhough *

			if (key == '0' || key == '+')		 // # - 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->Printf (KMessageC, key);	// also print typed character
			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) 
					icommand=printReceivedText(localInputBuffer,numberRead, command, icommand, dev_read, dev_write, commPort);
				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)
							icommand=printReceivedText(localInputBuffer,numberRead, command, icommand, dev_read, dev_write, commPort);
						}
					}
				}
			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 ();
	}
