android bluetoothsocket receive zero-value bytes? - android

Got a problem at receiving bytes from bluetooth socket. I'm trying to send message created by arduino - couple of single bytes values i.e. 0x41, 0x05, 0xFF(...) into my phone with android. It works fine until one of these value is zero (0x00). Transmission hangs until new message comes. Anyone meet with that situation?
My "reader" works in separate thread, processBuffer() do sth with data that should be received:
public void run() {
while(stop == false){
try {
bytes = InStream.read(readbuffer);
for (int i = 0; i < bytes; i++){
Log.d("FRAME", "Read bytes "+readbuffer[i]);
}
Log.d("FRAME", "Read number of bytes "+bytes);
processBuffer(bytes);
} catch (Exception e){
Log.d("BT_debug", "Cannot read bytes");
Log.d("BT_debug", "iterator: "+iterator);
e.printStackTrace();
break;
}
}
}

Related

Android send audio file via Bluetooth using BluetoothChat example

I am trying to send audio file via Bluetooth using the sample BluetoothChat code.
I have created a class that converts audio into bytes and vise-versa.
Here are the modifications I have made in the sample code
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
//Convert noti.mp3 into byte array (noti.mp3 is an audio file I am using for testing)
try{send = Converter.convertAudioToBytes(path+"noti.mp3");}
catch(Exception e){Logger.append("Error while converting audio into bytes", e);}
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
I am also adding some bytes at the end of the audio to identify the endOfFile on the receiving end.
On the receiving end I have updated the mHandler
//List to store bytes received from the other device
private List<Byte> list = new ArrayList<Byte>();
case Constants.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
//Status for end of data
boolean endOfData = false;
//Add bytes to the Array list
for(int i=0;i<msg.arg1;i++){list.add(readBuf[i]);}
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
//Check if the received message contains this string
//Also check if the length of the data is less than 990
if(readMessage.contains("END OF AUDIO FILE") && msg.arg1<990){
endOfData = true;
}
//Check if all the data has been received
if(endOfData)
{
try{
Converter.convertBytesToAudio(list,path);
mConversationArrayAdapter.add(mConnectedDeviceName + ": Audio saved!");
}
catch(Exception e){
Logger.append("Error while converting bytes to audio", e);
}
finally{
list.clear();
}
}
break;
The code works fine for small audio files but when I send a file that is bigger than 3KB it does not properly receive the data and does not transfer it to audio properly.
I tried to send some long text like this
String str = "Message number ";
for(int i=0;i<1000;i++){message += str+i+" ,\n";}
byte[] send = message.getBytes();
mChatService.write(send);
on the receiving end I noticed, the messages received are not synchronized.
Can someone please help me solve this issue, or any other way to transfer audio messages via Bluetooth. I am trying to do something like WhatsApp audio messages but via Bluetooth.
Any help is appreciated.Thanks
Still waiting for an answer :( Please help

Message received from Arduino showing up as boxed question marks.

I am working on a project that involves communication between an Android Uno and an Android phone. The phone sends a request signal "*" that once received, the Arduino sends random integers in a loop. Right now, the Android device is receiving the message but it is showing up as boxed question marks, and not receiving all of the messages. Any ideas? Thank you so much!
Arduino code:
#include <SoftwareSerial.h>
const int RX_PIN = 0;
const int TX_PIN = 1;
SoftwareSerial bluetooth(RX_PIN, TX_PIN);
char commandChar;
void setup (){
bluetooth.begin (9600);
Serial.begin(38400);
}
void loop () {
if(bluetooth.available()){
commandChar = bluetooth.read();
switch(commandChar){
case '*':
Serial.println("Got the request code");
for(int i = 0; i < 10; i++){
bluetooth.print(random(21));
}
break;
}
}
}
Android code:
public void run() {
initializeConnection();
byte[] buffer = new byte[256];
int bytes;
// Keep looping to listen for received messages
while (true) {
try {
bytes = mmInStream.read(buffer);//read bytes from input buffer
String readMessage = new String(buffer, 0, bytes);
Log.e("Received Message: ", readMessage);
} catch (IOException e) {
break;
}
}
}
public void initializeConnection() {
try {
PrintWriter out;
out = new PrintWriter(mmOutStream, true);
out.println("*");
out.flush();
}catch (NullPointerException NPE) {
}
}
Console output:
08-13 19:02:46.546 4019-4128/? E/Received Message:: �
08-13 19:02:46.596 4019-4128/? E/Received Message:: ����
Ah I think I spot the problem. Random numbers are being sent from the arduino to the app, and the app is logging these bytes as ascii literals. Instead of sending random numbers, try sending well-formed ascii (visual characters).
You can send the hex bytes [0x68,0x65,0x6c,0x6c,0x6f] for "hello", or use SoftwareSerialPrint's built-in HEX option.
So change it to this, see if that works.
bluetooth.print(random(21), HEX);
Edit:
Let's try this on the app side instead. This will convert the received bytes into a hexadecimal string representation so we can see it in ascii properly.
bytes = mmInStream.read(buffer);//read bytes from input buffer
StringBuilder sb = new StringBuilder(bytes * 2);
for(byte b: buffer)
sb.append(String.format("%02x", b));
Log.e("Received Message: ", sb.toString());

Android Bluetooth InputStream real time read

I am working on an Android application that receives a real time data by Bluetooth and plots it on the screen.
The data is a gyro sensor position information. I am sending it from a custom Freescale Kinetis K10 microcontroller board (designed and tested by myself). For the Bluetooth communication I am using HC-05 Bluetooth module.
The format of the data is as follows:
byte_1: position identification byte, always equals to -128
byte_2: position of axis 1
byte_3: position of axis 2
byte_4: position of axis 3
I am sending these 4 bytes continuously one after another, in that particular order. I am sending this packet of 4 bytes every 5 ms and sending the packet takes about 4.7 ms (9600 baud rate).
The data output from the microcontroller is perfect in terms of accuracy and timing (checked with a logic analyzer).
The problem is that when it is being received from the phone, some of the bytes seem to get lost. Here is the part of the code, where I am reading the InputStream:
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Printer Service", "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
#Override
public void run() {
Log.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[4];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
int position = 0;
if(buffer[0] == -128) {
if(bytes >= 2) {
sendArray.errorTilt = buffer[1];
}
if(bytes >= 3) {
sendArray.errorRoll = buffer[2];
}
if(bytes == 4) {
sendArray.errorPan = buffer[3];
}
}
else if(buffer[1] == -128) {
position = 1;
if(bytes >= 3) {
sendArray.errorTilt = buffer[2];
}
if(bytes == 4) {
sendArray.errorRoll = buffer[3];
}
if(bytes >= 2) {
sendArray.errorPan = buffer[0];
}
}
else if(buffer[2] == -128 && bytes >= 3) {
position = 2;
sendArray.errorRoll = buffer[0];
sendArray.errorPan = buffer[1];
if(bytes == 4) {
sendArray.errorTilt = buffer[3];
}
}
else if(buffer[3] == -128 && bytes == 4) {
position = 3;
sendArray.errorTilt = buffer[0];
sendArray.errorRoll = buffer[1];
sendArray.errorPan = buffer[2];
}
if(position <= bytes && bytes > 1) {
sendArray.errorUpdate = true;
}
} catch (Exception e) {
e.printStackTrace();
connectionLost();
BluetoothService.this.stop();
break;
}
}
}
public void write(int oneByte) {
try {
mmOutStream.write(oneByte);
} catch (IOException e) {
Log.e("BluetoothService", "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e("BluetoothService", "close() of connect socket failed", e);
}
}
}
sendArray is a singleton that keeps many different variables.
errorTilt, errorRoll and errorPan are the current values of the axis, which are being updated from the receiving buffer.
"position" keeps the position of the position identification byte. It is used for a check if any variables have been updated.
Many times just one byte is received in the input buffer and since I don't know which axis is that supposed to be, since I don't have information about it's relative position to the position byte, this particular byte is useless and gets lost.
I've tested the accuracy of receiving by the following method. I made the MCU output a triangular wave on one of the axis, instead of the axis data. On the phone the lines of the triangular wave are not straight as they are supposed to be, but randomly curved and containing artifacts.
To plot the data I am using GraphView and I am updating the graph on equal intervals from a separate thread.
I've tried using longer receiving buffer (with a modified receiving algorithm), but this doesn't help as only a few bytes are being received at a time.
I've tried implementing InputStream.available() but it was always giving 127 bytes available, which didn't seem to be true.
I've read many threads about similar problems and I spent the last 5 days working on it, but I couldn't find a good solution.
To summarize, I need to achieve accurate, real time (or close to real time) receiving of all the bytes.
Thread with a similar problem:
How to do good real-time data streaming using Java Android SDK
Thank you.
UPDATE:
I've tried sending the information just for one of the axis, so it is simple and clear, without the need of position bytes. I was sending it again every 5 ms, but this time it was more time between the consecutive bytes, since it's just one byte in the packet.
I used InputStream.read() this time, which doesn't require a buffer. However, the incoming data was corrupted again, because random bytes couldn't be received.
I've seen different project using this method successfully, I don't know why it's not working with me. I thought it might be a problem with the HC-05 Bluetooth module I'm using, but I tried a different one - HC-06, and the situation is the same. I haven't tried a different phone, but my phone (Samsung Galaxy S3, Android 4.1.2) seems to be working OK.
UPDATE2: I've tried again testing the original code with InputStream.available() before reading from the stream.
When the condition is available()>0, there are no major changes, maybe it works slightly worse.
When the condition is available()>1, it never reads. I guess that is because of the unreliable available() method, as it says in the documentation.
you have incorrect processing of data, if you want to get data from microcontroller board. You have to use bytesAvaliable because android bluetooth Socket is pretty slow over microcontroller boards with bluetooth. But "bytesAvaliable way" has nuance - As socket is slow receiver, bytesAvaliable can catch more then 1 packet from board in one time so you gotta devide readed data by yourself, Check my code out below! My code is getting 38 bytes packets from inertial sensor so you gotta only change count of bytes! 0xAA is the first byte of every next packet so if you find 0xAA byte and have 38 bytes you get packet and nullify iterator. But anyway I'm sure that you still can sometimes lose data because it's not high frequency data transfering way
public void run() {
byte[] bytes = new byte[38];
int iterator = 0;
while (true) {
try {
int bytesAvailable = mmInStream.available();
if (bytesAvailable > 0) {
byte[] curBuf = new byte[bytesAvailable];
mmInStream.read(curBuf);
for (byte b : curBuf) {
if (b == (byte) 0xAA && iterator == 38) {
mHandler.obtainMessage(MainActivity.DATA_READ, bytes.length, -1, bytes).sendToTarget();
iterator = 0;
bytes[iterator] = b;
} else {
bytes[iterator] = b;
}
iterator++;
}
}
} catch (IOException ex) {
Log.e(TAG, "disconnected", ex);
connectionLost();
break;
}
}
}

