quick_recipes (779892), страница 51
Текст из файла (страница 51)
For IrDA protocols the code is quite simple and is presentedbelow. For Bluetooth it is a bit more complicated, as you will see infurther recipes.As a first step, you need to fill in the TProtocolDesc structurewhich defines an address family and a protocol number. RSocketServ::FindProtocol() takes a protocol name as a parameter andreturns the appropriate protocol information. In case of IrDA, only theaddress family is important. The protocol number is forced to be valid byESOCK automatically.The core part of the device discovery process is the RHostResolverclass. This is where you obtain device names or addresses in either thesynchronous or asynchronous method.RSocketServ ss;TProtocolDesc pInfo;TInt ret;If ((ret = ss.Connect()) != KErrNone){return ret;}_LIT8(KTinyTP,"IrTinyTP");ret=ss.FindProtocol(KTinyTP,protoInfo);// IrTinyTP is the reliable transport layer of IRDA which corresponds// to sequenced packet service.
Irmux corresponds to unreliable// datagram service.if (ret!=KErrNone){// Error - protocol not loaded - prob. wrong ESOCK.INI// or protocol has locked serial port.}RHostResolver hr;ret=hr.Open(ss,pInfo.iAddrFamily,pInfo.iSockType);TNameEntry log;THostName name;ret=hr.GetByName(name,log);if (ret!=KErrNone){// No devices discovered - may be none present}// Call RHostResolver::Next() on 9.2 hereDiscussion: The code snippet above demonstrates the synchronous callfor host resolution for the sake of simplicity. As with most Symbian OS286SYMBIAN C++ RECIPESprogramming topics, it is preferable to use the asynchronous version ofthe same method to avoid UI unresponsiveness if it takes a few secondsto actually resolve the available device names.The first parameter of the RHostResolver::GetByName() methoddefines the device name mask that the caller is interested in.
For IrDAconnections it is ignored by the protocol. The documentation states thatwildcard names are supported in the mask, and you are recommended tospecify an asterisk there to ensure that the same code will work with allpossible future changes.On Symbian OS v9.2 and above, RHostResolver::Next() returnsthe next discovered device until no more devices are found.
In v9.1 itbehaves differently, and always returns the very first device informationand no error. Therefore, if your application should work on both OSversions, then the only robust way of detecting the end-of-discoveryprocess is to compare the given device address with already fetchedones.4.9.1.3Discover Bluetooth DevicesAmount of time required: 20 minutesLocation of example code: \Connectivity\BTDeviceSample\DeviceDiscovererRequired library(s): bluetooth.lib, btmanclient.lib,sdpagent.lib, sdpdatabase.lib, esock.libRequired header file(s): btdevice.h, bt_sock.h, btsdp.h,bttypes.h, es_sock.hRequired platform security capability(s): LocalServicesProblem: You want to discover the Bluetooth-enabled devices in range.Solution: Whilst it may sound quite complicated at first glance, thediscovery process for Bluetooth devices is actually pretty straightforwardand practically the same as for IrDA in Symbian OS.
You must use thefollowing classes:• RSocketServ – used to establish a session to the ESOCK server andget information about supported communication protocols.• RHostResolver – provides an interface to host name resolutionservices.• TInquirySockAddr – socket address class which is used for inquiries.• TNameEntry/TNameRecord – this class keeps the result of thequery.CONNECTIVITY287A typical scenario for device discovery is based on the sequencebelow.1.
Connect to the socket server (RSocketServ), and then select theprotocol to be used using RSocketServ::FindProtocol().Address and name queries are supplied by the stack’s BTLinkManager protocol layer, so this should be selected:RSocketServ sockServ;sockServ.Connect();TProtocolDesc pd;_LIT(KL2Cap, "BTLinkManager");User::LeaveIfError(sockServ.FindProtocol(KL2Cap, pd));2. Create and initialize RHostResolver:RHostResolver hr;User::LeaveIfError(hr.Open(sockServ, pd.iAddrFamily, pd.iProtocol));3.
Set up the TInquirySockAddr variable so that its Inquiry AccessCode (IAC) equals KGIAC (‘General Unlimited’) and an action isKHostResInquiry. The actual query is started by an RHostResolver::GetByAddress() call.TInquirySockAddr addr;TNameEntry entry;addr.SetIAC(KGIAC);addr.SetAction(KHostResInquiry);TRequestStatus status;hr.GetByAddress(addr, entry, status);User::WaitForRequest(status);4. On completion, the TNameEntry variable contains the address andthe class of the first found device. Subsequent calls to RHostResolver::Next() provide the data about other discovered devices until KErrHostResNoMoreResults is returned.5. In order to retrieve the name of the BT device instead of itsaddress, use the KHostResName flag in the TInquirySockAddr::SetAction() function.
Both flags may be combined with OR operation if you want to know the device name and address simultaneously.Discussion: Device discovery is usually an asynchronous process, asare many other communication APIs, and therefore it is often suitable toencapsulate it in an active object. Discovery process completion may takea long time, especially if there are many Bluetooth-enabled devices in the288SYMBIAN C++ RECIPESsurrounding area – hence an active object model provides a convenientway of processing the data for every found device ‘just in time’.Inquiry results are cached, so it may result in ‘ghost’ devices in thediscovered list while the device is no longer in range.
This fact doesnot lead to additional problems, as a particular device may be in- andout-of-range between its discovery and the actual communication session.You may find more information about protocol-related constants inthe bt_sock.h header file.4.9.1.4Discover Bluetooth Services for a Given DeviceAmount of time required: 20 minutesLocation of example code: \Connectivity\BTDeviceSample\ServiceDiscovererRequired library(s): bluetooth.lib, btmanclient.lib,sdpagent.lib, sdpdatabase.lib, esock.libRequired header file(s): btdevice.h, btmanclient.h, bt_sock.h,btsdp.h, bttypes.h, es_sock.hRequired platform security capability(s): LocalServicesProblem: You want to discover the services available for a particularBluetooth-enabled device.Solution: After remote Bluetooth devices have been discovered usingthe Bluetooth Sockets API, the next step is to retrieve the services thosedevices advertise along with the remote port or channel number whichyour application will connect to at later stages.
The following classesallow you to perform this task:• CSdpAgent – service discovery agent.• CSdpSearchPattern – service discovery search pattern.• CSdpAttrIdMatchList – attribute ID match list.• MSdpAgentNotifier – observer interface to provide callbacks forvarious queries.A service search returns the record handles of services that are ofa specified class or classes (UUID numbers). You can find exact values in btsdp.h. If the search is for more than one UUID, then allthe UUID numbers must exist in a service record for it to be considered a match. Service search results are returned through asynchronouscallbacks to an MSdpAgentNotifier interface, which the caller (thatis, your code) must implement in order to be notified about the querycompletion.CONNECTIVITY289The steps to perform a service search are as follows:1.
Create a CSdpAgent object, supplying it with an MSdpAgentNotifier object and the device address of the remote Bluetoothdevice obtained from the device discovery procedure:CSdpAgent* agent = CSdpAgent::NewLC(aObserver, aDevAddr);2. Create a CSdpSearchPattern object to specify the service classesto search for. Classes can be added through CSdpSearchPattern::AddL() calls:CSdpSearchPattern* list = CSdpSearchPattern::NewL();list->AddL(KL2CAPUUID);3.
Set the search pattern on the agent object:agent->SetRecordFilterL(*list);4. Call CSdpAgent::NextRecordRequestL() to get search resultsuntil results are exhausted, or sufficient results have been obtained:agent->NextRecordRequestL();The result is returned by a MSdpAgentNotifier::NextRecordRequestComplete() method call.In addition to the available services list, you usually need to fetchmore information about a particular service. This data is contained inservice attributes and can be gathered via a similar mechanism as for theservices:CSdpAttrIdMatchList* matchList = CSdpAttrIdMatchList::NewL();CleanupStack::PushL(matchList);matchList->AddL(KSdpAttrIdProtocolDescriptorList);agent->AttributeRequestL(serviceHandle, *matchList);CleanupStack::PopAndDestroy();The result is returned by the MSdpAgentNotifier::AttributeRequestResult() method implemented by the observer.Discussion: Clients that make service and attribute queries through CSdpAgent must implement the MSdpAgentNotifier interface to handlethe responses.All queries are asynchronous, so the interface functions that receiveresponses are only called when the thread’s active scheduler can schedulethe handling of the completion of the query.290SYMBIAN C++ RECIPESWhen a service search request completes, it calls NextRecordRequestComplete().