Monthly Archives: July 2015

First results from BLE battery consumption tests

UPDATE: After going through the results, I did notice that the Nexus 6 device I got, was indeed broken. It basically has something badly wrong with it, and even when there it nothing running it will drain its battery rather quickly, thus the results shown in this page are indeed faulty.

I was running the  BleGgOne test app for last four days to get some idea on how long battery life we could expect if we would be running BLE advertising and scanning on the devices all times.

Note that I only had one device capable of doing the BLE service advertising, thus effectively with the tests one device was advertising all times, and the other device was scanning continuously. The tests were conducted in space where we did not have other BLE devices active while the tests were running.

Nexus 6 has 3220 mAh battery and the Nexus 5 used as the client connecting to the service advertised by Nexus 6 has a 2300  mAh battery.

There was two rounds of testing. The first round was called Full Test, and with it the Nexus 6 was advertising one service. Nexus 5 then connected to the Nexus 6 and with 60 second timer, it did first read for a character that had 100 bytes of data, and then also write of 100 bytes to that same character.

Logs from tests showed that the read/write events were reported to happen once a minute from both ends during the whole testing. Also the connection was active for the whole duration of the tests, thus there were no disconnection events happening during testing.

In the second round, the client side code for connecting to the server was commented out. Meaning that there were no connection made between the devices, nor any read or write events happening. The Nexus 6 in this test was simply advertising the service, and the Nexus 5 was simply scanning and finding the service.

From logs it was also determined that with the 20 minute log period, the scanning resulted 4300 results in both tests, giving the scanner average of 3.6 Scan results for each second.

The results are summarized in following graph:

 

BLE_Battery_first

Following table shows the times when different threshold values on battery status were reached:

 Battery % / time reached N6_AdvertOnly N6_FullTest N5_ScanOnly N5_FullTest
90 3,45 3,45 5,51 5,85
80 6,86 6,52 9,63 9,97
70 9,97 9,29 13,72 14,07
60 12,71 12,36 17,83 18,17
50 15,44 14,74 20,91 21,96
40 18,17 17,50 25,37 26,41
30 20,91 20,24
20 23,34 22,99
10 26,06 25,71
0 28,45 27,76

 

Quick calculations from the values gives drop of 10% of battery charge happening with Nexus 6 after 2.8 hours, and with Nexus 5 its around 4 hours.

Surprisingly there appears to be no real difference between the device being just scanning / advertising, when compared to the battery consumption with devices that are connected and exchanging data.

As this test was only conducted with one device, we could say that the values are indicative at best, and to get clear picture of the battery consumption, we do need to make loads more testing with different devices.

 

Quick view to JxCore Thali plugin architecture (android part)

I’m going to have my summer vacation after this week, and wanted to make it a bit easier to anybody who wants to check my codes to actually understand what each parts are doing there.

And to do this I decided to draw some graphics depicting how different classes are interacting and being handled in the system.

The first part the the main view for the plugin from the part where JxCore android plugin meets the android library for Thali:

Main_stuff

The JxCore plugin is using the library through a helper class called BtConnectorHelper, which is the sole entry point  to the library. From library side, the sole entry point is the BtConnector class.

The BtConnector class then is handling two issues. It should know when to start/stop advertising & scanning. The codes for the task is handled in BtConnector_Discovery class. BtConnector_Discovery class then has its internal logic to find peers and uses simple three function interface to pass the results to the BtConnector.

The other task BtConnector has to do, is to handle connectivity to the peers. This is handled in BtConnector_BtConnection class.  BtConnector simply starts/stops the class instance, and the instance will simply tell the BtConnector when outgoing connection failed, or when it did manage to get fully connected socket connection to the remote peer.

Then lets have a look into these two classes and their internal works. The BtConnector_Discovery is rather simple.

BTConnector_Discovery

The WifiServiceAdvertiser, is simple started/stopped when the instance of BtConnector_BtConnection is created/deleted. Then the WifiServiceSearcher will have its own logic to find peers and services implemented in them, and use the three function interface to notify the instance of what it has found.

The BtConnector_BtConnection class then looks like this:

BTConnector_BtConnection

 

In essence, there is always one BtListenerThread active, and ready for any incoming connections. The one possible BtConnectToThread instance is created when there is tryConnect() call originating from BtConnectorHelper class. Error situations on incoming connections are never reported outside BtConnector_BtConnection , they simply re-start the listening process.

Once either of the previously mentioned class instances has managed to create connection successfully, they pass the connected socket to the BTHandShaker class instance.

This  instance will use its own BTHandShakerSocketThread for reading/writing to the socket to handle quick handshake. The handshake makes sure that the connection is fully working, as well as it is used for supplying the discovery data in cases where the device we are connecting to, does not have discovery data for the incoming peer yet.

The Connected callback function of the BtConnector will only be called if the BTHandShaker gets its handshake successfully done.  And once this happens the BtConnector will give the BtConnectorHelper fully connected socket, and also identify whether it was incoming connection we accepted in out listening thread, or whether it was connection we started.

The following picture then illustrates what happens in the BtConnectorHelper side for the connected socket:

BtConnectorHelper

If the socket was for incoming connection, then there is a new instance of BtToServerSocket  created for it. There can be multiple instance of BtToServerSocket , and currently the implementation does not pose any limits for the number of them, but do note that the Bluetooth performance likely drops when there are more connection to be handled.

For outgoing connection there can only be one instance of handler available at any moment. The handler is then instance of BtToRequestSocket  class.

Both BtToServerSocket  and BtToRequestSocket  are then having two instances of StreamCopyingThread class. One for copying incoming stream and one for copying data to outgoing stream.

