Android Slow Bluetooth RFCOMM Transfer Rate with RN4678 - android

We are experimenting with a bunch of new tablets, and every one we tried is having issues with slow transfer rates with the RN4678 board. We currently use the Lenovo M10 FHD Plus. We tried a few such as the Teclast M40S, Nokia T20, and Samsung Galaxy Tab A8. The first two had horrible transfer rates, while the latter was okay but not ideal. We cannot use the Lenovo M10 Plus 3rd Gen because the buttons are too close to the corner to use with our tablet holders.
Here is my code:
public void SendMessage(BluetoothSocket socket, String msg) {
OutputStream outStream;
try {
outStream = BluetoothConnectionService.outputStream;
outStream.write("S".getBytes());
Thread.sleep(4000);
processThread = true;
mApp.running = true;
BluetoothSocketListener bsl = new BluetoothSocketListener(socket,
CollectingDetail.this);
Thread messageListener = new Thread(bsl);
messageListener.start();
timer = new CounterClass(remaingTime, 1000);
timer.start();
bt_stop.setText("Stop");
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(bluetoothReceiver, filter);
bluetoothReceiver.setRegistered(true);
} catch (IOException | InterruptedException e) {
Log.e("BLUETOOTH_COMMS", e.getMessage());
connectSocket();
}
}
public static class BluetoothSocketListener implements Runnable {
private final WeakReference<CollectingDetail> wrActivity;
private BluetoothSocket socket;
public BluetoothSocketListener(BluetoothSocket socket, CollectingDetail collectingDetail) {
this.socket = socket;
wrActivity = new WeakReference<CollectingDetail>(collectingDetail);
}
#Override
public void run() {
final CollectingDetail activity = wrActivity.get();
if (activity != null) {
activity.inStream = null;
if (!Thread.currentThread().isInterrupted()) {
int bufferSize = 512;
byte[] buffer = new byte[bufferSize];
Log.i("Bluetooth bytes", new String(buffer));
activity.inStream = BluetoothConnectionService.inputStream;
int availableBytes;
int bytesRead = -1;
String message = "";
while (activity.processThread) {
message = "";
try {
availableBytes = activity.inStream.available();
if (availableBytes > 0) {
bytesRead = activity.inStream.read(buffer);
if (bytesRead != -1 && bytesRead < bufferSize) {
message = new String(buffer, 0, bytesRead);
if (activity.mainHandler != null) {
activity.mainHandler.post(new MessagePoster(message, activity));
}
}
}
} catch (IOException e) {
Log.e("BLUETOOTH_COMMS", "Error reading bytes");
try {
socket.close();
} catch (IOException e1) {
Log.e("BLUETOOTH_COMMS", "Could not close socket");
}
activity.processThread = false;
}
}
}
}
}
}
public void seprateData(String message) {
try {
message = message.replaceAll("(\\r\\n|\\n|\\r)", ",");
String[] a = message.split(",");
boolean goodData = false;
for (int i = 0; i < a.length; i++) {
final String data = a[i];
if (data.length() > 0 && !data.equals(" ")) {
if (data.length() >= 10 && data.startsWith("5A")) {
al_sepratedMessageList.add(data);
goodData = true;
}
}
}
if (goodData) {
calculation();
if (ConnectThrough.equalsIgnoreCase("usb")) {
UsbConnectionSerivce.sendMessage("K");
} else {
BluetoothConnectionService.sendMessage(socket, "K");
}
}
} catch (Exception e) {
Log.e("BiSym", "Error Parsing BiSym Data");
}
}
Is there any way we can increase the transfer rate without changing the firmware? It appears others have faced similar problems, but none of the answers have a real solution. Could you please help me out. Thanks.
I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?

I fear this may not be software-solvable and may be an issue with BT hardware or firmware. How would I communicate with my boss about this?
The difference is in the quality of the filtering of the signal, a better filter, narrower bandwidth, means lower Signal to Noise Ratio. Lower SNR means faster transfer.
Better analog filters, mean more components and slightly more cost and loss, however, due to the wide-band nature of Bluetooth, most analog filters can only filter out of band signals (nearby AM/FM/TV broadcasters).
In addition to the analog filters, digital filters are applied to the signal to narrow the bandwidth within the band, this technique incurs little loss, but requires more processing power to be included in the chip, more transistors, more costs.
The order of the filter and the type FIR or IIR determine the characteristics of the filer.
Most designers will minimize the cost to meet the minimum specifications, some will balance the cost versus performance and go further, you never know.
You tell your boss, the the better platforms perform digital filtering well beyond what the Bluetooth specification requires.

