diff -r 000000000000 -r 7f656887cf89 plugins/consoles/vt100cons/src/serial/vtc_serial.cpp --- /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 +#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(); + }