C H A P T E R  3

Porting the Bluetooth Optional Package

This appendix discusses the design and porting of the Bluetooth optional package (JSR 82) for the Java ME platform. The Bluetooth Specification provides a standard set of Java programming language APIs that enables low-power, handheld devices such as cell phones, pagers, PDAs, and other small devices to share functionality over a peer-to-peer wireless connection. Bluetooth wireless technology allows for heterogeneous connections between different kinds of devices (for example, between a cell phone and a PDA).

For a complete description of Bluetooth functionality, see the Bluetooth Specification 1.1 at the following URL:

http://jcp.org/aboutJava/communityprocess/final/jsr082/index.html


Bluetooth Overview

Bluetooth technology (the Bluetooth stack) is built upon the Connected Limited Device Configuration and can be loosely divided into two components:

Communication between the Bluetooth controller and the Bluetooth host is managed by the Host Controller Interface (HCI).

Bluetooth Profiles

Bluetooth technology supports a number of profiles, including the following generic profiles:

The generic profiles shown here and other functionality available with Bluetooth technology are found in the javax.bluetooth package, which depends upon javax.microedition.io.

In addition, Bluetooth technology supports the Object Exchange Protocol (OBEX). which is a separate optional package outside the core Bluetooth APIs, it is also used to establish connectivity between Bluetooth clients and Bluetooth servers and can be used to "push" or "pull" objects from one to the other.

OBEX functionality is available in the javax.obex package and also depends upon javax.microedition.io.

Bluetooth Functionality

Bluetooth technology supports three categories of basic functionality, including the following:

Bluetooth Control Center

The Bluetooth Control Center (BCC) is a set of capabilities that allows a user, device manufacturer, or Bluetooth service provider to define specific values for configuration parameters in a Bluetooth stack. The Bluetooth Control Center also makes it possible to manage and resolve conflicting requests made by wireless applications to a Bluetooth implementation, for example, by setting a specific security policy or defining a list of trusted devices.


BluetoothStack Interface and the Bluetooth Control Center

The JSR 82 optimized implementation of Java Wireless Client software uses the BluetoothStack interface whenever communication with the underlying Bluetooth stack is required. The BluetoothStack interface provides an API for device management and security. Typical scenarios include the following:

The BCC interface is used to provide access to services implemented by a dedicated application, which serves as a central authority for local Bluetooth device settings. Those services include retrieval of cached and preknown devices, pairing, authorization, and so on. The BCC application is usually already available on the target platform and is implemented in native code.

Some functionality of the BluetoothStack interface and BCC interface is overlapping. For example, both interfaces have methods for doing the following things:

In most cases, the default implementation of the BCC interface forwards these requests to the corresponding BluetoothStack interface methods. The idea is that the BCC interface provides a higher level of operation, while the BluetoothStack interface is used for low-level communication. For example, the authenticate() method of the BCC interface might request the user to enter a PIN code before asking the BluetoothStack interface to perform an actual authentication. The overlapping of APIs is also required for the emulation build, where the BluetoothStack interface is not used at all.



Note - The native part of the BluetoothStack interface is currently implemented in C++, while plain C is used for the native BCC implementation.



Porting the BluetoothStack Interface

The BluetoothStack interface is presented by an abstract BluetoothStack Java programming language class and a corresponding abstract CBluetoothStack C++ class. The Java programming language class handles parameter checking, exception handling, synchronization and other higher-level tasks, while the native class takes care of communication with the underlying Bluetooth stack. During porting on the target platform, it may be required to subclass the Java programming language class, native class, or both.

Assumptions About the Implementation

The following assumptions have been made in regard to the underlying stack implementation:

Often, polling for and extraction of events is not directly supported by the Bluetooth stack API. Instead, a Bluetooth stack implementation can provide a callback mechanism for delivering notifications and events. However, it must also be possible to implement polling for a callback-oriented API (for example, a callback function can save event data, which can be retrieved later during a polling call).

For passing Bluetooth events from the native to the Java programming language side, a binary serialization of events is used. To minimize your porting effort, serialize event data in the format used for representing corresponding HCI events, as it enables you to reuse event construction code provided by the GenericBluetoothStack interface. However, any other serialization method is also acceptable.

Implementation Requirements

The underlying Bluetooth stack implementation must be able to do the following:

The Bluetooth stack implementation must report the following events:


procedure icon  Porting the Bluetooth Stack

1. Determine whether your Bluetooth stack provides access to HCI.

