// btservices.cpp
//
// Copyright (c) 2009 - 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 <e32std.h>
#include <BTExtNotifiers.h>
#include <fshell/common.mmh>
#include <fshell/ioutils.h>
using namespace IoUtils;
#include "BtServicesEng.h"
#include "BtServiceView.h"
class CBTEngSettings;
#if FSHELL_PLATFORM_S60 >= 5
// This is an S60-only API
#define SUPPORT_ONOFF
#endif
#ifdef SUPPORT_ONOFF
#include <btengsettings.h>
#endif
CBtServiceView::CBtServiceView()
{
}
CBtServiceView::~CBtServiceView()
{
}
void CBtServiceView::PrintTextMsg(TInt /*aVerboseLevel*/, const TDesC& /*aMsg*/)
{
}
void CBtServiceView::AsyncCompleted()
{
}
class CCmdBtsvc : public CCommandBase, public CBtServiceView
{
public:
static CCommandBase* NewLC();
~CCmdBtsvc();
private:
CCmdBtsvc();
void DoScanDeviceL();
void DoListServiceL();
void DoAttributeL();
void DoLocalL();
void DoListUuidFilterL();
void SelectBTDeviceL(TBTDeviceName& aName, TBTDevAddr& aBDAddr, TBTDeviceClass& aDevClass);
TBool GetBTDevClassFromRegistryL(TBTDevAddr& aBDAddr, TBTDeviceClass& aDevClass);
#ifdef SUPPORT_ONOFF
void SetEnabledL(TBool aEnable);
void ShowStatusL();
TBool GetPowerStateL();
#endif
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private:
virtual void PrintTextMsg(TInt aVerboseLevel, const TDesC& aMsg);
virtual void AsyncCompleted();
private:
CBtServicesEng* iEngine;
CActiveSchedulerWait* iActiveWait;
RArray<TBool> iVerbose;
HBufC* iOptBTAddr;
HBufC* iOptSvcHandle; //service handle
HBufC* iOptUuidFilter; //uuid filter
enum TBtSvcCmd
{
ECmdDevice,
ECmdService,
ECmdAttribute,
ECmdLocal,
ECmdUuid,
ECmdStatus,
ECmdEnable,
ECmdDisable,
};
TBtSvcCmd iCommand;
CBTEngSettings* iSettings;
};
CCommandBase* CCmdBtsvc::NewLC()
{
CCmdBtsvc* self = new(ELeave) CCmdBtsvc();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdBtsvc::CCmdBtsvc()
{
iActiveWait = new (ELeave) CActiveSchedulerWait;
}
CCmdBtsvc::~CCmdBtsvc()
{
#ifdef SUPPORT_ONOFF
delete iSettings;
#endif
delete iOptBTAddr;
delete iOptSvcHandle;
delete iOptUuidFilter;
delete iActiveWait;
delete iEngine;
iVerbose.Close();
}
void CCmdBtsvc::PrintTextMsg(TInt aVerboseLevel, const TDesC& aMsg)
{
TInt VerboseLevel = iVerbose.Count();
if (aVerboseLevel <= VerboseLevel)
Printf(aMsg);
}
void CCmdBtsvc::AsyncCompleted()
{
if (iActiveWait->IsStarted())
{
iActiveWait->AsyncStop();
}
}
const TDesC& CCmdBtsvc::Name() const
{
_LIT(KName, "btservices");
return KName;
}
void CCmdBtsvc::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArgCommand, "command");
aArguments.AppendEnumL((TInt&)iCommand, KArgCommand);
}
void CCmdBtsvc::OptionsL(RCommandOptionList& aOptions)
{
aOptions.AppendStringL(iOptBTAddr, _L("address"));
aOptions.AppendStringL(iOptSvcHandle, _L("record"));
aOptions.AppendStringL(iOptUuidFilter, _L("uuid"));
aOptions.AppendBoolL(iVerbose, _L("verbose"));
}
void CCmdBtsvc::DoRunL()
{
switch (iCommand)
{
case ECmdDevice:
DoScanDeviceL();
break;
case ECmdService:
DoListServiceL();
break;
case ECmdAttribute:
DoAttributeL();
break;
case ECmdLocal:
DoLocalL();
break;
case ECmdUuid:
DoListUuidFilterL();
break;
#ifdef SUPPORT_ONOFF
case ECmdStatus:
ShowStatusL();
break;
case ECmdEnable:
SetEnabledL(ETrue);
break;
case ECmdDisable:
SetEnabledL(EFalse);
break;
#endif
default:
LeaveIfErr(KErrArgument, _L("Invalid command"));
}
}
void CCmdBtsvc::DoAttributeL()
{
TInt err;
//if want to query full attribute set of one particular service,
//call CBtServicesEng::GetAttributesL()
if (iOptSvcHandle && iOptSvcHandle->Length())
{
iEngine = CBtServicesEng::NewL();
iEngine->SetView(this);
iEngine->CancelSdpAgent();
iEngine->DeleteSdpAgent();
err = iEngine->BluetoothReady();
LeaveIfErr(err, _L("Bluetooth not ready"));
TBTDeviceName Name;
TBTDevAddr BDAddr;
TBTDeviceClass DevClass;
//iOptSvcHandle should begin with "0x" (hex)
if ((iOptSvcHandle->Left(2))==_L("0x"))
{
TSdpServRecordHandle Handle;
TLex lex(*iOptSvcHandle);
lex.SkipAndMark(2);
err = lex.Val(Handle, EHex);
LeaveIfErr(err, _L("Service Handle:\"%S\" is not in valid format"), iOptSvcHandle);
SelectBTDeviceL(Name, BDAddr, DevClass);
Printf(_L("==============================================\r\n"));
iEngine->GetDeviceAttributesL(BDAddr, Name, Handle);
//wait for results
iActiveWait->Start();
}
else
LeaveIfErr(KErrArgument, _L("Service Handle:\"%S\" is not in valid format"), iOptSvcHandle);
}
else
LeaveIfErr(KErrArgument, _L("use -r to specify a service record handle"));
}
//do a BT device scan with RHostResolver,
//and make a list of BT addresses, device name, and device class
//
void CCmdBtsvc::DoScanDeviceL()
{
TInt err;
TInt ItemsFound = 0;
TBTDevAddr BDAddr;
TBTDeviceName Name;
TBTDeviceClass DevClass;
Printf(_L("Scanning for BT devices ...\r\n"));
RSocketServ SktSrv;
CleanupClosePushL(SktSrv);
err = SktSrv.Connect();
LeaveIfErr(err, _L("Could not connect to socket server"));
RHostResolver Host;
CleanupClosePushL(Host);
RHostResolver HostForName;
CleanupClosePushL(HostForName);
TProtocolDesc ProtocolInfo;
err = SktSrv.FindProtocol(_L("BTLinkManager"), ProtocolInfo);
User::LeaveIfError(err);
err = Host.Open(SktSrv, ProtocolInfo.iAddrFamily , ProtocolInfo.iProtocol);
LeaveIfErr(err, _L("Could not open host resolver"));
err = HostForName.Open(SktSrv, ProtocolInfo.iAddrFamily , ProtocolInfo.iProtocol);
LeaveIfErr(err, _L("Could not open host resolver"));
TInquirySockAddr Inq;
Inq.SetIAC(KGIAC);
Inq.SetAction(KHostResInquiry/*|KHostResIgnoreCache*/);
TNameEntry Result;
err = Host.GetByAddress(Inq, Result);
//this is for querying name
TInquirySockAddr InqName;
InqName.SetAction(KHostResName);
TNameEntry ResultName;
Printf(_L("========================================================\r\n"));
Printf(_L("BTAddr | DeviceClass| Name\r\n"));
Printf(_L("========================================================\r\n"));
while(1)
{
if (err == KErrNone)
{
ItemsFound++;
TInquirySockAddr& sa = TInquirySockAddr::Cast(Result().iAddr);
const TBTDevAddr& bdaddr = sa.BTAddr();
BDAddr = bdaddr;
Name = Result().iName;
TUint16 MajorServiceClass = sa.MajorServiceClass();
DevClass = TBTDeviceClass(
MajorServiceClass, sa.MajorClassOfDevice(), sa.MinorClassOfDevice() );
TBuf<128> BTReadAddress;
BDAddr.GetReadable(BTReadAddress);
//query its name
InqName.SetBTAddr(bdaddr);
err = HostForName.GetByAddress(InqName, ResultName);
if (err==KErrNone)
Name = ResultName().iName;
else
Name.Format(_L("Unable to get the name, err=%d"), err);
Printf(_L("0x%S | 0x%08x | \"%S\" \r\n"),
&BTReadAddress, DevClass.DeviceClass(), &Name);
err = Host.Next(Result);
}
else if (err == KErrEof)
{
break;
}
else
LeaveIfErr(err, _L("Resolving address failed"));
}
CleanupStack::PopAndDestroy();
CleanupStack::PopAndDestroy();
CleanupStack::PopAndDestroy();
Printf(_L("%d devices found\r\n"),ItemsFound);
}
//NOT TESTED YET, do not use
//aBDAddr:[in]
//aDevClass:[out]
TBool CCmdBtsvc::GetBTDevClassFromRegistryL(TBTDevAddr& aBDAddr, TBTDeviceClass& aDevClass)
{
TInt err;
TBuf<128> buf;
aBDAddr.GetReadable(buf);
Printf(_L("Query DeviceClass for BTAddr:0x%S\r\n"), &buf);
RBTRegServ Srv;
CleanupClosePushL(Srv);
err = Srv.Connect();
User::LeaveIfError(err);
RBTRegistry Reg;
CleanupClosePushL(Reg);
err = Reg.Open(Srv);
User::LeaveIfError(err);
TBTNamelessDevice Dev;
Dev.SetAddress(aBDAddr);
TRequestStatus status;
Reg.GetDevice(Dev, status);
User::WaitForRequest(status);
err = status.Int();
User::LeaveIfError(err);
if (err == KErrNone )
{
aDevClass = Dev.DeviceClass();
}
CleanupStack::PopAndDestroy();
CleanupStack::PopAndDestroy();
return ETrue;
}
//select a BT device either from RNotifier,
//or using BT address string if it is specified
//aName: [out]
//aBDAddr: [out]
//aDevClass: [out]
void CCmdBtsvc::SelectBTDeviceL(TBTDeviceName& aName, TBTDevAddr& aBDAddr, TBTDeviceClass& aDevClass)
{
TInt err;
if (iOptBTAddr && iOptBTAddr->Length()>0)
//use RHostResolver to get name and device class
{
Printf(_L("Querying name for \"%S\"...\r\n"), iOptBTAddr);
RSocketServ SktSrv;
CleanupClosePushL(SktSrv);
err = SktSrv.Connect();
LeaveIfErr(err, _L("Could not connect to socket server"));
RHostResolver Host;
CleanupClosePushL(Host);
TProtocolDesc ProtocolInfo;
err = SktSrv.FindProtocol(_L("BTLinkManager"), ProtocolInfo);
User::LeaveIfError(err);
err = Host.Open(SktSrv, ProtocolInfo.iAddrFamily , ProtocolInfo.iProtocol);
LeaveIfErr(err, _L("Could not open host resolver"));
TBTDevAddr Addr;
err = Addr.SetReadable(*iOptBTAddr);
LeaveIfErr(err, _L("User-input BT address invalid"));
TInquirySockAddr Inq;
Inq.SetAction(KHostResName);
Inq.SetBTAddr(Addr);
TNameEntry Result;
err = Host.GetByAddress(Inq, Result);
if (err == KErrNone)
{
TInquirySockAddr& sa = TInquirySockAddr::Cast(Result().iAddr);
const TBTDevAddr& bdaddr = sa.BTAddr();
aBDAddr = bdaddr;
aName = Result().iName;
TUint16 MajorServiceClass = sa.MajorServiceClass();
aDevClass = TBTDeviceClass(
MajorServiceClass, sa.MajorClassOfDevice(), sa.MinorClassOfDevice() );
}
else
LeaveIfErr(err, _L("Resolving address failed"));
CleanupStack::PopAndDestroy();
CleanupStack::PopAndDestroy();
TBuf<128> AddressStr;
aBDAddr.GetReadable(AddressStr);
Printf(_L("Device \"%S\" BTAddr:0x%S\r\n"),
&aName, &AddressStr);
}
else
//use RNotifier to select a BT device
{
//about the search device, prompting user about curret status
Printf(_L("Searching Bluetooth device through RNotifier,\r\nplease go to main UI screen to select a device...\r\n"));
////////////////////////////////////////////
RNotifier noti;
User::LeaveIfError(noti.Connect());
// 2. Start the device selection plug-in
TBTDeviceSelectionParams selectionFilter;
//TUUID targetServiceClass(0x2345);
//selectionFilter.SetUUID(targetServiceClass);
TBTDeviceSelectionParamsPckg pckg(selectionFilter);
TBTDeviceResponseParams result;
TBTDeviceResponseParamsPckg resultPckg(result);
TRequestStatus status;
noti.StartNotifierAndGetResponse(status, KDeviceSelectionNotifierUid, pckg, resultPckg);
User::After(2000000);
// 3. Extract device name if it was returned
User::WaitForRequest(status);
if (status.Int() == KErrNone)
{
if (resultPckg().IsValidDeviceName() &&
resultPckg().IsValidBDAddr() &&
resultPckg().IsValidDeviceClass()
)
{
aName = (resultPckg().DeviceName());
aBDAddr = resultPckg().BDAddr();
aDevClass = resultPckg().DeviceClass();
}
}
// 4. Clean up
noti.CancelNotifier(KDeviceSelectionNotifierUid);
noti.Close();
TBuf<128> AddressStr;
aBDAddr.GetReadable(AddressStr);
Printf(_L("Device \"%S\" BTAddr:0x%S DeviceClass:0x%08X\r\n"),
&aName, &AddressStr, aDevClass.DeviceClass());
}
}
//search and make a list of results
void CCmdBtsvc::DoListServiceL()
{
TInt VerboseLevel = iVerbose.Count();
if (VerboseLevel >= 2)
Printf(_L("calling CBtServicesEng::NewL() ...\r\n"));
iEngine = CBtServicesEng::NewL();
if (VerboseLevel >= 2)
Printf(_L("calling CBtServicesEng::SetView()... iEngine=0x%08x\r\n"),
iEngine);
iEngine->SetView(this);
if (VerboseLevel >= 2)
Printf(_L("calling CBtServicesEng::CancelSdpAgent()...\r\n"));
iEngine->CancelSdpAgent();
if (VerboseLevel >= 2)
Printf(_L("calling CBtServicesEng::DeleteSdpAgent()...\r\n"));
iEngine->DeleteSdpAgent();
TInt err = iEngine->BluetoothReady();
LeaveIfErr(err, _L("Bluetooth not ready"));
TBTDeviceName Name;
TBTDevAddr BDAddr;
TBTDeviceClass DevClass;
SelectBTDeviceL(Name, BDAddr, DevClass);
//see if user has specified a UUID filter
if (iOptUuidFilter && iOptUuidFilter->Length())
{
TUint32 uuid;
if ((iOptUuidFilter->Left(2))==_L("0x"))
{
TLex lex(*iOptUuidFilter);
lex.SkipAndMark(2);
err = lex.Val(uuid, EHex);
if (err==KErrNone)
{
iEngine->SetUUIDFilterL(uuid);
goto QueryService;
}
}
//the UUID could be in string form.
TBool Match = iEngine->StringToUUID(*iOptUuidFilter, uuid);
if (Match==EFalse)
{
Printf(_L("UUID filter not recognised. Ignored\r\n"));
}
}
QueryService:
iEngine->NewDeviceSelectedL(BDAddr, Name);
iActiveWait->Start();
iEngine->MakeTextServiceList();
//test code: just to test if attributes query is OK
//iEngine->GetAttributesL(0);
//iActiveWait->Start();
}
void CCmdBtsvc::DoLocalL()
{
TInt err;
iEngine = CBtServicesEng::NewL();
iEngine->SetView(this);
iEngine->CancelSdpAgent();
iEngine->DeleteSdpAgent();
err = iEngine->BluetoothReady();
LeaveIfErr(err, _L("Bluetooth not ready"));
iEngine->DisplayLocalInfoL();
}
//make a list of UUID filters, values and strings
void CCmdBtsvc::DoListUuidFilterL()
{
TInt err;
iEngine = CBtServicesEng::NewL();
iEngine->SetView(this);
iEngine->CancelSdpAgent();
iEngine->DeleteSdpAgent();
err = iEngine->BluetoothReady();
LeaveIfErr(err, _L("Bluetooth not ready"));
iEngine->MakeTextUUIDList();
}
EXE_BOILER_PLATE(CCmdBtsvc)
#ifdef SUPPORT_ONOFF
TBool CCmdBtsvc::GetPowerStateL()
{
if (!iSettings)
{
TRAPL(iSettings = CBTEngSettings::NewL(NULL), _L("Couldn't construct CBTEngSettings"));
}
TBTPowerStateValue state;
LeaveIfErr(iSettings->GetPowerState(state), _L("Couldn't read BT power state"));
return state == EBTPowerOn;
}
void CCmdBtsvc::ShowStatusL()
{
if (GetPowerStateL())
{
Printf(_L("Bluetooth is enabled.\r\n"));
}
else
{
Printf(_L("Bluetooth is disabled.\r\n"));
}
}
void CCmdBtsvc::SetEnabledL(TBool aEnable)
{
TBool on = GetPowerStateL();
if (on && !aEnable)
{
LeaveIfErr(iSettings->SetPowerState(EBTPowerOff), _L("Couldn't set power state"));
}
else if (!on && aEnable)
{
LeaveIfErr(iSettings->SetPowerState(EBTPowerOn), _L("Couldn't set power state"));
}
}
#endif