How to send a chunk of data using shlib(nghttp2)?

alespressif73
Posts: 1
Joined: Mon Feb 15, 2021 12:20 pm

How to send a chunk of data using shlib(nghttp2)?

Postby alespressif73 » Tue Feb 16, 2021 1:24 pm

Hi,

I want to use HTTP2 to POST data continuously. As I found, the only solution is to use shlib. I can implement it and use it. But there are two problems that I faced:
1- shlib does not let us send a data bigger than 16KB theoretically. Here, the solution that I found was to feed the buffer couple of times without calling NGHTTP2_DATA_FLAG_EOF. But, the main problem is that we cannot return the size of the buffer which although is defined as int, but does not support more than 16K.
2- The fault rate of sending data more than about 3 to 4K goes exponentially high as in these situations, a few of packets are able to be sent correctly.

Any suggestion?
Thanks

I did all my bests to make sure that the resources don't interfere with each other. Here is my code:

Code: Select all


#include <Arduino.h>
#include <WiFiClientSecure.h>
#include "esp_camera.h"

extern "C" 
{
#include "sh2lib.h"
}

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif


// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22


const char* ssid     = "NETWORK";     // your network SSID (name of wifi network)
const char* password = "PASSWORD"; // your network password



bool request_finished = false;
 
String head = "--JPEG_IMAGE\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--JPEG_IMAGE--\r\n";

char data_to_post[16000];
uint32_t totalLen;
camera_config_t config;
struct sh2lib_handle hd;

bool is_captured;
bool is_posted;

uint16_t safety_counter;




void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(100);
  

  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  // attempt to connect to Wifi network:
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.print(".");
    // wait 1 second for re-trying
    delay(1000);
  }

  Serial.print("\n");
  Serial.print(F("Connected to: "));
  Serial.println(ssid);

  // Etablishing Connection
  Serial.println(F("Establishing Connection... "));
  if (sh2lib_connect(&hd, "My_Server") != ESP_OK) 
  {
    Serial.println("Error connecting to HTTP2 server");
    //vTaskDelete(NULL);
  }

  Serial.println(F("Connected to the webserver"));
  delay(1000);

  // Configuring the Cam
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  // init with high specs to pre-allocate larger buffers
  if(psramFound())
  {
    config.frame_size = FRAMESIZE_VGA;// FRAMESIZE_QVGA
    config.jpeg_quality = 10;  //0-63 lower number means higher quality
    config.fb_count = 2;
  } 
  else 
  {
    config.frame_size = FRAMESIZE_CIF;
    config.jpeg_quality = 12;  //0-63 lower number means higher quality
    config.fb_count = 1;
  }

  
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) 
  {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }
  
  
  
  
  // This task handles the POST requests
  xTaskCreatePinnedToCore(
    task_http2
    ,  "http2_task"
    ,  (1024 * 24)  // Stack size
    ,  NULL
    ,  3  // Priority
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);
    Serial.println(F("Task Called"));

}

void loop() 
{
  // To prohibit the interference between resources, I used main loop to capture the Images

  // Check if the posting has been finished
  if (is_posted)
  {
    Serial.println(F("Call to Capture"));
    camera_fb_t * fb = NULL;
    fb = esp_camera_fb_get();
    if(!fb) 
    {
      Serial.println("Camera capture failed");
      delay(1000);
      ESP.restart();
    }

    // to check if the size is not bigger than 16K
    uint32_t imageLen = fb->len;
    if(imageLen<16000)
    {  
      // Creating the body of the post
      uint32_t extraLen = tail.length()+head.length();
      totalLen = extraLen + imageLen;
      uint8_t *fbBuf = fb->buf;
      const char* head_char = head.c_str();
      const char* tail_char = tail.c_str();
      uint32_t totalLen_copy = totalLen;
      char alpha[totalLen];
      std::copy(head_char,head_char+head.length(), data_to_post);
      std::copy(fbBuf,fbBuf+imageLen , data_to_post+head.length());
      std::copy(tail_char,tail_char+ tail.length(), data_to_post+head.length()+imageLen);
      
      esp_camera_fb_return(fb);
      Serial.println(F("Camera captured"));
      delay(100);
      safety_counter++;
      // Stopping capturing until posting is finished
      is_captured = true;
      is_posted = false;
    }
  }

  delay(100);
  

}

