// lbs.cpp
//
// Copyright (c) 2008 - 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 <lbs.h>
#include <lbssatellite.h>
#include <LbsErrors.h>
#if defined (FSHELL_PLATFORM_S60) || defined (FSHELL_PLATFORM_FOUNDATION)
#include <EPos_CPosModules.h>
#include <EPos_CPosModuleUpdate.h>
#include <EPos_CPosModuleIdList.h>
#endif
#if !defined (FSHELL_PLATFORM_S60) && !defined (FSHELL_PLATFORM_FOUNDATION)
#include <lbs/lbsadmin.h>
#endif
#include <fshell/ioutils.h>
using namespace IoUtils;
class CCmdLbs : public CCommandBase
{
public:
void PrintTime(const TTime& aTime, TBool aNewline);
static const TDesC* TechnologyTypeToString(TPositionModuleInfo::TTechnologyType aType);
static const TDesC* DeviceLocationToString(TPositionModuleInfo::TDeviceLocation aLoc);
static const TDesC* CostIndicatorToString(TPositionQuality::TCostIndicator aCost);
static const TDesC* PowerConsumptionToString(TPositionQuality::TPowerConsumption aPower);
static void CapabilitiesToString(TPositionModuleInfo::TCapabilities aCap, TDes &aDes);
static CCommandBase* NewLC();
~CCmdLbs();
private:
CCmdLbs();
void PrintModuleDetail(TPositionModuleInfo& aModInfo);
void DoListModuleL();
void DoListModuleS60L();
void DoLocation();
void DoEnableModuleL(TBool aEnable = ETrue);
#if !defined (FSHELL_PLATFORM_S60)
void DoSynchTimeL();
#endif
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private:
CActiveSchedulerWait* iActiveWait;
RPositionServer iPosSrv;
RPositioner iPos;
TPositionSatelliteInfo iSatelliteInfo; //NOT all LBS modules accept satellite info
TPositionInfo iPosInfo;
TPositionInfoBase* ipPosInfo; //point to appropriate structure
RArray<TBool> iVerbose;
TInt iOptModuleIndex; //which module to use (module index, not id)
TInt iOptTimeoutSec; //timeout in second, default is 60 second
TInt iOptLoops; //how many loops (default 1)
enum TLbsCmd
{
ECmdLocation,
ECmdListModule,
ECmdListModuleS60,
ECmdEnableModule,
ECmdDisableModule,
ECmdSynchTime //synchronise system time with GPS timestamp
};
TLbsCmd iCommand;
};
CCommandBase* CCmdLbs::NewLC()
{
CCmdLbs* self = new(ELeave) CCmdLbs();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdLbs::CCmdLbs()
{
iOptModuleIndex = -1;
iOptTimeoutSec = 300;
iOptLoops = 1;
iActiveWait = new (ELeave) CActiveSchedulerWait;
}
CCmdLbs::~CCmdLbs()
{
iPos.Close();
iPosSrv.Close();
iVerbose.Close();
delete iActiveWait;
}
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
const TDesC& CCmdLbs::Name() const
{
_LIT(KName, "lbs");
return KName;
}
void CCmdLbs::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArgCommand, "command");
aArguments.AppendEnumL((TInt&)iCommand, KArgCommand);
}
void CCmdLbs::OptionsL(RCommandOptionList& aOptions)
{
_LIT(KOptVerbose, "verbose");
aOptions.AppendBoolL(iVerbose, KOptVerbose);
_LIT(KOptModuleIndex, "module-index");
aOptions.AppendUintL((TUint&)iOptModuleIndex, KOptModuleIndex);
_LIT(KOptLoops, "loops");
aOptions.AppendUintL((TUint&)iOptLoops, KOptLoops);
_LIT(KOptTimeout, "timeout");
aOptions.AppendUintL((TUint&)iOptTimeoutSec, KOptTimeout);
}
void CCmdLbs::DoRunL()
{
Printf(_L("Connecting to RPositionServer...\r\n"));
TInt err = iPosSrv.Connect();
LeaveIfErr(err, _L("Cannot connect to position server"));
switch(iCommand)
{
case ECmdLocation:
DoLocation();
break;
case ECmdListModule:
DoListModuleL();
break;
case ECmdListModuleS60:
DoListModuleS60L();
break;
case ECmdEnableModule:
DoEnableModuleL(ETrue);
break;
case ECmdDisableModule:
DoEnableModuleL(EFalse);
break;
case ECmdSynchTime:
//TODO There's no way of actually specifying this command
#if !defined (FSHELL_PLATFORM_S60)
DoSynchTimeL();
#else
LeaveIfErr(KErrNotSupported, _L("SynchTime not supported on S60"));
#endif
break;
}
}
void CCmdLbs::DoLocation()
{
TInt VerboseLevel = iVerbose.Count();
TInt err;
TBool bSatelliteCapable = EFalse;
TPositionModuleId modId; //which module to use
if (iOptModuleIndex != -1)
{
TPositionModuleInfo modInfo;
err = iPosSrv.GetModuleInfoByIndex(iOptModuleIndex, modInfo);
LeaveIfErr(err, _L("invalid module index"));
modId = modInfo.ModuleId();
}
else
{ //use the default module
err = iPosSrv.GetDefaultModuleId(modId);
LeaveIfErr(err, _L("Invalid default module"));
}
TPositionModuleInfo modInfo;
err = iPosSrv.GetModuleInfoById(modId, modInfo);
TBuf<128> modName;
modInfo.GetModuleName(modName);
Printf(_L("Openning RPositioner...(Module ID: 0x%X \"%S\")\r\n"), modId.iUid, &modName);
err = iPos.Open(iPosSrv, modId);
LeaveIfErr(err, _L("Cannot open positioner"));
// Set position requestor, it is compulsory on S60 only
err = iPos.SetRequestor( CRequestor::ERequestorService ,
CRequestor::EFormatApplication , _L("FSHELL FLBS COMMAND") );
LeaveIfErr(err, _L("Cannot set requestor"));
TPositionUpdateOptions UpdateOption;
TTimeIntervalMicroSeconds TimeoutMs = (TInt64)iOptTimeoutSec * (TInt64)1000000;
UpdateOption.SetUpdateTimeOut(TimeoutMs);
Printf(_L("SetUpdateOptions... Timeout = %d seconds\r\n"), iOptTimeoutSec);
err = iPos.SetUpdateOptions(UpdateOption);
LeaveIfErr(err, _L("Cannot set update options"));
//check if the module is capable of satellite info
{
TPositionModuleInfo::TCapabilities modCap = modInfo.Capabilities();
bSatelliteCapable = modCap & TPositionModuleInfo::ECapabilitySatellite;
if (bSatelliteCapable)
{
ipPosInfo = &iSatelliteInfo;
Printf(_L("This module is capable of receiving satellite information\r\n"));
}
else
ipPosInfo = &iPosInfo;
}
for (TInt i=0; i<iOptLoops; i++)
{
TRequestStatus status;
TPosition pos;
Printf(_L("Calling RPositioner::NotifyPositionUpdate...\r\n"));
iPos.NotifyPositionUpdate(*ipPosInfo, status);
User::WaitForRequest(status);
err = status.Int();
if (err != KErrNone)
LeaveIfErr(err, _L("NotifyPositionUpdate encountered an error"));
static_cast <TPositionInfo*>(ipPosInfo) -> GetPosition(pos);
TTime LocTime = pos.Time();
TReal32 HorizontalAccuracy = pos.HorizontalAccuracy();
TReal32 VerticalAccuracy = pos.VerticalAccuracy();
//print current location information
Printf(_L("Altit:%f Latit:%f Longt:%f HAccu:%.2f VAccu:%.2f\r\n"),
pos.Altitude(), pos.Latitude(), pos.Longitude(),
HorizontalAccuracy, VerticalAccuracy);
Printf(_L("Location Signal Time:"));
PrintTime(LocTime, ETrue);
//if there is satellite information, optionally print it out
if (bSatelliteCapable && (VerboseLevel>0) )
{
TPositionSatelliteInfo* pSateInfo = static_cast <TPositionSatelliteInfo*> (ipPosInfo);
TInt NumSatellitesInView = pSateInfo->NumSatellitesInView();
TInt NumSatellitesUsed = pSateInfo->NumSatellitesUsed();
TTime SatelliteTime = pSateInfo->SatelliteTime();
TReal32 HorizontalDoP = pSateInfo->HorizontalDoP();
TReal32 VerticalDoP = pSateInfo->VerticalDoP();
TReal32 TimeDoP = pSateInfo->TimeDoP();
Printf(_L("Satellite In View:%d Used:%d Time:"),
NumSatellitesInView, NumSatellitesUsed );
PrintTime(SatelliteTime, ETrue);
Printf(_L("HoriDop:%f VertDop:%f TimeDop:%f \r\n"),
HorizontalDoP, VerticalDoP, TimeDoP);
//Print each satellite info
for (TInt i=0; i<NumSatellitesInView; i++ )
{
TSatelliteData SatellliteData;
err = pSateInfo->GetSatelliteData((TUint)i, SatellliteData);
if (err == KErrNotFound)
{
Printf(_L("Satellite #%d Not Found\r\n"), i);
continue;
}
else
{
User::LeaveIfError(err);
}
TInt SatelliteId = SatellliteData.SatelliteId();
TReal32 Azimuth = SatellliteData.Azimuth();
TReal32 Elevation = SatellliteData.Elevation();
TBool IsUsed = SatellliteData.IsUsed();
TInt SignalStrength = SatellliteData.SignalStrength();
Printf(_L("Satellite #%d, ID:%d Azimuth %.2f Elevation %.2f IsUsed:%d Strenth:%d\r\n"),
i, SatelliteId, Azimuth, Elevation, IsUsed, SignalStrength);
}
}
}
}
void CCmdLbs::DoListModuleL()
{
TInt err;
TUint numModules;
TPositionModuleInfo modInfo;
err = iPosSrv.GetNumModules(numModules);
User::LeaveIfError(err);
Printf(_L("%d Modules found\r\n"),
numModules);
for (TUint i=0 ; i < numModules ; i++)
{
Printf(_L("============================\r\n"));
err = iPosSrv.GetModuleInfoByIndex(i, modInfo);
User::LeaveIfError(err);
Printf(_L("Module Index: %d\r\n"), i);
PrintModuleDetail(modInfo);
}
Printf(_L("=================================\r\n"));
//print default module ID
TPositionModuleId DefaultId;
err = iPosSrv.GetDefaultModuleId(DefaultId);
Printf(_L("Default Module ID 0x%X\r\n"), DefaultId.iUid );
}
//S60 proprietary
//similar to DoListModuleL, but list module based on S60 API,
//and sometimes it gives different results than symbain API
void CCmdLbs::DoListModuleS60L()
{
#ifdef FSHELL_PLATFORM_S60
//TInt err;
TUint numModules;
CPosModules* pModHand = CPosModules::OpenL();
CleanupStack::PushL(pModHand);
CPosModuleIdList* pIdList = pModHand->ModuleIdListL();
CleanupStack::PushL(pIdList);
numModules = pIdList->Count();
Printf(_L("%d Modules found\r\n"),
numModules);
for (TUint i=0 ; i < numModules ; i++)
{
Printf(_L("============================\r\n"));
TPositionModuleId S60modId = (*pIdList) [i];
TPositionModuleInfo S60modInfo;
TBuf<128> S60modName; //to store module name
pModHand->GetModuleInfoL(S60modId, S60modInfo);
S60modInfo.GetModuleName(S60modName);
Printf(_L("Module Index: %d\r\n"), i);
PrintModuleDetail(S60modInfo);
}
Printf(_L("=================================\r\n"));
CleanupStack::PopAndDestroy(pIdList);
CleanupStack::PopAndDestroy(pModHand);
#endif
}
void CCmdLbs::PrintModuleDetail(TPositionModuleInfo& aModInfo)
{
//TInt err;
TBool bAvailable = aModInfo.IsAvailable();
TPositionModuleId modId;
modId = aModInfo.ModuleId();
TBuf<128> modName;
aModInfo.GetModuleName(modName);
//==quality
TPositionQuality modQuality;
aModInfo.GetPositionQuality(modQuality);
TTimeIntervalMicroSeconds firstFix = modQuality.TimeToFirstFix();
TTimeIntervalMicroSeconds nextFix = modQuality.TimeToNextFix();
TReal32 horiAccu = modQuality.HorizontalAccuracy();
TReal32 vertAccu = modQuality.VerticalAccuracy();
TPositionQuality::TCostIndicator cost = modQuality.CostIndicator();
TPositionQuality::TPowerConsumption power = modQuality.PowerConsumption();
////////////////////////////////////////////////////////////////
TPositionModuleInfo::TTechnologyType modType = aModInfo.TechnologyType();
TPositionModuleInfo::TDeviceLocation modLoc = aModInfo.DeviceLocation();
TPositionModuleInfo::TCapabilities modCap = aModInfo.Capabilities();
TVersion modVersion = aModInfo.Version();
TVersionName VersionName = modVersion.Name();
//TPositionClassFamily aClassType;
//modInfo.ClassesSupported(aClassType);
Printf(_L("Module Id:0x%X, Name:\"%S\" Available:%d \r\n"),
modId.iUid, &modName, bAvailable);
Printf(_L("Type:%S Version:%S\r\n"),
TechnologyTypeToString(modType), &VersionName );
Printf(_L("Location:%S\r\n"), DeviceLocationToString (modLoc));
Printf(_L("Quality first fix:%Ld next fix:%Ld \r\n"),
firstFix.Int64(), nextFix.Int64());
Printf(_L("Horizontal Accuracy:%f Vertical Accuray:%f \r\n"),
horiAccu, vertAccu);
Printf(_L("Cost Indicator:%S\r\n"), CostIndicatorToString(cost));
Printf(_L("Power Consumption:%S\r\n"), PowerConsumptionToString(power));
TBuf<256> CapString;
CapabilitiesToString(modCap, CapString);
Printf(_L("Capabilities:%S\r\n"), &CapString);
}
//it is a S60 proprietary function
//
void CCmdLbs::DoEnableModuleL(TBool aEnable)
{
TInt err;
TBuf<128> modName; //to store module name
TPositionModuleInfo modInfo;
TPositionModuleId modId = TUid::Null(); //which module to use
TBool bIsCurAvail;
if (iOptModuleIndex != -1)
{
err = iPosSrv.GetModuleInfoByIndex(iOptModuleIndex, modInfo);
LeaveIfErr(err, _L("invalid module index"));
modId = modInfo.ModuleId();
}
else
{
LeaveIfErr(KErrArgument, _L("Need to specify a module"));
}
bIsCurAvail = modInfo.IsAvailable();
modInfo.GetModuleName(modName);
TPtrC AvailNow = (bIsCurAvail)?_L("Yes"):_L("No");
Printf(_L("Module Id=0x%08x Name:\"%S\" Current Availability:%S \r\n"),
modId.iUid, &modName, &AvailNow);
//modInfo.SetIsAvailable(ETrue); //Note: this has no effect on S60 platform
#ifdef FSHELL_PLATFORM_S60
CPosModules* pModHand = CPosModules::OpenL();
CleanupStack::PushL(pModHand);
//diagnosis code: to verify the information given by S60 API matches Symbian API
{
CPosModuleIdList* pIdList = pModHand->ModuleIdListL();
CleanupStack::PushL(pIdList);
TPositionModuleId S60modId = (*pIdList) [iOptModuleIndex];
TPositionModuleInfo S60modInfo;
TBuf<128> S60modName; //to store module name
pModHand->GetModuleInfoL(S60modId, S60modInfo);
S60modInfo.GetModuleName(S60modName);
RDebug::Print(_L("S60 LBS module name:%S"), &S60modName);
CleanupStack::PopAndDestroy(pIdList);
}
CPosModuleUpdate* pModUpdate = CPosModuleUpdate::NewLC();
TBool bNewAvail = aEnable;
pModUpdate->SetUpdateAvailability(bNewAvail);
TRAP(err, pModHand->UpdateModuleL(modId, *pModUpdate));
LeaveIfErr(err, _L("Could not update module information") );
CleanupStack::PopAndDestroy(pModUpdate);
CleanupStack::PopAndDestroy(pModHand);
#endif
//verify if the change has take effect
{
err = iPosSrv.GetModuleInfoByIndex(iOptModuleIndex, modInfo);
LeaveIfErr(err, _L("invalid module index"));
modId = modInfo.ModuleId();
bIsCurAvail = modInfo.IsAvailable();
TPtrC NewAvail = (bIsCurAvail)?_L("Yes"):_L("No");
Printf(_L("Module Id=0x%08x Name:\"%S\" New Availability:%S \r\n"),
modId.iUid, &modName, &NewAvail);
}
}
#if !defined (FSHELL_PLATFORM_S60)
void CCmdLbs::DoSynchTimeL()
{
// Set LBS setting to allow manual clock adjustment
//This may not be set by default
CLbsAdmin* admin = CLbsAdmin::NewL();
CleanupStack::PushL(admin);
CLbsAdmin::TClockAdjust clockAdjust;
User::LeaveIfError(admin->Get(KLbsSettingAllowManualClockAdjust,clockAdjust));
admin->Set(KLbsSettingAllowManualClockAdjust,CLbsAdmin::EClockAdjustOn);
CleanupStack::PopAndDestroy(admin);
}
#endif
EXE_BOILER_PLATE(CCmdLbs)
void CCmdLbs::PrintTime(const TTime& aTime, TBool aNewline)
{
TTime NullTime = Time::NullTTime();
if (aTime == NullTime)
{
Printf(_L("(NullTime)"));
}
else
{
_LIT8(KDateTimeFormat, "%d-%02d-%02d %02d:%02d:%02d");
TDateTime dt = aTime.DateTime();
Printf(KDateTimeFormat, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second());
}
if (aNewline) Printf(_L("\r\n"));
}
#define CASE_LIT(x) case x: { _LIT(KName, #x); return &KName; }
const TDesC* CCmdLbs::TechnologyTypeToString(TPositionModuleInfo::TTechnologyType aType)
{
switch(aType)
{
CASE_LIT(TPositionModuleInfo::ETechnologyUnknown);
CASE_LIT(TPositionModuleInfo::ETechnologyTerminal);
CASE_LIT(TPositionModuleInfo::ETechnologyNetwork);
CASE_LIT(TPositionModuleInfo::ETechnologyAssisted);
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdLbs::DeviceLocationToString(TPositionModuleInfo::TDeviceLocation aLoc)
{
switch(aLoc)
{
CASE_LIT(TPositionModuleInfo::EDeviceUnknown);
CASE_LIT(TPositionModuleInfo::EDeviceInternal);
CASE_LIT(TPositionModuleInfo::EDeviceExternal);
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdLbs::CostIndicatorToString(TPositionQuality::TCostIndicator aCost)
{
switch(aCost)
{
CASE_LIT(TPositionQuality::ECostUnknown);
CASE_LIT(TPositionQuality::ECostZero);
CASE_LIT(TPositionQuality::ECostPossible);
CASE_LIT(TPositionQuality::ECostCharge);
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
const TDesC* CCmdLbs::PowerConsumptionToString(TPositionQuality::TPowerConsumption aPower)
{
switch(aPower)
{
CASE_LIT(TPositionQuality::EPowerUnknown);
CASE_LIT(TPositionQuality::EPowerZero);
CASE_LIT(TPositionQuality::EPowerLow);
CASE_LIT(TPositionQuality::EPowerMedium);
CASE_LIT(TPositionQuality::EPowerHigh);
default:
{
_LIT(KUnknown, "Unknown");
return &KUnknown;
}
}
}
#define CAPFLAG(x) if (aCap & TPositionModuleInfo::x) { aDes += _L(#x); aDes += _L("|");}
void CCmdLbs::CapabilitiesToString(TPositionModuleInfo::TCapabilities aCap, TDes &aDes)
{
aDes.SetLength(0);
//if (aCap & TPositionModuleInfo::ECapabilityNone) aDes += _L("ECapabilityNone|");
CAPFLAG(ECapabilityNone);
CAPFLAG(ECapabilityHorizontal);
CAPFLAG(ECapabilityVertical);
CAPFLAG(ECapabilitySpeed);
CAPFLAG(ECapabilityDirection);
CAPFLAG(ECapabilitySatellite);
CAPFLAG(ECapabilityCompass);
CAPFLAG(ECapabilityNmea);
CAPFLAG(ECapabilityAddress);
CAPFLAG(ECapabilityBuilding);
CAPFLAG(ECapabilityMedia);
}