commands/btservices/btservices.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// 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