Android InputStream flush from Bluetooth adapter - android

My Arduino is listening for a character to be sent from my phone to print sensor data to send back via a Bluetooth module. This is working fine and the communication is fast and accurate. However, the problem occurs when I request data from two different sensors.
I will request data from sensor A and get my results fine. I then request data from sensor B, and I get what seems to be a leftover request to sensor A and get information from sensor A again. I can request data from sensor B twice in a row, and I will then receive data from sensor B accurately.
I have tried to flush the input stream, but that made my application crash. I also tried to use InputStream.wait() and then interrupt the wait with InputStream.notify() when requesting data from a different sensor. This also crashed the program.
This is my receive code. The character that is being passed in is the character that defines what sensor data to send back from the Arduino.
public String receive(Character c) {
try {
myOutputStream.write(c);
final Handler handler = new Handler();
final byte delimiter = 10; // ASCII code for a newline
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
myThread = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()
&& !stopWorker) {
try {
int bytesAvailable = myInputStream.available();
if (bytesAvailable > 0) {
byte[] packetBytes = new byte[bytesAvailable];
myInputStream.read(packetBytes);
for (int i = 0; i < bytesAvailable; i++) {
byte b = packetBytes[i];
if (b == delimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0,
encodedBytes, 0,
encodedBytes.length);
final String data = new String(
encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable() {
public void run() {
status = data;
}
});
} else {
readBuffer[readBufferPosition++] = b;
}
}
}
}
catch (IOException ex) {
stopWorker = true;
}
}
}
});
myThread.start();
return (status);
}
catch (IOException e) {
// TODO Auto-generated catch block
status = "Failed";
e.printStackTrace();
}
return (status);
}
This is some of the Arduino code, and it is very simple.
if(bluetooth.available()) //If something was sent from phone
{
char toSend = (char)bluetooth.read(); //Reads the char sent
if (toSend == 'T')
{
//If the char is T, turn on the light.
float voltage = analogRead(14) * 5.04;
voltage /= 1024.0;
float temperatureC = (voltage - .5) * 100;
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
bluetooth.println(temperatureF);
}
How can I fix this problem?

Related

Does the number of bytes slows the Bluetooth receiving proccess on Android?

I'm building an Android app that sends and receives values from Arduno, using Bluetooth. The Arduino sends the String "OBJECT_FOUND" when a ultrasonic sensor founds an object near by.
I'm using a code taken from a Tutorial. Sometimes, is possible to see the values sent by arduino while the ultrasonic sensor is in front of an object, but It takes too long to receive the data, and most of the time is not possible to see the sent values. The time is crucial for the functioning of my system, and I would like to receive the data in real time.
Here's the code:
public void beginListenForData() {
final Handler handler = new Handler();
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
workerThread = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted() && !stopWorker) {
try {
int bytesAvailable = mmInputStream.available();
if (bytesAvailable > 0) {
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for (int i = 0; i < bytesAvailable; i++) {
byte b = packetBytes[i];
if (b == delimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable() {
public void run() {
if (data.equals("OBJECT_FOUND")) {
anyObject = true;
} else {
anyObject = false;
}
}
});
} else {
readBuffer[readBufferPosition++] = b;
}
}
}
} catch (IOException ex) {
stopWorker = true;
}
}
}
});
workerThread.start();
}
Should I avoid the sending a "big" string, and send only 0's and 1's to increase the proccess?
The lag can be cause by another problem, I'm trying to figured out what's the problem.
Thank you.

Array out of bounds exception:

I am trying to recieve bluetooth messages and my app runs but then after some time (1min or so)I get an array out of bounds exception on the read buffer, also it doesn't seem to be reading my message and updating my textview?
void beginListenForData()
{
final Handler handler = new Handler();
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
workerThread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
int bytesAvailable = mmInputStream.available();
if(bytesAvailable > 0)
{
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for(int i=0;i<bytesAvailable;i++)
{
byte b = packetBytes[i];
if(b == delimiter)
{
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable()
{
public void run()
{
myLabel.setText(data);
}
});
}
else
{
readBuffer[readBufferPosition++] = b;
}
}
}
}
catch (IOException ex)
{
stopWorker = true;
}
}
}
});
workerThread.start();
}
You are using an Array with 1024 max number of cells.
1) Increase the number size of the Array. (But you can get this exception again if it will be too small again).
2) Use a List instead the Array, the items will be added to the list without max size an the list will increase until the method will be finished, and you won't get the "OutOfBoundException".

Android Bluetooth input stream not reading full array

