bertmelis / espMqttClient

MQTT 3.1.1 client library for the Espressif devices ESP8266 and ESP32 on the Arduino framework.
https://www.emelis.net/espMqttClient/
MIT License
100 stars 21 forks source link

[BUG] #113

Closed dacattack closed 10 months ago

dacattack commented 12 months ago

Do not use to discuss topics!

Describe the bug This library seems to have some kind of problem when working together with i2s driver. I've done many tests and the results are always the same. I'm sending audio files read by the inmp441 MEMS. You can get a few published messages withouth any problem, in fact, it only takes around 300 microseconds to publish a 14KB message(which is amazing) but eventually it will freeze and next message will take around 800-1200 ms and that is not acceptable at all. If I disable I2S then this won't happen. Well actually the sending time its very unestable and some messages might take a few miliseconds, but always within a reasonable amount of time.

Which platform, esp8266 or esp32? I'm using ESP32 Do you use TLS or not? I do use TLS. Do you use an IDE (Arduino, Platformio...)? PlatformIO Which version of the Arduino framework? 2.0.9 Please include any debug output and/or decoded stack trace if applicable.

Expected behaviour Estable sending time. I can expect messages to vary a bit, but not this huge amount of time.

To Reproduce Steps to reproduce the behaviour: Set up the mqtt library, objects,functions and get a valid SSL/TLS certificate for your broker. Then include library "/driver/i2s.h" and configure the microphone i2s communications( SR of 16KHz, 16 bit data width) and then send the audio files with a QoS 2. Measure with the function micros() the time the library spent delivering the message to de broker.

Example code

#include "Arduino.h"
#include <driver/i2s.h>
#include "espMqttClient.h"
#include "certificados.hpp"

espMqttClientSecure mqttclient(espMqttClientTypes::UseInternalTask::NO);

const char* broker="192.168.1.xx";
const char* SSID="xxxxx";
const char* PASS="xxxxx";
const uint16_t port=8883;

static TaskHandle_t taskHandle;
bool connectFlag=false;

uint32_t SAMPLE_RATE = 16000;
#define I2SPORT I2S_NUM_0

void i2s_init(){
  i2s_config_t i2s_config={
    .mode = i2s_mode_t (I2S_MODE_MASTER |I2S_MODE_RX ),
    .sample_rate = SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 4 ,
    .dma_buf_len = 256,
    .use_apll = false,
    .tx_desc_auto_clear = false,
    .mclk_multiple = I2S_MCLK_MULTIPLE_256,
    .bits_per_chan = I2S_BITS_PER_CHAN_32BIT
  };
  i2s_pin_config_t i2s_pinout={
    .bck_io_num = 32,
    .ws_io_num = 25,
    .data_out_num = -1,
    .data_in_num = 33,
  };
  i2s_driver_install(I2SPORT, &i2s_config,0,NULL);
  i2s_set_pin(I2SPORT,&i2s_pinout);
}
void MqttLoopTask(){
  for(;;){
  mqttclient.loop();
  }
}
void mqttOnConnect( bool sessionPresent){
  Serial.print(" Conexión con broker realizada con éxito.\n");
  mqttclient.subscribe("cnn",2);
  connectFlag=true;
}
void mqttOnDisconnect( espMqttClientTypes :: DisconnectReason reason){
  Serial.print("Desconectado del broker.\n");
  mqttclient.subscribe("cnn",2);
  connectFlag=false;
}
void mqttConnection(){
  if(mqttclient.connect()) Serial.println("Dispositivo ESP32 se ha conectado al broker.\n");
  else {
    Serial.println("Dispositivo ESP32 no logró conectarse al broker, reintentando de forma burda...");
    delay(3000);
    ESP.restart();
  }
}
void mqttinit(){
    mqttclient.setCACert(WifiCA_cert);
    mqttclient.setServer(broker,port);
    mqttclient.onConnect(mqttOnConnect);
    mqttclient.onDisconnect(mqttOnDisconnect);
    //mqttclient.setTimeout()
    mqttConnection();
    xTaskCreatePinnedToCore((TaskFunction_t)MqttLoopTask,"MqttloopTask", 8192,nullptr, 3, &taskHandle,0);
    Serial.print("Esperando conexión con el brokercito. "); 
}
void setup(){                                              
   Serial.begin(115200);
   i2s_init();
   WiFi.begin(SSID,PASS);
   Serial.print("Conectándose a red .");
   while(WiFi.status() != WL_CONNECTED){
    Serial.print(" ."); delay(500);
   }
   Serial.print(" Conexión con red realizada exitosamente.\n");
   mqttinit();
}

uint16_t samples = 7000;
uint32_t buff_size = samples* sizeof(int16_t); 
int16_t *buff= (int16_t*)malloc(samples*sizeof(int16_t));
void loop(){
  uint32_t ti=0,tf=0, tsi=0, tsf=0, bytes_read=0;

   while(!connectFlag){
    Serial.print(" .");
    delay(400);
   }
   tsi=micros();
   esp_err_t i2s_err = i2s_read(I2SPORT, buff, buff_size, &bytes_read,pdMS_TO_TICKS(100));
   if(i2s_err != ESP_OK) {
    Serial.print("\nSe ha producido un fallo desconocido durante la comunicación i2s.\n");
    delay(5000);
    return;
   }
   tsf=micros();
   ti=micros();
   mqttclient.publish("prueba",2,false,(uint8_t*)buff,buff_size);
   tf=micros();
   Serial.printf("t_i2s=%u       t_mqtt: %u\n",(tsf-tsi),(tf-ti));
   //mqttclient.clearQueue(false); Not solving anything
}

Additional context Add any other context about the problem here.

bertmelis commented 12 months ago

Do you have any kind of debug log output so we can see what's going on? I suspect some sort of concurrency/mutex-code blocking execution.

dacattack commented 12 months ago

Indeed I believe is an issue realted with the semaphores used by the i2s driver and the mqtt library but I have no idea how to fix it. There's not much additional info coming from the debug. You can check this yourself using my code or your own code as long as you send i2s audio buffers. To be honest the problem also occurs using PubSubClient library. At this point is important to understand that it affects the execution time of the publish function not the i2s_read function. I hope we end up finding the issue. If I find any solution I'll post it here. Thanks

bertmelis commented 12 months ago

What is the exact behaviour you're seeing? Does the publish function block? Or do you have a "delayed receipt". Could you post the output of your Serial.print statements? You might want to delay() in your mqtt task.

I don't have an i2s device. I can't do real-world testing.

vortigont commented 11 months ago
void MqttLoopTask(){
  for(;;){
  mqttclient.loop();
  }
}

writing a task function that never blocks is very poor application design. You run the task at 0's core with prio 3 and it makes other tasks on the same core starve, which is network WiFi stack on core 0. You may consider adding a vTaskDelay(1 / portTICK_PERIOD_MS); to you loop or add taskYIELD(); and run your task with lowest prio.

bertmelis commented 10 months ago

Is this issue still relevant? Any progress?

bertmelis commented 10 months ago

Closing due to inactivity. feel free to reopen if the issue is still relevant.