I just tested the Teclast M40 Plus which doesn't have this problem.
Something wants to make me believe it is an issue with the UNISOC Bluetooth stack. The Teclast M40 Plus has MediaTek which doesn't have this issue.
EDIT: Also tested on Lenovo M10 Plus 3rd Gen with MediaTek Helio G80, no issue. If we have to use it, we may need a new tablet holder.

Have you repeated the tests? Bluetooth uses the same frequencies as 2.4 GHz Wifi and microwave ovens. In a congested Wifi environment, and/or too many Bluetooth connections(mice, keyboards, headphones, speakers, watches ...), slowdowns are normal for high-speed transfers.
Wifi 6 MIMO utilizes all three distinct channels in the 2.4G band, (1,6,11) of the 12 overlapping. Higher bandwidth/speeds are available in 5.4G (and above), but wall penetration and signal propagation factors keep 2.4G as the primary band in the absence of other possibilities.
There is only so much space in the 2.4G band that Bluetooth operates.
Repeat your tests in an area without interference and see if you get the same results.
A cheap isolation method is to build a Faraday Cage out of .25 inch chicken wire fencing. Isolate the sender and receiver inside of the cage and measure the throughput.
In an uncontrolled environment, hundreds to thousands of tests for each device are required across different time spans to establish a true baseline measurement. You never know when you neighbor is going to start or stop a variable bit-rate video, or move a mouse.Every action contributes to the background noise in the band.

Related

Android Beacon Library | IBeacon - Advertising multiple beacons using Mobile device

