Bluetooth is a short-range wireless communication protocol, transmitting on a frequency of around 2.45 GHz. Connections can be point-to-point (between two devices) or multipoint (between many devices), over a range of up to 10 meters . Further information about Bluetooth, including technical specifications, can be found at the Official Bluetooth Membership Site, Consumer-oriented information on Bluetooth products is available on the website of the Bluetooth Special Interest Group (SIG),

Series 60 provides support for a range of Bluetooth technologies. Most usefully, it provides a Bluetooth plug-in to the Symbian OS Socket Server, which allows developers to form Bluetooth connections using the standard Sockets API. This API is covered in detail in the Sockets section earlier in this chapter, and you should ensure that you are familiar with that first.

This section presents a brief overview of Bluetooth technology before providing a detailed discussion of Bluetooth socket programming for Series 60. This is supported by an example application, BluetoothChat , which shows the key APIs in use.

Bluetooth Overview

This subsection provides a brief overview of Bluetooth essentials, in order to place the material that follows into context.

The Bluetooth Stack

The combination of hardware and software required on a device for it to support Bluetooth is known as the Bluetooth stack. It comprises the following parts :

  • Physical Layer ” The Bluetooth radio transceiver.

  • Baseband ” A low-level layer concerned with establishing connections and controlling the transmission of data bits over the physical layer. Typically this is also implemented in hardware.

  • Bluetooth Protocols ” A set of software components , similar in concept to network protocols such as IP and TCP, which provide support for Bluetooth communication at varying levels of capability and reliability.

  • Bluetooth Profiles ” Higher-level software components that implement well-defined services on Bluetooth-capable devices and ensure correct interoperability with other devices.

Bluetooth Protocols

The following are some of the most commonly used Bluetooth protocols:

  • Link Manager Protocol (LMP) ” Manages the behavior of the wireless link, controlling the baseband device and allowing service discovery (which will be covered later in this section). It also addresses security.

  • Logical Link Control and Adaptation Protocol (L2CAP) ” Offers connectionless and connection-oriented data services between the baseband layer and the upper protocols. It also supports data stream segmentation and reassembly, allowing the upper layers to use data packets larger than the baseband can handle.

  • Radio Frequency Communications (RFCOMM) ” A reliable transport protocol that provides emulation of RS-232 serial ports over the L2CAP protocol.

  • Service Discovery Protocol (SDP) ” Allows Bluetooth devices to discover services offered by other devices. It is responsible for broadcasting queries and fielding the responses to determine which devices offer particular services.

Bluetooth Profiles

A number of different profiles are defined by the Bluetooth specification, and each Series 60 device supports a subset of these. The exact set of profiles supported is determined by the handset manufacturer ”there is no single set of Series 60-supported profiles. However, commonly implemented profiles include:

  • Object Push Profile ” Allows a Bluetooth device to send and receive OBEX objects, such as vCard and vCal items.

  • File Transfer Profile ” Depending on the profile implementation on the device, this profile may allow you to browse, delete, send files to and receive files from a Series 60 device. File Transfer Profile can also be implemented as a server only.

  • Fax Profile ” The Fax profile will allow you to send faxes to, and receive faxes from, a Bluetooth device (typically a PC) using the phone as a fax modem.

  • DUN (Dial-Up Networking) Profile ” Allows a device such as a laptop to use a phone as a data modem.

  • Serial Port Profile ” Provides legacy support for older applications and protocols using the RFCOMM protocol. It provides a virtual COM port, similar to an RS-232 port on a PC. This profile is often used as the data carrier for other profiles and applications.

  • Headset Profile, Hands Free Profile ” Enable phones to connect to wireless headsets and Bluetooth car kits.

Service Advertisement and Discovery

A Bluetooth device may offer services for other devices to connect to, and/or connect to other devices itself and make use of their services. A Bluetooth device that offers services to others is known as a server, and the user is known as a client.

