Different results of same code in esp-idf and normal c++

wereworm
Posts: 7
Joined: Sat Apr 18, 2020 7:56 pm

Different results of same code in esp-idf and normal c++

Postby wereworm » Mon Oct 19, 2020 1:59 pm

Good Day!

First of all, I'm quite new to c++ programming, I only started last year with lots of inactive periods in between. I already implemented a bunch of features for my ESP32 but all based on the arduino framework (platformio). Now I'm trying to reimplement one of my programs to ESP-IDF and that's where my question comes from.

My Setup
  • IDE: CLion 2020.1.2
  • OS: Windows 10
  • Toolchain ESP: WSL (Ubuntu 20.04), using CMake 3.16.3
  • Compiler ESP: xtensa-esp32-elf-gcc (crosstool-NG esp-2020r3) 8.4.0
  • Toolchain c++: WSL (Ubuntu 20.04), using CMake 3.16.3
  • Compiler c++: /usr/bin/cc /usr/bin/c++ both (Ubuntu 9.3.0-10ubuntu2) 9.3.0
  • MCU: ESP32-Wrover-B (on a little development board where you can change the MCU)

My Code
I created a git repo to share the code

Problem
I'm currently trying to implement a - for me - easier to use wrapper for BLE/nimble, following the blehr example. What I want is a simplified interface that I can always reuse later. Also I want to use custom UUIDs in the following 16 byte format:

Code: Select all

#define wtServiceUUID       "8d50CAD0-0000-43c2-a33e-00f937249838"
Before the BLE part does its magic, I want to pre-define all services and their characteristics which I intend to store in the following structure:

Code: Select all

std::unordered_map<ble_gatt_svc_def, std::list<ble_gatt_chr_def>, ServiceHash, ServiceEqual> services;
following steps are performed
  1. convert the UUID from const char* to ble_uuid_t or to be more specific in this case to ble_uuid128_t
  2. create a ble_gatt_svc_def entity and store the converted UUID into its .uuid field
  3. and finally store the ble_gatt_svc_def entity into the services map

Code: Select all

void BLEUtil::addService(const char *uuid) {
    s_println("ADD SERVICE %s", uuid);

    ble_uuid_t *bleUuid = convertUUID(uuid);
    const ble_uuid128_t *test = (ble_uuid128_t *) bleUuid;
    logUUID(*test);
    logUUID(bleUuid);

    ble_gatt_svc_def service{
            .type = BLE_GATT_SVC_TYPE_PRIMARY,
            .uuid = bleUuid,
    };

    logUUID(service.uuid);
    services.insert({service, std::list<ble_gatt_chr_def>()});
}
Later on I intend to use this map to create the full structure used by the BLE library.

As the UUID of the services in the map didn't resemble the original UUID later in the program during a first test run, I tried to figure out what went wrong and added some log messages along the code (logUUID) and realized that the result was different pretty much every time.
ADD SERVICE 8d50CAD0-0000-43c2-a33e-00f937249838
convert uuid 8d50CAD0-0000-43c2-a33e-00f937249838
-> to 141802022080067194163620249553615256
141802022080067194163620249553615256
1416325130192128136513625500002550
566325130192128136513625500002550
Since - as I mentioned before - I'm currently quite fresh with c++ and still need to figure out how exactly key features like pointers etc. work in detail, I need to debug this code to get a better understanding. But unfortunately my JTAG Debugger hasn't been ordered yet (lazy) and needs a little while to be shipped from china. Therefore I tried to reimplement this part of the code in plain c++.

But here is the problem: There was none!! All logouts are exactly the same and what I expected:
ADD SERVICE 8d50CAD0-0000-43c2-a33e-00f937249838
convert uuid 8d50CAD0-0000-43c2-a33e-00f937249838
-> to 141802022080067194163620249553615256
141802022080067194163620249553615256
141802022080067194163620249553615256
141802022080067194163620249553615256
I only copy-pasted the code out into the new project and added some header files that contain the UUID and BLE Service structs, where I deleted everything that I didn't need for a better overview.

Maybe someone can see what's my mistake and if you find things worth to improve on the way it's always welcome.

If you need more information, don't hesitate to ask. Thanks in advance!

chegewara
Posts: 2309
Joined: Wed Jun 14, 2017 9:00 pm

Re: Different results of same code in esp-idf and normal c++

Postby chegewara » Mon Oct 19, 2020 4:54 pm

Hi,
i didnt check all your code, but after quick look at it i see this, maybe not an issue, but should help you a bit with debugging:

Code: Select all

s_print("%i", test->value[i]);
With that code you will print decimal values, but UUIDs are in hex, so 8d == 141 and so on. you can change it to something like this:

Code: Select all

s_print("%02x", test->value[i]);

wereworm
Posts: 7
Joined: Sat Apr 18, 2020 7:56 pm

Re: Different results of same code in esp-idf and normal c++

Postby wereworm » Mon Oct 19, 2020 5:07 pm

chegewara wrote:
Mon Oct 19, 2020 4:54 pm
Hi,
i didnt check all your code, but after quick look at it i see this, maybe not an issue, but should help you a bit with debugging:

Code: Select all

s_print("%i", test->value[i]);
With that code you will print decimal values, but UUIDs are in hex, so 8d == 141 and so on. you can change it to something like this:

Code: Select all

s_print("%02x", test->value[i]);

Hi!

Thanks for your hint. While it unfortunately didn't solve the problem, it is a great reminder for me to think more about what format i wanna display numbers. In this case i used %i, because this particular uuid is stored as an array of uint:

Code: Select all

