Bluetooth Low Energy on BlackBerry 10 – Cadence and Cascades

Cascades

I think everyone would agree that living a healthy lifestyle and following a suitable exercise regime is an important factor in keeping well in today’s world. It’s not without its challenges though! How many good intentions have fallen by the way-side? It’s not easy to get yourself out of that comfy chair and head off to the gym, take that walk or get on that bicycle. More often than not the comfy chair wins. At least that’s been my experience. Maybe I have a special, demonic chair or something.  It also tells me to eat cake sometimes. Hmmm.

That said there are…. apparently…. people in this world who have a bit more resolve than I do and take their sporting and fitness activities a bit more seriously. Not only do they manage to get out of the comfy chair, they even like to measure and analyse their performance so they can improve.

Now my colleague Martin (@mdwrim) has normal furniture in his house and seems more than capable of getting out of the comfy chair and down to the climbing wall or out on his bike. He and I (@jcmrim ) talked about the kind of technology available to sporty people, in particular cyclists. Martin had just come back from watching part of the Giro d’Italia and pointed out that all the pro cyclists have sensors on their bikes. BlackBerry 10, Bluetooth Low Energy and cycling! What a perfect combination of great technology, fun and exercise as well as a great opportunity for a new Blog post, video and sample app!

If you haven’t already done so, this is probably a good time to have a read of our previous blog posts and articles on the Internet of Things and Finding Car Keys since they cover the basic concepts needed in this blog post.

As before, the first thing we did was to do a little bit of research to see if the Bluetooth SIG had defined any standards in this area; no point in re-inventing the wheel [no pun intended] and the existence of a standard would mean that a vendor may have already implemented the technology in a product.

Whenever you have a requirement that may be solvable using Bluetooth LE the first place to look is here: http://developer.bluetooth.org/gatt/Pages/default.aspx.

Browsing through the GATT Profiles we came upon this one: Cycling Speed and Cadence (CSC)… this sounded promising, and the description looked like it was just what we needed.

“The Cycling Speed and Cadence Profile is used to enable a data collection device to obtain data from a Cycling Speed and Cadence Sensor (CSC Sensor) that exposes the Cycling Speed and Cadence Service.”

The key element of this profile is the Cycling Speed and Cadence Service (UUID 0×1816) which contains four really useful fields:

  • “Cumulative Wheel Revolutions”
  • “Cumulative Crank Revolutions”
  • “Last Wheel Event Time”
  • “Last Crank Event Time”

These are part of the “CSC Measurement” GATT Characteristic (UUID 0x2A5B). They are described in detail here: CSC Characteristics and outlined in Figure 1.

There are some other characteristics that allow configuration and control of the device but we’ll talk about these when we come across them.

TITLE_IMAGE

Figure 1 Key GATT Characteristics for CSC

So, if you think about these characteristics they allow you to derive a number of key measurements:

  1. Total distance travelled – using “Cumulative Wheel Revolutions” – all you need to know is the wheel circumference to calculate this, but if you combine this with a time and a geo-location measurement you can even derive sufficient information to plot your progress on a map.
  2. Speed – using “Last Wheel Event Time” – you can figure out how fast the bike is going if you do a simple calculation involving the time between successive Last Wheel Event Time values and the number of wheel revolutions that occurred in that time. But if you combine this with a geo-location measurement you can derive sufficient information to plot your speed on the map as well.
  3. Instantaneous effort – using ““Last Crank Event Time”” – this can help identify those times that you’re free-wheeling and not expending energy.

It’s at this point that the engineer in me begins to wonder how to instrument a bicycle to make use of this GATT profile. Martin’s a cyclist, so, after identifying a device that matched the requirements (Wahoo Fitness Blue SC[1] device), he attached it to his cycle as shown in Figure 2.

Figure 2 Attachment of cycle monitor

Figure 2 Attachment of cycle monitor

For those of you who are mechanically minded small magnets on both the crank and the rear wheel spokes activate the sensor strapped to the frame. The sensor maintains the counts and timings and will report them to a suitable Bluetooth LE device such as a BlackBerry 10 smartphone.

The application that we developed based on this is actually very similar in structure to the Heart Rate Monitor application that was described in a previous blog and article. The basic logic is the same:

  1. Pair the Bluetooth LE device with the BlackBerry 10 handset before using the application.
  2. Launch the application which:
    1. Discovers devices that support the CSC Service (UUID 0×1816)
    2. Connects to a discovered device selected by the user
    3. Requests the device to notify our application as changes are made to the CSC Measurement characteristic (UUID 0x2A5B) which contains the wheel and crank data that we’re interested in.
    4. Receive, parse and display in numerical (RPM) and historical graphical form the CSC Measurement data as they are received.

Here are some screenshots showing what the application looks like:

Figure 3 The CscMonitor Application

Figure 3 The CscMonitor Application

Instantaneous values of the wheel and crank readings in revolutions per minute (RPM) are shown in the upper part of the screen whilst historical RPM data are plotted on the lower half of the display. Wheel and crank historical data displays can be toggled by touching the screen. Mapping RPM values to distance or energy expended would require additional information to be provided, such as the wheel circumference or radius of the crank — we’ll leave this for a possible later iteration of the application and focus on the Bluetooth LE aspects for now.

