How to make good real-time data transfer using Java Android SDK

I have a bluetooth home device measuring ECG at a frequency of 500 Hz: every 2 ms the device sends 9 bytes of data (header, ECG measurement, footer). Thus, this is approximately 9 * 500 = 4.5 kB / s of data stream.

I have a C ++ Windows program capable of connecting a device and retrieving a data stream (displaying it with Qt / qwt). In this case, I use the Windows control panel to connect the device, and I connect it through the virtual COM port using the serial serial interface. This works fine, and I get a real-time data stream: I get a measuring point every 2 ms or so.

I ported the entire program to Android through QtCreator 3.0.1 (Qt 5.2.1). It seems that virtual COM ports cannot be accessed using boost (probably the SDK permissions will not allow this), so I wrote a piece of Java code to open and control a Bluetooth connection. Thus, my application remains C ++ / Qt, but only the layer connecting and reading data from the device was redesigned in Java (opening a connection with createInsecureRfcommSocketToServiceRecord):

Java code for reading data:

public int readData( byte[] buffer ) { if( mInputStream == null ) { traceErrorString("No connection, can't receive data"); } else { try { final boolean verbose = false; int available = mInputStream.available(); if ( verbose ) { Calendar c = Calendar.getInstance(); Date date = new Date(); c.setTime(date); c.get(Calendar.MILLISECOND); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); String currentTime = sdf.format(date); traceDebugString( currentTime + ":" + c.get(Calendar.MILLISECOND) + " - " + available + " bytes available, requested " + buffer.length ); } if ( available >= buffer.length ) return mInputStream.read( buffer ); // only call read if we know it not blocking else return 0; } catch (IOException e) { traceDebugString( "Failed to read data...disconnected?" ); } } return -1; } 

Called from C ++ as follows:

 bool ReceiveData( JNIEnv* env, char* data, size_t length, bool& haserror ) { bool result = false; jbyteArray array = env->NewByteArray(length); jint res = env->CallIntMethod(j_object, s_patchIfReceiveDataID, array ); if ( static_cast<size_t>(res) == length ) { env->GetByteArrayRegion(array, 0, length, reinterpret_cast<jbyte*>(data)); result = true; } else if ( res == -1 ) { haserror = true; } else { // not enough data in the stream buffer haserror = false; } return result; } bool readThread( size_t blockSize ) { BTGETANDCHECKENV // retrieving environment char* buf = new char[blockSize]; bool haserror = false; while ( !haserror ) { if ( !ReceiveData( env, buf, blockSize, haserror ) ) { // could not read data if ( haserror ) { // will stop this thread soon } else { boost::this_thread::sleep( boost::posix_time::milliseconds( 10 ) ); } } } delete [] buf; return true; } 

This works very well ... in the first five seconds I get the values ​​in real time, and then:

  • Sometimes it freezes forever, i.e. the value of mInputStream.available () remains below the requested one.
  • Sometimes it freezes for only a second or so, and then continues, but the data is received in blocks of ~ 1 second. The value of mInputStream.available () can move from 0 to more than 3000 between two calls (10 ms has passed). In fact, I see the same for the first 5 seconds, but the presence of a buffer never exceeds 150 bytes, after 5 seconds it can reach 3000 bytes.

Here is what the log might look like when verbose is true:

 14:59:30:756 - 0 bytes available, requested 3 14:59:30:767 - 0 bytes available, requested 3 14:59:30:778 - 0 bytes available, requested 3 14:59:30:789 - 1728 bytes available, requested 3 14:59:30:790 - 1725 bytes available, requested 6 14:59:30:792 - 1719 bytes available, requested 3 

My ECG device definitely did not send 1728 bytes in 11 ms!

I know that my device sends 9 bytes every 2 ms (otherwise it will not work in my PC application). It seems that Java does some unexpected buffering and does not make 9 bytes available every 2 ms .... These are also strange things, it seems to work fine only for 5 seconds at the beginning.

Note that I tried using read () without checking the available () (blocking version), but experienced exactly the same behavior.

So I wonder what I'm doing wrong ...

  • Is there a way to get the Java input stream to update itself?
  • Is there a way to ask Java to continue its pending events (for example, we have QApplication :: processEvents)?
  • Are there any global settings for specifying buffer sizes for streams (I did not find any at the BluetoothDevice / BluetoothSocket level)
  • On the PC, when I open the virtual COM port, I need to indicate the baud rate, stop bit, connection confirmation, etc. On Android, I just open the Rfcomm socket without the option, could this be a problem (then the ECG device and the smartphone did not synchronize ...)?

Any help or idea would be welcome!

Edit: I experience this on a Nexus 5 phone, Android 4.4.2 I just tested the same apk package on different devices:

  • Galaxy S4 with Android 4.4.2: same problem.
  • Galaxy S3 with custom CyanogenMod 11 Android 4.4.2: data streaming seems perfect, freezing after 5 seconds and the data arrives in real time .... it looks like the whole system is able to achieve what I want, but it looks like that the default setting in Android makes things too slow .... I don’t know if there can be a parameter that needs to be changed at the OS level to fix this problem.

Edit: Since I have no answer :-( I tried to do the same using a pure Java program (not C ++, not Qt). I had the same problem: Real- Bluetooth SPP data transfer time on Android only works 5 seconds

+1
source share
1 answer

This issue seems to be similar to the one reported here .

After 5 seconds, I had either a lost connection, or real-time streaming slows sharply.

As stated here, Android> 4.3 clearly does not like one-way communication exceeding 5 seconds. Therefore, I now send a dummy command to the device every 1 second (like "keep-alive"), and now Android is happy because it is not a one-way communication anymore ... and therefore streaming data is also good after the fifth second than before !

0
source

Source: https://habr.com/ru/post/1208043/


All Articles