Android + Arduino bluetooth communication - android

I have a question about android bluetooth working principle. I have an app that connects to arduino with HC-06 shield. And on receive i get new line after first char. Lets say i send from arduino
12345
and in android i see in ListView
1
2345
I believe this is about android not arduino, because i connected arduino to PC and i received correct data.
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(readMessage);
break;
Any ideas how to debug is it really android or maybe its arduino failing?
If you are interested i post arduino code:
void loop() // run over and over
{
if (mySerial.available())
Serial.write(mySerial.read());
if (Serial.available())
mySerial.write(Serial.read());
}
EDIT
The problem about "\n" comes out only with arduino+HC-06 bluetooth shield. While connected to pc the android tablet shows correct data.

The answer was to check string ending.
private void onBluetoothRead(byte[] buffer, int len) {
String output = new String(buffer, 0, len); // Add read buffer to new string
Log.i(LOGGER_TAG, String.format("Received: "+ output + " , " + "%d bytes", len));
outputTemp += output;
if (outputTemp.endsWith("\n")){
m_deviceOutput.append(outputTemp); // Add (not replace) string to TextView
StringTokenizer splitStr = new StringTokenizer(outputTemp, ","); // split string by comma
String numberOne = splitStr.nextToken().replaceAll("\\D+",""); // First split string
String numberTwo = splitStr.nextToken().replaceAll("\\D+",""); // Second split string
m_deviceOutputPrs.setText(numberOne);
m_deviceOutputSpeed.setText(numberTwo);
outputTemp = "";
}
}

Seems like you need more time to receive the whole message. You may either append data to the same buffer, not the new one; or you may add a small delay between the time you detected new input data and the time you read the whole input data.

Related

TCP client for Android: text is not received in full

