Page 1 of 1

how do I go with logical flow for BLE GATT client?

Posted: Mon Jul 31, 2017 6:47 pm
by Trialblazer47
I have from gattc_demo made basic code that connects to my pheripheral device(NRF51822 GATT Server). I can now connect find service and characteristics of my interest and then enable notification I am also able to send data to NRF51 and it respond back with the data I asked it for.

But there is much more I am doing on the pheripheral like I have made a command control where I ask for time to it and NRF51 sends time. ask for Battery level it sends me battery level ask for stored data it sends stored Data. But how do I implement that kind of logic? I mean there are all basic events that are called in ESP32.

such as for one single command I have done this.

Code: Select all

  case ESP_GATTC_WRITE_DESCR_EVT:
        ESP_LOGI(GATTC_TAG, "WRITE: status %d", p_data->write.status);
        char cmd='B';
        esp_ble_gattc_write_char(gattc_if,
                                 conn_id,
                                &Myservice_id,
                                            &Tx_char_ID,//esp_gatt_id_t *char_id, //get_char->char_id
                                            1,//uint16_t value_len,
                                            (uint8_t *)&cmd,//uint8_t *value,
                                            ESP_GATT_WRITE_TYPE_NO_RSP,//esp_gatt_write_type_t write_type,
                                            ESP_GATT_AUTH_REQ_NONE);//esp_gatt_auth_req_t auth_req)
after Notification is enabled this event is called and I send 'B' for battery level it send me that data and notify me. but I want to implement logic where on certain situation I will ask for other thing and it should respond. there is no loop() function in ESP32 IDF that keeps looking on flags and if flag is set I can perform or send command. or is there ? or a perodically called function.
Any Idea?

like in NRF51 I am programming with mbed BLE api and mbed API where I can set a periodic function to call with Tickerhttps://www.google.co.in/url?sa=t&rct=j ... AfhcYrg3Ug .I thought of using freeRTOS API to create task on connection and handle things and then delete it once the connection is done. But I am not sure should I do that.

Help would be appriciated.

Re: how do I go with logical flow for BLE GATT client?

Posted: Tue Aug 01, 2017 4:53 am
by kolban
Howdy,
I'd like to try and assist ... but there was too much in your last post ...

Let's take one part ... I think you were asking if you could periodically wake up, perform a task and then go back to sleep until it is time to wake up again.

For me, the simplest way would be to create a new FreeRTOS task and then have a while loop that logically performs:

Code: Select all

while(true) {
   delay for a period of time;
   do something now that I have woken up;
}
If that sounds good, then we have to break that story up into two sub-stories:

1) How to create a new parallel task in FreeRTOS
2) How to delay for a period of time

For creating a task, here is a quick link:
http://www.freertos.org/a00125.html

and for task delays, we have:
http://www.freertos.org/a00127.html

These should give you links to the APIs that are core here (xTaskCreate & vTaskDelay).

If you study these APIs and run into questions please don't hesitate to post back and the community will try and assist.

Re: how do I go with logical flow for BLE GATT client?

Posted: Tue Aug 01, 2017 5:26 am
by Trialblazer47
Yes I read last night about task in freeRTOS I think it should help. Basically I wanted to set flags and store data in Events(switch case) thn other function(task ) would do the logic part so that switch case are neat and main logic for porgram is seperate from the BLE functionality. Thanks I would implement Task but I am not sure should I give lot of stack space ? because I would later implement MQTT client and send BLE data to MQTT. Thanks for replying for every thing.

I am reading FreeRTOS_Reference_Manual_V9.0.0.pdf for freeRTOS

Re: how do I go with logical flow for BLE GATT client?

Posted: Tue Aug 01, 2017 1:57 pm
by kolban
The events handler is asynchronously called back when an event arrives. That event handler runs in its own task. However, within the event handler you have access to global data. This means that your call back can read and write from data that is set or read by another task. It isn't meaningful to say that you are "storing data in a switch". As for stack space, we need to determine "which" stack space we are talking about. Each task is configured with a maximum stack size. Some tasks are created by ESP-IDF in which case the stack size for those tasks can usually be configured through "make menuconfig". For tasks that you create, you are responsible for allocating stack space when the task is created. As a rule of thumb, I usually allocate 20K when I start prototyping. I normally don't find it useful to try and minimally size a stack when I am developing. So far, I haven't run out of RAM for ANY C or C++ application and over allocating RAM for a stack does no harm as long as I don't run out of RAM for the total of my tasks and heap storage ... which doesn't usually happen. If I ever developed anything that needed product quality polish, I would log the maximum stack used during runs ... and even then, if all is working, would only be looking for tasks that we coming close to USING the stack I gave them and not wasting stack space.

Re: how do I go with logical flow for BLE GATT client?

Posted: Tue Aug 01, 2017 6:27 pm
by Trialblazer47
Thanks for it. I went ahead with creating a task and handleing things there it made things easy for me and acts on flags and Data I set in Callbacks. Yes I think giving enough stack size for begining is fine but I will have to figure out how to trim the stack later to because I think I would be using another task for MQTT client(may be not I would see about that later).