Do not confuse the terms client and server used here with the Symbian OS Client/Server framework. The two are not the same ”for example, a Bluetooth server can be implemented in a Symbian OS client process. Throughout the Bluetooth section, unless otherwise specified, the terms client and server are used in the Bluetooth sense.

A Bluetooth server makes services available by means of a process known as Service Advertisement ”information about the new service is provided to any other Bluetooth devices that wish to query it. It does not necessarily guarantee that an attempted connection will be successful. When an application advertises its ability to accept connections, an entry is placed in the device's Bluetooth Service Discovery Database ( SDD ).

Regardless of the type of service provided, a Bluetooth service advertisement will consist of the following information:

  • Port ” The port number an incoming connection will be accepted on. Many applications can advertise their services on a device, with each accepting a connection on a specified port.

  • Class ID ” A class ID that will provide information on the type of service provided.

  • Availability ” The availability of this service. When an application accepts an incoming connection, it will mark its entry in the Service Discovery Database as not available. This will inform any other devices that may wish to connect that it is currently occupied.

Most entries will also contain user-readable text to explain the type of service they offer, and it is even possible to provide a graphical icon for a service.

On the client side, an attempt to make a Bluetooth connection is typically preceded by a process of searching for local Bluetooth-enabled devices and querying the services they provide. This process is known as Service Discovery .

The Series 60 APIs for service advertisement and discovery are covered later in this section.

Example Bluetooth Application

The rest of this section looks at the example application BluetoothChat , which allows two users to exchange short instant chat messages using Bluetooth as the communication medium. The application contains both client and server code and requires one user to act as a server and one as a client. This section examines the Bluetooth-specific APIs used by the application, in both the server and client code ”starting with the service advertisment and discovery phase, before moving on to detail the socket-based communication between the devices.

Service Advertisement

In the BluetoothChat application the user can choose whether they wish their device to act as the client or the server. If they choose Start Receiver from the menu, as shown in Figure 9-4, then their phone will act as the server and listen for incoming connections. After the appropriate port number is obtained from the Socket Server, the first step in this process is to advertise the BluetoothChat service.

Figure 9-4. The BluetoothChat menu options.

Service advertisement of the BluetoothChat service is performed by the CBluetoothAdvertiser class, in the StartAdvertisingL() function. This class's member data is shown below:

 RSdp                   iSdpSession; RSdpDatabase           iSdpDatabase; TSdpServRecordHandle   iRecord; TInt                   iRecordState; 

The first step is to connect to the Service Discovery Database (SDD). This is performed via an RSdp session. You may then use this RSdp session to open an RSdpDatabase subsession for access and manipulation of the database.

 // Connect to the Service Discovery Database. if (!iIsConnected)    {    User::LeaveIfError(iSdpSession.Connect());    User::LeaveIfError(iSdpDatabase.Open(iSdpSession));    iIsConnected = ETrue;    } 

You are now ready to create entries within the Service Discovery Database. First you must create a UUID (Universally Unique Identifier) that uniquely defines your service. In the BluetoothChat example, the UID of the application itself is used, as this is guaranteed to be unique within Series 60.

The CreateServiceRecordL() function is used to create service records within the database.

 // UID of the application. const TUint KServiceClass = 0x101F6148; iSdpDatabase.CreateServiceRecordL(KServiceClass, iRecord); 

The iRecord member is an instance of TSdpServRecordHandle . This is passed by reference, and when the function returns, it will contain the service handle of the newly created service record.

There are two overloaded versions of CreateServiceRecordL() . The example above assigns the record to one service class, whereas the overloaded version will assign the record to multiple service classes. (An example of a service with multiple classes is a color printer that can advertise its services as being a printing device and a color printing device.)

Now that a record has been entered into the database, you can assign some attributes to it.

Creating Service Record Attributes

Attributes are items of additional information that can be added to a service record. The BluetoothChat application adds the following attributes to its service record:

  • Protocol Description.

  • Service Name .

  • Service Description.