I am converting a Java desktop project to Android. Part of it includes a TCP connection to a server and parsing a long text from the server to the client (the Android application). This is the code that I have for the desktop project that I also try to use in Android:
// Method is called when a button is tapped
public void tapButton() {
// Create a message to the server that requests for the Departure navdata
String messageToServer = someMethodToMakeHandshakeMessage();
// Connect to the server
if (!messageToServer.equals("")) {
String finalMessageToServer = messageToServer;
new Thread(() -> {
String navdata = connectClient(finalMessageToServer);
getActivity().runOnUiThread(() -> messageReceived(navdata));
// I am also using messageReceived(navdata) without runOnUiThread with the same result
}).start();
}
}
public String connectClient(String messageOut) {
Socket socket = null;
DataInputStream input = null;
DataOutputStream output = null;
BufferedReader br = null;
// Final message from the server
String data = "";
// Message from the server that should terminate TCP connection
String terminator = "END_DATA";
try {
// Create socket and streams
socket = new Socket(someIPAddress, somePort);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
//Send message to the server
output.writeBytes(messageOut);
//Read Response
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
String s = "";
int value = 0;
// Process the message from the server and add to the StringBuilder
while((value = br.read()) != -1) {
// converts int to character
char c = (char)value;
sb.append(c);
if(sb.toString().contains(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
catch (UnknownHostException e) {
// Dealing with exception
}
catch (EOFException e) {
// Dealing with exception
}
catch (IOException e) {
// Dealing with exception
}
finally {
try {
if(socket!=null) { socket.close();}
if(input != null) { input.close();}
if(output != null) { output.close();}
if(br != null) { br.close();}
}
catch (IOException ex) {
// Dealing with exception
}
socket = null;
input = null;
output = null;
br = null;
}
return data;
}
public void messageReceived(String message) {
// Method to deal with received data
}
Whereas the code works fine in the desktop Java application, I have problems with Android (using an emulator). The text is not sent in full length and is cut somewhere in the middle (only 20-50% received by the client; the number of parsed characters differs all the time). Besides, I have noticed that it is taking too long to connect to the server, but, I guess, this is due to working with an emulator.
Should a TCP client receiving long texts from the server be implemented in Android somewhat differently?
EDIT: Implemented the following code using a suggestion by #blackapps:
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
if (line.trim().isEmpty()) {
Log.i("EMPTY LINE>>>>>>>>>>>>>>>>>",line);
}
if(line.equals(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
Two issues. I would like to keep the empty lines in the received text. The terminator is not detected. I think, it is separated from the main text with two empty lines. However, after the first empty line, it goes to indefinite loop and connection never terminated.
EDIT #2.
After having spent several hours trying to figure out what is going on, making changes to the server, and comparing the number of bytes sent and received, I have noticed that this is not the problem with the code. It appears that the client receives the full text. The problem is with how the text is written in the console using the Log.i(String, String) method. I have added the good old System.out.println() in the code, and the whole text was shown in the console. However, the text from Log.i() was cut off in the middle. As this is my first experience with Android Studio, what the heck is going on?
Thanks a lot!
Let talk about TCP socket first.
When talking about TCP socket, it's a stream of data.
TCP views data as an unstructured, but ordered, stream of bytes. It's different from the kinds of socket.io.
From time to time, TCP will grab chunks of data from the send buffer and pass the data to the network layer. The maximum amount of data that can be grabbed and placed in a segment is limited by the maximum segment size (MSS). The MSS is typically set by first determining the length of the largest link-layer frame.
So it depends on the device.
For example, you have two messages, each of them has 1000 bytes data, and you call:
-------------- client side ----------------
client.send(theFirstMessage) // 1000 bytes
client.send(theSecondMessage) // 1000 bytes
-------------- server side -----------------
socket.onReceived(data => {
// process(data)
})
With above pseudocode you should note that:
The data which received and called on onReceived block couldn't be 1000 bytes of theFirstMessage.
It could be first 400 bytes, then on other event you receive 400 bytes, then more 400 bytes (200 of the first one and 200 of the second one).
It could be 1200 bytes (1000 of the first one and 200 of the second one).
TCP views data as an unstructured, but ordered, stream of bytes. Socket.io is a wrapper, when it uses TCP socket, it collect and combine/split the data for you, so that you received the events with exactly the data was sent from other side.
When you work with TCP, you have to do it your self, you have to define the application protocol to do it.
There're two common ways to send/receive TCP requests:
Splitter, you choose a splitter. For example, we choose 32 bits AABBCCDD as the splitter (same as you choose END_DATA string), but keep in mind it's binary data. Then you have to ensure that the data in request doesn't contains the splitter. To do that, you have to encode the request. For example we can encode request as base64, then use the character which isn't included in base64 table as the splitter.
Prefix length, the above method has its overhead as we have to encode request data. The prefix length method is a better choice.
We can prefix the length of request before.
The pseudocode:
// use Int32, 4 bytes to indicate the length of message after it
-------------- client side ----------------
client.send(theFirstMessage.length) // Int32
client.send(theFirstMessage) // 1000 bytes
client.send(theSecondMessage.length)
client.send(theSecondMessage) // 1000 bytes
-------------- server side -----------------
var buffer = Buffer()
socket.onReceived(data => {
buffer.append(data)
let length = Int32(buffer[0...3])
if (buffer.length >= length + 4) {
let theRequest = buffer[4 ... 4 + length - 1]
process(theRequest)
buffer = buffer.dropFirst(4 + length)
}
})
One more thing, when working with TCP socket, it's just stream of bytes, so the endianness is important https://en.wikipedia.org/wiki/Endianness
For example, an android device is little endian and server side (or other android device) is big endian. Then 4 bytes of Int32 from the android device, when received on server side, it will be decoded wrongly if you don't care about it.
So, the prefix length should be encoded by specific endianness.

Serial BT data from Arduino is chopped up in Android, how to solve this?

The exact problem I am having is the same as in this thread:
Why does the serial BT data I received get chopped out?
So I know I need to make delimiters and parse, which I what I need, but sadly the answer to that thread wasn't specific enough.
I need to send analog data (from 0-1023) in the Arduino over to the Android device, so I added a "n" as a delimiter to the end of each string before sending over as such:
#include <SoftwareSerial.h>
int bluetoothTx = 2;
int bluetoothRx = 3;
boolean toggle = true;
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
void setup()
{
//Setup usb serial connection to computer
Serial.begin(9600);
//Setup Bluetooth serial connection to android
bluetooth.begin(115200);
bluetooth.print("$$$");
delay(100);
bluetooth.println("U,57600,N");
bluetooth.begin(57600);
}
void loop()
{
//Read from serial to bluetooth
while(1) //to reduce jitters
{
String sensorString = String(analogRead(A0), DEC);
sensorString = sensorString + "n";
bluetooth.println(sensorString);
delay(100);
}
}
This is for the Arduino side.
For the Android side, I used the BluetoothChat example, so in the mHandler and in the switch-case of MESSAGE_READ, the codes are as such:
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(readMessage);
Where mConversationArrayAdapter is a String ArrayAdapter. May i know how I can modify the code within the MESSAGE_READ case so as to solve this problem?
Send a string of ascii characters formed by each nibble of 0-1023 code (2 bytes), and append it by newline character (i.e. /n). As an example if hex code to send is 0x03FF (i.e. 1023 decimal), then string to send will be 0x30,0x33,0x46,0x46,0x0A.

HC-05 + Android ( Wrong echos / data )

So I am facing a problem from a while now . Any suggestion would be good.
First I used my code to receive data from arduino , then I used the bluetoothChat and changed the uuid , I can pair , everything is good , but if I send an entire string from arduino to android I get only parts of that string.
If I use bluetooth terminal from google play everything is ok, and on the description it says it is made from the bluetooth Chat sample .
Code Arduino
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 9); //RX,TX
long int i = 0;
void setup(){
mySerial.begin(9600);
}
void loop(){
mySerial.print("This is a message n. ");
mySerial.println(i);
i++;
delay(100);
}
Android code : Bluetooth Chat Sample
Exemple of message received on Android:
Message to be sent!
So first messages I think are waiting while the module is paired .
because every time I get .
is is a message n. 466
This is a message n.467
.
. ( here I get correct messages )
.
This is a message n.470
message n. 495
.
.
and after the first messages I get messages like
ssage n.534
t
essage n.m
essage n.
535
( I neved again get an entire message )
Handler :
h = new Handler() {
public void handleMessage(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
Log.d("Arduino", "Mesaj:"+ sbprint.toString());
}
Log.d("Arduino", "...Mesaj:"+ sb.toString() + " Byte:" + msg.arg1 + "...");
break;
}
};
};
Listener to InputStream
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
} catch (IOException e) {
break;
}
}
}
note you are using a software emulation of serial port, hence timing is not as good as it would be with a hardware UART.
It is likely one or both of the following two possible issues:
1) the start and stop bit are not properly timed, causing back to back bytes. Which occur when a string is set, rather then pecking in keys one at a time.
The solution would be to space out each key.
2) baud rates do not match with in tolerance. Either SLOWING DOWN or SPEEDING UP the baud rate on both the HC05 and Arduino will better match the timing.
I would also recommend ensuring your library is SoftwareSerial, states that it is NewSoftSerial. It has many issues fixed. It was implemented in to the Arduino IDE 1.0.+ core libraries, so if you have recent IDE you should have it.

