My life with Android :-)

Friday, February 6, 2015

In the previous post I demonstrated, how a Bluetooth Low Energy dongle can be used to connect a PC and an Android device. While this is sort of project is appealing, connecting PCs and smartphones is not such an interesting use case. It is much more interesting, however, to transfer the PC-side program directly to an embedded device and that's what I will demonstrate in this post.

There are two baskets of embedded platforms out there. One of them is optimized for low power consumption. They are too limited to run a full-scale operating system therefore their system is often proprietary. Arduino (of which we have seen the RFDuino variant) is one of them but there are many more, e.g. Bluegiga modules also have a proprietary application model. We can typically expect power consumption in the 1-10 mA range with some platforms offering even lower standby consumption.

The other basket contains scaled-down computers and they are able to run stripped down versions of a real operating system. Their power consumption is in the 100-500 mA range and they often sport 100s of megabytes of RAM and gigabytes of flash memory. They are of course not comparable to low power platforms when it comes to power consumption but their much higher performance (which can be relevant for computation-intensive tasks) and compatibility with mainstream operating systems make them very attractive for certain tasks. The card I chose is BeagleBoard Black and my main motivation was that Ubuntu chose this card as a reference platform for its Ubuntu Core variant.

The point I try to make in this post is how easy it is to port an application developed for desktop PC to these embedded computers. Therefore let's just port the BLE server part of the CTS example demo to BeagleBone Black.

Then unpack the BLE server application into a directory and set up these environment variables.

export CROSS_COMPILE=arm-linux-gnueabihf-; export ARCH=arm

Enter the beagle_conn_example directory that you unpacked from the ZIP package and execute:

make

This should re-generate cts_1.0.0_all.snap which is already present in the ZIP archive in case you run into problems with building the app. The snap is the new package format for snappy. Then you can install this package on the card.

snappy-remote --url=ssh://192.168.1.123 install ./cts_1.0.0_all.snap

You have to update the IP address according to what your card obtained on your network. The upload tool will prompt you for username/password, it is ubuntu/ubuntu by default.

Update the GATT tree in the BLED112 firmware as described in the previous post. Plug the BLED112 dongle into the BeagleBoard's USB port. Then open a command prompt on the BeagleBoard either using the serial debug interface or by connecting to the instance with ssh and execute the following command:

sudo /apps/cts/1.0.0/bin/cts /dev/ttyACM0

The familiar console messages appear and you can connect with the Android app as depicted in the image below.

One thing you can notice here is that Snappy's shiny new package system is not ready yet. In order for this package to access the /dev/ttyACM0 device (to which the BLED112 is mapped without problem), it has to run as root. This is something that the Snappy team is yet to figure out. The experience, however, is smooth enough that application development can be started now.

Tuesday, December 30, 2014

My conclusion with the RFDuino adventures
was that RFDuino is a perfect platform to start familiarizing with the
Bluetooth Low Energy (BLE) technology. BLE programming was made so
simple with RFDuino that it provides quick success. Simplification comes
with limitations, however, and eventually time has come for me to step
further toward a more flexible BLE platform. Bluegiga's BLE121LR long
range module seems to have outstanding range but first I tried a piece
of hardware that is equivalent from the API point of view with the
BLE121LR but is easier to start with and that is Bluegiga's BLED112 USB dongle.

The BLED112 implements the same API (called BGAPI, check out Bluetooth Smart Software API reference)
that other Bluegiga BLE modules do but there's no need to buy the
pricey DKBLE development board or build any hardware. It plugs neatly
into the USB port and is functional without any additional piece of
hardware. From the serious BLE application development perspective it
has drawbacks too. Firstly, its USB interface is drawing a
constant 5mA current so this solution is not very much "low energy".
Second disadvantage is that its single USB interface is shared between
the BGAPI API and the programming interface so installing scripts into
the BLED112 is a risky enterprise. If the script running on the BLED112
occupies the USB port, there's no way to update it so the module is
essentially bricked. Hence in this exercise we will keep the BLE
application logic on the PC hosting the module and talk to the module
with BGAPI. This is very similar setup when the application logic is
running on a microcontroller or embedded PC.

