This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2640R2F: Question regarding few specific functions and operations of "HeartRate" example code

Part Number: CC2640R2F

Hello All,

I am very new to C and embedded C programming. I am trying to learn Bluetooth communication. From these resources:

  1. Bluetooth Low Energy Fundamentals
  2. Scanning and Advertising
  3. Connections
  4. Custom Profile

 

At the same time, I am also going through some examples to understand how those things are implemented. That brings me to this project repository:

https://github.com/ti-simplelink/ble_examples

 

Here I am trying to understand the “heart_rate” examples. Right now I am only interested to figure out how it is sending the measured simulated data to Bluetooth.

So, from the main.c file, I can see that from this function:

HeartRate_createTask();

We are running all the heartrate-related measurements. So, I opened up that function and it seemed to me all the notifications is sent from this function:

HeartRate_measNotify(void)

I am very new to C and embedded C programming so I tried to understand that section and tried to write comments for each line. I am not completely sure whether I have done a good job or not. But I would greatly appreciate it if you can read through my comments.

 

static void HeartRate_measNotify(void)

{

    attHandleValueNoti_t heartRateMeas;  // its a stracture type with three variables and here I am declaring a variable (heartRateMeas) of that type

 

    heartRateMeas.pValue = GATT_bm_alloc(gapConnHandle, ATT_HANDLE_VALUE_NOTI,  //allocation the memory location for pValue

    HEARTRATE_MEAS_LEN,

                                         NULL);

    if (heartRateMeas.pValue != NULL)  // if the MCU was able to allocate 9 (HEARTRATE_MEAS_LEN) consecutive memory location then it will enter this "if" statement

    {

        uint8_t *p = heartRateMeas.pValue;  // saves the address of the first location of the pointer variable "pvalue" in pointer "p".

                                            // The first location address of the allocated memory

        uint8_t flags = heartRateflags[flagsIdx];  // save the value of the first variable of the "heartRateflags" array in the "flag" variable

 

        // Build heart rate measurement structure from simulated values.

        *p++ = flags;  // save the value of "flag" in the first location of the allocated memory and then increment "p"

                       //so that the next variable can be saved in the 2nd location of the allocated memory.

        *p++ = heartRateBpm;  // save the value of "heartRateBpm" in the second location of the allocated memory and then increment "p"

                              //so that the next variable can be saved in the 3rd location of the allocated memory.

 

//        if (flags & HEARTRATE_FLAGS_FORMAT_UINT16)

//        {

 //           // Additional byte for 16 bit format.

   //         *p++ = 0;

   //     }

 

     //   if (flags & HEARTRATE_FLAGS_ENERGY_EXP)

     //   {

      //      *p++ = LO_UINT16(heartRateEnergyLvl);

      //      *p++ = HI_UINT16(heartRateEnergyLvl);

      //  }

 

//        if (flags & HEARTRATE_FLAGS_RR)

  //      {

            *p++ = LO_UINT16(heartRateRrInterval);  // same procedure as before

            *p++ = HI_UINT16(heartRateRrInterval);

            *p++ = LO_UINT16(heartRateRrInterval2);

           *p++ = HI_UINT16(heartRateRrInterval2);

      //  }

 

        heartRateMeas.len = (uint8) (p - heartRateMeas.pValue);  // in same cases, all the "if" statement may not be executed so the whole allocated memory (HEARTRATE_MEAS_LEN),

                                                               //may not have been used. Thats why save the actual length of the allocated memory.

 

        // Send notification.

        if (HeartRate_MeasNotify(gapConnHandle, &heartRateMeas) != SUCCESS)  // it takes the ........ and the address of the "heartRateMeas" ?????

        {

            GATT_bm_free((gattMsg_t*) &heartRateMeas, ATT_HANDLE_VALUE_NOTI);  // free ups the allocated memory

        }

 

        // Update simulated values.

//        heartRateEnergyLvl += HEARTRATE_ENERGY_INCREMENT;

//        if (++heartRateBpm == HEARTRATE_BPM_MAX)

//        {

//            heartRateBpm = HEARTRATE_BPM_DEFAULT;

//        }

//        heartRateBpm =55;

        heartRateRrInterval = heartRateRrInterval2 = HEARTRATE_BPM2RR(   //Why??

                heartRateBpm);

    }

}
 

 

 

I want to send multiple sensor data. Please correct me if I wrong, if I have understood it correctly then I just need to use this method to pass all the data to Bluetooth as long as I don’t go over 512 bytes (dev.ti.com/.../ble_01_custom_profile.html):

 

 *p++ = LO_UINT16(heartRateRrInterval);

 *p++ = HI_UINT16(heartRateRrInterval);

 *p++ = LO_UINT16(heartRateRrInterval2);

 *p++ = HI_UINT16(heartRateRrInterval2);
 