I'm creating an app to read string values over Bluetooth serial port. My data receiving but in two parts. If I send $F00,A,B,0,M# via bluetooth it only reads $ in first part and F00,A,B,0,M# in next part. I provided my code here. Please do correct me if I'm wrong.
InputStream inputStream=null;
int avilableBytes=0;
public ConnectedThread(BluetoothSocket socket){
InputStream temp=null;
try{
temp=socket.getInputStream();
}catch (IOException e){
e.printStackTrace();
}
inputStream=temp;
}
public void run() {
try{
int bytes;
while (true){
try{
avilableBytes=inputStream.available();
if (avilableBytes>0){
byte[] buffer=new byte[avilableBytes];
bytes=inputStream.read(buffer);
final String readMessage=new String(buffer,0,bytes);
bt_handler.obtainMessage(handlerState,bytes,-1,readMessage).sendToTarget();
Log.d("PRAVEEN",readMessage);
}
}catch (IOException e){
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
}
Data are like stream bytes and can not be processed immediately when it comes with a few bytes. Data will not come all at once as a single packet. You have to use the other byte[] buffer (MainBuffer) in which you will gradually save incoming byte and move the index in that buffer. Then, from time to time (e.g. in the timer once per second) take data from the main buffer and processed it. By default you must implement some data frame with a separator (eg. Data * data * data * - Many ways to do it good or bad). I dealt with this in .net via Xamarin, but just as an example it may be helpfull :
update example, format
In ConnectedThread :
public override void Run()
{
while (true)
{
try
{
int readBytes = 0;
lock (InternaldataReadLock)
{
readBytes = clientSocketInStream.Read(InternaldataRead, 0, InternaldataRead.Length);
Array.Copy(InternaldataRead, TempdataRead, readBytes);
}
if (readBytes > 0)
{
lock (dataReadLock)
{
dataRead = new byte[readBytes];
for (int i = 0; i < readBytes; i++)
{
dataRead[i] = TempdataRead[i];
}
}
Bundle dataBundle = new Bundle();
dataBundle.PutByteArray("Data", dataRead);
Message message = btlManager.sourceHandler.ObtainMessage();
message.What = 1;
message.Data = dataBundle;
btlManager.sourceHandler.SendMessage(message);
}
}
catch (System.Exception e)
{
btlManager.btlState = BTLService.BTLState.Nothing;
}
}
}
In BTLHandler :
public override void HandleMessage(Message msg)
{
switch (msg.What)
{
case 1:
{
byte[] data = msg.Data != null ? msg.Data.GetByteArray("Data") : new byte[0];
btlService.BTLReceiveData(data);
}
break;
}
}
public void BTLReceiveData(byte[] data)
{
lock (dataReadLock)
{
for (int i = 0; i < data.Length; i++)
{
dataRead[dataReadWriteCursor] = data[i];
dataReadWriteCursor++;
}
}
}
In Timer :
int tmpWriteCursor = dataReadWriteCursor;
int tmpReadCursor = dataReadReadCursor;
lock (dataReadLock)
{
int newBytes = dataReadWriteCursor - dataReadReadCursor;
for (int i = 0; i < newBytes; i++)
{
dataReadMain[dataReadReadCursor] = dataRead[dataReadReadCursor++];
}
}
bool odradkovani = false;
string tmpRadek = "";
int lastLineIndex = 0;
List<string> list = new List<string>();
for (int i = LastWriteLineIndex; i < tmpWriteCursor; i++)
{
if (dataReadMain[i] >= 32 && dataReadMain[i] <= 255)
{
tmpRadek += (char)dataReadMain[i];
}
else if (dataReadMain[i] == 13) odradkovani = true;
else if (dataReadMain[i] == 10)
{
if (odradkovani)
{
odradkovani = false;
list.Add(Utils.GetFormatedDateTime(DateTime.Now) + " " + tmpRadek);
tmpRadek = "";
lastLineIndex = i + 1;
}
}
else
{
tmpRadek += "?" + dataReadMain[i].ToString() + "?";
}
}
WriteDataToLog(list);
LastWriteLineIndex = lastLineIndex;

How do I display more data separately?

**bluetoothdatadisplay**
void beginListenForData() {
//final Handler handler = new Handler();
final Handler handler = new Handler(Looper.getMainLooper());
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[2048];//It uses a 1024 bytes long buffer because it doesn't have any way of knowing the length of the input stream.
workerThread = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted() && !stopWorker) {
try {
int bytesAvailable = mmInputStream.available();
if (bytesAvailable > 0) {
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for (int i = 0; i < bytesAvailable; i++) {
byte b = packetBytes[i];
if (b == delimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable() {
public void run() {
myLabel.setText(data);
//Log.d("MyLabel", data);
}
});
} else {
readBuffer[readBufferPosition++] = b;
}
}
}
} catch (IOException ex) {
stopWorker = true;
}
}
}
});
workerThread.start();
}//end of begindata
Hi I trying to receive the data from Arduino, But when I send all my data were flashing very fast since there is only one textview use. How do I separate them in Android for eg into different textbox? Thanks!
A simple fix would be to append the newly received data instead of replacing the old one.
Use a RecyclerView, with a List<String> representing your data set and connected to the Adapter of the RecyclerView :-)
Each time you add something to the data list, use
adapter.notifyDataSetChanged()
method to have the RecyclerView update :-)
EDIT:
As stated by Kernald, you should actually use the
adapter.notifyItemInserted(list.size())
method instead of notifying the whole data set change, if you want to use a 100% correct and up-to-time approach :-)

