plugins/consoles/vt100cons/src/serial/vtc_serial.cpp
changeset 0 7f656887cf89
child 27 17e35ffe449b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/vt100cons/src/serial/vtc_serial.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,210 @@
+// vtc_serial.cpp
+// 
+// Copyright (c) 2007 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+// 
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+
+#include <fshell/common.mmh>
+#include "vtc_serial.h"
+
+const TInt KMaxWriteLength = 2 * 1024; // Some serial drivers fail with KErrNoMemory if writes are too big, so they have to be broken up.
+
+#define LEAVE_IF_ERROR_ALLOW_ALREADY_EXISTS(_x) { TInt _err = _x; if ((_err < 0) && (_err != KErrAlreadyExists)) { User::Leave(_err); } }
+
+EXPORT_C CVtcSerialConsole::CVtcSerialConsole()
+	{
+	}
+
+EXPORT_C CVtcSerialConsole::~CVtcSerialConsole()
+	{
+	iCommPort.Close();
+	iCommServ.Close();
+	}
+
+TInt CVtcSerialConsole::ReadConfig(const TDesC& aConfigDes, TPortConfig& aConfig)
+	{
+	_LIT(KKeywordPdd, "pdd");
+	_LIT(KKeywordLdd, "ldd");
+	_LIT(KKeywordCsy, "csy");
+	_LIT(KKeywordPort, "port");
+	_LIT(KKeywordRate, "rate");
+
+	TBool keywordFound(EFalse);
+	TLex lex(aConfigDes);
+	while (!lex.Eos())
+		{
+		TPtrC keyword;
+		TPtrC value;
+		TInt err = ReadKeywordValuePair(lex, keyword, value);
+		if (err != KErrNone)
+			{
+			break;
+			}
+
+		if (keyword == KKeywordPdd)
+			{
+			aConfig.iPdd.Set(value);
+			keywordFound = ETrue;
+			}
+		else if (keyword == KKeywordLdd)
+			{
+			aConfig.iLdd.Set(value);
+			keywordFound = ETrue;
+			}
+		else if (keyword == KKeywordCsy)
+			{
+			aConfig.iCsy.Set(value);
+			keywordFound = ETrue;
+			}
+		else if (keyword == KKeywordPort)
+			{
+			aConfig.iPort.Set(value);
+			keywordFound = ETrue;
+			}
+		else if (keyword == KKeywordRate)
+			{
+			TLex lex(value);
+			TUint rate;
+			if (lex.Val(rate) == KErrNone)
+				{
+				switch (rate)
+					{
+				case 115200:
+					aConfig.iRate = EBps115200; break;
+				case 9600:
+					aConfig.iRate = EBps9600; break;
+				case 19200:
+					aConfig.iRate = EBps19200; break;
+				case 57600:
+					aConfig.iRate = EBps57600; break;
+				default:
+					break;
+					}
+				}
+			keywordFound = ETrue;
+			}
+		}
+
+	if (!keywordFound)
+		{
+		// Treat unrecognised string as a port name (to preserve backwards compatibility with earlier releases).
+		aConfig.iPort.Set(aConfigDes);
+		}
+
+	return KErrNone;
+	}
+
+EXPORT_C void CVtcSerialConsole::ConstructL(const TDesC& aTitle)
+	{
+	TPortConfig portConfig;
+	User::LeaveIfError(ReadConfig(aTitle, portConfig));
+	if (portConfig.iPort.Length() == 0)
+		{
+		User::Leave(KErrArgument);
+		}
+	if (portConfig.iPdd.Length())
+		{
+		LEAVE_IF_ERROR_ALLOW_ALREADY_EXISTS(User::LoadPhysicalDevice(portConfig.iPdd));
+		}
+	else
+		{
+		// If not specified, assume they probably intended the standard ones (but don't error if they fail, since the user might actually know what they're doing
+#ifdef __WINS__
+		User::LoadPhysicalDevice(_L("ecdrv"));
+#else
+		User::LoadPhysicalDevice(_L("euart1"));
+#endif
+		}
+
+	if (portConfig.iLdd.Length())
+		{
+		LEAVE_IF_ERROR_ALLOW_ALREADY_EXISTS(User::LoadLogicalDevice(portConfig.iLdd));
+		}
+	else
+		{
+		User::LoadLogicalDevice(_L("ecomm"));
+		}
+
+	User::LeaveIfError(iCommServ.Connect());
+	if (portConfig.iCsy.Length())
+		{
+		LEAVE_IF_ERROR_ALLOW_ALREADY_EXISTS(iCommServ.LoadCommModule(portConfig.iCsy));
+		}
+	else
+		{
+		iCommServ.LoadCommModule(_L("ecuart"));
+		}
+	User::LeaveIfError(iCommPort.Open(iCommServ, portConfig.iPort, ECommExclusive));
+
+#ifdef __WINS__
+	// For BC reasons, we always set rate on WINS
+	if (portConfig.iRate == EBpsAutobaud) portConfig.iRate = EBps115200;
+#endif
+
+	if (portConfig.iRate != EBpsAutobaud)
+		{
+		TCommConfig cfg;
+		cfg().iRate = portConfig.iRate;
+		cfg().iDataBits = EData8;
+		cfg().iStopBits = EStop1;
+		cfg().iParity = EParityNone;
+		cfg().iHandshake = 0;
+		cfg().iParityError = KConfigParityErrorFail;
+		cfg().iFifo = EFifoEnable;
+		cfg().iSpecialRate = 0;
+		cfg().iTerminatorCount = 0;
+		cfg().iSIREnable = ESIRDisable;
+		User::LeaveIfError(iCommPort.SetConfig(cfg));
+		}
+	
+	User::LeaveIfError(iCommPort.ResetBuffers());
+	CVtcConsoleBase::ConstructL(aTitle);
+	}
+	
+EXPORT_C TInt CVtcSerialConsole::Output(const TDesC8& aDes)
+	{
+	TRequestStatus status;
+	TInt offset = 0;
+	TInt err = KErrNone;
+	while ((offset < aDes.Length()) && (err == KErrNone))
+		{
+		const TInt bytesToWrite = Min(aDes.Length() - offset, KMaxWriteLength);
+		do
+			{
+			iCommPort.Write(status, aDes.Mid(offset, bytesToWrite));
+			User::WaitForRequest(status);
+			err = status.Int();
+			if (err == KErrNone)
+				{
+				offset += bytesToWrite;
+				}
+			else if (err == KErrNoMemory)	// Necessary because of nasty behaviour in loopback.csy where it returns KErrNoMemory when its buffer is full, rather than simply delaying completion of the request until there is enough space.
+				{
+				User::After(200000);
+				}
+			}
+#ifdef FSHELL_PLATFORM_OPP // Temporary OPP specific change - the drivers for the mid-sized prototype currently complete requests with KErrAbort just before power management sends the device to sleep.
+		while ((err == KErrNoMemory) || (err == KErrAbort));
+#else
+		while (err == KErrNoMemory);
+#endif
+		}
+
+	return err;
+	}
+
+EXPORT_C void CVtcSerialConsole::Input(TDes8& aDes, TRequestStatus& aStatus)
+	{
+	iCommPort.ReadOneOrMore(aStatus, aDes);
+	}
+
+EXPORT_C void CVtcSerialConsole::CancelInput(TRequestStatus&)
+	{
+	iCommPort.ReadCancel();
+	}