For stacks providing primitives to access HCI layer, the GenericBluetoothStack implementation is the best starting point for the port. The HCI specifies a uniform command interface to the Bluetooth controller and covers all the functionality represented in the BluetoothStack porting interface. If the target Bluetooth stack provides an API for the HCI, it can be beneficial to use that API, so that the porting effort can be reduced to a minimum. When using this approach, it is often enough to just implement the HCI transport, as all higher-level methods are already provided by the GenericBluetoothStack interface implementation.

However, some stack implementations might lack a usable API to access the HCI layer, or provide other reasons to use a high-level API instead. In such cases, use the BluetoothStack as a base class for the implementation.

2. Subclass CGenericBluetoothStack C++ class.

Usually, the GenericBluetoothStack Java programming language class does not need to be subclassed or modified, as it already implements all abstract methods of the BluetoothStack accordingly. In the CGenericBluetoothStack C++ class, the following three HCI-related abstract methods are declared, which need to be implemented in a subclass:

Also, the following event-related methods declared in CBluetoothStack class need to be defined:

All other HCI events are filtered out.

3. Subclass the BluetoothStack Java programming language class and the CBluetoothStack C++ class.

When using higher-level API provided by the Bluetooth stack, it is required to make appropriate API calls in the following C++ class methods:

All of these methods must not block and must perform asynchronously. Also, the two event-related methods declared in CBluetoothStack class need to be defined.

Bluetooth events are usually provided using callback functions in the stack API. The usual practice is to store events when a callback function is invoked and access the events stored from CheckEvents() and ReadData() methods.

It is also required to subclass the BluetoothStack Java programming language class and override the retrieveEvent() method, which converts binary data of an event extracted with ReadData() into the corresponding Java programming language class. See the GenericBluetoothStack implementation for an example.

4. Implement other device management methods.

The following methods need to be implemented:

See the Doxygen-generated documentation for details on these methods and their arguments.

All of these methods are also present in the BCC interface and the default BCC implementation forwards calls to the BluetoothStack interface. However, in some cases, the BCC itself is responsible for all or some of the functionality provided by these methods.

Even though all of the methods mentioned can be implemented using the HCI, the GenericBluetoothStack currently does not provide such an implementation. None of the methods access remote devices and all of them must perform synchronously, so a higher-level API usually can be used. Still, future versions of GenericBluetoothStack might include an HCI-based implementation, which reduces the porting efforts of an HCI-compatible API even further.

5. Implement SDDB functionality.

The Service Discovery Database functionality is contained in two methods:

Both methods take a record handle as their first parameter. These handle values are not related to the ServiceRecordHandle attributes associated with the service records. Instead, these handles are only used to uniquely identify service records in the upper-level code, and might or might not match the ServiceRecordHandle attribute values used by the SDDB internally.

The updateRecord() method replaces the existing SDDB entry identified by the given handle with a new one. The new record is passed in a byte array, containing attribute-value pairs in the format identical to the one used in the AttributeList parameter of the SDP_ServiceAttributeResponse protocol data unit (PDU). See the Bluetooth specification for details. This method returns the new handle value (or the same handle value, if it has not changed).

The removeRecord() method is permanently deletes an existing SDDB entry identified by the given handle. The handle value specified can then be reused by new SDDB entries.

Porting the BCC Interface

The BCC is an abstract Java programming language class. The class currently has two implementations, JavaBCC for use with the emulation build and NativeBCC for working with Bluetooth radio. Ensure the latter class is instantiated in the BCC.getInstance() method.

Following is a list of NativeBCC methods and possible actions you might need to perform when porting:

Before enabling Bluetooth, the user must to be prompted. If the prompt dialog is to be displayed by the native BCC application, the native bt_bcc_confirm_enable() function needs to be implemented. If the Java programming language-based dialog is expected, the native modifier is dropped and the method is implemented using the Java programming language modifier.

This method is used to check if the local device is available for connection. The native bt_bcc_is_connectable() function returns the connectable status, according to the native BCC application policy.

This method determines if the local and remote device can proceed with authentication without requesting a PIN from the user. The corresponding native bt_bcc_is_paired() function needs to be implemented accordingly.

This method determines if the remote device has previously been authenticated. The corresponding bt_bcc_is_authenticated() function needs to be implemented accordingly. If the authentication status is not known, this function returns false.



Note - At least one connection to the remote device must be present. When the last connection to the remote device is closed, clear the "previously authenticated" state.



This method determines if the remote device is a trusted device. If the concept of trusted devices is supported by the native BCC application, the corresponding native bt_bcc_is_trusted() function needs to be implemented accordingly, otherwise this method always returns false.