convert byte array to Bitmap Android

I changed the Android BluetoothChat sample project to transfer files over Bluetooth. I succesfully transfered text files and print them on a ListActivity. I want to do the same thing with an image, but couldn't make it work. There is a Handler object that sends the byte array received at the InputStream to the UserInterface. There I need to convert this bytearray to an image. I tried the following but doesn't work:
#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 MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
myImg.setImageBitmap(BitmapFactory.decodeByteArray(readBuf, 0, readBuf.length));
//the following lines would actually display the text of the file in the ListActivity
//String readMessage = new String(readBuf, 0, msg.arg1);
//mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
}
}
};
The handler code that sends messages to the UI looks like following:
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1,buffer).sendToTarget();
ANSWER
I read many other posts and I found somebody else that successfully made it work. he used a little trick that saved me. I won't give the answer here because it's explained in a better way in the questions page Sending image from android to PC via bluetooth
Thanks everybody for your help though
Try using BitmapFactory.decodeByteArray(byte[] data, int offset, int length) method to get bitmap from byte array.

Why is data from Arduino to Android using Android host api garbled?

I followed this tutorial to get started using Android host api with an Arduino board. I am using the Arduino Uno. I am able to transmit data and turn on a LED on the Arduino board and I can receive feedback from the Arduino board. I am trying to write to my Android device over the USB connection from the Arduino board like so:
Serial.print("Test");
I am receiving the Arduino data on the Android side like this:
byte[] buffer = new byte[10];
int bytes;
//try-catch statements omitted for simplicity
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
Every once and awhile the data will be intact but more often than not, what I receive from the Arduino is a garbled mix of those letters from my original message(t,e,s, and t). Many times only 1 or 2 letters are displayed. If anyone could point me in the right direction or share some similar experience I would be appreciative. Thanks.
Edit
When I print out the data into Logcat, there are multiple copies of the data. For example, if I receive "ste" from Arduino, it will be printed out 2-5 times in Logcat.
I think I found something that works at least temporarily:
public void run(){
int i = 0;
byte[] buffer = new byte[4];
byte[] finalBuffer = new byte[8];
byte[] sendBuffer = new byte[8];
int bytes = 0;
while(true){
try{
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
if (bytes == EXIT_CMD) {
return;
}
if (bytes > 0){
byte[] temporaryBuffer = new byte[bytes];
System.arraycopy(buffer, 0, temporaryBuffer, 0, bytes);
System.arraycopy(temporaryBuffer, 0, finalBuffer, i, bytes);
i += bytes;
java.util.Arrays.fill(buffer, (byte) 0);
}
//Dollar sign terminates string to indicate end of line
if (finalBuffer[7] == 36){
i = 0;
System.arraycopy(finalBuffer, 0, sendBuffer, 0, sendBuffer.length);
messageHandler.obtainMessage(UsbHostTestActivity.ARDUINO_MESSAGE,
sendBuffer.length, -1, sendBuffer).sendToTarget();
java.util.Arrays.fill(finalBuffer, (byte) 0);
}
I had to send strings that were 8 characters exactly from Arduino and they had to end with a dollar sign($) in order to indicate the end of the line, but the data being passed to my message handler always seemed to be correct. It's not the most robust solution but maybe someone can modify it to make it better or take another approach? Please let me know!

Categories

Resources