Bluetooth BLE 16bit Ints and accessing ints in byte array

893 views
Skip to first unread message

Elliot Mebane

unread,
Sep 24, 2016, 9:56:23 PM9/24/16
to MIT App Inventor Forum
For the BLE extension I would like a readInt16Value block. When using the Heart Rate Measurement Characteristic RR values are sent as 16 bit ints. 

In addition, the Heart Rate Characteristic bytes are sent as a byte array, so I'm not sure how to access more than one int in the array that is received. e.g.: 
a) extract the Heart Rate (array[1])
b) extract other info, like RR values (array[4] - array [8])

I'm able to see the heart rate with a readIntValue and an offset of 1 in the block that responds to intValueChanged. I tried the intValueRead response block but it doesn't seem to read values from the current bytes in the characteristic. Is intValueRead working properly? 

——————

For reference, here is the Heart Rate Measurement Characteristic spec:

And you can see how the Heart Measurement Characteristic's bytes are handled in Nordic's nRF Toolbox source:

Ghica

unread,
Sep 25, 2016, 10:12:18 AM9/25/16
to MIT App Inventor Forum

Palm Tree(TimeOfSands)

unread,
Sep 25, 2016, 12:49:12 PM9/25/16
to MIT App Inventor Forum
You can use lists as arrays.

Elliot Mebane

unread,
Sep 25, 2016, 2:10:52 PM9/25/16
to MIT App Inventor Forum
Yes, that's the starter app I worked with. It transmits only a single int using a potentiometer as a way of simulating the changing values that would come from a true HRM. There's 2 limitations that I can't seem to get around: 

— access 16 bit ints. 
— access more than one byte in the byte array (I can only access one of the bytes each time the new values are sent as a byte array). 

Elliot Mebane

unread,
Sep 25, 2016, 2:15:02 PM9/25/16
to MIT App Inventor Forum
@Palm Tree
If I could use readIntValue to access the individual ints of the array I'd be able to store them in a list, but I am not getting any values when using readIntValue (I only get values with intValueChanged, which means I'm limited to only accessing one int each time I receive a new byte array, so I can choose to look at the int storing the HR value or the RR value, but not both). 

Ghica

unread,
Sep 25, 2016, 3:13:18 PM9/25/16
to MIT App Inventor Forum
I see that it is a problem. The BLE component is still worked upon and you should expect changes for better support.
In the meantime...
Maybe you could try to read a string instead and dissect the numerical values out of it.
Cheers, Ghica.

Abraham Getzler

unread,
Sep 25, 2016, 3:18:34 PM9/25/16
to MIT App Inventor Forum
Where is this BLE component?

I only see the old BlueToothClient and BTServer components in the Connectivity drawer, and neither has the blocks used in that tutorial?

ABG

Ghica

unread,
Sep 25, 2016, 3:21:57 PM9/25/16
to MIT App Inventor Forum
@Abraham,
You need to install the experimental BLE extension first, the only official MIT extension so far.
Cheers, Ghica

Abraham Getzler

unread,
Sep 25, 2016, 4:08:06 PM9/25/16
to MIT App Inventor Forum
Thanks, Ghica.

I see the blocks now, had forgotten about the extension.

I see by the inclusion of an "offset" parameter that there must be some kind of mechanism for
accessing a stored buffer of a message one int, float, or string at a time based on increasing offset values?

Since the blocks that read by offset don't have output nipples, I guess their read values come back
in the CHANGED event blocks?

So I imagine to read a sequence of integers, you need to keep a global offset ,
and increment it each time you get back a piece of the buffer for the next request?

Is the Original Poster doing this?

Did I guess right as to how this works?

ABG

msherman

unread,
Sep 26, 2016, 8:29:13 AM9/26/16
to MIT App Inventor Forum
Either way, it would be helpful for Elliot (OP) to post what data he's getting and seeing.

I could imagine using "getInt" to pop 8 bits at a time, then putting them together as 16s in app inventor.

Abraham Getzler

unread,
Sep 26, 2016, 11:57:21 AM9/26/16
to MIT App Inventor Forum
Time for @Elliot to show his blocks?
ABG

Abraham Getzler

unread,
Sep 26, 2016, 10:43:36 PM9/26/16
to MIT App Inventor Forum
int is like the elephant surrounded by blind men in the old parable.

