About ESP_GATT_CONGESTED

Serdar
Posts: 18
Joined: Fri Sep 02, 2022 7:33 pm

About ESP_GATT_CONGESTED

Postby Serdar » Sun Dec 04, 2022 11:56 am

Hi, I have a BLE project where i use NORDIC UART Service on ESP32-S3.
I developed this on top of the GATT_SEERVER demo
https://github.com/espressif/esp-idf/tr ... att_server

I created a top layer over the GATT_SERVER demo and controlled it like this.
Here is a code I created to test the max speed.

Code: Select all

void test_task(void *pvParameters)
{
    int64_t times = 100;
    int64_t res = 0;
    long res_2;

    for (;;)
    {
        if (device_status_p->enable_data_ntf == true && device_status_p->is_connected == true && 1)
        {
            unsigned long endTime = (esp_timer_get_time() / 1000) + (2* 1000);
            while (1)
            {
                ble_printf(" times = %i \n", times);
                times++;
                times = times%100;
                if ((esp_timer_get_time() / 1000) > endTime)
                {
                    break;
                }
            }
            vTaskDelay((100) / portTICK_PERIOD_MS);
            res = (times / 2) * 12;
            res_2 =res;
            printf("it's send %ld  bytes per second \n", res_2);
            ble_printf("it's send %i times \n", times);
            ble_printf("it's send %i bytes per second \n", res);
            times = 0;
            vTaskDelay((20000) / portTICK_PERIOD_MS);
        }
        vTaskDelay((50) / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    bluetooth_init(&device_status_p);
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    xTaskCreate(test_task, "test_task", 4096, NULL, 3, NULL);
    while (1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    return;
}
Let me explain to you how the my project works.

ble_printf() transfers the entered data to an array and passes it to the spp_uart_queue.

Code: Select all

uint8_t ble_printf(char *format, ...)
{
    char *traverse;
    char *traverse_dumy;
    char *pointer;
    int i, index_l, index_k;
    message_t yaz;
    yaz.len = learn_size((char *)format);
    // printf("ilk = %i\n", yaz.len);
    traverse = (char *)malloc(99 * sizeof(char));
    yaz.data = (uint8_t *)malloc(99 * sizeof(uint8_t));
    memset(traverse, 0, 80);
    memset(yaz.data, ' ', 80);

    // Module 1: Initializing Myprintf's arguments
    va_list arg;
    va_start(arg, format);
    index_l = 0;
    index_k = 0;
    traverse_dumy = traverse;
    traverse = format;
    while (traverse[index_l] != 0)
    {
        while (traverse[index_l] != '%' && traverse[index_l] != 0)
        {
            // printf("//= %c_%i // %i \n", traverse[index_l], traverse[index_l ], index_l );
            yaz.data[index_k] = (uint8_t)traverse[index_l];
            index_l++;
            index_k++;
        }

        // printf("///= %c_%i // %i \n", traverse[index_l], traverse[index_l], index_l);
        if (traverse[index_l] == 0)
        {
            // printf("sorun cikmadi = %i \n", index_l);
            break;
        }
        index_l++;
        // Module 2: Fetching and executing arguments
        switch (traverse[index_l])
        {
        case 'c':
            i = va_arg(arg, int); // Fetch char argument
            yaz.data[index_l] = (uint8_t)i;
            break;

        case 'd':
            // printf("integer \n");
            i = va_arg(arg, int); // Fetch Decimal/Integer argument
            if (i < 0)
            {
                i = -i;
                yaz.data[index_k] = (uint8_t)'-';
                index_k++;
            }
            pointer = convert(i, 10);
            sprintf((char *)&yaz.data[index_k], "%s", pointer);
            //  printf("Nedir = %s // len = %i // %i\n", pointer, learn_size(pointer), index_l);

            // learn_size(pointer)
            index_k = index_k + learn_size(pointer);
            index_l++;
            break;
        case 'i':
            // printf("integer \n");

            sprintf((char *)&yaz.data[index_k], "%i", va_arg(arg, int64_t)); // Fetch Decimal/Integer argument);
            //  printf("Nedir = %s // len = %i // %i\n", pointer, learn_size(pointer), index_l);

            // learn_size(pointer)
            index_k = index_k + learn_size((char *)&yaz.data[index_k]);
            index_l++;
            break;

        case 'o':
            i = va_arg(arg, unsigned int); // Fetch Octal representation
            pointer = convert(i, 8);
            memcpy(&yaz.data[index_l], (uint8_t *)pointer, learn_size(pointer));

            index_l = index_l + learn_size(pointer);
            break;

        case 'x':
            i = va_arg(arg, unsigned int); // Fetch Hexadecimal representation
            pointer = convert(i, 16);
            memcpy(&yaz.data[index_l], (uint8_t *)pointer, learn_size(pointer));

            break;
        }
    }
    // printf("Index = %i\n", index);
    //  Module 3: Closing argument list to necessary clean-up
    va_end(arg);
    yaz.len = index_k;
    yaz.way = going_to_phone;
    xQueueSend(spp_uart_queue, (void *)&yaz, (TickType_t)100);
    // printf("sorun cikmadi = %i \n", yaz.len);
    free((traverse_dumy));
    return 0;
}
uart task() checks the queue and performs the necessary bluethoot operation according to the incoming message.

Code: Select all

void uart_task(void *pvParameters)
{
    uint16_t attr_handle_g = 44;
    message_t uart_data;
    uint8_t deneme[20];
    int free_buff_num;
    //  uart_data = (message_t *)pvParameters;
    for (;;)
    {
        // Waiting for UART event.
        if (xQueueReceive(spp_uart_queue, (void *)&uart_data, (TickType_t)portMAX_DELAY))
        {
            if ((device_status.is_connected))
            {
                // printf("Kuyruk tetiklendi = %i \n",uart_data.way);
                if (uart_data.way == going_to_phone)
                {
                    if (!device_status.enable_data_ntf)
                    {
                        ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable data Notify\n", __func__);
                        break;
                    }
                    for (int i = 0; i < uart_data.len; i++)
                    {

                        deneme[i] = uart_data.data[i];
                    }
                    // printf("TX data = %s \n", deneme);
                    // printf(" \n");
                    if (uart_data.len < 20)
                    {
                        //unsigned long endTime = esp_timer_get_time();
                        free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);
                        // printf("free buf %i \n",free_buff_num);
                        if (free_buff_num > 0)
                        {
                            // ESP_LOGI(GATTS_TABLE_TAG, "Its ok \n");
                            esp_ble_gatts_send_indicate(spp_gatts_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, attr_handle_g, uart_data.len, uart_data.data, false);
                        }
                        else
                        {
                            // ESP_LOGE(GATTS_TABLE_TAG, "Its slow \n");
                            unsigned long endTime = esp_timer_get_time();
                            while (1)
                            {
                                free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);

                                if (free_buff_num > 0)
                                {
                                    //endTime = esp_timer_get_time() - endTime;
                                    //printf("Time = %iuS \n", (endTime));
                                    esp_ble_gatts_send_indicate(spp_gatts_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, attr_handle_g, uart_data.len, uart_data.data, false);
                                    break;
                                }

                                if ((esp_timer_get_time()) > (endTime+5000))
                                {
                                    break;
                                }
                            }
                        }

                        free(uart_data.data);

                        // endTime = esp_timer_get_time() - endTime;
                        // printf("Time = %iuS \n", (endTime));
                    }
                    else
                    {
                        int data_size = uart_data.len;
                        int index = 0;
                        while (1)
                        {
                            unsigned long endTime = esp_timer_get_time() + (1 * 1500);
                            esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, attr_handle_g, 10, &uart_data.data[index * 10], false);
                            index = index + 1;
                            while (1)
                            {
                                if ((esp_timer_get_time()) > endTime)
                                {
                                    break;
                                }
                            }
                            data_size = data_size - 10;
                            if (data_size < 10)
                            {
                                esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, attr_handle_g, data_size, &uart_data.data[index * 10], false);
                                break;
                            }
                        }
                    }
                }
                if (uart_data.way == coming_from_phone)
                {

                    device_status.saved_data[device_status.saved_data_index] = uart_data.data;
                    device_status.saved_data_index++;
                    // printf("RX len = %i \n", uart_data.len);
                    if (device_status.saved_data_index > 7 || uart_data.len > 17)
                        ESP_LOGE(GATTS_TAG, "RX buffer overflow \n");

                    /*
                    memset(mesaj, 0, 20);
                    printf("Poinder:%p && LEN:%i \n", uart_data.data, uart_data.len);
                    for (int i = 0; i < uart_data.len; i++)
                    {
                        mesaj[i] = uart_data.data[i];
                    }
                    printf("Gelen mesaj = %s \n", mesaj);

                    free(uart_data.data);*/
                }
            }
            else
            {
                ESP_LOGE(GATTS_TAG, "Device is NOT Connected \n");
            }
        }
    }
    vTaskDelete(NULL);
}
Here is my problem

