I have a Raspberry Pi which I am using to read some sensor data and then trying to send that data through Bluetooth RFCOMM socket to Android phone. I can send data from the Android phone to the Raspberry Pi without problems but for some reason I am not able to read the sensor data with the Android phone sent by the Raspberry Pi.
The write function on the Raspberry Pi always returns the right amount of bytes that have been sent and on the Android side I have a thread reading the InputStream and there is a available function to check if there is any bytes to read but it almost every time returns nothing. However, it sometimes reads (maybe 1 time of 20) the sensor data and after the message handler has passed the data back to the another activity and printed the data on a text view, the program crashes.
Maybe someone could give me some explanation why the InputStream isn't receiving any data even though the Raspberry Pi sends the data. Huge thanks in advance!
Here is my BluetoothTransferThread class:
public class BluetoothTransferThread extends Thread {
private final BluetoothSocket connectedSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private Context context;
private final Handler threadHandler;
public BluetoothTransferThread(BluetoothSocket socket, Context context, Handler mHandler) {
this.context = context;
connectedSocket = socket;
threadHandler = mHandler;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
//Send a transfer thread created message to activity
threadHandler.obtainMessage(BluetoothClientActivity.TRANSFER_THREAD_CREATED).sendToTarget();
int[] buffer;
int readByte;
int i = 0, bytesAvailable;
/**
* Keep listening to the InputStream while connected
*/
while (true) {
try {
//Check if there is bytes available to read in the InputStream
bytesAvailable = mmInStream.available();
if(bytesAvailable > 0) {
buffer = new int[bytesAvailable];
Log.d(getClass().getName(), String.format("value = %d", bytesAvailable));
/*
* Read the stream byte at a time and store it to a buffer until we have received the end of the frame char
*/
do {
//readByte = dInputStream.readUnsignedByte();
readByte = mmInStream.read();
buffer[i] = readByte;
i++;
} while (readByte != 0xEE);
//Send the received data through handler back to activity
threadHandler.obtainMessage(BluetoothClientActivity.MESSAGE_READ, buffer).sendToTarget();
}
try {
currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Write to the connected OutStream.
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
Toast.makeText(this.context, "Wrote to the socket", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(this.context, "Couldn't write to the socket", Toast.LENGTH_SHORT).show();
}
}
/**
* Close the transfer thread
*/
public void cancel() {
try {
connectedSocket.close();
Toast.makeText(this.context, "Transfer thread socket closed", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(this.context, "Couldn't close the transfer thread socket", Toast.LENGTH_SHORT).show();
}
}
And here is the Raspberry Pi's side code snippet:
case READ_SENSOR_DATA:
/* Serialize the data and send it through the socket */
pthread_mutex_lock(&sensorData->mutex1);
pthread_mutex_lock(&sensorData->mutex5);
serializationLengthPtr = serializeStruct(sendBuffer, sensorData);
pthread_mutex_unlock(&sensorData->mutex1);
pthread_mutex_unlock(&sensorData->mutex5);
sendBuffer[8] = FRAME_END_CHAR;
bytes_sent = write(client, sendBuffer, serializationLengthPtr - sendBuffer + 1);
if(bytes_sent <= 0) {
perror("Write failed!\n");
socketCloseFlag = true;
break;
}
else {
printf("Bytes sent: %d\n", bytes_sent);
}
break;
Related
So, I am using my arduino to collect some data and send it to my android app , so that I can store this data in a file, making my android a sort of datalogger.
I am using an hC-06 for this, working at 115200 bauds/sec. Seems to be allright when the arduino sends the data chunks ( 60bytes every chunk) every 100ms aprox.
The problem begins when I "query" the arduino for some special data, by sending a single byte with the OutputStream method. From the moment the app uses the "mmOutStream.write(buffer);" the data received by InputStream becomes unstable, varying the chunk size with random values ( 60 bytes, 45 butes, 100 bytes, etc...)
It seems like using OutputStream kind of corrupts the InputStream buffer...
Anyone has been through this? Thaks in advance
below the code:
// It handles all incoming and outgoing transmissions.
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private boolean send_request=false;
private byte[] send_buffer;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer;
ArrayList<Integer> arr_byte = new ArrayList<Integer>();
// Keep listening to the InputStream while connected
while (true) {
try {
int data = mmInStream.read();
if(data == 0x0A) {
}
else if(data == 0x0D) {
buffer = new byte[arr_byte.size()];
for(int i = 0 ; i < arr_byte.size() ; i++) {
buffer[i] = arr_byte.get(i).byteValue();
}
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothState.MESSAGE_READ
, buffer.length, -1, buffer).sendToTarget();
arr_byte = new ArrayList<Integer>();
}
else {
arr_byte.add(data);
}
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start(BluetoothService.this.isAndroid);
break;
}
}
}
// Write to the connected OutStream.
// #param buffer The bytes to write
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// mmOutStream.close(); //vdv , close after writing to see if liberates memeory . uncommenting this causes the phone not to connect
//TODO: investigate and solve why a single writing in the outstream causes the inputstream to get corrupted after a while.
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothState.MESSAGE_WRITE
, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.d(TAG,"write exception"); //vdv
}
}
I am working on a Bluetooth multiplayer game project.I followed the android Bluetooth overview https://developer.android.com/guide/topics/connectivity/bluetooth strictly.I used the following code to read and write data:-
public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler handler; // handler that gets info from Bluetooth service
// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;
// ... (Add other message types here as needed.)
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte[] mmBuffer; // mmBuffer store for the stream
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams; using temp objects because
// member streams are final.
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating input stream", e);
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating output stream", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
mmBuffer);
readMsg.sendToTarget();
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}
// Call this from the main activity to send data to the remote device.
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
// Share the sent message with the UI activity.
Message writtenMsg = handler.obtainMessage(
MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
writtenMsg.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Error occurred when sending data", e);
// Send a failure message back to the activity.
Message writeErrorMsg =
handler.obtainMessage(MessageConstants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString("toast",
"Couldn't send data to the other device");
writeErrorMsg.setData(bundle);
handler.sendMessage(writeErrorMsg);
}
}
// Call this method from the main activity to shut down the connection.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
}
For writing data I am using the following code:-
String[] myString={"HI!","How Are YOU"};
mConnected.write(Arrays.toString(myString).getBytes());
But I see that inputstream.read() is receiving data quite late after another device is sending the data.I found some questions regarding this,but none of them seem to provide a satisfactory answer.Any suggestion will be highly helpful.
After
mmOutStream.write(bytes);
try to call:
mmOutStream.flush();
this will cause the bytes to be sent immediately.
https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#flush()
Im using one app to send data to the elm327 through bluetooth and I'm trying the AT Z command but everything I get back from the OBD2 is AT Z too, my code is missing something or its supposed to answer like that ? I expected the AT Z to return elm327 text (tested with playstore apps and thats what I got)
// runs during a connection with a remote device
private class ReadWriteThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;
public ReadWriteThread(BluetoothSocket socket) {
this.bluetoothSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
inputStream = tmpIn;
outputStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream
while (true) {
try {
// Read from the InputStream
bytes = inputStream.read(buffer);
// Send the obtained bytes to the UI Activity
handler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1,
buffer).sendToTarget();
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
ChatController.this.start();
break;
}
}
}
// write to OutputStream
public void write(byte[] buffer) {
try {
outputStream.write(buffer);
handler.obtainMessage(MainActivity.MESSAGE_WRITE, -1, -1,
buffer).sendToTarget();
} catch (IOException e) {
}
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Perhaps you're not reading enough – make sure you concatenate all fragments you read until you receive the actual prompt \r>.
ELM327 usually starts out in echo mode, where it echos every command you are giving to it, that may explain why you're reading it back. Use ATE0 to turn off this behavior.
In general, https://www.sparkfun.com/datasheets/Widgets/ELM327_AT_Commands.pdf explains all that.
I have downloaded the android sample of Bluetooth chat app to send text between two android devices using Bluetooth.
I have installed and run this app in two android devices.
I faced many problems in that code
Service discovery failed exception - Fixed
java.io.IOException: Software caused connection abort - Fixed
java.io.IOException: Connection reset by Peer - Struck on this
1. Cleared the Service discovery failed exception:
For service discovery failed exception, In Bluetooth Chat Service, I have checked sdk version and for the sdk version which is greater than Ginger Bread,
I have used Method class to invoke RfCOMM socket connection and my first exception is solved in this approach.
Exception Code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
Fixed Exception code
try {
if (Build.VERSION.SDK_INT < 9) {
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e1) {
e1.printStackTrace();
}
} else {
Method m = null;
try {
m = device.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
tmp = (BluetoothSocket) m.invoke(device, 1);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
Log.e(TAG, "create() failed", e);
}
2. Cleared java.io.IOException: Software caused connection abort
I have made check whether the InputStream is available
Exception Code
bytes = mmInStream.read(buffer);
Fixed Exception code
if (mmInStream.available() > 0) {
// Read from the InputStream
bytes = mmInStream.read(buffer);
Now my problem is when I try to send data between connected devices, it throws the following error message "Connection Reset By Peer" while writing to output stream
Exception code:
public void write(byte[] buffer, int start, int end) {
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
if (mmOutStream !=null) {
try {
mmOutStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else{
Log.e("OutputStream Null","");
}
}
== Update ==
Even though it shows that both devices are connected, the accept method returns fail
**06-19 10:30:23.625: D/BluetoothChatService(2630): connected
06-19 10:30:23.625: D/BluetoothChatService(2630): cancel Thread[AcceptThread,5,main]
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): abortNative
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): ...asocket_abort(50) complete
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): ...accept(50, RFCOMM) = -1 (errno 125)
06-19 10:30:23.632: E/BluetoothChatService(2630): accept() failed
06-19 10:30:23.632: E/BluetoothChatService(2630): java.io.IOException: Operation Canceled
06-19 10:30:23.632: E/BluetoothChatService(2630): at android.bluetooth.BluetoothSocket.acceptNative(Native Method)
I had alot of problems with the chat example myself, so i tried another approach.
First you have to make one device host and the other the client, this works with the example pretty well. if you dont have this running, i can provide you with that code aswell.
Using the classes above, you get the socket for the connection. Use that to pass it to this class and then you can send using the write method. and the incoming messages are automatically parsed in the run-method (i added a message id and length to the front, thats why there is so much things going on in there)
private class ConnectedThread extends Thread {
/** the connection socket */
private final BluetoothSocket mmSocket;
/** input stream for incoming messages */
private final InputStream mmInStream;
/** output stream for outgoing messages */
private final OutputStream mmOutStream;
/**
* save the socket and get the streams
*
* #param socket
*/
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
/**
* reads incoming data and splits it into single messages
*/
public void run() {
/** buffer for a single byte message */
byte[] buffer = new byte[1024];
/** number of bytes returned from read() */
int bytes;
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// read overhead from the InputStream
bytes = mmInStream.read(buffer, 0, LEN_SIZE + LEN_TYPE);
// if no bytes are read, wait for a new message
if (bytes == 0)
continue;
// get the size bytes and convert them to int
byte[] size_arr = new byte[LEN_SIZE];
for (int i = 0; i < LEN_SIZE; i++)
size_arr[i] = buffer[i];
int size = convertByteArrayToInt(size_arr, LEN_SIZE);
// the type is 1 byte after the size
byte type = buffer[LEN_SIZE];
// array for the output data
byte[] output = new byte[size + LEN_TYPE];
output[0] = type;
// current position, read until cPos == size
int cPos = 0;
while (cPos < size) {
// either read the buffer lenght or the remaining bytes
int read_len = Math.min(buffer.length, size - cPos);
bytes = mmInStream.read(buffer, 0, read_len);
// write the bytes to the output
for (int i = 0; i < bytes; i++)
output[cPos + i + LEN_TYPE] = buffer[i];
// increase the current position
cPos += bytes;
}
// add the message to the queue
mMessageData.add(output);
// tell the service about the new message
mHandler.obtainMessage(BluetoothService.CONNECTION_RECV_MSG, mConnectionAddress).sendToTarget();
} catch (IOException e) {
// tell the service about the disconnect
mHandler.obtainMessage(BluetoothService.CONNECTION_LOST, mConnectionAddress).sendToTarget();
e.printStackTrace();
break;
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* writes a byte stream to the connection
*
* #param bytes
* the byte stream
*/
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes, 0, bytes.length);
mmOutStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* close the socket
*/
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
This worked for me, i hope it also does for you. If you have any question, feel free to ask :-)
You could try this, although it probably shouldn't be a final fix. When I followed that example, I had this onResume() in my main activity, and I imagine you have something similar:
#Override
public synchronized void onResume() {
super.onResume();
if(D) Log.e(TAG, "+ ON RESUME +");
}
Try this:
#Override
public synchronized void onResume() {
// super.onResume();
if(D) Log.e(TAG, "+ ON RESUME +");
}
This will stop the main activity from creating the AcceptThread more than once.
I think your reading is wrong. I have the line
while (true) {
try {
// read overhead from the InputStream
bytes = mmInStream.read(buffer, 0, LEN_SIZE + LEN_TYPE);
in my code and it is working perfectly, without .available() and so does #gtRfnkN. From my interpretation of the Java documentation, you cannot use .available() with InputStream.
See: http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available() particularly the part where it says "always returns zero for class InputStream".
And just in case, here is an example of my write:
public void write(byte[] buffer){
try{
//a delay of 20ms occurs after each flush...
mmOutStream.write((byte)buffer[0]);
mmOutStream.flush();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I'm trying to communicate with a bluetooth device. The information I have on the device states that
"The communications protocol is ASCII, commas separate output values. The message is terminated by carriage return and line feed pair. When saved as a file using a terminal emulator these results can be read into an Excel spreadsheet."
How do I send and receive from this device? I have tried using InputStreamReader and OutputStreamWriter, but I don't think that's working.
EDIT:
for sending data I'm trying:
public void send(String s){
try {
writer.write(s);
} catch (IOException e) {
e.printStackTrace();
}
}
where
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
inStream = tmpIn;
writer = new OutputStreamWriter(tmpOut);
You can also see there where I am using inStream that is a simple InputStream. I have also tried InputStreamReader, but I just got random characters back. With the InputStream I am only reading 4 bytes no matter what I send the device, so I'm not sure if even the sending is working.
What should I be using? Thanks!
You should take a look at Java documentation on IO Streams to make the whole picture.
For retrieval I assume you are using InputStream.read() method, which reads one byte at a time. To retrieve several bytes at a time you should use byte[] buffer. But that's not your case, just FYI.
In your case you don't need to use InputStream methods, but InputStreamReader instead, because
Reader operates on characters, not bytes. As stated in your quotation of protocol description, you have separate lines of ASCII. In this situation BufferedReader is handy, because it has readLine() method.
So you can just
in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
And then
String line = br.readLine();
For sending data you should use OutputStreamWriter.
REMEMBER:Please close streams after use!!! in finaly{} clause
I am following up on this in case anyone else is having the same problems. One of the problems I was having was that the device I was trying to communicate with was expecting a specific order of /n and /r and would lock up if that was incorrect so I had no was of knowing if it was working or not.
Here is he code I use for sending and receiving, I have used it on a couple of devices now and it seems to work well.
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket socket;
private final InputStream inStream;
private final OutputStream outStream;
private final DataInputStream datIn;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
this.socket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
inStream = tmpIn;
outStream = tmpOut;
datIn = new DataInputStream(inStream);
}
public void run() {
Log.i(TAG, "BEGIN ConnectedThread");
Bundle data = new Bundle();
// Keep listening to the InputStream while connected
while (true) {
Log.i(TAG, "Reading...");
try {
// Read from the InputStream
String results;
Log.i(TAG, "Recieved:");
results = datIn.readLine();
Log.i(TAG, results);
// Send the obtained bytes to the UI Activity
data.putString("results", results);
Message m = handler.obtainMessage(); // get a new message from the handler
m.setData(data); // add the data to the message
m.what = MESSAGE_READ;
handler.sendMessage(m);
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
handler.obtainMessage(MESSAGE_DISCONNECTED).sendToTarget();
setState(STATE_NONE);
// Start the service over to restart listening mode
break;
}
}
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
outStream.write(buffer);
Log.i(TAG, "Sending: " + new String(buffer));
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* Write to the ConnectedThread in an unsynchronized manner
* #param out The bytes to write
* #see ConnectedThread#write(byte[])
*/
public void send(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (state != STATE_CONNECTED) return;
r = connectedThread;
}
// Perform the write unsynchronized
r.write(out);
}