This method determines if all connections to the specified remote device are encrypted. The corresponding native bt_bcc_is_encrypted() function needs to be implemented accordingly.

This method retrieves the PIN code associated with a specified remote device. If the PIN code is not known, the user is prompted to enter one. The corresponding native bt_bcc_get_passkey() function needs to be implemented accordingly. In some cases, PIN code retrieval and bonding (pairing) cannot be separated. If this is the case, the getPasskey()method returns any non-null value. A separate method for PIN code retrieval is provided for convenience, or if the UI dialog is implemented in the Java programming language instead.

This method performs bonding with the specified remote device using the given PIN code. The corresponding native bt_bcc_bond() function needs to be implemented accordingly.

This method asks the user whether to allow a connection from the specified remote device to the given service. The corresponding native bt_bcc_authorize() function needs to be implemented accordingly.

These two methods retrieve a list of Bluetooth addresses of cached and previously known devices from the native BCC application. Separate the addresses by a specific character (the default is a colon). The corresponding native bt_bcc_get_cached_devices() and bt_bcc_get_preknown_devices() functions need to be implemented accordingly.

This method retrieves the default ACL connection handle for the specified remote device. This handle is used for authentication and encryption in the BluetoothStack interface. The corresponding native bt_bcc_get_handle() function needs to be implemented accordingly.

This method retrieves the number of connections to the specified remote device, including connections from native applications, if any. The corresponding native bt_bcc_get_connection_count() function needs to be implemented accordingly.

This method increases or decreases the counter of encrypted connection requests for the specified device, including connections from native applications, if any. Once the counter makes a transition from 0 to 1, indicating that the encryption mode needs to be changed, the method must return true. The corresponding native bt_bcc_set_encryption() function needs to be implemented accordingly.

Additionally, two native methods might need to be implemented:


L2CAP Protocol and BTSPP Profile

The descriptions of the Logical Link and Control Application Protocol (L2CAP) and the Bluetooth Serial Port Profile (BTSPP) and have much in common. The major difference is that L2CAP is a packet protocol while BTSPP is a stream protocol.

They differ in the following ways:

The set of Java programming language classes for each protocol consists of two major classes: One represents the Connection class and the other represents the Notifier class. Currently, the L2CAP and BTSPP protocols are implemented on the Linux platform using the BlueZ library, which provides a GNU socket-based interface.

BlueZ Library

Although the BlueZ library has been in development for many years and is in wide use, it has major bugs, especially in non-blocking mode. Comments in the bt*Connection.c files mark workarounds for bugs found in the BlueZ 2.19 library. To install the BlueZ library, you can either build it from the sources downloaded from the official site or get the binaries using the package manager for your version of Linux.

You must also build the Bluetooth kernel modules for your Linux kernel.

Although the library is undocumented, some information can be found in the various forums and mail lists.

The hcidump utility analyzes Bluetooth HCI packets and is very useful for debugging.

Making Connections in L2CAP and BTSPP

The typical name for the connection class is *ConnectionImpl, where (*) is the name of the protocol. *ConnectionImpl classes are inherited from the BluetoothConnectionImpl class. This is a base class for both protocols. It keeps the things associated with the connection, including the following items:

Each *ConnectionImpl contains the native methods initialize() and finalize(). The initialize() method retrieves fieldIDs used to access the Java platform class members from native code. The finalize() method releases native resources. That is, it closes the native connection handle if it is not closed explicitly.

Each connection implementation consists of three parts, where (*) represents L2CAP or BTSPP for the equivalent protocol:

The mode-specific functionality is put in separate methods, whose names end with a "0".

Long-running native code is not suitable for protocol operation because it blocks the VM. Therefore, for asynchronous operations (for example, connect, accept, send, and receive) use the Java Wireless Client software midp_thread_wait and midp_thread_signal mechanism. This is a common mechanism utilized by all Java Wireless Client software network protocols.

The following differences exist between the JSR implementation of GNU sockets, QSockets and event-oriented (callback-oriented) stacks.

*ConnectionGlue.c contains implementations for the native methods of *ConnectionImpl class. To avoid race conditions, native connection handles stored in the fields of the *ConnectionImpl and *NotifierImpl Java platform classes are accessed only from native code. All KNI oriented code is located in these two files and the porting layer is utilized to call native platform-specific connection methods.

There are no global native variables except jfieldID variables that are set once by static initializers and can be safely used by multiple tasks.

This information holds true for the *NotifierGlue.c as well, except for the *NotifierImpl class.

