I am writing an embedded application for Infineon XMC4500 microprocessor.
I read data from different sensors and I send this data by means of bluetooth module in order to visualize them on the screen of Android smarphone. I use GraphView library.
I implemented BluetoothClass according to Android tutorial. If I get data from single sensor then everything is ok. But when I get data from multiple sensors unfortunately my application does not work smoothly.
Of course I am doing Bluetooth connection in seperate thread and I try to update UI in Handler.
Tell me please what am I doing wrong. Of course I send data by means of JSON exchange format:
I send something like this from the microcontroller side:
sprintf(json_data, "{"
"\"m\":"
"["
"{"
"\"id\":a,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":g,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":m,"
"\"x\":%.2f,"
"\"y\":%.2f,"
"\"z\":%.2f"
"},"
"{"
"\"id\":t,"
"\"x\":%.2f"
"},"
"{"
"\"id\":h,"
"\"x\":%.2f"
"}"
"]"
"}", getAccelXf(), getAccelYf(), getAccelZf(), getGyroXf(), getGyroYf(), getGyroZf(), getMagnetXf(), getMagnetYf(), getMagnetZf(), readTemperature(), readHumidity());
As an attachment to my request I add pieces of source code:
public class ConnectedThread extends Thread
{
BluetoothSocket connectedSocket;
InputStream inStream;
OutputStream outStream;
public ConnectedThread(BluetoothSocket socket)
{
connectedSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try
{
if (connectedSocket != null)
{
tmpIn = connectedSocket.getInputStream();
tmpOut = connectedSocket.getOutputStream();
mHandler.obtainMessage(Constants.MESSAGE_DEVICE_CONNECTED_SUCCESSFULLY).sendToTarget();
// Toast.makeText(activityContext, "connectedSocket != null", Toast.LENGTH_LONG);
}
}
catch (IOException e) {
mHandler.obtainMessage(Constants.MESSAGE_INPUT_OUTPUT_STREAM_UNAVAILABLE).sendToTarget();
e.printStackTrace();
}
inStream = tmpIn;
outStream = tmpOut;
}
public void run()
{
if(bluetoothAdapter.isDiscovering()){
bluetoothAdapter.cancelDiscovery();
}
byte[] buffer = new byte[4096];
int bytes;
String dupa;
while (true)
{
try {
if (inStream != null)
{
bytes = inStream.available();
if(bytes > 0 && bytes <= 200)
{
byte[] pocketBytes = new byte[bytes];
inStream.read(pocketBytes);
//Log.d(TAG, "setState() " + mState + " -> " + state);
System.out.println(pocketBytes.toString());
dupa = pocketBytes.toString();
System.out.println(dupa);
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, pocketBytes).sendToTarget();
}
}
} catch (IOException e) {
mHandler.obtainMessage(Constants.MESSAGE_REMOTE_DEV_DISCONNECTED).sendToTarget();
break;
}
/*try
{
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
outStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
connectedSocket.close();
} catch (IOException e) { }
}
}
}
And after that I try to update UI in the Handler.
This is link to sample of my application:
https://www.youtube.com/watch?v=_Buv64vADNk&feature=youtu.be
It does not work smoothly, morever sometimes it does not respond.
Could you please tell me what am I doing wrong ? Thx in advance.
Mateusz; Look into operational blocks force your code into the background at a lower priority that the UI code. You can also try GCD. Here a very simple block of code, spun off as a separate process.
How to determine when all images have been downloaded from a set in Swift?
Put the UI code at the highest priority and bluetooth at the lowest; making double sure the only statements you put into UI updates are doing that, don't put anything there that isn't updating the UI.
Related
I need to listen to a socket as long as the app is alive. We do it in this way in Java (infinite loop):
public void listen() throws Exception {
String msg;
while (isRunning) {
byte[] buf = new byte[5 * 1024]; // Size: 5K
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// blocks until a packet is received
udpSocket.receive(packet);
msg = bytesToHexString(buf);
print("Message from " + packet.getAddress().getHostAddress() + ": " + msg);
pm.setNotification(msg);
}
}
I am able to run it in another thread by using RxJava2 (to prevent Network On Main Thread Exception in Android).
try {
udpClient = new UDPClientMulticast("232.17.29.10", 4444);
Disposable d1 = Single.just(udpClient)
.subscribeOn(Schedulers.io())
.map(client -> {
client.listen();
return true;
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(isListening -> print("UDP Client is listening: " + isListening), t -> print("Error: " + t.getMessage()));
cd.add(d1);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Even though it is working, I think this is super ugly. Is there any Rx way that let me to simulate infinite loop?
Why use RxJava for this? There's no need to. Just start a thread. You're overcomplicating things by adding in Rx at all.
I am trying to send a photo from my Raspberry Pi using Python 3, to my Android Device. I am doing this over TCP with the Pi as the Client, and the Android Device as my Server. My goal is to send a photo file from Pi to my Android Device. My Android Device would then decode that photo data and then set it as the drawable for an ImageView in my App. Kindly note that I'm sending a 200kB image that's 640x480.
I have tried a set up where the Pi sends text to my Android Device via TCP, and I've had success with that.
What I did next was to attempt to send a photo from a Python3 client to a Python3 Server. In this case, I used the Pi still as my client, and I used my MacOS Laptop as the Server. This are the code that I ended up using.
Server - MAC OS
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 11111 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
f = open('torecv.jpg','wb')
s.listen(5) # Now wait for client connection.
while True:
c, addr = s.accept() # Establish connection with client.
print('Got connection from', addr)
print("Receiving...")
l = c.recv(1024)
while (l):
print("Receiving...")
f.write(l)
l = c.recv(1024)
f.close()
print("Done Receiving")
c.send(b'Thank you for connecting')
c.shutdown(socket.SHUT_RDWR)
c.close() # Close the connection
Client - Pi
import socket # Import socket module
import os
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
host = '192.168.254.194' # Get local machine name
port = 6001 # Reserve a port for your service.
CWD_PATH = os.getcwd()
PATH_TO_IMG_DIR = os.path.join(CWD_PATH, 'img_folder', 'test.jpg')
s.connect((host, port))
#s.send(b'Hello Server!')
f = open(PATH_TO_IMG_DIR,'rb')
print('Sending...')
l = f.read(1024)
while (l):
print('Sending...')
s.send(l)
l = f.read(1024)
f.close()
print("Done Sending")
s.shutdown(socket.SHUT_WR)
print(s.recv(1024))
s.close # Close the socket when done
Using this code, I was able to transfer the photo from my Pi to my MacOS laptop.
Now, I used the code here as reference in order to transfer my photo from my Pi to my Android Device. Now, this is my code:
Server - Android
class ServerThread implements Runnable {
public void run() {
Socket socket;
try {
Log.e(TAG, "starting the serverthread at port 6001");
serverSocket = new ServerSocket(6001);
} catch (IOException e) {
Log.e(TAG, "exception in creating server socket: ", e);
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
}
}
}
}
class CommunicationThread implements Runnable{
private Socket clientSocket;
private DataInputStream input;//private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
Log.e(TAG, "getting data from the input stream!");
//this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
InputStream in = this.clientSocket.getInputStream();
this.input = new DataInputStream(in);
} catch (IOException e) {
Log.e(TAG, "error in creating data input stream: ", e);
e.printStackTrace();
}
}
public void run() {
Log.e(TAG, "running the code!");
while (!Thread.currentThread().isInterrupted()) {
try {
Log.e(TAG, "parsing the input data stream!");
byte[] data;//String read = input.readLine();
int len= this.input.readInt();
if (len > 0) {
data = new byte[len];
this.input.readFully(data,0,data.length);
}
/*
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] data;
int length = 0;
while ((length = this.input.read(data))!=-1) {
out.write(data,0,length);
}
data=out.toByteArray();
*/
Log.e(TAG, "Updating the UI through a thread!!");
// updateConversationHandler.post(new updateUIThread(data));
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e(TAG, "error in reading sent data! ", e);
e.printStackTrace();
}
}
}
}
And in order to use these classes, I had declared the following as global variables:
Thread serverThread = null;
Handler updateConversationHandler;
And in my onCreate(), I have the following:
updateConversationHandler = new Handler();
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
The app would start, and the socket would be opened. However, when I attempt to send in the photo from my Pi, I hit an error at this block of code:
public void run() {
Log.e(TAG, "running the code!");
while (!Thread.currentThread().isInterrupted()) {
try {
Log.e(TAG, "parsing the input data stream!");
byte[] data;//String read = input.readLine();
int len= this.input.readInt();
if (len > 0) {
data = new byte[len];
this.input.readFully(data,0,data.length);
}
/*
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] data;
int length = 0;
while ((length = this.input.read(data))!=-1) {
out.write(data,0,length);
}
data=out.toByteArray();
*/
Log.e(TAG, "Updating the UI through a thread!!");
// updateConversationHandler.post(new updateUIThread(data));
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e(TAG, "error in reading sent data! ", e);
e.printStackTrace();
}
}
}
class updateUIThread implements Runnable {
private byte[] byteArray;//private String msg;
public updateUIThread(byte[] array){ //public updateUIThread(String str) {
this.byteArray=array; //this.msg = str;
}
#Override
public void run() {
Log.e(TAG, "running the photo update!");
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray , 0, byteArray .length);
ivBed.setImageBitmap(bitmap);//text.setText(text.getText().toString()+"Client Says: "+ msg + "\n");
}
}
Originally, the line:
data = new byte[len];
was outside the if(len>0) condition. But what happened was, for some reason, the Pi sent in a negative value, and of course we don't want a negative value for the len variable. Of course, I hit an error when I tried to create the byte array data with a negative length. I then put that line in the if condition.
However, after I did, I hit on OOM Error in the same line data = new byte[len];
Process: agict.work.freelance.patientsensor, PID: 15224
java.lang.OutOfMemoryError: Failed to allocate a 1677608328 byte allocation with 6291456 free bytes and 254MB until OOM, max allowed footprint 7797480, growth limit 268435456
I have a hunch that in the 2nd error, I was trying to initialize the byte array with a value that was actually the image data already, hence, the OOM error.
However, if I just take in the first value and assign it as the len, there's a chance that I'd get a negative number and the code would hit the first error.
Would there be a chance that I have to tweak something in order to transfer a photo data from Python3 to Android? I have a feeling that there's a format mismatch of sorts that's happening.
Again, my goal is to send a photo file from Python3 to my Android Device via TCP. The Python3 will be given a file, and the Android Device will decode the input it gets, and once decoded, use that data as the drawable for an ImageView.
According to me that error is caused by the size of the bitmap that you are trying to set for the ImageView. Checking sizes before use and/or scaling the bitmap may solve the issue. I've encountered such problems in the past before I start using third party libraries to load images.
You can take a look at this article from Android Developers and I think it can help:
https://developer.android.com/topic/performance/graphics/load-bitmap#java
I got it. You're supposed to use a ByteArrayOutputStream Object.
class ServerImageThread implements Runnable{
ServerSocket ss;
Socket s;
DataInputStream dis;
byte[] data;
#Override
public void run(){
try{
ss = new ServerSocket(6001);
while(true){
s = ss.accept();
InputStream in = s.getInputStream();
dis = new DataInputStream(in);
// read from the stream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] content = new byte[1024];
int bytesRead = -1;
while( (bytesRead = in.read(content)) != -1 ) {
baos.write( content, 0, bytesRead );
} // while
Log.e(TAG, "made it through!");
Log.e(TAG, "baos size is = " + baos.size());
File file = new File(
Environment.getExternalStorageDirectory(), "test.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
baos.writeTo(fos);
Log.e(TAG, "managed to write baos to fos");
} catch(IOException ioe) {
// Handle exception here
Log.e(TAG, "baos IOException = ", ioe);
ioe.printStackTrace();
} finally {
Log.e(TAG, "closing fos");
fos.close();
}
}
}
catch(IOException e) {
Log.e(TAG, "exception in creating server socket: ", e);
e.printStackTrace();
}
}
}
You can call this via:
Thread myThread = new Thread(new ServerImageThread());
myThread.start();
I'm trying to build an application that reads information sent on a bluetooth service using rfcomm.
The device is an hardness tester (HT-6510A), unfortunalty specs about the device data format can't be found I'm faced with a strange problem, I've to understand how to read these information.
01-11 17:47:28.940 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:29.581 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.211 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:30.872 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:31.513 11862-13447/joinstore.it.testhardness V/result: ��S
01-11 17:47:32.143 11862-13447/joinstore.it.testhardness V/result: ��T
01-11 17:47:32.794 11862-13447/joinstore.it.testhardness V/result: ��T
This is the data I receive from the device, I don't think there's something wrong with the implementation tha simply uses this thread after stabilizing a rfcomm connection.
//After connection, handle data transfer
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;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
// readAndPublishRaw();
readAndPublishString();
Log.v("result", "Reading data ended.");
setStatusText(-1);
}
void readAndPublishRaw(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
Log.v("result", "Start reading...");
// 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
Log.v("result", bytes + "");
} catch (IOException e) {
break;
}
}
}
void readAndPublishString(){
//String method, not useful in this case?
try {
BufferedReader r = new BufferedReader(new InputStreamReader(mmInStream));
StringBuilder total = new StringBuilder();
String line;
Log.v("result", "Start reading...");
while ((line = r.readLine()) != null) {
total.append(line);
Log.v("result", line);
}
Log.v("result", total.toString());
//TODO publish read string to the view
} catch (Exception e) {
//
try {
mmSocket.close();
}catch (Exception ex){}
Log.v(TAG, "exception reading data from service");
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
setStatusText(-1);
} catch (IOException e) {
}
}
}
Can you guys give me any information about how to correctly parse this raw data? I think I should have a stream of float values, but instead I've just this random stuff.
Suggestion on how to get some usable log output first:
void readAndPublishRaw(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
Log.v("result", "Start reading...");
// 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
final StringBuilder sb = new StringBuilder();
sb.append("Received ").append(bytes).append(" bytes: ");
for ( int i = 0; i < bytes; i++ ) {
sb.append( Integer.toHexString(((int)buffer[i]) & 0xff) ).append(", ");
}
Log.v("result", sb.toString());
} catch (IOException e) {
break;
}
}
}
The next step should be to calibrate the data, i.e. make note of which input/display value yields what raw data. From there, you may or may not be able to infer the actual encoding.
Your device may or may not include other information besides the actual measurement in the data, e.g. to indicate a low battery. That would have to be factored out to get raw measurement values.
If one data value comprises more than one byte the byte-order (little- or big-endian) needs to be determined.
Often floating point data of small devices is represented in a fixed point representation. Sometimes, esp. if negative numbers are needed too, with an offset added, so that
realValue = rawValue * a + c
If you find out a and c you're good. Hence, once you can relate only two different realValues and corresponding rawValues from the calibration done above, you have enough data to solve the equation for a and c.
Devices with a little more "punch", embedded linux devices for instance, may also use regular IEEE floating point data. - Not that small embedded devices cannot use IEEE, but floating point is often more than is required and comes at the price of higher complexity (memory & CPU) for the floating point emulation code.
I'm facing the following problem:
I am connecting two devices via Bluetooth socket, one tablet android and a bluetooth device like reader barcode, up to now it's ok, the problem is, when a read the barcode by the bluetooth device and I send it to tablet, the bar code sometimes it's sent in two parts, for example, if I read a barcode with content "212154521212", the tablet receive "2121" and after "54521212", Anyone know tell me what should I do to avoid this?
Thanks in advanced.
My code that read the data from bluetooth device:
[code]
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private BluetoothSocket socket;
public ConnectedThread(BluetoothSocket socket) {
this.socket = socket;
InputStream tmpIn = null;
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
new LogDeErrosRodesTablet(e);
Log.e(TAG, e.getMessage());
Log.e(TAG, "Erro no construtor da classe ConnectedThread.");
}
mmInStream = tmpIn;
}
public void run() {
// continua lendo o inputstream até ocorrer um erro
while (true) {
int read = 0;
byte[] buffer = new byte[128];
do {
try {
read = mmInStream.read(buffer);
Log.e(TAG, "read: " + read);
final String data = new String(buffer, 0, read);
Log.e(TAG, "data: " + data);
//TODO
//send data only (bar code) only after read all
Bundle bundle = new Bundle();
bundle.putString(TelaInserirPedido.CODIGO_BARRAS, data);
Message message = new Message();
message.what = TelaInserirPedido.MSG_COD_BARRAS;
message.setData(bundle);
//Send a message with data
handler.sendMessage(message);
} catch(Exception ex) {
read = -1;
return;
}
Log.e(TAG, "inside while.");
} while (read > 0);
Log.e(TAG, "outside of while.");
}
}
public void cancel () {
try {
socket.close ();
} catch ( IOException e) { }
}
}
[/code]
This isn't a Bluetooth error. The Bluetooth device is sending all of the data to your application, but you are reading the stream before all of the data have been received. You could check for the amount of bytes available() on the stream before reading, if you know the exact length of the data; you could concatenate the results of all of the reads until you reach a known end point. Or you could put in an arbitrary time delay and hope the transmission completed in that time.
You would create the Bundle and Message after the while loop that collects the input string, because you don't know the entire string until that loop finishes. (Unless you are expecting multiple strings in one connection, in which case you need more complex code to handle partial numbers).
Use OutputStream.flush() to force send the all data.
I'm trying to find a solution for this setup:
I have a single Android device, which I would like to connect to multiple serial embedded devices...
And here is the thing, using the "Normal" way to retrieve the Bluetooth socket, doesn't work on all devices, and while it does, I can connect to multiple devices, and send and receive data to and from multiple devices.
public final synchronized void connect()
throws ConnectionException {
if (socket != null)
throw new IllegalStateException("Error socket is not null!!");
connecting = true;
lastException = null;
lastPacket = null;
lastHeartBeatReceivedAt = 0;
log.setLength(0);
try {
socket = fetchBT_Socket_Normal();
connectToSocket(socket);
listenForIncomingSPP_Packets();
connecting = false;
return;
} catch (Exception e) {
socket = null;
logError(e);
}
try {
socket = fetchBT_Socket_Workaround();
connectToSocket(socket);
listenForIncomingSPP_Packets();
connecting = false;
return;
} catch (Exception e) {
socket = null;
logError(e);
}
connecting = false;
if (socket == null)
throw new ConnectionException("Error creating RFcomm socket for" + this);
}
private BluetoothSocket fetchBT_Socket_Normal()
throws Exception {
/* The getType() is a hex 0xXXXX value agreed between peers --- this is the key (in my case) to multiple connections in the "Normal" way */
String uuid = getType() + "1101-0000-1000-8000-00805F9B34FB";
try {
logDebug("Fetching BT RFcomm Socket standard for UUID: " + uuid + "...");
socket = btDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
return socket;
} catch (Exception e) {
logError(e);
throw e;
}
}
private BluetoothSocket fetchBT_Socket_Workaround()
throws Exception {
Method m;
int connectionIndex = 1;
try {
logDebug("Fetching BT RFcomm Socket workaround index " + connectionIndex + "...");
m = btDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
socket = (BluetoothSocket) m.invoke(btDevice, connectionIndex);
return socket;
} catch (Exception e1) {
logError(e1);
throw e1;
}
}
private void connectToSocket(BluetoothSocket socket)
throws ConnectionException {
try {
socket.connect();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e1) {
logError("Error while closing socket", e1);
} finally {
socket = null;
}
throw new ConnectionException("Error connecting to socket with" + this, e);
}
}
And here is the thing, while on phones which the "Normal" way doesn't work, the "Workaround" way provides a solution for a single connection. I've searched far and wide, but came up with zip.
The problem with the workaround is mentioned in the last link, both connection uses the same port, which in my case, causes a block, where both of the embedded devices can actually send data, that is not been processed on the Android, while both embedded devices can receive data sent from the Android.
Did anyone handle this before?
There is a bit more reference here,
UPDATE:
Following this (that I posted earlier) I wanted to give the mPort a chance, and perhaps to see other port indices, and how other devices manage them, and I found out the the fields in the BluetoothSocket object are different while it is the same class FQN in both cases:
Detils from an HTC Vivid 2.3.4, uses the "workaround" Technic:
The Socket class type is: [android.bluetooth.BluetoothSocket]
mSocket BluetoothSocket (id=830008629928)
EADDRINUSE 98
EBADFD 77
MAX_RFCOMM_CHANNEL 30
TAG "BluetoothSocket" (id=830002722432)
TYPE_L2CAP 3
TYPE_RFCOMM 1
TYPE_SCO 2
mAddress "64:9C:8E:DC:56:9A" (id=830008516328)
mAuth true
mClosed false
mClosing AtomicBoolean (id=830007851600)
mDevice BluetoothDevice (id=830007854256)
mEncrypt true
mInputStream BluetoothInputStream (id=830008688856)
mLock ReentrantReadWriteLock (id=830008629992)
mOutputStream BluetoothOutputStream (id=830008430536)
**mPort 1**
mSdp null
mSocketData 3923880
mType 1
Detils from an LG-P925 2.2.2, uses the "normal" Technic:
The Socket class type is: [android.bluetooth.BluetoothSocket]
mSocket BluetoothSocket (id=830105532880)
EADDRINUSE 98
EBADFD 77
MAX_RFCOMM_CHANNEL 30
TAG "BluetoothSocket" (id=830002668088)
TYPE_L2CAP 3
TYPE_RFCOMM 1
TYPE_SCO 2
mAccepted false
mAddress "64:9C:8E:B9:3F:77" (id=830105544600)
mAuth true
mClosed false
mConnected ConditionVariable (id=830105533144)
mDevice BluetoothDevice (id=830105349488)
mEncrypt true
mInputStream BluetoothInputStream (id=830105532952)
mLock ReentrantReadWriteLock (id=830105532984)
mOutputStream BluetoothOutputStream (id=830105532968)
mPortName "" (id=830002606256)
mSocketData 0
mSppPort BluetoothSppPort (id=830105533160)
mType 1
mUuid ParcelUuid (id=830105714176)
Anyone have some insight...
WOW, every time this strike me down with one big WTF?
This was a race condition issue, which clearly works on one version of android, and not on another. On Android peer I was parsing the packets received from the socket:
public class SocketListener
implements Runnable {
private boolean stop;
private OnIncomingPacketListener packetListener;
#Override
public void run() {
InputStream inputStream;
try {
stop = false;
inputStream = socket.getInputStream();
while (!stop) {
Packet packet = Packet.getPacket(inputStream);
lastPacket = packet;
if (packet.getDescriptor() == Packet.HeartBeat)
lastHeartBeatReceivedAt = System.currentTimeMillis();
else if (packet.getDescriptor() == Packet.LogEntry)
log.append(((LogEntryPacket) packet).getLogEntry());
synchronized (this) {
if (packetListener != null)
packetListener.onIncomingData(EmbeddedDevice.this, packet);
}
}
} catch (IOException e) {
logError("----- BLUETOOTH IO ERROR -----\n #: " + EmbeddedDevice.this, e);
return;
} catch (RuntimeException e) {
logError("----- BLUETOOTH LISTENER ERROR -----\n #: " + EmbeddedDevice.this, e);
throw e;
} finally {
socketListeningThread = null;
}
}
}
Where the Packet.getPacket(inputStream) is:
public static synchronized Packet getPacketInstance(InputStream inputStream)
throws IOException {
int data = inputStream.read();
Packet type = null;
for (Packet packetType : values())
if (packetType.packetType == data) {
type = packetType;
break;
} // race condition here...
if (type == null)
throw new IllegalArgumentException("Unknown packet type: " + data);
try {
Packet packet = type.incomingPacketType.newInstance();
packet.setDescriptor(type);
packet.readPacketData(inputStream);
return packet;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Error instantiating type: " + type.incomingPacketType.getName(), e);
}
}
And every time a packet is completed, the next thread should have gone in to perform it parsing.
My guess is that there is some sort of lock on the port, that together with my implementation caused the second thread to block indefinitely, once I've removed the parsing to different instances per thread, the issue dissolved.
This insight was inspired by Daniel Knoppel, the guy from the mPort link.
Thanks Daniel!