Department of Automatic Control

Bluetooth




The Harald Homepage

A Bluetooth stack in Java

Harald is a small Bluetooth stack for wireless communication between Java applications. Harald accesses the Bluetooth chip via the serial port and therefore requires the JavaComm package to be installed. The stack will operate on any system where Java runs. The package is free for any use and for distribution.


Installation

download harald_v1.0


Download the zip-file and unzip into a desired directory <dir>. Go to <dir>/source/ and type 'make'. There are a few demos included in the distribution and they are found under <dir>/source/demo. After doing 'make' there will also some limited documentation which is accessed from <dir>/doc/index.html.


The 'simple'-demo includes three short programs 'test1', 'test2' & 'test3', which show how to initiate the stack, create a link, open a channels and then pass arbitrary Java objects back and forth. The are two script-files 'slave' & 'master' which show how to invoke a test. To use them open two console windows, go to the 'simple'-directory and type 'slave' in one window and 'master' in the other and now hopefully you will have a small wireless system. The above example of course assumed that you had two Bluetooth cards attached to your machine, one at each serial port.


The 'Chat'-demo screen is a bit more complicated. Again open two console windows and type 'chat1' in the first one and 'chat2' in the second. You will now see the following screen. You now need to do the following:

  1. Check 'Page/Scan Enable' in the first chat application (chat1)

  2. Chose 'Do Inquiry' in the second chat application (chat2). screen.

  3. If the inquiry was successful, i.e. chat1 was found, do a connect. screen. If the inquiry failed repeat step 2.

  4. Accept the connection (If you wait to long here there will be a time out and you will have to repeat step 2) and a link will be ready.

  5. Now it should read 'Link established' on the status bar on each window. Before any communication can take place you must open a channel. To do this chose 'Open' channel from the menu, select a channel number. screen.

  6. Chat your heart out! screen.



An overview of the suggested usage of the class library

This section requires the reader to have some basic knowledge of the Bluetooth standard, found at www.bluetooth.com.

The main class is Local which is connected to the Bluetooth card via a Driver class. The Local class is used to send and receive HCI (Host-Controller Interface) messages.

  • The Local class must be initiated before use

    Create a comm port driver:

    RS232Driver driver = new RS232Driver(portName);

    Construct a new Local class:

    local = new Local(driver);

    Give the card a name and a class of device

    local.init('myName', 0x010101);

    Print out some information about the Local class and the card to which it now is connected:

    local.display();
  • Make the unit visible for others, i.e. make it discoverable. In order for others to see you when doing a scan your card must be in scan enable mode, and for others to be able to connect to you, i.e. page you, the card must be in page enable mode

    Allow inquiries and paging to your unit:

    local.writeScanEnable(HCI.INQUIRY_AND_PAGE_SCAN);

    Allow connection attempts from everybody but you must explicitly confirm any connection:

    local.setConnectionFilter(HCI.ALL_DEVICES, HCI.DO_NOT_AUTO_CONNECT);

    Alternatively you can use a different second parameter and now the card will connect to any that wants to. This is mainly for debug and such.

    local.setConnectionFilter(HCI.ALL_DEVICES, HCI.DO_AUTO_CONNECT);
  • Perform an inquiry, i.e. search for other Bluetooth units, is done like this. The argument gives the duration of the scan in seconds.

    List discoveredUnits = local.inquiry(5)

    The inquiry method returns a list containing the discovered units. The elements of the list are of type Remote

  • Try to connect to a unit that was found from the inquiry. First select a remote unit

    Remote remote = (Remote) discoveredUnits.get(index);
  • Now send the connection request to the selected Bluetooth unit.

    local.connectionRequest(remote, HCI.DM1);

    The second parameter determines the packet size for the link.

  • So far it was quite easy, but now it becomes slightly more complicated. In order for us the receive any messages (such as a connection request) , we must tell the stack to dispatch the HCI messages to us. This is done by adding a listener to the stack. The listener below will respond positively to an connection request and when an connection is established it will retrieve the Link object from the Local class.

            Link local;
            .....
            local.addHCIEventListener(new HCIEventListener() {
              public void eventArrived(HCIEvent e) {
                switch(e.getCode()) {
                case HCI.CONNECTION_REQUEST:
                  /* Send a connection accept */
                  local.acceptConnectionRequest(e);
                break;
              case HCI.CONNECTION_COMPLETE:
                link = local.getLink(e);
                break;
              }
             }  
            });
  • When the link setup is done. we now want to open up a channel on that link. The method calls below are blocking until the channel connection is confirmed or rejected.sadsa

    L2CAPChannel channel = link.openChannel(channelNumber, new InfiniteBuffer());

    JavaChannel jchannel = link.openJavaChannel(channel);

    In order to respond to actions from the remote we must also add a listener to the link as shown below:

            L2CAPChannel channel;
            JavaChannel jchannel;
            int channelNo;
            ...
            link.addEventListeners(new LinkEventListener(){
              public void eventArrived(LinkEvent e) {
                switch (e.type()) {
                  case LinkEvent.OPEN_CHANNEL_REQUEST:
                    channelNo = (LinkEvent.OpenChannelRequest)e).channel;                   
                    channel = link.openChannelResponse(channelNumber, 
                                                                    true, 
                                                                    new InfiniteBuffer());
                    jchannel = Link.openJavaChannel(L2CAPChannel);
                  break;     
                  case LinkEvent.CLOSE_CHANNEL_REQUEST:
                    channelNo = ((LinkEvent.CloseChannelRequest)e).channel;
                    link.closeChannelResponse(channelNumber);
                    channel = null; 
                    jchannel = null;
                }  
            });



  • Finally we can start to send and receive data. Write

            try {
              jchannel.writeObject(new String("Hi World!"));
            } catch (Exception  e) {
              System.out.println("Channel exception: " + e);
            }



or read

          String s = (String) jchannel.readObject();

Pretty simple, huh?

Address: Johan Eker
Phone: +46-[0]702-242 343
Email: johan dot eker at emp dot ericsson dot se