/** 128-bit UUID */
typedef struct {
    ble_uuid_t u;
    uint8_t value[16];
} ble_uuid128_t;
But hex definitely would make sense as well


For anyone who is interested in the new results, it looks now as follows as compared to the output in my initial post (i didn't update github).
ADD SERVICE 8d50CAD0-0000-43c2-a33e-00f937249838
convert uuid 8d50CAD0-0000-43c2-a33e-00f937249838
-> to 8d50cad0000043c2a33e00f937249838
8d50cad0000043c2a33e00f937249838
8d3ffb1ec0800d4242ff00000000ff00
383ffb1ec0800d4242ff00000000ff00

chegewara
Posts: 2309
Joined: Wed Jun 14, 2017 9:00 pm

Re: Different results of same code in esp-idf and normal c++

Postby chegewara » Mon Oct 19, 2020 5:20 pm

This is local variable, which does not exists outside convertUUID() function. It will be randomly overwritten:
https://github.com/tagtraeumer/esp-idf- ... le.cpp#L40

wereworm
Posts: 7
Joined: Sat Apr 18, 2020 7:56 pm

Re: Different results of same code in esp-idf and normal c++

Postby wereworm » Tue Oct 20, 2020 12:18 pm

chegewara wrote:
Mon Oct 19, 2020 5:20 pm
This is local variable, which does not exists outside convertUUID() function. It will be randomly overwritten:
https://github.com/tagtraeumer/esp-idf- ... le.cpp#L40

Hi, yeah maybe this method doesn't look good right now I was just kind of preparing it to use it for more kinds of UUID layouts as opposed to only using the before mentioned style. *** EDIT: see an additional remark to this at the bottom
But yet, I've been messing around a bit and still have no clue why the apparent same code produces different results. I don't know where my mistake is.

I stripped my example down and made it a little easier. in general the focus lies on the convertUUID method and how to use its results.

following is the example from the c++ project (esp-idf looks basically the same)

Code: Select all

void logUUID(const ble_uuid_t *uuid) {
    ble_uuid128_t *test = (ble_uuid128_t *) uuid;
    for (int i = 16 - 1; i >= 0; i--)
        s_print("%02x", test->value[i]);
    s_println("");
}

void logUUID(ble_uuid128_t uuid) {
    for (int i = 16 - 1; i >= 0; i--)
        s_print("%02x", uuid.value[i]);
    s_println("");
}

ble_uuid_t *convertUUID(const char *uuid) {
    s_println("convert uuid %s", uuid);
    ble_uuid_t *bleUuid;
    if (strlen(uuid) == 36) {
        ble_uuid128_t temp;
        temp.u.type = BLE_UUID_TYPE_128;

        int n = 0;
        for (int i = 0; i < strlen(uuid);) {
            if (uuid[i] == '-')
                i++;
            std::string s;
            s += uuid[i];
            s += uuid[i + 1];
            uint8_t x = std::stoul(s, nullptr, 16);
            temp.value[15 - n] = x;
            n++;
            i += 2;
        }
        bleUuid = ((ble_uuid_t *) (&temp));
    }
    s_print("-> to ");
    logUUID(bleUuid);

    return bleUuid;
}


int main() {

    ble_uuid_t *uuid = convertUUID(wtServiceUUID);
    logUUID(uuid);

    return 0;
}
I struggle to use the ble_uuid128_t struct, since its value is based on a uint8 array. I think my difficulty here is to properly cast between this and its generic UUID type ble_uuid_t.

also here between plain c++ and xtensa esp-idf you can find the different log results:

c++ (as i would expect it)
convert uuid 8d50CAD0-0000-43c2-a33e-00f937249838
-> to 8d50cad0000043c2a33e00f937249838
8d50cad0000043c2a33e00f937249838
esp-idf (last log shows a different uuid)
convert uuid 8d50CAD0-0000-43c2-a33e-00f937249838
-> to 8d50cad0000043c2a33e00f937249838
8d3ffb1f4080084763ff00000000ff00

*** EDIT:

As you mentioned the variable will be overwritten, I did a little more research on basics and could find a solution (for now?) on my problem. I changed the convert method to the following, which seems to work on my test code. yet I will not fix the github code, since it still shows how there's different results for different compilers (assumed I did no mistake). My question remains, why is there a difference?

Code: Select all

ble_uuid_t *convertUUID(const char *uuid) {
    s_println("convert uuid %s", uuid);
    ble_uuid_t *bleUuid;
    if (strlen(uuid) == 36) {
        ble_uuid128_t *temp = new ble_uuid128_t;
        temp->u.type = BLE_UUID_TYPE_128;

        int n = 0;
        for (int i = 0; i < strlen(uuid);) {
            if (uuid[i] == '-')
                i++;
            std::string s;
            s += uuid[i];
            s += uuid[i + 1];
            uint8_t x = std::stoul(s, nullptr, 16);
            temp->value[15 - n] = x;
            n++;
            i += 2;
        }
        bleUuid = ((ble_uuid_t *) (temp));
    } else {
        bleUuid = nullptr;
    }
    s_print("-> to ");
    logUUID(bleUuid);

    return bleUuid;
}

chegewara
Posts: 2309
Joined: Wed Jun 14, 2017 9:00 pm

Re: Different results of same code in esp-idf and normal c++

Postby chegewara » Tue Oct 20, 2020 1:20 pm

I think espressif devs can explain it better, but embedded device and PC differ in memory amount, so compiler is using different optimization and usage.
Again, variable created in function is a local variable and is not valid after exiting from that function (you can make it static inside function and it will works). You can make google search and i believe you will find many similar issues on stackoverflow.

Who is online

Users browsing this forum: Majestic-12 [Bot] and 88 guests