In this exercise, we will implement the Current Time Service
(CTS) and access this service from an Android application. CTS is a
standard Bluetooth service. The PC application will fetch the current
time from its clock and will update the characteristic exposed by the
BLED112. The Android application will detect the advertised CTS service,
connect to it, retrieve the time and display it to the user. The
Android application will also subscribe to time changes demonstrating
the notification feature of BLE GATT.

Let's start with the PC part. Unpack the cts_example.zip file and inside
there are a set of C files belonging to the PC application in the root
directory. I developed and tested the application on Ubuntu 14.10 so if
you use a similar system, you have good chances that you just type
"make" and it will compile. Preparing the BLED112 dongle is more
complicated, however and this is the result of the quite cumbersome
Bluegiga tool chain. Any change to the GATT services (read this presentation if you don't know what GATT is) requires a firmware update
of the BLED112. This sounds scary but it is not too complicated if you
have a Windows system. Bluegiga SDK supports only Windows and there is
one element of the tool chain, the firmware downloader that does not run
on emulated Windows either - you need the real thing. So the steps are
the following:

Get the content of the config subdirectory in cts_example.zip and
copy somewhere in the Windows directory system. Then generate the new
firmware with the <bluegigasdk_install_location>\bin\bgbuild.exe
cts_gattBLED112_project.bgproj command. The output will be the
cts_BLED112.hex file which is the new firmware. We could have placed
application logic into the firmware with a script but as I said, it is a
bit risky with the BLED112 so this time the new firmware contains only
the GATT database for the CTS service.

Launch the BLE GUI application, select the BLED112 port and try to
connect by clicking the "Attach" button. If all goes well, you will see
green "Connected" message. Then select Commands/DFU menu item, select
the HEX file we have just generated, click on the "Boot into DFU mode"
button. One pecularity of the BLED112 that in DFU mode it becomes
logically another USB device so the main window will display red
"Disconnected" message. Then click "Upload". If the upload counter
reaches 100% and you see the "Finished" message, the firmware update is
done.

At this point we are finished with Windows and can start the serious
business. Plug the dongle into the Ubuntu machine and check out its
port.

So this time the dongle is mapped to /dev/ttyACM0. Launch the BLE server with the following command:

./conn_example /dev/ttyACM0

The server is ready, let's see the Android client. Import the Android
project in CTS.zip into Android Studio. Note that I am still baffled by
the fact that this shiny new IDE does not have a project export command
so I had to zip part of the project's directory tree manually. Once you
launch the Android application, you will see a screen like this:

The device named "test" is our device and the CTS service is
identified by the UUID of 0x1805. The other entry is just another BLE
device that I threw in for demonstration. Click on the device name and
you get the time emitted by the BLE dongle:

The current time is also updated every second demonstrating that the client successfully subscribed to the changes.

On the server side, it is important to note that the BGAPI protocol
is defined in terms of byte arrays sent and received over the serial
port (which is mapped to USB in the case of BLED112). The BGAPI support
library coming from Bluegiga that I used in this demo is just a wrapper
over this interface so it can be replaced with an optimized
implementation if the library is too heavy for the application platform
(e.g. for a microcontroller) or is not implemented in the desired language (e.g. in Python). On the Android client side, it is interesting to note how the BLE advertisement parser library I presented in this post is used to figure out, whether the device advertises the CTS service we are interested in.

Friday, December 19, 2014

Ever since I created the Gas Sensor demo (post here, video here, presentation here),
I had the feeling of an unfinished business. That demo sent the sensor
data in BLE advertisement packets so the client never connected to the
sensor but received data from the sensor in a broadcast-like fashion. The
implementation looked like this:

This was a quick & dirty solution that remained there from my earliest
prototypes. It sort of assumes that the structure of the BLE
advertisement packet is fixed so the sensor data can always be found at
fixed locations of the advertisement packet. This does not have to be
the case, Bluetooth 4.0 Core Specification,
Part C, Appendix C (or Core Specification Supplement in case of 4.2
version) describes, how the fields of the advertisement packets look
like. It just so happens that with the given version of the RFDuino BLE
module, the Manufacturer Specific Data field where RFDuino puts the user
data for the advertisement packet can always be found at a specific
location.

The proper way is of course to parse this data format according to the
referred appendix of the specification and in this post I will show you
how I implemented it.

Let's see first the BLEScan project. The parser code is under the
hu.uw.pallergabor.ble.adparser package. Then you just give the
scanRecord array to AdParser's parseAdData method like this:

ArrayList<AdElement> ads = AdParser.parseAdData(scanRecord);

and then you get an array of objects, each describing an element in the
scan record. These objects can also produce printable representation
like this:

Now let's see the revised GasSensorDemo project, how the gas sensor
measurement is properly parsed out of the scan record. First we parse
the scan packet fields:

ArrayList<AdElement> ads = AdParser.parseAdData(scanRecord);

Then we look for a TypeManufacturerData element which corresponds to a
Manufacturer Specific Data field in BLE. We make an extra check to make
sure that the manufacturer field in the Manufacturer Specific Data is
0x0000 because RFDuino always creates a Manufacturer Specific Data field
like that if the application programmer specifies additional
advertisement data.

It would be tempting to use a custom manufacturer field or better, a
Service Data field. But then we run into another limitation of RFDuino
because RFDuino with its default firmware is only able to create
advertisement packets like in the previous example. This is not bad
because it allows the programmer to achieve quick success but later on,
we will need more flexibility and that will need another BLE module.

Friday, November 21, 2014

My previous post about Bluetooth Low Energy applications with RFDuino and Android presented a connectionless gas sensor. That prototype was based solely on BLE advertisements, no connection was built between the scanner device (Android phone or tablet) and the sensor. While this connection-less operation is advantageous for sensors that just broadcast their measurement data, more complex scenarios that e.g. require authentication or build a communication session cannot be implemented in this model. The prototype I am going to present in this post demonstrates connection-oriented operation between RFDuino and an Android application.

Watch this video to see what the application is about.

The story behind this motor boat project is that I bought this RC-controlled model boat while I worked in the UK. But when we moved back to Hungary, I lost the RC controller. So the boat had been unused for years until I realized how great it would be to use an Android device as a controller. Hence I quickly integrated the RFDuino with the motor boat's original control circuitry and wrote the necessary software. As you can see in the video, it has quite respectable range even though I did not dare go into the October water of Lake Balaton where the second part of the video was shot (water temperature: some 10 degrees centigrade).

First about the "hardware". I did not have the circuit schema of the original RC controller in the boat so I had to experiment a bit. By following the motors' cables I quickly found two three-legged stocky elements that looked like switching transistors (although the labels on them were not readable after all those years in service). I removed one end of the resistors that I thought connected the base of these transistors to the rest of the RC control circuit and tried out, how much current is needed to switch on the motors. To my pleasant surprise, 1 mA current was enough so I rather believe that these are actually not transistors but power switching ICs. Anyway, RFDuino outputs can provide 1 mA switching current so I just connected the other end of those removed resistors to two spare RFDuino I/O ports. Lo and behold, it worked. If RFDuino raises any of these pin to 1, the respective motor starts. One minor additional problem was about the power supply of RFDuino. The motor boat employs an 7.2 Volt battery and RFDuino needs 3.3 V. I added an LM1117-3.3V power regulator circuit between the battery and RFDuino and the "hardware" was ready.

Do you know about BLE concepts like service and characteristics? If not, please read this presentation for a quick introduction. In short: BLE services (also called GATT profiles) are composed of characteristics which are key-value pairs decorated by meta-information that the BLE specification calls descriptors. RFDuino with its default firmware is not able to implement any standard GATT profile except for its own custom GATT profile. This is a major disadvantage in product-level development but makes RFDuino code super-easy because the programmer does not have to deal with BLE details. In the RFDuino custom service, a "read" and a "write" characteristic is defined. Whatever the client (in our case, the Android application) writes into the "write" characteristic appears for the RFDuino code as incoming data callback. If the RFDuino code calls the RFduinoBLE.send(v) method, the data appears in the "read" characteristic. The Android client can register a callback for data manipulations of the "read" characteristic so it will receive callbacks when RFDuino code invokes the RFduinoBLE.send() method. There are additional callbacks for service connections and disconnections.

First about the RFDuino code. Beside the familiar setup() and loop() functions, you will see three functions characteristic to RFDuino. RFduinoBLE_onConnect() is called if a client connects to the RFDuino BLE service, RFduinoBLE_onDisconnect() is called on disconnection and RFduinoBLE_onReceive() is called when there is incoming data. There is only one complication in the code that requires explanation: this is a powerful motorboat and it can go out of BLE radio range very quickly. In the early versions the boat became uncontrollable in this case meaning that it just continued with the last command received. That was not a nice feature so I implemented a heartbeat message feature which is sent in every 5 second. The loop() method starts by sending the heartbeat to the client and goes to sleep. It wakes up after 5 seconds and if it finds that the client did not send back the heartbeat, it stops the motors. Otherwise the client just sends a bit mask about which motors to stop or start and the RFDuino just responds with the same mask informing the client that the motors were indeed started or stopped. This means that the arrows on the user interface showing which motors are running represent the actual state of the boat which is advantageous if something goes wrong.

Then about the Android side. The code starts by discovering the device. Once the device is discovered, we connect to the device with the connectGatt() method then discover its services with gatt.discoverServices() method. Once the service discovery callback arrives, we retrieve the RFDuino service (getService(), we expect this custom service) and obtain the characteristic handles (getCharacteristic()). We use the "read" characteristic's client configuration descriptor to enable notifications from the RFDuino server to the Android client so that we get a callback when the RFDuino side sends something to us.

Disconnection is worth detailing because there's an RFDuino speciality here. Normally, one can just disconnect from the service with the disconnect() method invocation. RFDuino however is left in a limbo state in this case: the BLE session is disconnected but the RFDuino application does not receive a callback and cannot accept a new connection request. The "disconnect" characteristic has to be written to (the value does not matter) for the RFDuino server to properly disconnect.

Friday, October 3, 2014

I just got a mail that our gas sensor entry (a gas sensor with Bluetooth Low Energy connectivity and the associated Android application) has just won 3rd place on the We Know RFDuino contest. Thanks to everyone who viewed our video and thus helped us to compete successfully! Meanwhile the source code of the prototype was made open source so you may want to check out that too!

Monday, September 29, 2014

The "We know RFDuino" contest has not ended yet but its end is sufficiently close so that I can explain our prototype application. Our entry is a Bluetooth Low Energy-connected gas sensor and it is presented in the video below. Make sure that you watch it, you help us win the competition.

The prototype demonstrates a unique capability of Bluetooth Low Energy device advertisement messages: you can embed user data into these broadcasts. These come handy if you just want to send out some measurement data to whoever cares to listen without creating a session between the BLE client and server. This broadcast-type data transfer may support unlimited number of clients with very low energy consumption on the sensor side.

The prototype works like the following. The microcontroller presented in the video measures the Lower Explosion Limit and sends this value to the RFDuino microcontroller over a super-simpe serial protocol. A message of this protocol looks like this:

0xA5 <seq_no> <LEL%>

where seq_no is an increasing value and LEL% is the measured Lower Explosion Limit value. The microcontroller code is not shared here but you can get the idea. The RFDuino code receives the LEL% value over the serial port it creates on GPIO pins 3 and 4, creates a custom data structure for BLE advertisements consisting of the site ID and the LEL% value then starts advertising. This is performed cyclically so the LEL% value is updated in the sensor's BLE advertisement every second.

Now let's see what happens on the Android side. This is a non-trivial application with multiple activities but the Real Thing (TM) happens in the MapScreenActivity, in the onLeScan method. This method is called every time the Android device's BLE stack discovers a device. In this case we check whether the device's name is "g" (this is how we identify our sensor) and we retrieve the LEL% data from the advertisement packet. We also handle the Received Signal Strenght Indicator (rssi) value for proximity indication. Bluetooth device discovery is restarted in every 2 seconds so that we can retrieve the latest LEL% value. The rest is just Plain Old Android Programming.

The identification of the sensor and the encoding of the sensor data is obviously very naive but this is not really the point. You can make it as complex as you like, e.g. you can protect the sensor data with a hash and place that hash also into the advertisement so that the receiver can make sure that it gets data from an authorized sensor and not a fake one. The important thing is that the entire framework is sufficiently flexible so that relatively complex functionality can be implemented and RFDuino really simplifies sensor programming a lot.

If you enjoyed the example application, make sure you watch the video (many times if possible :-)) and if you happen to be in London on 2014 November 19, you might as well come to the Londroid meetup where I present this and another BLE project (a connection-oriented one, called MotorBoat).

About the blog

This blog is a personal diary about my adventures with the Google Android platform. I write it in the hope that others may find my experiences useful but please, beware. The blog is created as I gain experience about the platform myself so errors, omissions, etc. may be found in the entries.