Every one expects a different number of bits, whether it be 8, 16, or 32.

The tool tips for the BLE blocks offer no guidance.


Anyway,  took a crack at how I imagine the blocks would request and show those uint16 values,
based on my assumption that ints have 16 bits.
(enclosed .aia file and blocks)

Could some one with hardware try it?
ABG
HeartRateMonitor_V2.aia
blocks.png

Ghica

unread,
Sep 27, 2016, 6:45:49 AM9/27/16
to MIT App Inventor Forum
@Abraham,
I do have hardware (an Arduino 101 with the same potmeter simulation as all tutorials I saw), but to try out your code, I should also have the proper sketch in the Arduino,
so unless Elliot publishes his sketch, we cannot do very much.
Besides, looking at your code, I think it is not going to work. The sketches I saw, just keep continuously sending data to the BLE client (your phone) and this is cought in a ...ValueChanged event. No need for a clock.
So, for me receiving strings is the most useful option and the numerical data in it can be filtered out easily.
Cheers, Ghica.

Elliot Mebane

unread,
Sep 27, 2016, 1:03:37 PM9/27/16
to MIT App Inventor Forum
Hmm. replying via email didn't work, so here goes again: 

Here's the sample I'm working with (attached).

With my Zephyr HxM Smart Heart Rate monitor the byte array returned from ReadByteValue always begins with 22 (2264-563 is a sample of what a full byte array looks like. Sometimes it contains the dash, other times not. Lots of variance.). That first byte is the flags byte (22) which describes what the remaining bytes in the array contain. The second byte is the heart rate, so I set ReadIntValue to an offset of 1 in order to skip over the flags byte and read the Heart Rate byte. I can also skip ahead to offset 4 to see the first half (first byte) of the RR byte (a 16 bit int).

On alternate receipts of data, I either grab the ByteValue or IntValue and display them in labels. This is just a hack so I can see more than one thing in the session.

Ideally, I'd be able to use ByteValueChanged to determine when the byte array is new (on average once per second) and then make as many ReadIntValue calls as needed (paired with IntValueReads) on to process the received and stored data. 

I tried your sample. It displays the raw byte array data (e.g., 22701043 BPM) as in the original sample. The Log field you added does not update. 

Based on the way the original sample works, I believe ReadByteValue was designed with the expectation that only single bytes would be received. Using it to step through the byte array, nibbling off bytes as you go, won't work. If there were a ReadByteValue block with an offset notch (like ReadIntValue) it would do what you expected it to do. In addition, I have not seen ReadIntValue send anything to an IntValueRead block, so the idea of looping over the received byte array won't work with the current blocks. Again, ReadIntValue does work when paired with IntValueChanged. 

Hopefully, the next revision which will fix and add some things. BLE is a great feature to have in AI and I look forward to seeing its continued development and integration into AI. 
HRM2.aia

Elliot Mebane

unread,
Sep 28, 2016, 12:40:33 AM9/28/16
to MIT App Inventor Forum
I think I see why ReadIntValue may not work as I expected. I thought it would read int values from the last-received byte array, but instead it only responds if there is a new byte array it has not read from yet. 

I reviewed this doc: 

It describes these 4 server/host connection types as part of the BLE communication format:
— Read  - This operation is requested by the GATT client on a specific characteristic held by the GATT server such as integers. The server complies by providing the requested value.  
— Write  - This operation is initiated by the GATT client on a specific characteristic held by the GATT server, providing the server with the new value. The server stores this new value and may or may not send an acknowledgement to the client.  
— Notify - This operation is initiated by the GATT server when a new value is written to one of its characteristics, provided that the GATT client has subscribed to notifications on that characteristic. The server returns the new value so that it can be read by the client.
— Indicate - The only difference between this operation and notify is that it is acknowledged.

BLE Heart Rate Service uses the Notify communication approach, so we can't make Read requests to the device. 

Here's the Heart Rate Service doc indicating Notify as the communication type:

I believe that the IntValueRead response block is designed to handle responses from Read-type server devices and the IntValueChanged block is designed to handle messages sent from Notify-type server devices. It seems like both are used as responses to ReadIntValue, and depending on the server device type your client is connected with, the appropriate associated response block (IntValueRead or IntValueChanged) is triggered with the return value.
Reply all
Reply to author
Forward
0 new messages