Anyways thanks for that awesome advice. ;)

here is how I managed it... (just in Case some one is searching for it.)
My device advertises for with different names for different things like to log that its working it sets alive Adv packet, then ESP connects sets time on it(RTC I am doing with Ticker on NRF51 so Just to make sure it does not drift away), adv for data is for transfering data , Range is for testing Range(ya I have to figure out API for getting NRF51 RSSI value in ESP32 After connection, does anyone know?) this sends back RSSI value ESP32 sees of NRF51 to NRF51 and it blinks LEDS based on LEVEL of signal like if only -90dB then blink only one LED if -10dB then Blink all 5 LEDS. I hope this helps to someone.

Code: Select all

void bytelens_task(void *params)
{
ESP_LOGI(GATTC_TAG,"TASK Running.");
char cmd[20];
  while(1)
    {
      switch(dev.connState){
        case forALIVE:
              ESP_LOGI(GATTC_TAG,"For Alive..");
              if(dev.Connected && dev.notify && !dev.timer_set)
              {
                    ESP_LOGI(GATTC_TAG,"Setting Time.");

                    char *time="1234567890";
                    cmd[0]='T';
                    memcpy(&cmd[1],time,11);

                    dev.timer_set=true;
                    esp_ble_gattc_write_char(dev.gattc_if,
                                             dev.conn_id,
                                            &my_service_id,
                                                        &Tx_char_ID,						//esp_gatt_id_t *char_id, //get_char->char_id
                                                        12,								//uint16_t value_len,
                                                        (uint8_t *)&cmd,					//uint8_t *value,
                                                        ESP_GATT_WRITE_TYPE_NO_RSP,		//esp_gatt_write_type_t write_type,
                                                        ESP_GATT_AUTH_REQ_NONE);			//esp_gatt_auth_req_t auth_req)
              }
              else{
                if(!dev.processing)
                    esp_ble_gattc_close(dev.gattc_if,dev.conn_id);//close connection on setting
              }//for Alive
        break;
        case forREG:
              ESP_LOGI(GATTC_TAG,"For REG..");
              if(dev.Connected && dev.notify && !dev.timer_set)
              {
                    ESP_LOGI(GATTC_TAG,"Setting Time.");

                    char *time="1234567890";
                    cmd[0]='T';
                    memcpy(&cmd[1],time,11);

                    dev.timer_set=true;
                    esp_ble_gattc_write_char(dev.gattc_if,
                                             dev.conn_id,
                                            &Bytelens_service_id,
                                                        &Tx_char_ID,//esp_gatt_id_t *char_id, //get_char->char_id
                                                        12,//uint16_t value_len,
                                                        (uint8_t *)&cmd,//uint8_t *value,
                                                        ESP_GATT_WRITE_TYPE_NO_RSP,//esp_gatt_write_type_t write_type,
                                                        ESP_GATT_AUTH_REQ_NONE);//esp_gatt_auth_req_t auth_req)
              }
              else{
                if(!dev.processing) 						       //causes trouble when ESP is searching for chars and this closes connection so this special flag to make sure it does not close connection while processing.
                    esp_ble_gattc_close(dev.gattc_if,dev.conn_id);   //close connection on setting
              }//for Alive
        break;
        case forDATA:
              ESP_LOGI(GATTC_TAG,"For DATA..");
              while(!dev.finish)			//finised with Data?  also have to add connection flag it ma get trapped if device is lost.
              {
                ESP_LOGI(GATTC_TAG,"Data Coming..");
                vTaskDelay(500/portTICK_RATE_MS);
              }
              if(!dev.processing)
                    esp_ble_gattc_close(dev.gattc_if,dev.conn_id);//close connection on setting
        break;
        case forRANGE:
              ESP_LOGI(GATTC_TAG,"For RANGE..");
        break;
        case NONE:
//              ESP_LOGI(GATTC_TAG,"for NONE.. should not be the Case you should Get.");
                  if(!dev.processing)
                    esp_ble_gattc_close(dev.gattc_if,dev.conn_id);//close connection on setting
        break;
        default:
              ESP_LOGI(GATTC_TAG,"default..(1)");
        break;
      }//switch
      if( !dev.Connected && !dev.scanning ) //not connected and not scanning then start Scanning.
        {
          dev.scanning=true;
          esp_ble_gap_start_scanning(Scanning_duration);
        }
	    vTaskDelay(200 / portTICK_RATE_MS);

    }//end while

Re: how do I go with logical flow for BLE GATT client?

Posted: Wed Aug 29, 2018 12:02 pm
by Pyponou
Hi Trialblazer 47,

I am having issue when closing a gatt client while it is reading/writing and I saw your comment :

Code: Select all

if(!dev.processing)                          //causes trouble when ESP is searching for chars and this closes connection so this special flag to make sure it does not close connection while processing.
                    esp_ble_gattc_close(dev.gattc_if,dev.conn_id);   //close connection on setting
              }//for Alive
When are you changing this dev.processing value to true ? It can maybe solve my issue.