Reading wrong number of bytes from socket inputstream in android

I wrote the following code to read some data (specifically a file) received by an Android app through a socket:
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
byte[] buffX = new byte[30054];
int k = inputStream.read(buffX,0,30054);
I know that the data I am sending from a code written in C is a file with 30054 bytes.
The problem is that the variable k is less than 2000, ie, it does not read all the file that was sent or some part of the file was thrown away. I already checked that the size of the receiver buffer (in the Android app) is more than 80kB.
I tested the same code with a file of size 1662 bytes, and as I expected the variable k is equal to 1662 bytes.
What am I doing wrong? What am I missing?
Do I need to close the socket?, which is something I prefer to do when I close the app, not during the code I showed.
ANDROID APP CODE:
#SuppressLint("HandlerLeak")
public class DisplayNewActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainnewact);
mHandler = new Handler() { // used to show the number of bytes that were read
#Override
public void handleMessage(Message msg) {
int d2 = (Integer)msg.obj;
commentS.setText(Integer.toString(d2));
}
}
...
cThread = new Thread(new ClientThread()); // used to start socket connection
rThread = new Thread(new RcvThread()); // used to read incoming packages once the socket has been connected
cThread.start();
}
public class ClientThread implements Runnable {
public void run() {
try {
...
socket = new Socket(serverIpAddress, Integer.parseInt(serverPort));
rThread.start();
while (connected) { };
...
} catch (Exception e) { startActivity(intentback);}
}
}
#SuppressLint("HandlerLeak")
public class RcvThread implements Runnable {
public void run() {
while (connected) {
try {
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] imBytes = new byte[31000];
int numRead = 0;
while ((numRead = inputStream.read(imBytes)) >= 0) {
baos.write(imBytes,0,numRead);
}
byte[] imageInBytes = baos.toByteArray();
int k = imageInBytes.length;
Message msg = new Message();
msg.obj = k;
mHandler.sendMessage(msg);
} catch (Exception e) {
Log.e("SocketConnectionv02Activity", "C: ErrorRCVD", e);
}
}
}
}
}
C CODE:
...
#include <sys/sendfile.h>
...
int main(int argc, char *argv[]){
int sockfd, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int fdfile;
struct stat stat_buf;
off_t offset = 0;
int img2send = 1;
char buffer[256];
int closeSocket = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {error("ERROR opening socket"); exit(1);}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 55000;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
error("ERROR on binding");
close(sockfd);
exit(1);
}
listen(sockfd,1);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
close(sockfd);
exit(1);
}
while (closeSocket == 0) {
if (img2send == 1) { // interchange the file that is sent through the socket
fdfile = open("/home/gachr/Desktop/CamaraTest/fig1bmp.bmp", O_RDONLY);
img2send = 2;
} else {
fdfile = open("/home/gachr/Desktop/CamaraTest/fig2bmp.bmp", O_RDONLY);
img2send = 1;
}
if (fdfile == -1) {
close(sockfd);
close(newsockfd);
exit(1);
} else {
fstat(fdfile, &stat_buf);
offset = 0;
n = sendfile(newsockfd, fdfile, &offset, stat_buf.st_size);
if (n == stat_buf.st_size) { printf("Complete transfering file\n"); }
close(fdfile);
}
sleep(5);
bzero(buffer,256);
n = recv(newsockfd,buffer,1,MSG_DONTWAIT); // to close the socket from the Android app, which is working
if (n > 0) {
if (buffer[0] == 48){ closeSocket = 1;}
}
}
close(newsockfd);
close(sockfd);
return 0;
}
It's hard to say when you are not there:)
But I would do the following:
read progressively fewer bytes at a time and build the complete
array of bytes from this smaller chunks
debug these lines and see exactly when the 'bug' appears
The read method does not read the full stream. it only reads the currently available bytes in the stream buffer.
To read the full data from stream you can either use the readFully() method or use the following code to read the full data from stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[8192];
int numRead = 0;
while ((numRead = inputStream.read(bytes)) >= 0) {
baos.write(bytes,0,numRead);
}
byte[] fileData = baos.toByteArray();

Categories

Resources