But I still need to verify that idea. And still not sure in which section of the Handler or UUID it would show up. The main issue is that I am unable to understand this section of the code:

 

if (HeartRate_MeasNotify(gapConnHandle, &heartRateMeas) != SUCCESS)

 

I can understand that we are passing the “heartRateMeas” structure address to this function but from there when I directly went to the actual function I got completely lost. We have passed the address of the structure as “pNoti”. Then in this line:

return GATT_Notification(connHandle, pNoti, FALSE);

We sent the notification. Presumably the heart rate data (BPM value). But if I open up the declaration of that function, it actually does not go anywhere, just jumps back and forth between different declarations.

(icall_directAPI(ICALL_SERVICE_CLASS_BLE, (uint32_t) IDX_GATT_Notification , ##__VA_ARGS__))

 

I would really appreciate it if someone can explain to me how are we actually sending the data to Bluetooth? And what is actually happing here in this function or declaration?

Also, in the “heartrateservice.c” file there is a section:

pNoti->handle = heartRateAttrTbl[HEARTRATE_MEAS_VALUE_POS].handle;

What is this section of the code doing? As the handler value is zero why are we passing that zero value to PNoti (pNoti->handle)?

 

That is a lot of questions for a single post Sweat smile. I would appreciate any help that I would get.

 

Thanks.

  • Hi,

    Thank you for reaching out.

    I have asked an engineer to comment.

    Best regards,

  • Hi Ifthekar

    Please correct me if I wrong, if I have understood it correctly then I just need to use this method to pass all the data to Bluetooth

    While I'm not able to read through all your comments line-by-line, most of them seemed quite accurate. I think you're on the right path for a lot of this, which is very impressive for a beginner to embedded-C. Keep up the good work!

    I am not completely sure whether I have done a good job or not. But I would greatly appreciate it if you can read through my comments.

    Yes this is where you're populating the struct that contains the data.

    And still not sure in which section of the Handler or UUID it would show up

    The UUID will not show up in the code. The handler is the HeartRate_MeasNotify function that you've identified. 

    Then in this line:

    Where in the code do you see this? I'm looking at the 4.10 SDK and I can't find it.

    how are we actually sending the data to Bluetooth? And what is actually happing here in this function or declaration?

    Our devices have multiple cores on them. So, the way you send bluetooth messages is by sending messages from the application layer to the bluetooth stack layer, which is handled by a separate radio core, which is why you don't see explicit functions that send packets out. It's all handled by the separate radio core.

    What is this section of the code doing? As the handler value is zero why are we passing that zero value to PNoti (pNoti->handle)?

    I don't see where this code is either. Please specify the SDK version and the file / line number.

  • Hello Nathan,

    Thank you. I am binging through a couple of beginners C programming courses but there is still a lot to learn. Embedded C feels a bit different in the sense that there is too much stuff that is done through pointer and structures. And oh boy pointers, pointers that point to another pointer, and so on. And professional programmers do multiple tasks in a single line where I take dozens of lines, so sometimes it’s a bit difficult to understand. Also so many nested functions and nested definitions declarations Head bandage. But I am getting the hang of it. There are very few materials available for embedded C, still have not found something that goes from absolute beginners to advance level. Any suggestion there?

    Anyway, I digress, coming back to the point at hand. I think I am using a slightly different SDK, it is the “4.10.0.10” version.

     

    Secondly, I reached that part of the code by right-clicking and going to the “Open Declaration” of the “HeartRate_MeasNotify” part of the below-menthoned line of the “heart_rate.c” file. You can also see it in the previous screenshot of the SDK version page.

    if (HeartRate_MeasNotify(gapConnHandle, &heartRateMeas) != SUCCESS)

     

    By doing so I jumped from the “heart_rate.c” file to the “heartrateservice.c” file. And in that file on line “396”, I have found that return statement:

    return GATT_Notification(connHandle, pNoti, FALSE)

     

    Then again I right-clicked on the “GATT_Notification” part of that line and then I reach a new file called “icall_ble_api.h”. And on line 467 I have found this declaration:

    (icall_directAPI(ICALL_SERVICE_CLASS_BLE, (uint32_t) IDX_GATT_Notification , ##__VA_ARGS__))

     

    From there I completely got lost. From this part, I am not actually sure where the stored Heart Rate (BPM) is going.

     

    So, if I again opened up the declaration of “icall_directAPI”. It takes me to the  “icall.c” file, where I am passing the same address as “id”. The “id” variable gets picked up by the “liteMsg.msg” struct at the line “3888” and it sent the address to “ICall_sendServiceMsg” at line 3890. If I open up the declaration of “ICall_sendServiceMsg”, it takes me to line “2470” where the address is stored as “msg”. That “msg” pointer is sent to “ICall_send” at line 2480. Again if I open up the declaration of “ICall_send”, it takes me to line “2732”. And again saves the address as “msg” and sends the address to the “ICall_msgEnqueue” function at the line “2761”. Opening up that declaration takes me to line “793” of the same file and here the address is again saved as “msg_ptr”.

    Here, if the address is zero then it is stored in another pointer named “q_ptr” (line 805) otherwise it is added to a different queue function called “ICALL_MSG_NEXT” at the line “814”. After opening up the declaration of that function it brings me to this definition:

    #define ICALL_MSG_NEXT(_p) (((ICall_MsgHdr *)(_p) - 1)->next)


    From there if I go to “ICall_MsgHdr”, it shows me the structure of it. At the line “772”. After that I am not sure what's going on or how am I, at the end sending the data to the correct Handler’s  UUID as Value Dizzy face .

    I would really appreciate it if you can tell me how am I actually sending the heart rate to the “ATT protocol”. To me “ICall_MsgHdr” looks like a dead-end Thinking.  

    AT the end it felt like I am just over thinking by going through all those stages. I am mainly interested to know that if I send a data or a bunch of data using this method of dividing the higher and lower bits and put them in to a sequential addressed memory:

    *p++ = LO_UINT16(heartRateRrInterval); 
    
     *p++ = HI_UINT16(heartRateRrInterval);
    
     *p++ = LO_UINT16(heartRateRrInterval2);
    
     *p++ = HI_UINT16(heartRateRrInterval2);
     

    Then, where it actually goes? There should be a memory location for the Bluetooth. Bluetooth service should monitor that memory location and should spit out any data that is located there. I know I am oversimplifying Sweat smile.

    Also After sending it over Bluetooth, how do I know which Handler and UUID actually have my data?

    I thought that the value of the UUID should contain the Heart rate data. So, I took another launchpad and burned the “host_test” project on it so that I can read the Handler, UUID, and the Value. And turned on the “BTool” software.

     

    But after connecting to the other launchPad which is transmitting the BLE data, I wanted to read the HeartRate Data but as the “Handler” has 0x0000 to 0xFFFF address I am not sure which “Handler” value I should read to get the data (HeartRate) that I have sent over Bluetooth.

     

    Please let me know if you need further information. And again sorry for such a long post.

     

    Best Regards,
    Ifthekhar

  • Then, where it actually goes? There should be a memory location for the Bluetooth. Bluetooth service should monitor that memory location and should spit out any data that is located there. I know I am oversimplifying .

    Our stack is not viewable all the way down. Since there are multiple cores on your device, the code that you see is what gets run on the main core, and the actual bluetooth portion is run on a separate core. This is done to abstract away the more granular parts of bluetooth.

    But after connecting to the other launchPad which is transmitting the BLE data, I wanted to read the HeartRate Data but as the “Handler” has 0x0000 to 0xFFFF address I am not sure which “Handler” value I should read to get the data (HeartRate) that I have sent over Bluetooth.

    To see the data, once you've connected to the device (as you have shown in your screenshot :) ) right-click on Handle:0000->read values.

    This will discover the characteristics and read the readable characteristics of the device you're connected to (the heart rate launchpad). Now, you can find the heart-rate CCCD. Change the value to 01:00 to enable notifications on the heart-rate device. The reason you weren't seeing the values change is that you hadn't scanned the UUID's, and you hadn't configured the heart-rate sensor to send notifications (via BTool). After you read the values, and set the CCCD to 01:00, you should see the values update in real-time.

    If you're looking for more resources on how to develop BLE, I would strongly recommend consulting the SimpleLink Academy Trainings. Here is a link to the SLA for your device.

    Best,

    Nate

  • Hello Nathan,

    I am able to read the data through BTool now. I'll keep on working on those study materials. Looks like it would be a long journey.

    I have one more question. Right now I am able to send 20-bytes of data at a time.

    but if I include one more byte to the memory address, I don't get anything on the BTool terminal.

    I am planning to send 70 to 80 bytes of data. Is there a way around it? I thought that there might be some kind of declaration on the code that doesn't allow anything over 20-bytes because the payload is supposed to be around 512 bytes (MAX) but could not find anything like that. Do I need to use "GATT ReadLongCharValue or GATT WriteLongCharValue" functions to send larger data set?

    Best Regards,

    Ifthekhar

  • Hello Nathan,

    I actually read it earlier and tried to find the location where that size may have been defined. I have found "ble_user_config.h", "l2cap.h", and "att.h" files. I have attached screenshots of those pages below. I tried to change the minimum and maximum values of those declaration and also some other values but it did not solve my issue. Can you please specify which ".h" file I need to find and in that ".h" file what I need to change?

    I may not actually have understood what the thread has advised to change. 

    Best, 

    Ifthekhar

  • Hi Ifthekhar,

    Please open a new thread when you have a new question. We like to keep each thread associated with only a single problem/bug/question for organization and easy lookup in the future. Feel free to copy this message exactly and start a new thread with it, and I will be happy to assist you with it.

    Best,

    Nate