Bluetooth data loss between Android and Arduino - java

Straight to the point - my application due to some mysterious reason looses part of a data (String) when receiving an InputStream. I am talking about Bluetooth connection here. Most of the time, I am receiving correct string but once in while it is shortened. Weirdest thing in here is that I am printing every InputStream into my ScrollView and I can tell that the whole string is there... Nevertheless here is the code:
#Override
public void run() {
InputStream inputStream;
try {
inputStream = mBTSocket.getInputStream();
while (!bStop) {
byte[] buffer = new byte[256];
int bytes;
if (inputStream.available() > 0) {
bytes = inputStream.read(buffer);
final String strInput = new String(buffer, 0, bytes);;
mTxtReceive.post(new Runnable() {
#Override
public void run() {
mTxtReceive.append(strInput);
int txtLength = mTxtReceive.getEditableText().length();
if (txtLength > mMaxChars) {
mTxtReceive.getEditableText().delete(0, txtLength - mMaxChars);
}
scrollView.post(new Runnable() {
#Override
public void run() {
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
});
runOnUiThread(new Runnable() {
#Override
public void run() {
weather = strInput.split(",");
mTxtHumidity.setText(weather[0]);
mTxtTemperatureDHT.setText(weather[1]);
mTxtPressure.setText(weather[2]);
mTxtLux.setText(weather[3]);
mTxtRainMM.setText(weather[4]);
mTxtRainDaily.setText(weather[5]);
mTxtWSKPH.setText(weather[6]);
mTxtWGKPH.setText(weather[7]);
mTxtWSAVG2.setText(weather[8]);
mTxtWGAVG10.setText(weather[9]);
}
});
}
Thread.sleep(500);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The problem in here is null exception on array weather as according to my app I am sometimes accessing items out of boundry (weather length is 6/7/8 most of the time once it errors). App crashes in 10% of the time.
Any reason behind it?
EDIT: while receiving InputStream sometimes instead of receiving 56 bytes I get 33 and 22 separetely

Answer to be found here: Android InputStream dropping first two bytes (modified BluetoothChat)
Adding
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
solves only for non-dynamic data exchange between Android and Arduino due to sleep method. It turns out that even sleep(50) works in this condition. For some reason after this short sleep buffer is never divided nor lost. If it is bad coding please explain before downvoting.

Related

How to increase record and play volume with Java sound?

I use the following code to record and play sounds with Java, but the volume is too low, how to make it louder, at least 2,3 times louder ?
public void Record_Audio(String File_Path,AudioFileFormat.Type File_Type)
{
try
{
audioFormat=getAudioFormat(); // Get things set up for capture
DataLine.Info dataLineInfo=new DataLine.Info(TargetDataLine.class,audioFormat);
targetDataLine=(TargetDataLine)AudioSystem.getLine(dataLineInfo);
//Create a thread to capture the microphone data into an audio file and start the thread running. It will run
// until the Stop button is clicked. This method will return after starting the thread.
new Record_Thread(File_Path,File_Type).start();
}
catch (Exception e)
{
System.out.println(e);
System.exit(0);
}
}
private void Play_Audio_Recording()
{
File Audio_File=new File(Current_Folder_Path+File_Name_ComboBox.getSelectedItem().toString().trim()+"."+Get_Audio_File_Type());
try
{
Audio_Clip=Applet.newAudioClip(Audio_File.toURI().toURL());
Audio_Clip.play();
}
catch (Exception e) { e.printStackTrace(); }
}
class Record_Thread extends Thread
{
String File_Path;
AudioFileFormat.Type File_Type;
Record_Thread(String File_Path) { this(File_Path,AudioFileFormat.Type.WAVE); }
Record_Thread(String File_Path,AudioFileFormat.Type File_Type)
{
this.File_Path=File_Path;
this.File_Type=File_Type;
}
public void run()
{
Audio_File=new File(File_Path);
try
{
targetDataLine.open(audioFormat);
targetDataLine.start();
AudioSystem.write(new AudioInputStream(targetDataLine),File_Type,Audio_File);
}
catch (Exception e) { e.printStackTrace(); }
}
}
You would use the FloatControl.Type (https://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/FloatControl.Type.html) to set either the volume or the master gain. Something like:
targetDataLine=(TargetDataLine)AudioSystem.getLine(dataLineInfo);
javax.sound.sampled.FloatControl c = (FloatControl)targetDataLine.getControl(FloatControl.Type.VOLUME);
c.setValue(c.getMaximum());
might work.

Why was I able to send more than the apparent maximum amount of data via Bluetooth 4.2?

My research showed (see pg. 5) that the maximum amount of data that can be sent via Bluetooth 4.2 is 257 bytes.
However, I was able to send 990 bytes between my Python script and Java application. Why was I able to send so much data? Is the information I found about the maximum data wrong, or did something else happen?
Python Bluetooth script:
#Parameters config
sdr=RtlSdr()
sdr.fc=100e6
sdr.gain=48
sdr.rs=1.024e6
#Bluetooth connection
server_sock=BluetoothSocket(RFCOMM)
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port=server_sock.getsockname()[1]
uuid="94f39d29-7d6d-437d-973b-fba39e49d4ee"
client_sock,client_info=server_sock.accept()
while (1):
samples= sdr.read_samples(256*1024)
result=psd(samples, NFFT=70, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6)
tab_freq=(result[1])
value_freq=str(tab_freq)[1:-1]
value_freq2=[format(float(v),".4f")[:6] for v in value_freq.split()]
value_freq3="\n".join(value_pxx2)
#SAME FOR POWER VALUE
#THEN I SEND DATA BY BLUETOOTH
client_sock.send(value_freq3)
Java Bluetooth code:
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
boolean running;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
running = true;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
#Override
public void run() {
byte[] buffer = new byte[1048576]; // 20 bits
int bytes;
String strRx = "";
while (running) {
try {
bytes = connectedInputStream.read(buffer);
final String strReceived_freq = new String(buffer,0, bytes/2);
final String strReceived_pxx = new String(buffer,(bytes/2)+1, bytes);
//final int samples_sdr=new Integer(buffer,0,bytes);
final String strByteCnt = String.valueOf(bytes) + " bytes received.\n";
runOnUiThread(new Runnable(){
#Override
public void run() {
Pxx_value.setText(strReceived_pxx+"\n"); // get data PXX
freq_value.setText(strReceived_freq+"\n"); // get data freq
// plot value
/* for (int i=0; i<nb_points; i++)
{
freq[i]=Double.parseDouble(strReceived_freq);
pxx[i]=Double.parseDouble(strReceived_pxx);
series.appendData(new DataPoint(freq[i],pxx[i]), true,500);
}*/
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
cancel();
final String msgConnectionLost = "Connection lost:\n" + e.getMessage();
runOnUiThread(new Runnable(){
#Override
public void run() {
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
running = false;
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The document you link to shows the LE (low energy) Link Layer packet format, as specified in Vol 6, Part B, Section 2.1 of the Bluetooth Core Specification.
You are using RFCOMM, which is a Bluetooth Classic (aka BR/EDR) profile. The Link Layer packet format for BR/EDR is specified in Vol 2, Part B, Section 6 and shows that the payload can be up to 2790 bytes long.
In any case the API you are using doesn't give you access to the Link Layer. You are writing on an RFCOMM channel (which is designed to work more or less like a serial port) and you can write as many bytes as you want. Your library and the underlying platform will take care of placing your data into the appropriate number of L2CAP packets, which will then be further encapsulated in link layer packets. The main limitation you will run into are the buffer sizes in your implementation. In this case your socket based API will return the number of bytes that were written in the call to send, and you will be able to attempt retransmission later.

send correctly data between python and Java by Bluetooth

I am actually develop an app (spectrum analyzer) on smartphone. This app can communicate by bluetooth with a raspberry pi 3 and scan frequency from my RTLSDR-2832 (plug on RPI3).
I wrote a script to get samples from my RTLSDR-2832 and I send it on my app by bluetooth :
from pylab import*
from rtlsdr import*
from bluetooth import*
import sys
#configure device
sdr= RtlSdr()
sdr.sample_rate=double(sys.argv[3])
sdr.gain=double(sys.argv[2])
sdr.center_freq=double(sys.argv[1])
NFFT=50
#Bluetooth connection
server_sock=BluetoothSocket(RFCOMM)
server_sock.bind(("",PORT_ANY))
server_sock.listen(1)
port=server_sock.getsockname()[1]
uuid="94f39d29-7d6d-437d-973b-fba39e49d4ee"
client_sock,client_info=server_sock.accept()
while(1):
samples=sdr.read_samples(256*1024)
result=psd(samples,NFFT, Fs=sdr.sample_rate/1e6, Fc=sdr.center_freq*1e6/1e6)
tab_freq=(result[1]/1e6)
value_freq=str(tab_freq)[1:-1]
value_list=[format(float(v), ".10f") for v in value_freq.split()]
value_freq2= "\n".join(value_list)
tab_pxx=result[0]
value_pxx=str(tab_pxx)[1:-1]
client_sock.send(value_freq2+'\n'+'\n'.join(value_pxx.split()))
So with this script, I can get data from my RTLSDR2838 and send data. I send by bluetooth all data freq in first then, pxx value (in db/Hz).
I get all data on my app with that :
private class ThreadConnected extends Thread {
private final BluetoothSocket connectedBluetoothSocket;
private final InputStream connectedInputStream;
private final OutputStream connectedOutputStream;
boolean running;
public ThreadConnected(BluetoothSocket socket) {
connectedBluetoothSocket = socket;
InputStream in = null;
OutputStream out = null;
running = true;
try {
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
connectedInputStream = in;
connectedOutputStream = out;
}
#Override
public void run() {
byte[] buffer = new byte[1048576]; // 20 bits
int bytes;
String strRx = "";
while (running) {
try {
bytes = connectedInputStream.read(buffer);
final String strReceived_freq = new String(buffer,0, 15*nb_points);
final String strReceived_pxx = new String(buffer,15*nb_points, bytes);
//final int samples_sdr=new Integer(buffer,0,bytes);
final String strByteCnt = String.valueOf(bytes) + " bytes received.\n";
runOnUiThread(new Runnable(){
#Override
public void run() {
Pxx_value.setText(strReceived_pxx+"\n"); // get data PXX
freq_value.setText(strReceived_freq+"\n"); // get data freq
// plot value
/* for (int i=0; i<nb_points; i++)
{
freq[i]=Double.parseDouble(strReceived_freq);
pxx[i]=Double.parseDouble(strReceived_pxx);
series.appendData(new DataPoint(freq[i],pxx[i]), true,500);
}*/
}});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
cancel();
final String msgConnectionLost = "Connection lost:\n" + e.getMessage();
runOnUiThread(new Runnable(){
#Override
public void run() {
}});
}
}
}
public void write(byte[] buffer) {
try {
connectedOutputStream.write(buffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void cancel() {
running = false;
try {
connectedBluetoothSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The variable nb_points is fix to 50 like NFFT on my script. But when I did that I don't get my 50 values. If I try to fix nb_points and NFFT at 30 or less it works but not after...
I thinked at early maybe the problem is from the buffer but no apparently...
Did someone have any idea to fix this ?
Thanks for your help !
EDIT : It works until 33 exactly, after I don't know if it's about my buffer or not, but for each case of my tab, I get 2 values in sames times (my frequence, and pxx value) as the tab is writing again

Creating conditions inside a Runnable in android

I've created a code that reads data thrown to my android device from an Arduino. It goes like this:
public void run() {
byte[] buffer = new byte[1024];
int bytes;
final StringBuilder readMessage = new StringBuilder();
while (true) {
try {
bytes = connectedInputStream.read(buffer);
final String string_now = new String(buffer, 0, bytes);
readMessage.append(string_now);
// final int finalBytes = bytes;
runOnUiThread(new Runnable() {
#Override
public void run() {
tvBPM.setText(string_now);
readMessage.setLength(0);
}
});
} catch (IOException e) {
Toast.makeText(getApplicationContext(),"Connection Lost!",Toast.LENGTH_LONG).show();
}
}
}
This code is located inside my 'private class ThreadConnected extends Thread'
Now the values held by string_now are numbers. I want to tell the user if the value stored there is greater than 150 or less than 50. Here's a code I've tried but I doesn't fully work.
runOnUiThread(new Runnable() {
#Override
public void run() {
final int getValue = Integer.getValue(Integer.parseInt(string_now));
if (getValue > 150 || getValue < 50) {
Toast.makeText(getApplicationContext, "Unstable", Toast.LENGTH_SHORT).show(); }
else {
tvBPM.setText(string_now);
readMessage.setLength(0); }
}
});
Any tips on how I can make this work? Thank you.
bytes = connectedInputStream.read(buffer);
final String string_now = new String(buffer, 0, bytes);
This code will run forever even after the peer closes the connection, when it will start showing rubbish, giving ArrayIndexOutOfBoundsException, or whatever. You are missing the following between those two lines:
if (bytes == -1)
{
break;
}
and the following after the catch block:
finally
{
try
{
connectedInputStream.close();
}
catch (IOException exc)
{
// whatever ...
}
}

Java event is killed when a function for audio playing is called

I am facing a strange programming problem. It has exhausted me but with no solution found!
My program is mainly dependent on an event (Java Listener) that is fired from an external hardware for receiving an audio message from that hardware.Inside the eventHandler i do the following
pass the received message to a static method "decode" from another class which returns data
then I open FileOutputStream, write these data "audio" to a file,and close the FileOutputStream.
I call a static method "play" from another class to play the audio file.
The problem is: whenever the method "Play" is called for the first time, it executes correctly but it causes the event to stop raising and the program to terminate but without exceptions. When I comment out the play method, everything becomes okay!
Do you have some idea about a method causing program termination ?
public void messageReceived(int to,Message message)
{
speexAudioMsg msg = (speexAudioMsg)message;
try{
byte[] output = jspeexDecoder.decode(msg.get_frame());
os = new FileOutputStream(file);
os.write(output);
os.close();
Player.play();
}
catch (IOException ex) {ex.printStackTrace();}
}
You are probably using the event thread to play the music. Try calling Player.play() in a new thread.
new Thread(new Runnable() { public void run() {Player.play()}}).start();
here is an example:
static String url = "http://www.stackoverload.com";
public static void threadTest() {
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try {
URL url2 = new URL(url);
url2.openStream();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).run();

Categories

Resources