*Connection.h is the porting interface declaration for the protocol, while *Connection.c contains an implementation for the specific platform (the OS plus the underlying bluetooth stack). This API has GNU style sockets but can also be used with other sockets underlying the Bluetooth stacks. The API contains the client connection and server connection. Some functions can be applied only for a dedicated entity, but other functions are common to all.

Be aware of the following issues when using the ROMizer to tune the jsr82_rom.config file:

The Java Wireless Toolkit stores JSR public properties as well as internal properties in Java platform files.

The Java Wireless Client software has its own technology to manipulate properties. It uses the following XML configuration files for this purpose. The configuration files are share, emul, real, and linux.


procedure icon  Porting L2CAP and BTSPP

In the following steps, platform is the name of the target OS (for example, Linux) and protocol is the name of the protocol being used (the possible values are btl2cap, btspp, and irdaobex).



Note - Do not change files located in directories named common during porting.



The following steps describe how to port the Bluetooth optional package to your platform.

1. Create the jsr82/src/config/platform/properties_jsr82.xml file and fill it with valid property values.

Use jsr82/src/config/share/properties_jsr82.xml as a template.

2. Create the jsr82/src/protocol/protocol/native/platform/*Connection.c file that contains an implementation of the protocol's porting layer (*Connection.h) for your target platform.

3. Create a customized subsystem.gmk for the target platform, which is similar to the Linux subsystem.gmk.

4. Build your target platform executable using the newly-created subsystem.gmk file.

A common subsystem.gmk is available for emulation and real modes. Currently linux_qte and linux_fb are supported in real mode.

This customized subsystem.gmk file can include the following declarations:

The current release includes its own trace system for debugging. The trace system is located in btMacros.h. The following macros are declared: PRINT_INFO, PRINT_ERROR, and EXCEPTION_MSG.

You can independently switch each of the macros on and off. You can switch the EXCEPTION_MSG macro on during development in order to catch problems, and switch it off in the production release to reduce the code footprint.

TCK and Java Device Test Suite software can be used to test the implementation. Note that the following permissions must be enabled in the Java Device Test Suite software:


Porting the OBEX Interface

OBEX is a protocol developed by the Infrared Data Association (IrDA) for pushing and pulling objects to or from clients and servers.

The irdaobex protocol is used for devices that make connections using only an infrared port and is implemented in two Java programming language classes: IrNativeConnection and IrNativeNotifier. The Native prefix is used to identify that these classes are mostly implemented in native code and are intended to be used with a non-emulation build. No corresponding implementation is available for an emulation build at the moment.

The porting interface is defined in the IrConnection.h header file. Most of the functions declared there must be implemented during the porting process.

In some cases, when the connection is known to be synchronous, ir_connect_complete is not required.


JavaCall Porting Layer

All JavaCall API Bluetooth functions and variable types have prefix javacall_bt_ or javanotify_bt_.

JavaCall API Bluetooth Variable Types and Values

Most JavaCall API Bluetooth functions return the result value. The type of it is the same as for other JSRs and it has name javacall_result. Most often values are as follows:

Some JavaCall API Bluetooth functions have boolean arguments or return a boolean value (i.e. isDeviceAuthenticated). The JavaCall API boolean type is javacall_bool and it can be JAVACALL_TRUE or JAVACALL_FALSE.

The most important type is javacall_bt_address which is a pointer to a six byte Bluetooth address. For more information on Bluetooth addresses, see the Bluetooth specification at http://www.bluetooth.org/spec.

Definition of JavaCall API Bluetooth Variable Types, Values and Functions

The file javacall_bt.h contains the definition of all variable types, values and function prototypes of the JavaCall API Bluetooth interface.

JavaCall API Bluetooth Function Groups

Memory Allocation

Buffers for all output parameters are allocated by the caller, unless specified otherwise.

In case of strings and arrays, a parameter represents the size of the buffer. If output data does not fit into the buffer of the given size, the JavaCall API function must return JAVACALL_FAIL.

Porting steps

This section explains how the JSR 82 code can be ported to a new platform using the JavaCall API .

1. All functions contain empty bodies. When a function returns javacall_result value it should return JAVACALL_FAIL. Boolean return value should be JAVACALL_FALSE. Be sure that the build contains no mistakes. Insert trace into each function for debugging.

2. Implement functions from the first three groups (Bluetooth Control Center, Bluetooth Stack, Service Discovery Database).

3. Implement L2CAP protocol functions and run available L2CAP tests.

4. Implement RFCOMM protocol functions and run available RFCOMM tests.

5. (Optional) Implement notification functions if needed.