Bluetooth communication and multi-threading

This is where you talk about the NXJ software itself, installation issues, and programming talk.

Moderators: 99jonathan, roger, imaqine

Bluetooth communication and multi-threading

Postby prigole » Fri Sep 07, 2007 2:58 pm

Hi,

On a Bluetooth connection, why is it impossible to to let a thread read from a DataInputStream if that stream was opened by another thread? Below is a slightly altered version of the HelloWorld bluetooth example (works with BTsend on the PC side). The original example works well with my setup. The code is so that it simply starts a separate thread for reading out the received data.

The listed application simply blocks on dis.readInt(), never receiving any integers (yes the BTsend program is connected to the NXT and is sending the integers). Changing this application so that the for loop replaces this.start() and Thread.Sleep(60000) makes the application work again...

Best regards,
Peter


Code: Select all
import lejos.nxt.*;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;

import java.io.DataInputStream;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;

public class HelloWorld extends Thread {

    private DataInputStream dis;
    private DataOutputStream dos;

    public static void main(String[] aArg) {
        HelloWorld hello = new HelloWorld();
        hello.doIt();
    }

    public void doIt() {

        String connected = "Connected";
        String waiting = "Waiting";

        while (true) {
            try {
                LCD.drawString(waiting, 0, 0);
                LCD.refresh();

                BTConnection btc = Bluetooth.waitForConnection();


                LCD.clear();
                LCD.drawString(connected, 0, 0);
                LCD.refresh();

                InputStream is = btc.openInputStream();
                OutputStream os = btc.openOutputStream();
                DataInputStream dis = new DataInputStream(is);
                DataOutputStream dos = new DataOutputStream(os);
               
                this.start();

                Thread.sleep(60000); // which should be long enough for the other thread to send out the integers

                dis.close();
                dos.close();
                btc.close();
                LCD.clear();
            } catch (Exception e) {
            }
        }
    }

    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                int ii = dis.readInt();
                LCD.drawInt(ii, 3, 0, 1);
                LCD.refresh();
                dos.writeInt(-ii);
                dos.flush();
            } catch (Exception e) {
            }
        }
    }
}
[/quote]
--
Peter
prigole
New User
 
Posts: 1
Joined: Fri Sep 07, 2007 2:21 pm

Re: Bluetooth communication and multi-threading

Postby Shawn » Wed Sep 12, 2007 5:41 am

prigole wrote:Hi,

I'd expect a Null Pointer Exception from int ii = dis.readInt();

The reason is that you never initialize it.

You declare it globally --
private DataInputStream dis;

but the intialized version is local. --DataInputStream dis = new DataInputStream(is);

so your run() method will never see the local dis.

try dis = new DataInputStream(is);
in doIt() and see what happens.

Just my guess. New to lejos but not new to input streams!

Code: Select all
import lejos.nxt.*;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;

import java.io.DataInputStream;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;

public class HelloWorld extends Thread {

    private DataInputStream dis;
    private DataOutputStream dos;

    public static void main(String[] aArg) {
        HelloWorld hello = new HelloWorld();
        hello.doIt();
    }

    public void doIt() {

        String connected = "Connected";
        String waiting = "Waiting";

        while (true) {
            try {
                LCD.drawString(waiting, 0, 0);
                LCD.refresh();

                BTConnection btc = Bluetooth.waitForConnection();


                LCD.clear();
                LCD.drawString(connected, 0, 0);
                LCD.refresh();

                InputStream is = btc.openInputStream();
                OutputStream os = btc.openOutputStream();
                DataInputStream dis = new DataInputStream(is);
                DataOutputStream dos = new DataOutputStream(os);
               
                this.start();

                Thread.sleep(60000); // which should be long enough for the other thread to send out the integers

                dis.close();
                dos.close();
                btc.close();
                LCD.clear();
            } catch (Exception e) {
            }
        }
    }

    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                int ii = dis.readInt();
                LCD.drawInt(ii, 3, 0, 1);
                LCD.refresh();
                dos.writeInt(-ii);
                dos.flush();
            } catch (Exception e) {
            }
        }
    }
}
User avatar
Shawn
Advanced Member
 
Posts: 723
Joined: Wed Sep 12, 2007 4:59 am
Location: Tokyo

Postby esmetaman » Wed Sep 12, 2007 10:11 pm

Hi I tested your Program and I did a modification, but, I dont know why the thread doesnt send to BTConnectTest data.

Code: Select all
import lejos.nxt.*;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;

public class HelloWorld2 extends Thread {

    private DataInputStream dis;
    private DataOutputStream dos;
   
    private BTConnection btc;

    public static void main(String[] aArg) {
        HelloWorld2 hello = new HelloWorld2();
        hello.doIt();
    }

    public void doIt() {

        String connected = "Connected";
        String waiting = "Waiting";

        while (true) {
            try {
                LCD.drawString(waiting, 0, 0);
                LCD.refresh();

                BTConnection btc = Bluetooth.waitForConnection();


                LCD.clear();
                LCD.drawString(connected, 0, 0);
                LCD.refresh();

                this.start();
               
            } catch (Exception e) {
            }
        }
    }