Service Name and Service Description are just extra textual information that may prove to be useful:

 _LIT(KServiceName, "EMCC Chat"); _LIT(KServiceDescription, "Bluetooth Chat Application"); 

The Protocol Description contains information that is needed to establish a successful connection. Creating the protocol description will involve building a Data Element Sequence ( DES ) using the CSdpAttrValueDES class.

The CSdpAttrValueDES::StartListL() function opens and returns a new DES list within the current list sequence, and by using the BuildxxxxL() functions it is possible to populate this list with actual data. When the current DES list has been appropriately populated , calling the EndListL() function will close it and return its parent list. In the BluetoothChat application this is performed in the function CBluetoothAdvertiser::BuildProtocolDescriptionL() .

Notice that the bulk of this function is a single line of code, split over a number of lines for readability. As the CSdpAttrValueDES APIs used here all modify the DES list and then return a pointer to it, this is a standard way of building a list, which you will see used in Bluetooth code throughout Series 60.

[View full width]
[View full width]
void CBluetoothAdvertiser::BuildProtocolDescriptionL(CSdpAttrValueDES* aProtocolDescriptor , TInt aPort) { TBuf8<1> channel; channel.Append((TChar)aPort); aProtocolDescriptor ->StartListL() // List of protocols required ->BuildDESL() ->StartListL() // Details of lowest level protocol ->BuildUUIDL(KL2CAP) ->EndListL() ->BuildDESL() ->StartListL() ->BuildUUIDL(KRFCOMM) ->BuildUintL(channel) ->EndListL() ->EndListL(); }

KL2CAP and KRFCOMM are constant values that represent parts of the Bluetooth stack. Their actual values are defined within the Bluetooth specification.

The parameter channel represents the port that this service will be advertised on. This is retrieved via a call to obtain an available RFCOMM channel on the listening socket that the server will advertise on, and which the client should bind to.

[View full width]
[View full width]
// Get a channel to listen on // same as the socket's port number TInt channel; User::LeaveIfError(iListeningSocket.GetOpt(KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, channel));

Now the attributes are added in the following manner:

[View full width]
[View full width]
// Add protocol information iSdpDatabase.UpdateAttributeL(iRecord, KSdpAttrIdProtocolDescriptorList, *vProtocolDescriptor);

The KSdpAttrIdProtocolDescriptorList constant value is part of the Bluetooth specification and defines attributes key to every service record.

[View full width]
[View full width]
// Add a name to the record iSdpDatabase.UpdateAttributeL(iRecord, KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceName, KServiceName); // Add a description to the record iSdpDatabase.UpdateAttributeL(iRecord, KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceDescription, KServiceDescription);

Removing Service Records

Once the service record has been added to the database, it will become available to other devices and their applications. When a connection is made, you should stop advertising the service. You can do this by marking the service as busy, using UpdateAttributeL() to modify the KSdpAttrIdServiceAvailability parameter in the service record. Alternatively, you could delete the record from the database, as shown in this code snippet from CBluetoothAdvertiser::StopAdvertisingL() :


Closing the Service Discovery Database

When a client application has finished with its Bluetooth services, it should disconnect from the Service Discovery Database. In BluetoothChat this is performed in the destructor of CBluetoothAdvertiser . The SDP session is closed at this point as well.

 iSdpDatabase.Close(); iSdpSession.Close(); 

Series 60 keeps track of all sessions that are connected to servers. Once a server no longer has any sessions accessing it, the operating system will shutdown the server. This means that the SDD will be shutdown once there are no longer any applications with open sessions onto it, even if there are other Bluetooth devices accessing it. It is therefore recommended that the client application keep a session to the database open during the period it wishes to publicize its services.

Bluetooth Security

Typically a receiving device will stipulate a collection of security settings for the Bluetooth connections it offers. Series 60 provides a Bluetooth Security Manager API, and this allows applications to specify a set of security settings in order to determine whether user authorization, authentication or encryption are required when establishing a connection. These security settings are applied to a specific server, protocol and channel.

The Bluetooth Security Manager ensures that incoming connections adhere to the application settings; it is implemented as a server within the Series 60 Bluetooth API. The class RBTMan encapsulates a session to this server, and subsessions are used to access specific functionality. The subsession required for a service to register its security settings with the security manager is RBTSecuritySettings .

The TBTServiceSecurity class encapsulates the security settings of a Bluetooth service ”containing information regarding the service UID, the protocol and channel IDs and access requirements. Access requirements are set either on or off by passing a TBool value to the functions SetAuthentication() , SetAuthorisation() and SetEncryption() . It is also possible to deny all access using the SetDenied() function.

Once the security settings within TBTServiceSecurity have been set, the RBTSecuritySettings::RegisterService() function allows the application to register its security settings with the Security Server.

The UnregisterService() function allows an application to remove any security requirements.

Once the security settings are registered with the Security Server, the application no longer requires access to the server, so its session and connection can be terminated . In the BluetoothChat application these steps are carried out by the CBluetoothServer class using the following member data:

 RBTMan                    iSecManager; RBTSecuritySettings       iSecSettingsSession; TState                    iState; 

The function CBluetoothServer::SetSecurityOnChannelL() is responsible for configuring security settings:

[View full width]
[View full width]
void CBluetoothServer::SetSecurityOnChannelL(TBool aAuthentication, TBool aEncryption, TBool aAuthorisation) { // connect to the security manager // and open a settings session. User::LeaveIfError(iSecManager.Connect()); User::LeaveIfError(iSecSettingsSession.Open(iSecManager)); // the security settings TBTServiceSecurity serviceSecurity(KUidBluetoothChat, KSolBtRFCOMM, 0); //Define security requirements serviceSecurity.SetAuthentication(aAuthentication); serviceSecurity.SetEncryption(aEncryption); serviceSecurity.SetAuthorisation(aAuthorisation); serviceSecurity.SetChannelID(iChannel); // make an asynchronous request iSecSettingsSession.RegisterService(serviceSecurity, iStatus); iState = ESettingSecurity; SetActive(); }

Typically it is the receiving device that stipulates the security settings for any given Bluetooth connection. When a requesting device discovers that a receiving device stipulates a set of security requirements, the requesting device will automatically implement these requirements, and this process will appear transparent to the application.

Device and Service Discovery

The preceding subsection demonstrated how to advertise services in a Bluetooth server application. This subsection covers the API for searching for devices and querying their SDD for the services they provide.

There are two methods of searching for remote devices:

  • RNotifier ” The RNotifier class presents the user with a UI dialog listing all Bluetooth devices currently in range and advertising appropriate services. The address of the device selected by the user is returned to the application. This is sufficient for most client applications, but its major drawback is that it does not filter the list of devices it displays. Therefore it is not possible for the client application to use this API to display a list of devices providing a specific service.

  • RHostResolver ” The RHostResolver API provides a way for the client application to programmatically search for local devices. This allows the author of the application to filter the list of locally available devices before displaying them on the screen. Although this method provides more control over the list of displayed devices, it is more complicated than using RNotifier .

As the use of RHostResolver has already been documented in the Infrared section, the BluetoothChat application uses the RNotifier API.

Device Discovery Using RNotifier

RNotifier represents a session to the Notifier Server, which is used to display system dialogs. As with any other session class, the first step in using it is to create and connect an instance. In this case, the CBluetoothDeviceSearcher class has an RNotifier member variable ( iNotifier ) which is connected in its SelectDeviceL() method by calling iNotifier.Connect() .

The RNotifier class is responsible for displaying many different types of dialog. Each type is represented by a unique ID. The UID representing the Bluetooth Device Selection dialog is KDeviceSelectionNotifierUid , and this is passed to RNotifier::StartNotifierAndGetResponse() to invoke the dialog.

The full list of parameters passed to this function is as follows:

  • A TRequestStatus& , as this is an asynchronous function.

  • The RNotifier UID.

  • A TBTDeviceSelectionParamsPckg ”a package descriptor containing an instance of TBTDeviceSelectionParams , which specifies a way of filtering the number of devices that are returned. This parameter is currently ignored and could be left uninitialized . However, it is hoped that it will be supported in future releases of the platform, so its correct use is shown in the BluetoothChat application.

  • A TBTDeviceResponseParamsPckg , which will be populated with device information after a device successful selection.

The call to the function can be seen here:

[View full width]
[View full width]
void CBluetoothDeviceSearcher::SelectDeviceL(TBTDeviceResponseParamsPckg& aResponse) { // store a pointer to the response buffer iResponse = &aResponse; TUUID targetServiceClass(KServiceClass); TBTDeviceClass deviceClass(KServiceClass); TBTDeviceSelectionParams selectionFilter; selectionFilter.SetUUID(targetServiceClass); selectionFilter.SetDeviceClass(deviceClass); // These filtering methods do not work at // the time of writing, and ALL Bluetooth // devices in range are returned TBTDeviceSelectionParamsPckg selectionParams(selectionFilter); User::LeaveIfError(iNotifier.Connect()); iNotifier.StartNotifierAndGetResponse(iStatus, KDeviceSelectionNotifierUid, selectionParams, aResponse); SetActive(); }

As you can see, CBluetoothDeviceSearcher is an Active Object which will handle completion of the request in its RunL() method. The following code is used to verify successful device retrieval and close the handle to the notifier:

 void CBluetoothDeviceSearcher::RunL()    {    TInt retVal = iStatus.Int();    if (retVal == KErrNone)       {       if ((*iResponse)().IsValidDeviceName())          {          retVal = KErrNone;          }       }    iNotifier.CancelNotifier(KDeviceSelectionNotifierUid);    iNotifier.Close();    iObserver.DeviceFoundL(retVal);    } 

The TBTDeviceResponseParamsPckg variable now contains the 48-bit Bluetooth device address ( TBTDevAddr ) of the device you have chosen to communicate with. This may be retrieved via a call to TBTDevAddr::BDAddr() .

Service Discovery

Once you have the address of a Bluetooth device, you can query it for the services it provides. This is essential, as you will need to discover whether the remote device provides the service you require ”in this case, BluetoothChat. You will also need to discover on what port number the service is advertised, and whether it is presently available.

Service discovery involves querying the remote device's SDD to see whether the service you requested is advertised. The process involves finding records that correspond to the required service and then viewing attributes on those records.

Service discovery is an asynchronous process, and a number of callback functions need to be implemented in order to handle information retrieval from it. The Bluetooth API provides the MSdpAgentNotifier mixin class in order to handle callbacks, and this contains the following three pure virtual functions that need to be implemented:

[View full width]
[View full width]
virtual void NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount) = 0; virtual void AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue) = 0; virtual void AttributeRequestComplete(TSdpServRecordHandle, TInt aError) = 0;

A CSdpAgent object is used to perform the query. The CSdpAgent must be created specifying an MSdpAgentNotifier observer object, and the Bluetooth device address of the device the client application wishes to query. In the BluetoothChat application, the CBluetoothServiceSearcher class implements the MSdpAgentNotifier mixin.

The CSdpSearchPattern class is used to specify the SDD records that you are interested in. Once a search pattern list has been built you should pass it through to CSdpAgent::SetRecordFilterL() .

The following code shows these APIs in action:

 iSdpSearchPattern = CSdpSearchPattern::NewL(); iSdpSearchPattern->AddL(KServiceClass); ... iAgent = CSdpAgent::NewL(*this, aDeviceAddress); iAgent->SetRecordFilterL(*iSdpSearchPattern); iAgent->NextRecordRequestL(); 

When the record request completes, the function NextrecordRequestComplete() will be called on the CBluetoothServiceSearcher class. The parameters of this function are an error code, a service record handle and a count of matching records.

Within the implementation of this function you must first check that the aError variable is set to KErrNone , indicating that the record request was successful. Next check the value of aTotalRecordsCount to see how many matching records were found. If there was no error and the number of records is greater than zero, then aHandle will be a valid handle on the first record matching the search filter parameters. Its attributes can be queried via a call to CSdpAgent::AttributeRequestL() , as shown below:

 iMatchList = CSdpAttrIdMatchList::NewL(); // Availability iMatchList->AddL(KSdpAttrIdServiceAvailability); // Port Number, RFCOMM, L2CAP iMatchList->AddL(KSdpAttrIdProtocolDescriptorList); ... TRAPD(error, iAgent->AttributeRequestL(aHandle, *iMatchList)); 

You can also search for a single attribute using an overloaded version of AttributeRequestL() . See the SDK documentation for further details.

When performing an attribute search, the AttributeRequestResult() function will be called once for every attribute that matches the search criteria. The parameters passed to this function are a record handle, an attribute ID and a pointer to an attribute value ( CSdpAttrValue ) object. The attribute ID can be queried to see which attribute's values are being passed back, and the aAttrValue parameter will contain a pointer to the relevant attributes values, as shown below:

 void CBluetoothServiceSearcher::AttributeRequestResult(TSdpServRecordHandle aHandle,    TSdpAttributeID aAttrID,    CSdpAttrValue* aAttrValue)    {    TRAPD(error, AttributeRequestResultL(aHandle, aAttrID, aAttrValue));    } void CBluetoothServiceSearcher::AttributeRequestResultL(TSdpServRecordHandle /*aHandle*/,    TSdpAttributeID aAttrID,    CSdpAttrValue* aAttrValue)    {    if (aAttrID == KSdpAttrIdProtocolDescriptorList)       {       // Validate the attribute value, and extract       // the RFCOMM channel       // iContinueSearching flag will show ETrue if this       // parse is successful       TBluetoothAttributeParser parser(*this, iContinueSearching);       aAttrValue->AcceptVisitorL(parser);       }    else if (iContinueSearching && aAttrID == KSdpAttrIdServiceAvailability)       {       if (aAttrValue->Type() == ETypeUint)          {          iAvailable = static_cast<TBool>(aAttrValue->Uint());          ...          }       }    delete aAttrValue;     // Ownership has been transferred    } 

Ownership of the aAttrValue parameter is passed into the function. It is your responsibility to delete this, once you have finished with it, otherwise a memory leak will occur.

It is important to know the type of each value passed into this function, as the CSdpAttrValue class provides retrieval functions for many different types. You can call aAttrValue->Type() to find the value's type, and then you must call the appropriate getter for that type. The code above shows how to get an unsigned integer value in this way.

An attribute may also be a list of values; such lists are known as Data Element Alternatives (DEA) or Data Element Sequences (DES). If an attribute is of one of these types, it needs to be parsed in order to extract individual values. The mixin class MSdpAttributeValueVisitor is used for this purpose. In the BluetoothChat application, this mixin is implemented by the TBluetoothAttributeParser class and is used for extracting values from the KSdpAttrIdProtocolDescriptorList element. TBluetoothAttributeParser is passed through as a parameter to the aAttrValue->AcceptVisitorL() function, and VisitAttributeValueL() is called for each member of the list. Below is the implementation of this function in the BluetoothChat application:

[View full width]
[View full width]
void TBluetoothAttributeParser::VisitAttributeValueL(CSdpAttrValue& aValue, TSdpElementType /*aType*/) { switch (iProcessingState) { case EStartOfDesOne: case EStartOfDesTwo: case EL2Cap: case EEndOfDesTwo: case EStartDesThree: break; // check nothing case ERFComm: CompareRFCOMM(aValue); break; case ERFCommPort: GetPort(aValue); break; case EEndOfDesThree: case EEndOfDesOne: break; // check nothing default: // unexpected output panic Panic(EBadAttributeValue); break; } Next(); }

This enables you to extract whether RFCOMM is an available protocol and to obtain the port number of the remote device that this service is advertised on.

Once all attributes matching the search parameters have been returned to the client application, the observer function MSdpAgentNotifier::AttributeRequestComplete() will be invoked. At this point, if the service you are interested in has not been found, then it is normal practice to issue another iAgent->NextRecordRequestL() , unless the error code parameter to this function is equal to KErrEOF , which highlights that all records have been processed .

Bluetooth Socket Communication

Provided that the device and service discovery phase was successful, you now have an address and port number identifying a service on a remote device. This information can be used to open a socket session with that device.

Note that the general steps involved in opening a socket in Series 60 are covered in detail in the Sockets section earlier in this chapter ”you should read through that section to familiarize yourself with it before continuing with this section. The generic steps that have been described previously will not be covered in detail again here.

The Bluetooth Server

Just as before, socket communication starts by connecting to the Symbian OS Socket Server and then opening a socket. The only difference in this case is the protocol specified when opening the socket, which is set to "RFCOMM" (here represented by the constant KServerTransportName ).

 User::LeaveIfError(iSocketServer.Connect()); User::LeaveIfError(iListeningSocket.Open(iSocketServer, KServerTransportName)); 

Next you need to obtain a channel (a port number) to listen on. This is achieved with a call to RSocket::GetOpt() . The parameters define the type of option request ( KRFCOMMGetAvailableServerChannel ) and the protocol ( KSolBtRFCOMM ). These constants are defined in the system header file bt_sock.h . The third parameter represents the channel to listen on, and it is populated if this function returns without error.

[View full width]
[View full width]
User::LeaveIfError(iListeningSocket.GetOpt(KRFCOMMGetAvailableServerChannel, KSolBtRFCOMM, iChannel));

You then create a Bluetooth socket address object ( TBTSockAddr ), set its port to the channel just obtained and bind the socket to this address. Note you do not have to set the local Bluetooth device address in this case.

 TBTSockAddr listeningAddress; listeningAddress.SetPort(iChannel); User::LeaveIfError(iListeningSocket.Bind(listeningAddress)); 

Now you are ready to listen for incoming connections. As before, you need to specify a listening queue size ”in other words, the number of outstanding requests you want to queue before further requests are rejected. Presently devices are limited to only one Bluetooth connection at a time, so the value of KListeningQueSize is set to 1.

 // Listen for incoming connections User::LeaveIfError(iListeningSocket.Listen(KListeningQueSize)); 

Finally, you should make a call to the asynchronous function Accept() , which will complete when the first connection attempt is successful.

 iListeningSocket.Accept(iAcceptedSocket, iStatus); SetActive(); 

Once the socket has been set up successfully, you need to configure the security manager. In the BluetoothChat example application this is performed in the function CBluetoothServer::SetSecurityOnChannelL() , which is shown in the Bluetooth Security subsection above. Once this is done, you are ready to advertise the new Bluetooth service you have created. In the BluetoothChat application this is achieved using the CBluetoothAdvertiser methods StartAdvertisingL() and UpdateAvailabilityL() . The server must also ensure that when an incoming connection is accepted, the appropriate entry in the SDP database is marked as being used (if the record has not been deleted). This ensures that a second client will not attempt to connect on the same port. This is performed in the CBluetoothAdvertiser::StopAdvertisingL() function, detailed above.

You should also ensure that you call StopAdvertisingL() when your application is shut down, in order to remove your entry from the SDD.

Once these steps are complete, you can start to send and receive data over iAcceptedSocket in the generic way described in the Sockets section.

The Bluetooth Client

As with the server code, the first step on the client side is to connect to the Symbian OS Socket Server and then open a socket, specifying RFCOMM as the required protocol.

As shown previously in this section, the service discovery phase is used to obtain an address and port number, which are then used to initialize a TBTSockAddr object. This object is then passed to RSocket::Connect() :

 iSendingSocket.Connect(iSocketAddress, iStatus); SetActive(); 

Once the connection succeeds, client and server can communicate using standard RSocket function calls.

Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139 © 2008-2017.
If you may any questions please contact us: