Implemented RObjectIx-based memoryaccess APIs.
Upshot is that objinfo now works again on platforms that define FSHELL_NO_DOBJECTIX_SUPPORT.
// 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 ErrOrDebug(err) (((err) < 0 && (err) != KErrAlreadyExists) ? EError : EDebug)
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");
_LIT(KKeywordDebug, "debug");
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;
}
else if (keyword == KKeywordDebug)
{
aConfig.iDebug = ETrue;
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;
TInt err = ReadConfig(aTitle, portConfig);
if (err)
{
Message(EError, _L("Error reading config: %d"), err);
User::LeaveIfError(err);
}
if (portConfig.iPort.Length() == 0)
{
User::Leave(KErrArgument);
}
if (portConfig.iDebug) SetDebug(ETrue);
if (portConfig.iPdd.Length())
{
err = User::LoadPhysicalDevice(portConfig.iPdd);
Message(ErrOrDebug(err), _L("Loading PDD %S returned %d"), &portConfig.iPdd, err);
if (err != KErrAlreadyExists) User::LeaveIfError(err);
}
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())
{
err = User::LoadLogicalDevice(portConfig.iLdd);
Message(ErrOrDebug(err), _L("Loading LDD %S returned %d"), &portConfig.iLdd, err);
if (err != KErrAlreadyExists) User::LeaveIfError(err);
}
else
{
User::LoadLogicalDevice(_L("ecomm"));
}
err = iCommServ.Connect();
Message(ErrOrDebug(err), _L("Connecting to RCommServ returned %d"), err);
User::LeaveIfError(err);
if (portConfig.iCsy.Length())
{
err = iCommServ.LoadCommModule(portConfig.iCsy);
Message(ErrOrDebug(err), _L("Loading CSY %S returned %d"), &portConfig.iCsy, err);
if (err != KErrAlreadyExists) User::LeaveIfError(err);
}
else
{
iCommServ.LoadCommModule(_L("ecuart"));
}
err = iCommPort.Open(iCommServ, portConfig.iPort, ECommExclusive);
Message(ErrOrDebug(err), _L("Opening port %S returned %d"), &portConfig.iPort, err);
User::LeaveIfError(err);
#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;
err = iCommPort.SetConfig(cfg);
Message(ErrOrDebug(err), _L("Setting port config returned %d"), err);
User::LeaveIfError(err);
}
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();
}