If we inspect the GATT services the CSC device supports using a tool like BTool we can see (Figure 4) that the CSC Measurement Characteristic (UUID 0x2A5B) is exposed at handle 0×0023. Handles are the references to entries in the GATT that our application will discover and use to access the value associated with a characteristic. We’ve used handles before in both our previous examples.

Figure 4 GATT showing CSC Characteristics

Figure 4 GATT showing CSC Characteristics

Associated with the CSC Measurement Characteristic is a “Client Characteristic Configuration” characteristic (UUID 0×2902) exposed at handle 0×0024. The value of this field determines whether our application will receive Notifications or Indications for the CSC Measurement Characteristic. We’ve used these before as well in our previous examples. In this case this characteristic will be set to enable Notifications using the BlackBerry 10 Bluetooth LE API.

So, how do we manage the data that is notified to us from the CSC device? The CSC data received is managed by a class called “CscDataContainer” … here’s part of its definition:

class CscDataContainer: public QObject {
       Q_OBJECT
private:
       CscDataContainer();
...
       // notification data
       QQueue<csc_notification_t> _csc_notifications;
       // CSC values
       QQueue<csc_values_t> _csc_values;
       int _min_wheel_rpm;
       int _max_wheel_rpm;
       int _avg_wheel_rpm;
       long _total_wheel_rpm;
...
}

At its core are a couple of queues that maintain the data that is received. The queue has a maximum length that can accommodate one notification per second for an 8 hour period. A future version might persist these data in a database but this is sufficient to demonstrate the principle in this case.

Once again the excellent little JavaScript library called “Flot” is used to plot these data in a WebView component in QML.

As notifications are received by our application the addNotification() method of the CscDataContainer class is called with the CSC Measurement data passed as a (uint8_t *) and a length (uint16_t) — that is an array of bytes.

Parsing this data is the first task and it’s instructive to see how this works – the main points are highlighted in the code fragment below:

void CscDataContainer::addNotification(const uint8_t *val, uint16_t len) {
       // parse value, paying attention to the bit settings in the FLAGS field
       bool wheel_revolution_data_present = false; // bit 0 of Flags field
       bool crank_revolution_data_present = false; // bit 1 of Flags field
       uint32_t cumulative_wheel_revolutions = 0;
       uint16_t cumulative_crank_revolutions = 0;
       uint16_t last_wheel_event_time = 0;
       uint16_t last_crank_event_time = 0;
       int index = 0;
       uint8_t flags = val[index];
       wheel_revolution_data_present = ((
flags & WHEEL_REVOLUTION_DATA_PRESENT) == WHEEL_REVOLUTION_DATA_PRESENT);
       crank_revolution_data_present = ((
flags & CRANK_REVOLUTION_DATA_PRESENT) == CRANK_REVOLUTION_DATA_PRESENT);
       // Fields are in the order of LSO to MSO.
       // Where LSO = Least Significant Octet and MSO = Most Significant Octet.
       index++;
       if (wheel_revolution_data_present) {
              // Cumulative Wheel Revolutions, 4 bytes.
             // Field exists if the key of bit 0 of the Flags field is set to 1.
              cumulative_wheel_revolutions =
(val[index + 3] << 24) | (val[index + 2] << 16) |
(val[index + 1] << 8)  |  val[index];
index += 4;
              // Last Wheel Event Time, 2 bytes. 
              // Field exists if the key of bit 0 of the Flags field is set to 1.
              last_wheel_event_time = (val[index + 1] << 8) | val[index];
              index += 2;
...
}
       if (crank_revolution_data_present) {
// Cumulative Crank Revolutions, 2 bytes. 
// Field exists if the key of bit 1 of the Flags field is set to 1.
              cumulative_crank_revolutions =
(val[index + 1] << 8) | val[index];
              index += 2;
              // Last Crank Event Time, 2 bytes. 
              // Field exists if the key of bit 1 of the Flags field is set to 1.
              last_crank_event_time = (val[index + 1] << 8) | val[index];
              index += 2;
    ...
    }
...
}

The first byte of data contains an 8-bit flag field (see Figure 1 for details). This indicates whether crank or wheel data is present in the following data.  If these are present they are represented in Little-endian form and need to be extracted by shifting them out a byte at a time.

The rest of the application is more focussed on the display of this data using QML so I’ll leave that for you to look at yourself since the main learning points are to do with how to interface to the Bluetooth Low Energy device itself.

We made a video which has Martin (@mdwrim) showing the application in action and explaining the code. Here it is:

If you want to know more then check out the following resources:

I hope you’ve enjoyed this short note and hope it has piqued your interest to find out more about Bluetooth Low Energy and how it can be integrated into your BlackBerry 10 applications.


[1] This should not be regarded as an endorsement by BlackBerry, explicit or implied.

Join the conversation

Show comments Hide comments
+ -
blog comments powered by Disqus