And as the name suggest, the BtToServerSocket  is connecting the incoming Bluetooth socket streams to the NodeJs TCP/IP server streams, and the BtToRequestSocket is catching the NodeJs TCP/IP client request and connecting it to the Bluetooth streams.

Basically this is just really brief overview of the implementation, there are of course loads of things that happens when the codes are run, anyway, I do hope this article would help on understanding the internal structure of the android implementation.

Starting my BLE investigation

I finally got myself a device that supports BLE advertising. First issue on getting one was to figure out what devices are actually supporting the feature. Even though there are claims that some Android devices can be used as BLE peripheral while having only Bluetooth 4.0 chip on them, I would strongly suggest getting a device that supports Bluetooth 4.1. Currently only confirmed 4.0 device I know would be Samsung S5, though I have not used it myself. Nexus 5 also was claimed to work with earlier preview versions of Lollipop, but I also found discussions suggesting that while it was used to advertise, it could not be used for scanning same time, supposedly that was the main reason it’s not supporting the feature with official Lollipop versions.

So from API perspective the requirement is Lollipop support, and from hardware it would be Bluetooth 4.1 support, and with quick search my list of supporting device got to look like this:

  • Nexus 6,
  • Nexus 9,
  • LG G4
  • LG G Flex 2
  • HTC One M9
  • Samsung Galaxy S6
  • Sony Xperia™ M4 Aqua

 

The first device I got was Nexus 6, for historical reasons I have several Nexus 4 & 5 devices, so it makes nice continuity to have one 6 as well. I should be getting Sony XPeria M4 Aqua also soon, and as the device is loads cheaper than Nexus, as well as even its having smaller battery, it does have double standby time ( according to ubergizmo:). It also has less RAM, and slower CPU, thus it likely make nice device to do tests and compare the results with the Nexus.

And to get started I had to get some codes. I was surprised that I couldn’t really find any nice full code samples that would do scanning (and parsing the scan info), connecting & character/descriptor read and write. Thus I made my own full example to create & tests helper classes I can re-use in later tasks. The resulting example is stored at DrJukka/BLETestStuff/MyBLETest . The implementation is still work on progress, and current limitations include for example, that only string-type values are supported, and that only non-reliable write is implemented.

I alsready used the classes developed with the example in other project DrJukka/BLETestStuff/BleGgOne. This project was used to test that we can run the app in background and still do advertisement & scanning. I also made second version of it, to test that we can have more than one background app doing the advertising.

The result was that Yes, we can do advertising in the background, and Yes we can do scanning in the background as well. Then as I only have one device to test, I did not get to see whether I could do both same time. I’ll need to wait my XPeria device to finalize the testing.

And for the question that “can we have multiple services advertising in background” the answer is also Yes.

As with the BLE, each time you start advertising, the device is advertised with new virtual-mac-address. So if you stop and start a service, it will get new address which the client device must use (using the old one will cause 0x85 error to appear)

When using two services same time, these is something similar happening, basically a new device advertisement with new virtual-mac-address will be visible to the clients. But also the first services virtual-mac-address is still visible, and in this case both of them are valid and can be used for connecting to the device.

But when you connect either one of them, you will be getting the all services from the device. So it does not matter which one you would be using for connecting, you would still get service advertised by both of them.

Continuing the Dns-Sd Txt record size measurements

Earlier research with Wi-Fi Direct and Dns-Sd Txt record size measurements  suggested that there maximum size that is less than 1k buffer for the Dns-Sd records. With the Delivering discovery data via Wi-Fi Direct UPnP I also noted that at least with UPnP the buffer is actually shared with all apps, meaning that its actually not a limit of one service advertisement, but actually its limiting the combined size of all service advertisements active on the device.

I did quick tests and determined that, indeed this its same with the Dns-Sd records, and there also the latest added service can easily make the previously set advertisement to never actually be advertised, effectively making the service invisible for anybody looking for it.

Additionally it was earlier determined that the instance name does effect on the data amount. With my investigation I also determined that also the length of the service type string will affect the limits posed for the instance name.

As I never really did finalize the instance name limit investigation, I decided to get it done now. I was using the good old WifiTestPower  app, and modified the service type to be just 10 characters long. I was using Nexus 5 devices. Two of them had KitKat (4.4.4 and 4.4.3) and two had Lollipop (5.0.1 and 5.1.0).

The result showed that the max limit is not really set by the receiver (as I earlier thought), but actually its set by the limits posed on the sending device.

With KitKat I determined that when using 10 character long Service type string, then the usable limit appears to be 100 characters.

Actually I can see 101 very often, but its causing loads of time when the service discovery after finding one service will timeout without finding anything, and as this does not appear to happen when using 100 characters long instance name, I would put the limit there.

Funnily enough, when I give the WifiP2pDnsSdServiceInfo empty txt-record array, then even when I’m not getting the DnsSdServiceResponseListener called for instance names over 101, I do get the DnsSdTxtRecordListener called with 103 characters long instance name, and indeed the fullDomainName argument is having the full instance name included.

That all said, with the current knowledge of the topic, if the service type is 10 characters long, I would still put the maximum length of the instance name to be 100 characters.

With Lollipop, if the service type is 10 characters long, the limit appears to be 255 characters limit works with both interfaces, and if exceeded no discovery data is seen to arrive either of them.

So if you want to get the discovery work with and between both KitKat and Lollipop then with 10 character long service type we could use up to 100 characters long instance names.

Note then that if we also take account the less than 1K total limit, I would assume we could safely assume that in one device we can have 6-8 services advertised before the system starts dropping them from the actual advertisement.