int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
    if (len > 0) 
    {
        Serial.printf("%.*s\n", len, data);
        
    }
    
 
    if (flags == DATA_RECV_RST_STREAM) 
    {
        Serial.println("STREAM CLOSED");
    }
    return 0;
}

int handle_post_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
    if (len > 0) {
        Serial.printf("%.*s\n", len, data);
        // decreasing the counter to prevent fault loop
        safety_counter--;
    }
    
    //Serial.print(F("Safety_Counter in Response: ")); Serial.println(safety_counter);
 
    if (flags == DATA_RECV_RST_STREAM) {
        request_finished = true;
        Serial.println("STREAM CLOSED");
    }
    return 0;
}
 
int send_post_data(struct sh2lib_handle *handle, char *buf, size_t length, uint32_t *data_flags)
{
    // To check the body of the post
    /*
    Serial.println("Post Buffer");
    for(int i;i<totalLen;i++)
      Serial.print(data_to_post[i]);
    Serial.println("Post Buffer End");
    */

    
    if (totalLen < length) 
    {
        memcpy(buf, data_to_post, totalLen);
    }
    else 
    {
        Serial.println("Cannot write to buffer");
        //copylen = 0;
    }
 
    (*data_flags) |= NGHTTP2_DATA_FLAG_EOF;
    return totalLen;
}
 
void task_http2(void *args)
{

  Serial.println(F("Task Runs"));

  // Start capturing
  is_posted = true;                            

  int counter = 0;
  for(;;)
  {
    // if capturing finished:
    if(is_captured)
    {

      // after each five unsuccessful posts, reestablish the connection
      Serial.print(F("Safety_Counter is: ")); Serial.println(safety_counter);
      if(safety_counter>5)
      {
        is_posted = false;
        vTaskDelay(100);
        counter = 0;
        safety_counter = 0;
        sh2lib_free(&hd);
        vTaskDelay(100);
        Serial.println(F("Safety Counter Occured ... "));
        if (sh2lib_connect(&hd, "My_Server") != ESP_OK) 
        {
          Serial.println("Error connecting to HTTP2 server");
          //vTaskDelete(NULL);
        }
  
        Serial.println(F("Connected to the webserver"));
        vTaskDelay(1000);
        // Preparing capturing again
        is_posted = true;
        is_captured = false;
        continue;
      }
      
      
      char len[20];
      sprintf(len, "%d",totalLen); //length_of_body);
      Serial.print("the length is: ");
      Serial.println(len);
      const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "POST"),
                             SH2LIB_MAKE_NV(":scheme", "https"),
                             SH2LIB_MAKE_NV(":authority", hd.hostname),
                             SH2LIB_MAKE_NV(":path", "/mvp/upload_image"),
                             SH2LIB_MAKE_NV("Content-Length", len),
                             SH2LIB_MAKE_NV("Content-Type", "multipart/form-data; boundary=JPEG_IMAGE")
                            };
      sh2lib_do_putpost_with_nv(&hd, nva, sizeof(nva) / sizeof(nva[0]), send_post_data, handle_post_response);

      

      while (1) 
      {
   
        if (sh2lib_execute(&hd) != ESP_OK) 
        {
          Serial.println("Error in execute");
          break;
        }
     
        if (request_finished) 
        {
          // a general counter to reestablish the connection
          counter++;
          break;
        }
        
      //vTaskDelay(1000);
    }
      
      
    } 
    // General counter
    if(counter>30)
    {
      counter = 0;
      sh2lib_free(&hd);
      vTaskDelay(100);
      Serial.println(F("Establishing Connection... "));
      if (sh2lib_connect(&hd, "My_Server") != ESP_OK) 
      {
        Serial.println("Error connecting to HTTP2 server");
        //vTaskDelete(NULL);
      }

      Serial.println(F("Connected to the webserver"));
    }
    is_captured = false;
    is_posted = true;
    Serial.println("Sending finished");
    vTaskDelay(1000);
  }
 
}

Who is online

Users browsing this forum: No registered users and 74 guests