Why is my android receiver dropping 10-60% of UDP broadcast packets?

I have an 802.3 wired transmitter application on my computer that I've written to broadcast UDP packets every 10ms. Each broadcast packet contains a 4-byte integer value that is unique to its particular packet, which allows me to figure out on the receiver end exactly how many packets have been dropped.
I have verified that the transmitter works with Wireshark. I set up four 802.11 receivers (2 android phones and 2 laptop computers) on the same network. The laptops received 95% of the UDP broadcast packets; one phone received 89%; the other phone received 40%.
Why?
Here is part of my android receiver code:
public class NetThread extends Thread {
int[] pkt_nums;
int p;
NetThread(int[] pkt_nums)
{
this.pkt_nums = pkt_nums;
for (int i=0; i<pkt_nums.length; i++)
{
pkt_nums[i]=0;
}
p = 0;
}
#Override
public void run()
{
receiveData();
}
public void receiveData()
{
// request permission to do network operations in manifest file...done
// start the network side of things
DatagramSocket sock = null;
DatagramPacket pkt = null;
try
{
byte[] data = new byte[C.PAYLOAD_MAX];
sock = new DatagramSocket(C.NET_PORT);
sock.setSoTimeout(C.NET_SO_TIMEOUT);
pkt = new DatagramPacket(data, 0, C.PAYLOAD_MAX);
while (true)
{
Thread.sleep(0); // allow for an interrupt
try
{
sock.receive(pkt);
int length = pkt.getLength();
boolean success = writeToBuffer(pkt.getData(), length);
if (!success) break;
}
catch (InterruptedIOException e)
{
// thrown when a timeout occurs
Log.d(C.DTAG, "net: no packets yet");
}
}
Log.d(C.DTAG, "buffer is full. done receiving.");
if (sock != null) sock.close();
}
catch (InterruptedException x)
{
Log.d(C.DTAG, "net: was interrupted.");
}
catch (SocketException e)
{
Log.d(C.DTAG, "net: SocketException");
e.printStackTrace();
}
catch (IOException e)
{
Log.d(C.DTAG, "net: IOException");
e.printStackTrace();
}
if (sock != null) sock.close();
}
public boolean writeToBuffer(byte[] data, int length)
{
// each packet should have exactly 4 bytes - a number
int pkt_num = data[0] & 0x000000FF | data[1]<<8 & 0x0000FF00 | data[2]<<16 & 0x00FF0000 | data[3]<<24 & 0xFF000000;
if (p < pkt_nums.length)
{
pkt_nums[p++] = pkt_num;
return true; // success
}
else
{
return false;
}
}
}
I declare the above class in my main activity as follows:
mNetThrd = new NetThread(pkt_nums);
mNetThrd.setDaemon(true);
mNetThrd.start();
I will try boosting the thread priority now, but I have a feeling I'm doing something wrong. I need to get at least 95% of UDP broadcast packets for my application.
More details: Laptops and phones are situated next to each other, 30 ft from the router with line-of sight visibility. Laptop 1 received 95% of packets. Laptop 2 received 94%. Phone 1 received 89%. Phone 2 received 40%. Both ran the same app. Other network traffic is minimal. Dropped packets in android typically happen in groups of 20-50 at a time. 802.11 has a clean channel. Each packet contains a 4-byte payload.
Is there something drastically wrong with my receiver code or is this another issue altogether?

How to detect EOF on android bluetooth file transfer?

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;
}
}
}

Categories

Resources