I am using Bluetooth Chat sample app from Android website. I want to pass the complete incoming message, (message format included in the code below as this website is parsing the message for me which is my job in the code as well, to a function which removes the tags and extracts message name and value and uses it for further action. The readMessage string (in the switch case Message_Read) sends selected characters and omits few special characters. Following is the code from Bluetooth Chat app (from Android website).
I am not able to receive the complete message in the format which I have mentioned in the code. It gets displayed in multiple lines and many characters get deleted. Any suggestion why this is happening?
// The Handler that gets information back from the BluetoothChatService
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
mTitle.setText(R.string.title_connected_to);
mTitle.append(mConnectedDeviceName);
mConversationArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
mTitle.setText(R.string.title_connecting);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
//Make sure there is a received message. Extract it's name and value
//int msgLen = readMessage.length();
//if( msgLen!= 0)
// Message format is <MSG><N>shiftDirection<!N><V>1<!V><!MSG>
if (readBuf.equals("<MSG><N>.*<!N><V>.*<!V><!MSG>"))
extractData(readMessage);
else mTitle.setText(R.string.floor_it);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
The part of the code which reads the incoming stream of bytes into a buffer and passes the buffer object for display.
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);
//String Incoming = new String(buffer);
//Pass "Incoming" instead of "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();
break;
}
}
}
I think the problem is, that case MESSAGE_READ: is not only called if a complete Packet is received, it is also called if a small fragment is received. So you should place the readMessage in a separate buffer (i.e. mNewBuf += readMessage) check the mNewBuf has a complete packet in it. If so, you parse your message and after that you clear your buffer. It worked for me.
if (readBuf.equals("<MSG><N>.*<!N><V>.*<!V><!MSG>"))
extractData(readMessage);
equals() doesn't apply regular expressions. If you want to match .*, use classes from java.util.regex to help you.
I was having the same issue, and I'm not 100% this will always work but I found this on the javadoc:
read(byte[] b, int off, int len)
Reads up to len bytes of data from the input stream into an array of bytes.
If you know how many bytes you are expecting then you could try using
bytes = mmInStream.read(buffer, 0, lengthYouWant);
However, this wouldn't work if your incoming data is variable in length.
Related
I am sending data from an arduino through a Bluetooth module. I am simply streaming different integers;
int bluetoothData;
//give value to bluetoothData
Serial1.println(bluetoothData);
In my Android code, I have a Bluetooth socket that receives the data from the arduino. The data is taken care of by a Handler. And here lies the problem, sometimes the data is misread. For instance, I am sending '100', but instead the Handler saves in my database '000' or I send '194' and what is read is '994'. Sometimes such a reading mistake would occur once in every 15. Sometimes there will not be any mistake at all. Does someone know what may the reason be? Is it some hardware malfunction of the bluetooth module, is it the way I am reading the data, etc. Here is the Android code for the Thread receiving data:
final int RECIEVE_MESSAGE = 1;
...
mmInStream = socket.getOutputStream();
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
bytes = mmInStream.read(buffer);
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();
}
Here is the code for the handler itself:
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE:
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1);
sb.append(strIncom);
int endOfLineIndex = sb.indexOf("\r\n");
if (endOfLineIndex > 0) {
String sbprint = sb.substring(0, endOfLineIndex);
sb.delete(0, sb.length());
btData = Integer.parseInt(sbprint);
M = btData;
insert = mDataBaseHelper.insert(M,DataBaseHelper.TABLE_Temp);
}
I am building an Android application to communicate with my NR-42 bluetooth device. I am able to connect to the bluetooth and send data to the device which is a PIC18F but I am not able to receive bluetooth data from my device to my android phone.
I am following this example http://solderer.tv/data-transfer-between-android-and-arduino-via-bluetooth/comment-page-1/
When I use tera-term it shows me that the bluetooth module is doing what it is suppose to do, but I can't get the data in my textViews. I am trying to send float data. I am new to android but the issue is happening here I assume.
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
txtArduino.setText("Data from Arduino: " + sbprint); // update TextView
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
"
The input stream is being read here."
public void run() {
byte[] buffer = new byte[256]; // 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); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
Log.d(TAG, "sent handler");
} catch (IOException e) {
break;
}
}
}
Has anyone come across this issue or can help me out?
Thanks
I am working with Android's RFCOMM Tutorial. I have it working, but I'm having an issue when I send large messages (this is intentional, and cannot be changed).
The issue is that I will see the same data transferred multiple times, but it stops after sending X bytes, even though N of those bytes were duplicates.
As an example, sending a chunk of 12800 bytes, my receiving side sees this data (cut down from the full log -- the numbers indicate the length of the string):
Reading: (990)yJv;ZU>h8JCfAEttQEA7V9BSkITgDn5350SdahFILcbwrYAfD7b_Oavhqr:DF
Reading: (2970)HQTZWMFv08G3qHiHn#4_f8KWrQX9v]gmV=tvqGFpP:c8yV^a0i17:ndDiOS
Reading: (990)ZdXZvCxK5sdLlKDnPrrP;2nuEItZ9<\29e7x7lNFafHU]R#Ap=lBF\M?1\W_O
Reading: (990)ZdXZvCxK5sdLlKDnPrrP;2nuEItZ9<\29e7x7lNFafHU]R#Ap=lBF\M?1\W_O
Reading: (990)ZdXZvCxK5sdLlKDnPrrP;2nuEItZ9<\29e7x7lNFafHU]R#Ap=lBF\M?1\W_O
Reading: (1980)ZdXZvCxK5sdLlKDnPrrP;2nuEItZ9<\29e7x7lNFafHU]R#Ap=lBF\M?1\W_
Reading: (990)TD?lyEvS;[PMj>xpg5RiAIK8di61QNngkOvpoMhl=0`I#32iUuScR1xiGiZ:
Reading: (990)Ahyxc2PMA?sub8l^:prr=D5vIaGw73#rS0EHTeT;XLcsq9k6li;MVw_IJ4QiSs
Reading: (990)YQe:OWv_Iv_6eL#Yu>KUnbjmsN9KsidM1Vx6:LSsgZ[sbG3V>0dp7kkvUhX1^n
Reading: (920)YQe:OWv_Iv_6eL#Yu>KUnbjmsN9KsidM1Vx6:LSsgZ[sbG3V>0dp7kkvUhX1^n
As you can see, there are 3 exact retransmissions, and one retransmission that had more data appended. However, the sum of all the lengths is 12800 -- the original size of the message.
In case you're wondering, presently the data is just a random string. So, no, it's not getting the same bits of data in there more than once. And I have confirmed this by looking at the sending side.
Now, I need the data to come through without any corruption, so I'm checking a hash on the other side. However, with the retransmissions, and the lost data, it isn't matching most of the time. And cutting out the retransmissions just leaves me with missing data.
So, the issue seems to be two-fold:
Retransmissions are happening even though the data is received successfully.
Even when I'm smart about ignoring the retransmissions, all the data doesn't come through. If N bytes are retransmitted, I'm left with N bytes of missing data.
All relevant code for this has come directly from Android's website (link above). Key points of interest however are:
Managing A Connection
And this block, which comes from the full code from the tutorial I linked to:
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
mTitle.setText(R.string.title_connected_to);
mTitle.append(mConnectedDeviceName);
mConversationArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
mTitle.setText(R.string.title_connecting);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
I am writing software for Android for communication between Arduino and Android.
The Arduino sends data using serial.println - I send the text "It works!".
The Android is receiving data in this way:
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
And it displays some code instead of "it works!", more exactly it displays [B#40e3f9b8.
What is the reason and how can this problem be fixed?
You just tried to print a byte array. In Java, that just prints out the type of the object [B, followed by its address #40e3f9b8.
If you want to print the text out, use new String(bytes) to get a string from the bytearray (using the default charset), then print the string out.
You have to create a string from a byte array:
String strIncom = new String(buffer, 0, msg.arg1);
Full example with \r\n handler:
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
txtArduino.setText("Data from Arduino: " + sbprint); // update TextView
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
See full example program with apk and sources here
I've been playing around with Androids sample code Bluetooth Chat. I'm thinking about using it as a base for my own app but I keep running into outofmemory errors. Right now I have it set up to read tons of data from a bluetooth device at a pretty fast rate. The app changes the byte array it receives into a String but after a while I get the outofmemory error. Is the gc too slow in removing all the String objects it creates? How do I free up the memory of the String
Bluetooth Chat
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
mConversationArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
setStatus(R.string.title_connecting);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
setStatus(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
The MESSAGE_READ case is the one that runs tons of times. Also I'm converting the String into a Hex String. Is there a way to change the byte[] directly to a hex String which can save the precious memory?
about out of memory errors: i have not the perfect solution but nullifying the variable after the last use might help the GC to speed up its process.
About byte[] to a string of hexes, you may try to iterate over the byte array and call Integer.toHexString(...) on each byte.