    public void run() {
       
       try{
           InputStream is = btc.openInputStream();
           OutputStream os = btc.openOutputStream();
           DataInputStream dis = new DataInputStream(is);
           DataOutputStream dos = new DataOutputStream(os);
          
                  
          
           for (int i = 0; i < 100; i++) {
               try {
                   int ii = dis.readInt();
                   LCD.drawInt(ii, 3, 0, 1);
                   LCD.refresh();
                   dos.writeInt(-ii);
                   dos.flush();
               } catch (Exception e) {
               }
           }
          
         try {
            dis.close();
            dos.close();
            btc.close();
         } catch (IOException ioe){
            //
         }       
       }catch(Exception e){
          
       }
       LCD.clear();
    }
}
[/code]
User avatar
esmetaman
Advanced Member
 
Posts: 295
Joined: Wed Sep 13, 2006 12:16 am
Location: Madrid, Spain

Postby Shawn » Thu Sep 13, 2007 8:34 am

HI,

I think this has the same problem

Code: Select all
 
public class HelloWorld2 extends Thread {

    private DataInputStream dis;
    private DataOutputStream dos;
   
    private BTConnection btc;


Here btc is global.

Code: Select all
    public void doIt() {

        String connected = "Connected";
        String waiting = "Waiting";

        while (true) {
            try {
                LCD.drawString(waiting, 0, 0);
                LCD.refresh();

                BTConnection btc = Bluetooth.waitForConnection();



This btc is not the same as the globally defined one.
Code: Select all
BTConnection btc = Bluetooth.waitForConnection();

that will be locally defined and won't be seen in run();

instead do:
Code: Select all
  btc = Bluetooth.waitForConnection();


Code: Select all
    public void run() {
       
       try{
           InputStream is = btc.openInputStream();
           OutputStream os = btc.openOutputStream();
           DataInputStream dis = new DataInputStream(is);
           DataOutputStream dos = new DataOutputStream(os);
          
                  
          
           for (int i = 0; i < 100; i++) {
               try {
                   int ii = dis.readInt();
                   LCD.drawInt(ii, 3, 0, 1);
                   LCD.refresh();
                   dos.writeInt(-ii);
                   dos.flush();
               } catch (Exception e) {
               }
           }
          
         try {
            dis.close();
            dos.close();
            btc.close();
         

the btc in run is your globally defined btc and not the one in doIt();

I think this code still throws a null pointer because you never initialize the global btc and only initialize the local btc which run() can't see.

I am really new though and don't even know the difference between Bluetooth.waitForConnection(); and Bluetooth.Connect();

Still the code shows the above described problem.

Try this:
Code: Select all

import lejos.nxt.*;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;

public class HelloWorld2 extends Thread {

    private DataInputStream dis;
    private DataOutputStream dos;
   
    private BTConnection btc;

    public static void main(String[] aArg) {
        HelloWorld2 hello = new HelloWorld2();
        hello.doIt();
    }

    public void doIt() {

        String connected = "Connected";
        String waiting = "Waiting";

        while (true) {
            try {
                LCD.drawString(waiting, 0, 0);
                LCD.refresh();

                 btc = Bluetooth.waitForConnection();


                LCD.clear();
                LCD.drawString(connected, 0, 0);
                LCD.refresh();

                this.start();
               
            } catch (Exception e) {
            }
        }
    }

    public void run() {
       
       try{
           InputStream is = btc.openInputStream();
           OutputStream os = btc.openOutputStream();
           DataInputStream dis = new DataInputStream(is);
           DataOutputStream dos = new DataOutputStream(os);
         
                 
         
           for (int i = 0; i < 100; i++) {
               try {
                   int ii = dis.readInt();
                   LCD.drawInt(ii, 3, 0, 1);
                   LCD.refresh();
                   dos.writeInt(-ii);
                   dos.flush();
               } catch (Exception e) {
               }
           }
         
         try {
            dis.close();
            dos.close();
            btc.close();
         } catch (IOException ioe){
            //
         }       
       }catch(Exception e){
         
       }
       LCD.clear();
    }
}
User avatar
Shawn
Advanced Member
 
Posts: 723
Joined: Wed Sep 12, 2007 4:59 am
Location: Tokyo

Postby Shawn » Thu Sep 13, 2007 10:28 am

my 885 page java books says you can't call start() on a method more than once.

So instead, put your while(true) clause in the run() method and only call start once.

Once a run method stops, the thread is dead and you can not restart it, though you can call methods and access data from it since it is still around.


a regular java program that shows this is:

Code: Select all
package test;

public class ttest implements Runnable {
static int i=0;
static int ii=0;
   public static void main(String args[]){
      ttest t=new ttest();
      Thread works = new Thread(t);
      
      i=0;
      Thread fails = new Thread(t);
      works.start();
      System.out.println("works finished");
      
      
      while(ii<10){
         System.out.println("about to try fails:"+ii);
         fails.start();
         ii++;
               }
      
   }
   public void run() {
      while(i++<10){
System.out.println("hi!");
      }
   

}
}


your output will be like:

Code: Select all
works finished
about to try fails:0
hi!
hi!
hi!
hi!
hi!
hi!
hi!
hi!
hi!
hi!
about to try fails:1
Exception in thread "main" java.lang.IllegalThreadStateException
   at java.lang.Thread.start(Thread.java:571)
   at test.ttest.main(ttest.java:18)


it tries the fail thread before the works thread finishes because well that is what threading does -- shares turns at the cpu.

anyway, when you try to fails.start() the second time, you can see it doesn't work.
User avatar
Shawn
Advanced Member
 
Posts: 723
Joined: Wed Sep 12, 2007 4:59 am
Location: Tokyo


Return to NXJ Software

Who is online

Users browsing this forum: No registered users and 1 guest

more stuff