Bluetooth SPP reader problem

Hi Folks,

having an infuriating problem trying to read bluetooth serial port data in a midp application.  seems like the serial port is unreliable at best (although I assume that it is something to do with how I am handling it), but the upshot is that at the moment, I can't get any reliable data out of it at all.

Here is a function I use to try to get the data:

    public final static String readData(StreamConnection conn)
    {
   
        InputStream input = null;
        byte[] data = null;
        String result = "OK";
   
        try
        {
            input = conn.openInputStream();
     
            // Probably want to throw an exception if length is not greater then 0
            int length = input.read();
            data= new byte[length];
            length = 0;

            // Assemble data
            while (length != data.length)
            {
                int ch = input.read(data, length, data.length - length);
                if (ch == -1)
                {
                    throw new IOException("Can't read data");
                }
                length += ch;
            }
        }
        catch (IOException e)
        {
            result = e.toString();
        }
        finally
        {
            // close input stream      
            if (input != null)
            {
                try
                {
                    input.close();
                }
                catch (IOException e)
                {
                    result = e.toString();
                }
            }
        }
        if( result == "OK" ) result = data.toString();
        return new String( result );
    }  

I call it like:

        try
        {
            StreamConnection con = (StreamConnection) Connector.open(printerUrl);
            String cardData = readData( con );
            con .close();
        }

Right now, the function ALWAYS returns "Can't read data"

Any guidance on how I can get this thing working will be most appreciated!

Any suggestions at all, also very welcome :)

Regards,  Mike.
LVL 37
meverestAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mayank SAssociate Director - Product EngineeringCommented:
BTW:

>> if( result == "OK" )

Should be if ( result.equals ( "OK" ) )
0
Mayank SAssociate Director - Product EngineeringCommented:
>> int length = input.read();

Check the value of length there:

if ( length < 0 )
  throw new IOException ( "Can't read data" ) ;
0
meverestAuthor Commented:
Hi mayankeagle,

(thanks for the fast reply!)

I put:

if ( length < 0 )
  throw new IOException ( "length < 0" ) ;

but that seems to be never true.  Odd thing now is that sometimes i still get "Can't read data" returned as before, but ometimes, too, I get some data returned (but it is string representation of the bytes read, and not the ascii text that I expect to find)

I must be missing something serious....

Cheers.
 
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

Mayank SAssociate Director - Product EngineeringCommented:
>> but it is string representation of the bytes read

Try result = new String ( data ) ; instead of data.toString () ;
0
Mayank SAssociate Director - Product EngineeringCommented:
>> return new String( result );

Not needed, make it return result ;
0
meverestAuthor Commented:
Thanks mayankeagle!

Seems like I'm making some progress, and adding a few debug lines, I seem to be getting some indication that there is some problem with this:

            StreamConnection con = (StreamConnection) Connector.open(printerUrl);

Seems like maybe it doesn't close down properly sometimes - if I repeat the read process over and over, sometimes I get to the readData routine, other times it throws an exception at connector.open...

Unless you have some tips for me, I'll play with it a bit more and see what comes out.

Cheers.
0
Mayank SAssociate Director - Product EngineeringCommented:
Do you call this from multiple threads? If so, try to synchronize it, also close the connection in a finally block:

synchronized ( this )
{
  StreamConnection con = null ;
  try
  {
    con = ( StreamConnection ) Connector.open ( printerUrl ) ;
    String cardData = readData ( con ) ;
  }
  finally
  {
    if ( con != null )
          con .close () ; // end if
  }
}

I'm not a J2ME expert, so I can't give you more tips on this, but hope this would help. Otherwise wait for more experts to comment.
0
meverestAuthor Commented:
Thanks very much for your help so far, mayankeagle.

I am at least able to get data that I need out of the serial port, but it is still strangely unreliable.  Sometimes I get all the data, sometimes exceptions on connector.open(), sometimes I get that "Cant read data" exception - I made it into:

            while (length != data.length)
            {
                int ch = input.read(data, length, data.length - length);
                if (ch == -1)
                {
                    throw new IOException("Can't read data:" + length + "");
                }
                length += ch;
            }

and discover that length is invariably zero.

Haven't tried out that synchronisation concept yet.  It is not called from different places, but it is possible that the device has data stacked up in the output buffer before connecting - not sure what implication that might have though...

Regards,  Mike.
0
Mayank SAssociate Director - Product EngineeringCommented:
>> Haven't tried out that synchronisation concept yet.

Maybe try it once.

>> sometimes I get that "Cant read data" exception

Why not ignore that exception and instead just break out of the loop, to see what data is read:

if ( ch == -1 )
  break ; // end if

Then check what is there in result.
0
meverestAuthor Commented:
I'm getting highly variable results.

Sometimes 'length' comes back as zero, and thus no data is read.

Is there some way I can format the inputstream to flush anything that is there or keep a hold of it until i get data through - at the same time I need to make sure that there is some time-out capability so that I don't end up in a deadlock...

Cheers.
0
Mayank SAssociate Director - Product EngineeringCommented:
I prefer reading in a do-while loop, like:

do
  int i = is.read () ;
while ( is.available () > 0 ) ;
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
meverestAuthor Commented:
Hello mayankeagle,

I think that I have almost got it.

It turns out that the client platform is too quick for the server, and only ever gets the first part of the whole data on first try.

Therefore, I have to make several shots at it to be sure to get it all:

                try
                {
                    input = swiperConn.openInputStream();
                     ByteArrayOutputStream buff = new ByteArrayOutputStream( );

                    // Probably want to throw an exception if length is not greater then 0
                    buff.write( input.read() );

                    while ( true )
                    {
                        cycle++;
                        int count = input.available();
                        if( count < 0 ) break;

                        for ( int i = 0; i < count; i++ )
                            buff.write( input.read() );

                        swipeData = buff.toString().trim();
                        parseData( swipeData );
                        if( swipeData.length() == length ) break;
                        length = swipeData.length();
                        if( cycle > 6 ) break;
                    }
                }
 
still not quite done, but at least I am getting more reliable results now.

I'll leave this open for just a bit longer, then I'll close it off and award the points - thanks!

Mike.

0
Mayank SAssociate Director - Product EngineeringCommented:
Try it in a do-while loop. First read, then check available () and re-loop.
0
meverestAuthor Commented:
Thanks for hanging in there with me.

Much appreciated! :)

Not sure what the advantage of do while instead of while(true) - i did it that way so that I can break it with more than one condition.

cheers!
0
Mayank SAssociate Director - Product EngineeringCommented:
do while will read first and then check the condition - so you make sure you wait for input to come to the input-stream instead of directly looping out.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.