Code: Select all

if (uart_data.way == going_to_phone)
                {
                    if (!device_status.enable_data_ntf)
                    {
                        ESP_LOGE(GATTS_TABLE_TAG, "%s do not enable data Notify\n", __func__);
                        break;
                    }
                    for (int i = 0; i < uart_data.len; i++)
                    {

                        deneme[i] = uart_data.data[i];
                    }
                    // printf("TX data = %s \n", deneme);
                    // printf(" \n");
                    if (uart_data.len < 20)
                    {
                        //unsigned long endTime = esp_timer_get_time();
                        free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);
                        // printf("free buf %i \n",free_buff_num);
                        if (free_buff_num > 0)
                        {
                            // ESP_LOGI(GATTS_TABLE_TAG, "Its ok \n");
                            esp_ble_gatts_send_indicate(spp_gatts_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, attr_handle_g, uart_data.len, uart_data.data, false);
                        }
                        else
                        {
                            // ESP_LOGE(GATTS_TABLE_TAG, "Its slow \n");
                            unsigned long endTime = esp_timer_get_time();
                            while (1)
                            {
                                free_buff_num = esp_ble_get_cur_sendable_packets_num(gl_profile_tab[PROFILE_A_APP_ID].conn_id);

                                if (free_buff_num > 0)
                                {
                                    //endTime = esp_timer_get_time() - endTime;
                                    //printf("Time = %iuS \n", (endTime));
                                    esp_ble_gatts_send_indicate(spp_gatts_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, attr_handle_g, uart_data.len, uart_data.data, false);
                                    break;
                                }

                                if ((esp_timer_get_time()) > (endTime+5000))
                                {
                                    break;
                                }
                            }
                        }

                        free(uart_data.data);

                        // endTime = esp_timer_get_time() - endTime;
                        // printf("Time = %iuS \n", (endTime));
                    }
                    else
                    {
                        int data_size = uart_data.len;
                        int index = 0;
                        while (1)
                        {
                            unsigned long endTime = esp_timer_get_time() + (1 * 1500);
                            esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, attr_handle_g, 10, &uart_data.data[index * 10], false);
                            index = index + 1;
                            while (1)
                            {
                                if ((esp_timer_get_time()) > endTime)
                                {
                                    break;
                                }
                            }
                            data_size = data_size - 10;
                            if (data_size < 10)
                            {
                                esp_ble_gatts_send_indicate(spp_gatts_if, spp_conn_id, attr_handle_g, data_size, &uart_data.data[index * 10], false);
                                break;
                            }
                        }
                    }
                }
                
If I don't use esp_ble_get_cur_sendable_packets_num() the speed increases. but I get ESP_GATT_CONGESTED error in some places.

Image

If I use esp_ble_get_cur_sendable_packets_num() like in current code. The maximum speed I can reach is 4400 bytes per second.

Image
///////////////////////////////////////////////////////////////////////////

What should I do to increase my speed, Can you explain to me?
I searched many places but couldn't find any results.

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

Re: About ESP_GATT_CONGESTED

Postby chegewara » Mon Dec 05, 2022 11:05 pm

Sending data too fast to HCI controller (too tight loop) will cause congestion and some packets will be dropped by controller.
You should read more about MTU to get faster transfer.

Serdar
Posts: 18
Joined: Fri Sep 02, 2022 7:33 pm

Re: About ESP_GATT_CONGESTED

Postby Serdar » Tue Jan 24, 2023 9:30 pm

I increased MTU size increase and i created timer controlled flush mechanism.
It works very well now, thank you.

Who is online

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