I am using the Android beacon library with,
version -
compile 'org.altbeacon:android-beacon-library:2.15.1'
I am trying to develop one APK for transmitting multiple beacons from my mobile device.
I need to perform this to test or POC to test, how many beacons a reader can read at a time.
I am using the below code to transmit the BLE messages with Android Beacon Library.
btn_transmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isBluetoothEnabled)
{
try
{
String customUuid = "";
for(int i=0;i<=50;i++)
{
if( i < 10){
customUuid = "99999999-b00"+i+"-4807-b747-9aee23508620";
} else if ( i < 999){
customUuid = "99999999-b0"+i+"-4807-b747-9aee23508620";
}
Thread.sleep(5000);
trasmitClick(customUuid);
beaconTransmitter = null;
}
}
catch(Exception e)
{
Toast.makeText(BeaconTransmitterActivity.this, "Something went wronggg", Toast.LENGTH_LONG).show();
}
}
else
Toast.makeText(BeaconTransmitterActivity.this, "Check your bluetooth connection", Toast.LENGTH_LONG).show();
}
});
Here above I am dynamically trying to create 50 new Id's to transmit the beacons.
Method to createBeacon and transmit its advertisements
public void trasmitClick(String customUuid) {
if (beaconTransmitter == null) {
String major, minor, uuid;
uuid = customUuid;
major = etMajorValue.getText().toString().trim();
minor = etMinorValue.getText().toString().trim();
if (TextUtils.isEmpty(uuid))
uuid = customUuid;
if (TextUtils.isEmpty(major))
major = "8";
if (TextUtils.isEmpty(minor))
minor = "2";
currentType=beaconLayout;
currentuuid=uuid;
currentmajorValue=major;
currentminorValue=minor;
beacon = new Beacon.Builder()
.setId1(uuid)
.setId2(major)
.setId3(minor)
//.setManufacturer(0x0118) // It is for AltBeacon. Change this for other beacon layouts
.setManufacturer(0x004C)
.setTxPower(-59)
//.setDataFields(Arrays.asList(new Long[]{6l, 7l})) // Remove this for beacon layouts without d: fields
.build();
// Change the layout below for other beacon types
beaconParser = new BeaconParser()
.setBeaconLayout(parserLayout[beaconLayout]);
beaconTransmitter = new BeaconTransmitter(getApplicationContext(), beaconParser);
beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
#Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
}
});
btn_transmit.setText("Stop Advertising");
btn_apply.setEnabled(false);
} else {
beaconTransmitter.startAdvertising();
beaconTransmitter = null;
btn_transmit.setText("Start Advertising");
btn_apply.setEnabled(false);
}
}
I am able to make this code work, but what is the result is I am able to transmit only 4 messages, the rest of the messages are not being visible in the simulator.
I am trying to find if the library has some limitations or I am wrong above.
Well I am novice in Android coding.
Below is the result that I can get in my simulator:
I would like to know how can I transmit 50 messages in one go.
This is most certainly a limitation of the Bluetooth chip on your mobile phone. Different device models have different advertising limits. The Huawei P9 Lite, for example can transmit only one advertisement at a time. The Nexus 5x can advertise 10 or more. It is unlikely that many phone models (if any) support 50 simultaneous advertisements.
There is no way to know the limit programmatically, as the OS provides no API to query this limit -- you just have to try. You can check when you get an error advertising by putting code in the onStartFailure callback.
You might also use the [BeaconScope]((https://play.google.com/store/apps/details?id=com.davidgyoungtech.beaconscanner) app to test this. But remember that transmission limits are device-wide. If one app is advertising a beacon, that takes one advertisement slot away from the next app. And no, there is no way to know if other apps are advertising.

zebra scanner integration in android

we are using symbol ls4278 bluetooth scanner to integrate in android application. It is connected as keyboard and types scanned barcode in any edittext field...
After scanner OnKeyUp event is called.
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
..
}
I was searching documentation and android sdk, but I can't found such one. But for LI4278 they have android sdk here : https://www.zebra.com/us/en/support-downloads/scanners/general-purpose-scanners/li4278.html
here is also documentation for sdk but LS4278 is not in supported device list.
Does anyone implemented LS4278 scanner in android devices?
The LS4278 product page is here: https://www.zebra.com/us/en/support-downloads/scanners/general-purpose-scanners/ls4278.html and lists support for the "Windows Scanner SDK" ONLY. The LS4278 was discontinued on September 24th 2012 so I am not surprised it does not have Android support. As you say, its successor, the LI4278 does have Android support. As the other answer states, if you want more control over how you receive data then I suggest trying SPP if the scanner supports it.
If it works as a bluetooth keyboard, then no support is needed. Just capture the key events, and react to the data when enter is pressed. Its just a mediocre experience and can mess with on screen keyboards and stop them from using an actual bluetooth keyboard. If the scanner supports SPP, you can pretty trivially parse the scan data out of it via bluetooth serial (I did this about 2 weeks ago).
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
if(bta != null) {
Set<BluetoothDevice> devices = bta.getBondedDevices();
for (final BluetoothDevice device : devices) {
BluetoothClass btClass = device.getBluetoothClass();
if (btClass.getMajorDeviceClass() == 0x1f00) {
//Only look at devices which are considered uncategorized, so we don't screw up any bt headset, leyboard, mouse, etc
new DeviceThread(device).start();
}
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
if (state == BluetoothDevice.BOND_BONDED) {
new DeviceThread(device).start();
} else if (state == BluetoothDevice.BOND_NONE) {
DeviceThread thread = threadMap.get(device.getAddress());
if (thread != null) {
thread.interrupt();
}
}
}
}, filter);
}
private class DeviceThread extends Thread {
private BluetoothDevice device;
public DeviceThread(BluetoothDevice device) {
this.device = device;
threadMap.put(device.getAddress(), this);
}
#Override
public void run() {
try {
BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
socket.connect();
InputStream inputStream = socket.getInputStream();
while (!Thread.interrupted() && socket.isConnected()) {
inputStream.skip(5);
String data = "";
do {
int code = inputStream.read();
char character = (char) code;
data = data + character;
} while (inputStream.available() > 0);
data = data.substring(0, data.length() - 2);
if (scannerEventListener != null) {
scannerEventListener.onScan(data);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
Log.d("GABE", "Exiting thread");
}
}
This code will register for bluetooth devices being paired, then check and see if they're unknown device types (scanners don't have a device class). If so, it will start a thread to listen for that device. When its unbonded, it will interrupt that thread. On the thread it opens up a SPP connection to the device and waits for input. When it gets it, it parses the input and sends the result to a listener.
For this to work, the scanner needs to be in SPP mode. Some scanners support it, some don't, and how to set it into that mode varies (the one on my desk has a control barcode I need to scan to set the mode). Generally I would code for it to accept either type of input- hardware keyboard mode or SPP.

What is the purpose of the PowerProfile class in android

I was tasked with writing an app that gets details of how much power is being consumed by different apps. I was looking at the PowerProfile class and I am not sure what exactly it is used for. There is this method in the class
Returns the average current in mA consumed by the subsystem
Parameters:
type the subsystem type
Returns:
the average current in milliAmps.
public double getAveragePower(String type) {
if (sPowerMap.containsKey(type)) {
Object data = sPowerMap.get(type);
if (data instanceof Double[]) {
return ((Double[])data)[0];
} else {
return (Double) sPowerMap.get(type);
}
} else {
return 0;
}
}
If I test it by using it as follows:
String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
String POWER_PROFILE = "com.android.internal.os.PowerProfile";
try{
Constructor[] constructors = Class.forName(POWER_PROFILE).getConstructors();
Constructor c = constructors[0];
Class[] paramTypes = c.getParameterTypes();
Object params = (Object) this.getActivity().getBaseContext();
Object filledObject = c.newInstance(params);
Method batteryMeth1 = Class.forName(POWER_PROFILE).getMethod("getAveragePower", String.class);
Object barglist1[] = new Object[1];
barglist1[0] = new Object[1];
barglist1[0] = POWER_BLUETOOTH_ACTIVE;
double btlife = (Double) btMeth1.invoke(filledObject, barglist1);
Log.d("BatteryLog", "average BT active mAH " + btlife);
btInfo.setText("avg bt mAH is " + btlife);
}
catch (Exception e)
{
Log.d("BTLOg", "average BT active mAH " + btlife);
}
Then I always get 38.8 for bluetooth mAH used, even if I use my Bluetooth a bunch in between runs. Is this normal, and why would I always get the same mAH values?
The bluetooth is consuming power when pairing with other device or transmitting/receiving mode. Pairing mode is responsible to discover active bluetooth nearby then make a connection for the first time to get the MAC address & name of the bluetooth. It's like you are going to say hi to a beautiful stranger (pairing), it takes much courage ,no? then you can make a conversation (transmitting/receiving mode). Power consume in pairing mode is greater (more courage) than bluetooth transmittin/receiving mode whether there are data streamed or not. But for some bluetooth module embedded in your device there are some bluetooth supported sleep mode. The power draw in sleep mode is so little.
So in your case, maybe the bluetooth already in paired mode so it's consume the same amount. Try to pair the bluetooth or discovery bluetooth in Android it might consume more power

Android app reading bluetooth socket can't keep up with data rate

I have a bluetooth GPS that outputs data at around 2000bytes/sec. When I first start my app it is able to keep up with this rate, but within about 5-10 seconds the rate falls all the way down to 500bytes/sec. From there it goes up and down (between 300bytes/sec and 700bytes/sec usually, but I've seen as high as 6000bytes/sec as a quick spike when it tries to catch up). The stream just falls further and further behind and data ends up getting dropped (the GPS is outputting 10 samples per second and it gets to the point where I will miss several seconds worth of data).
When I connect to this same device via bluetooth from my laptop I get all the data no matter how long it runs. So I know the device itself is able to transmit at this rate. But on android (HTC Droid DNA) it falls behind right away. I have tried bumping up the thread priority and that didn't help. The app stays in the foreground the entire time with the screen on. I have also tried it without the phone plugged into the debugger just in case that was slowing things down and it's still the same issue. I don't know if this is a bluetooth stack speed issue, or a thread priority issue or what. Any ideas?
UPDATE: I just tested the same code on my Galaxy Tab 10.1 and it is able to maintain around 2000 bytes/sec indefinitely. I then tested on an old Motorola Photon 4G and it also is able to maintain the data rate. On the Droid DNA I tested with WiFi disabled as well to see if that was hurting bluetooth performance but it didn't make a difference. And because the DNA is able to do the higher rate for 5-6 seconds I would think the hardware has the capability. For some reason it just falls off after that...
OutputStream mmOutputStream;
InputStream mmInputStream;
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //Standard SerialPortService ID
mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
mmSocket.connect();
mmOutputStream = mmSocket.getOutputStream();
mmInputStream = mmSocket.getInputStream();
dataReader();
...
...
void dataReader()
{
worker = new Thread(new Runnable()
{
public void run()
{
int priority = Process.getThreadPriority(Process.myTid());
Log.d("testApp", String.format("data thread priority %d", priority));
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
priority = Process.getThreadPriority(Process.myTid());
Log.d("testApp", String.format("data thread priority %d", priority));
int bufferSize = 1024;
byte[] readBuffer = new byte[bufferSize];
long time1 = System.currentTimeMillis();
long time2 = 0;
long datacount = 0;
while(!Thread.currentThread().isInterrupted() && !stopWorker)
{
try
{
// read what we can
int bytesRead = mmInputStream.read(readBuffer);
datacount += bytesRead;
time2 = System.currentTimeMillis();
// every second output the data rate
if (time2 - time1 > 1000)
{
final float rate = ((float)datacount * 1000.0F) / (float)(time2 - time1);
handler.post(new Runnable() {
public void run()
{
String text = String.format("%.1f bytes/sec", rate);
myLabel.setText(text);
}
});
time1 = time2;
datacount = 0;
}
}
catch (IOException ex)
{
stopWorker = true;
}
}
}
}
}

Bluetooth on 2.0+

I'm doing bluetooth development for connecting with a PC. I've basicly used the BTChatExample and changed the UUID to the standard PC SPP-profile.
Trying to close a bluetooth application during a blocking read, by closing the BluetoothSocket will leave the Bluetooth stack in a unusable state. This can only be fixed by disabling and enabling bluetooth and restarting the application. Checking logcat, you can see that some of the internal methods are failing, leaving a open port. Any information on this?
First of all there seams to be differences on how bluetooth is implemented on N1 and HTC Legend/Desire both running 2.1, do you know anything about this?
Connecting isn't 100% reliable, sometimes I get a warning saying ~PortSystemContext init: FAILED. This leaves bluetooth unusable, and restarting is needed.
Am I right in assuming that SPP is the only profile supported for use with the APIs? That's what the docs on the BluetoothAdapter says.
I would love to discuss issues on bluetooth with a developer and iron out these bugs so that Android can have good proper Bluetooth support it deserves.
Closing a socket in one thread during a blocking read should definitely cause the read to return (by throwing IOException) and should not leave the stack in a 'bad state'. This is the behavior on Droid and Nexus.
I spoke directly to the original poster, and he had observed this problem on HTC Legend and HTC Desire. It appears like they are not implementing the API's correctly. I am raising the issue with them.
You are correct that SPP/RFCOMM is the only profile that is intended for use with the API's. SPP/RFCOMM gets you a streaming socket which is good enough for a lot of use cases.
For now I recommend BT development on Nexus One / Motorola Droid, which are considered 'reference' implementations of the Bluetooth API's.
May I suggest that you do not perform blocking read() calls unless you have first checked that there is data ready to be read by using inputstream.available() which returns an integer indicating how many bytes are waiting in the input buffer.
long timeouttime = gettimeinseconds() + 2;
String response = "";
while (gettimeinseconds() < timeouttime) {
if (inputstream.available() > 0)
response = response + inputstream.read();
} else {
Thread.sleep(100); // sleep to slow down the while() loop.
}
}
return response;
That's just pseudo code, and its oversimplified. The bottom line is that we're not performing any blocking calls (read()) unless we're sure they will return immediately without delay.
Also, I highly recommend using BufferedInputStream instead of the standard InputStream.
Anyone could solve this problem ?
I try the following code :
// Keep listening to the InputStream while connected
while (!isInterrupted)
{
try
{
//Clear buffer
buffer = new byte[1024];
// Read from the InputStream
if (mmInStream != null && mmInStream.available() > 0)
{
if (isInterrupted)
break;
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Act_Main.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
else
{
try
{
synchronized (this)
{
this.wait(100);
}
if (isInterrupted)
break;
}
catch(InterruptedException ex)
{
Log.e(TAG, "WAIT_EXCEPTION:"+ ex.getMessage());
}
}
}
catch(Exception ex)
{
Log.e(TAG, "disconnected", ex);
connectionLost();
break;
}
}
And I changed the isInterrupted boolean in the cancel() method. Here is my stop() method:
/**
* Stop all threads
*/
public synchronized void stop()
{
isStop = true ;
if (D)
Log.d(TAG, "stop");
if(mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if(mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}

Categories

Resources