In the bluetoothChat example app, the sent and received data is added into a ArrayAdapter called mConversationArrayAdapter. There, each character is added into the array.
In my case, I have a String instead of an array because I don't need to send and receive several data, I only need to send one string, and receive one string each time.
The problem that I'm getting is that if I first receive a string like hello world, and then I receive a shorter one, the first is overwrited by the second, instead of deleting the first and writing the new.
So, if i first receive hello world, and then I supposse that I have to receive bye, what I really receive is byelo world.
So, how can I clear the buffer each time a receive what I want?
Code Snipets
Send data:
byte[] send1 = message_full1.getBytes();
GlobalVar.mTransmission.write(send1);
Write call:
public void write(byte[] out) {
/**Create temporary object*/
ConnectedThread r;
/**Synchronize a copy of the ConnectedThread*/
synchronized (this) {
if (GlobalVar.mState != GlobalVar.STATE_CONNECTED) return;
r = GlobalVar.mConnectedThread;
}
/**Perform the write unsynchronized*/
r.write(out);
}
Write Thread:
public void write(byte[] buffer) {
try {
GlobalVar.mmOutStream.write(buffer);
/**Share the sent message back to the UI Activity*/
GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {}
}
Finally, read Thread:
public void run() {
byte[] buffer = new byte[12]; // buffer store for the stream
int bytes; // bytes returned from read()
/**Keep listening to the InputStream until an exception occurs*/
while (true) {
try {
/**Read from the InputStream*/
bytes = GlobalVar.mmInStream.read(buffer);
/**Send the obtained bytes to the UI activity*/
GlobalVar.mHandler.obtainMessage(GlobalVar.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
GlobalVar.mTransmission.connectionLost();
/**Start the service over to restart listening mode*/
//GlobalVar.mTransmission.start();
break;
}
}
}
try this
bytes = inputStream.read(buffer);
buffer[bytes] = '\0';
Related
I'm working on a BluetoothChat sample based app, one device send another device parameters and the second send the data. I think that problem is in Connected thread run() method which i must edit because the original version receive data in not correct order . If I close program running on one device the second device is still connected to disconnected device.
public void run() {
int bytes;
int availableBytes=0;
while (true) {
try {
availableBytes=mmInStream.available();
byte[] buffer = new byte[availableBytes];
// Read from the InputStream
bytes = mmInStream.read(buffer);
if (bytes>0){
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
}
// Send the obtained bytes to the UI Activity
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
BluetoothClientService.this.start();
break;
}
}
}
I use some of the Bluetooth chat samplecode for sending a SMALL (177 byte to 3617 byte) "settings-file" "securly" between apps.
when it is under 1024 bit everything works fine: (so the 177 works PERFECT)
sendingdevice press "send button" and the reciver gets it (with a dialog if they want it..) (and I save the "string" to a "settings"file on that device)
but if the file is over 1024 it gets chunkt/cut off.. (example: 2000byte)
so the file gets corrupted (data-loss but some info remains..)
Probably I need to "split" my file in 1024 bits and send the bits and in the receiver-end, I need to "add them all up"..
but I don't know the "standard best practices" for this, do you have any suggestions?
I have tryed to "only higher" the 1024 byte to 65536byte, but that don't work..
(or maby I do this wrong..)
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
}
}
}
sedan write:
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mmOutStream.flush();
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
and when i "click on send settings":
String message = view.getText().toString();
String settingInAString = getSettingInALargeString();
sendMessage(settingInAString);
and in "sendMessage":
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send); //SO convert to byte and then send the byte..
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
and:
/**
* Write to the ConnectedThread in an unsynchronized manner
* #param out The bytes to write
* #see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
but I think you know what Im lookning for ...
(or can I some how change the "BluetoothChat" so it can sent and recive a large Sring, and not "byte:s"? :-) )
Best REGARDS to you all :-)
EDIT:
on the reader side I have this:
on the "reader end" I have:
....
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
//only a byte redebuffer, hmm can I change this? or do i use a whileloop?
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
recivedStringCheckFirst(readMessage);
//simple-check if the data is a "data-setting-file"
String [] allSettingsInALargeArray1 = doSplitOnLargeString(readMessage);
int titleArrayLength1 = getLengthOffTheUpCommingTitleArrayFromNew(allSettingsInALargeArray1); //this do a split and looks if it is 1,2,3..20 settings..)
mConversationArrayAdapter.add(titleArrayLength1 + " datasettings recived from " + mConnectedDeviceName + " SAVE THIS?");
//this type this text to the "chatwindow"
break;
Here is the splitting-chunk-problem now..
if i send under ~ 1024 I receive the correct amount of settings ant i can save this fine :-)
If i sent larger then 1024 I get first for exampel "6 settings from.." and then a new message that I recived "1 settings from.." message :-(
just for your info:
protected void recivedStringCheckFirst(String readMessage) {
String eventuellSettings = readMessage;
if (isThisASettingFile(eventuellSettings)){
//of ok..
System.out.println("incommingISAsetting :-) ");
inkommenSettings = eventuellSettings;
showDialog(); //dialog for save settings?
}
if (!isThisASettingFile(eventuellSettings)){
//not a settingsfile!
Toast.makeText(this, "try again..", Toast.LENGTH_LONG).show();
}
}
so i think it is:
case MESSAGE_READ:
is not only called if a complete file is received,
it is also called if a small chunks is received.
So I probably should place the "readFile-chunk" in a separate buffer
(i.e. mNewBufForFile += readFileChunk)
And then check the mNewBufForFile has a complete packet in it (how?). If it is done: I "save" the file message and then clear all buffer.
but how can i "split this from "Message_read", and do I "add a stopping bit" so i can check when i recive all the data? or can i do this better?
You can send as many bytes as you want. They come in in chunks smaller than the size of buffer (1024). Indeed the original code will mix all up caused by using one buffer. Change
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
to
while (true) {
try {
byte[] buffer = new byte[1024];
// Read from the InputStream
int nbytes = mmInStream.read(buffer);
Log.i(TAG, "read nbytes: " + nbytes);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, nbytes, -1, buffer)
.sendToTarget();
The data still comes in in chuncks but now you get all displayed in the rigth sequence.
As the chunck sizes -during some tests- are smaller than 1024 it makes no sense to have a bigger buffer. If you want to transfer a real file you should concatenate all together. This is a normal action using sockets.
I have been using InputStream.read( byte[] b, int off, int len ) method to read in data, but now have run into a timeout problem. I am sometimes expecting timeouts from reading, and should have the program adjust itself accordingly after a timeout. I have tried to implement a Thread but I really know nothing about Threads and cannot get it to work. I also want to add that this thread is being initialized within another thread. I'm not sure what the implications of this are but it may cause a problem.
My initial code had worked for the majority of times I need to read, but whenever I'm expecting a timeout, my program freezes at the read() call and never times out. When I implemented this new code, the times when my initial code worked now time out. I use Thread.wait(500) which I assume is 500 milliseconds, but I cannot find any Javadocs including the wait() function. Here and Here.
Other posts relating to this: 1, 2, 3.
I have also looked into declaring a timeout for the BluetoothSocket, but I cannot find it anywhere in the documentation.
Here is what my initial code looks like:
public void run(int length) throws IOException {
buffer = new byte[1024];
try {
bytes = mmInStream.read(buffer, 0, length);
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
This is what I have tried to implement:
public void run(int length) throws IOException {
buffer = new byte[1024];
length1 = length;
Thread myThread = new Thread(new Runnable() {
public void run() {
try {
bytes = mmInStream.read( buffer, 0, length1 );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (myThread) {
myThread.start();
try {
myThread.wait(500);
if(myThread.isAlive()) {
mmInStream.close();
Log.i( "InStream", "Timeout exceeded!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
myThread.run();
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Message msg = mHandler.obtainMessage(MainMenu.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString( TOAST, "Device has disconnected from the Bluetooth Module." );
msg.setData(bundle);
mHandler.sendMessage(msg);
connectionLost();
BluetoothService.this.start();
}
EDIT:
So I'm trying to recreate
buffer = new byte[1024];
bytes = mmInStream.read(buffer, 0, length);
I have done the following:
Scanner scan = new Scanner(new InputStreamReader(mmInStream));
String readIn;
try {
readIn = scan.next();
bytes = 5; // I tried with or without this, since I do not think it matters...
buffer = readIn.getBytes( Charset.forName( "US-ASCII" ) );
}
Later in my code I make this call....Sorry edit again, the buf=read( 5 ) call goes to what is shown above.
byte[] buf = buffer;
write( a );
buf = read( 5 );
Log.i(TAG, "Before buf[5]" );
try {
buf[5] = '\0';
} catch( NullPointerException e ) {
return false;
}
When I use the original method, It passes this buf[5] call fine. But when I use the new method, it gives me an IndexOutOfBoundsException at that spot. Am I missing something? The expected input should be CMD\r\n
The bluetooth chat example is really poor in this respect, you should use an input scanner instead of mmInStream.read. Here's what I use and it works reasonably well...
For your use case you skip the entire buffer and byte and write and read (no need to use any of those when you are using a scanner and inputstreamreader as those handle that stuff for you)... in other words the below code takes care of all that for you. I changed the delimiter for you to CRLF. What the code below does is you send a string and it writes it and then reads. If you don't need to send anything to the remote device, just start at scan = new Scanner. Each time a line is read and it ends with \r\n it will store it in the string instring.
So if you want to send "a", you would write
String readIn = beginListenForData("a");
The a will be sent under the mmOutStream and then the scanner will read the mmInStream and collect all the characters, then once it sees a CRLF it will return the characters it read and return them in your readIn string. Make sense?
private String beginListenForData(String msg0) {
msg0 += "\r"; //this adds a return character to the string, you can omit this if you just send an a and the remote device understands what that means.
String instring = "";
try {
mmOutStream.write(msg0.getBytes());
} catch (IOException ex) {
stop();
}
scan = new Scanner(new InputStreamReader(mmInStream));
scan.useDelimiter(Pattern.compile("[\\r\\n]+"));
instring = scan.next();
scan = null;
return instring;
}
I'm really stumped with this and I've trying to debug for the passed three days. Hopefully someone will be able to tell me what I am doing wrong.
I am implementing a BlockingQueue (FIFO) buffer to receive information being streamed from my PC over bluetooth. I am sending prerecorded electrocardiogram signal over a Hyperterminal link using RealTerm.
I have tested the buffer as I start up the app by adding values and then removing them, and it seems to work as it should.
The problem comes in when I try to store in the buffer while I'm receiving data from the bluetooth connection. I don't know if I am adding faster than the BlockingQueue can cope, but when I stop the data transmission and check my buffer, the whole buffer contains the last value that was added. The size of the buffer is correct, but the content isn't.
Here is my buffer:
public class IncomingBuffer {
private static final String TAG = "IncomingBuffer";
private BlockingQueue<byte[]> inBuffer;
public IncomingBuffer() {
inBuffer = new LinkedBlockingQueue<byte[]>();
Log.i(TAG, "Initialized");
}
public int getSize() {
int size;
size = inBuffer.size();
return size;
}
// Inserts the specified element into this queue, if possible. Returns True
// if successful.
public boolean insert(byte[] element) {
Log.i(TAG, "Inserting " + element[0]);
boolean success = inBuffer.offer(element);
return success;
}
// Retrieves and removes the head of this queue, or null if this queue is
// empty.
public byte[] retrieve() {
Log.i(TAG, "Retrieving");
return inBuffer.remove();
}
// Retrieves, but does not remove, the head of this queue, returning null if
// this queue is empty.
public byte[] peek() {
Log.i(TAG, "Peeking");
return inBuffer.peek();
}
}
The portion of my BluetoothCommunication class which receives the information and sends it to the buffer is the following:
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
ringBuffer = new IncomingBuffer();
byte[] buffer = new byte[1024];
Log.i(TAG, "Declared buffer byte");
int bytes;
byte[] retrieve;
int size;
Log.i(TAG, "Declared int bytes");
//Setting up desired data format 8
write(helloworld);
Log.i(TAG, "Call write(initialize)");
// Keep listening to the InputStream while connected
while (true) {
try {
Log.i(TAG, "Trying to get message");
// Read from the InputStream
bytes = mmInStream.read(buffer);
//THIS IS WHERE THE BYTE ARRAY IS ADDED TO THE IncomingBuffer
RingBuffer.insert(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
Log.i(TAG, "Sent to target" +ringBuffer.getSize());
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothCommService.this.start();
break;
}
}
}
So an example of my problem would be:
Send values over bluetooth connection (8 bit values from 1 to 20). In the insert method of the IncomingBuffer class, the log message confirms the proper value is sent. When values are retrieved from buffer, it contains twenty byte arrays which all contain the last number inserted (20).
Any clue as to why the buffer would work in other circumstances but not during the bluetooth communication?
I figured out what my problem was.
When I was using the variable buffer to read from mmInStream and then pass that to the ringBuffer, I pass the same byte array variable every time i go through the while loop. From what I can understand that simply assigns a specific memory location where the byte array is calculated and that is why at the end all of the elements in my ringBuffer are the last value that was assigned to 'buffer' from the mmInStream.
What i did to change that is make a separate variable that i clone the 'buffer' byte array to. Before I pass 'buffer' to 'RingBuffer', i do the following:
byte[] newBuf;
newBuf = buffer.clone();
ringBuffer.store(newBuf);
This takes care of my problem.
I have implemented a bluetooth connection using the now-classic Google Bluetooth Chat code. However, I have a question which I just cannot seem to wrap my brain around.
The reading of the input stream goes something like this:
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
Now, that's fine if I was just printing out the characters I was receiving as in the original example. However, suppose I wanted to transfer an image file. I don't know the size of the file, so I cannot count the bytes received or anything like that. In my tests, I don't seem to be ever receiving a "-1" from the input stream, which appears to be the "norm" for reading from input streams. So how can I know that I have reached the end of the file that was being sent?
Thank you for your help and your time.
It seems Android bluetooth input streams never return -1.
I guess setup a simple protocol by sending file size in the first place and EOF signals at last will help.
No it does not. Android sends -1 only when the Socket is closed as far as I know. So a workaround could be to do a reconnect, but I was trying that for hours and did not get it working, since I do not understand this "special" Code here (copied from a Stackoverflow Thread) for setting up the socket:
BluetoothSocket tmp = null;
Log.d(TAG, "New Connection initialized");
Method m;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
mmSocket = tmp;
This Socket only works, when my App is started for the first filetransfer. If I want to "Reconnect" with a completely new instantiated Object (and a new Socket created with that Code), the program freezes on the blocking method mmSocket.connect(). It seems like the Method never comes to an ending. This is driving me nuts...
Try
while ((bytes = mmInStream.read(buffer) != -1)
and see if that helps.
Try this:
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
while (true) {
try {
int data = mmInStream.read();
if(mmInStream.available()>0) {
arr_byte.add(data);
} else {
arr_byte.add(data);
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
Log.e("INPUT",new String(buffer));
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
arr_byte = new ArrayList<Integer>();
}
} catch (IOException e) {
break;
}
}
}