ESP32 Semaphores to connect to wifi and MQTT error Help

Hi everyone,
im starting a new topic here specific for semaphores to connect to MQTT and to wifi as the previous topic i was posting to was for an other thing.

I am trying to implant the code of an other very helpful member here (idohawalker) but im getting errors:

#include <ESP32Ping.h>
#include <WiFi.h>

#include <PubSubClient.h>
#define WIFI_NETWORK "mywifi"
#define WIFI_PASSWORD "mypass"
#define WIFI_TIMEOUT_MS 30000 // 30 second WiFi connection timeout
#define WIFI_RECOVER_TIME_MS 10000 // Wait 10 seconds after a failed connection attempt

const char* mqtt_server = "myserver";
#define mqtt_port 111111
#define MQTT_USER "user1"
#define MQTT_PASSWORD "pass1"
#define MQTT_SERIAL_PUBLISH_CH "app/myuser1"
#define MQTT_SERIAL_RECEIVER_CH "app/myuser1"
WiFiClient wifiClient;
PubSubClient MQTT_client(wifiClient);




SemaphoreHandle_t MQTT_ConnectListen;
SemaphoreHandle_t InternetConnection;
SemaphoreHandle_t InternetStatus;

bool isonline=false;


void MQTT_callback(char* topic, byte *payload, unsigned int length) {
   // Serial.println("-------new message from broker-----");
   // Serial.print("channel:");
   // Serial.println(topic);
    Serial.print("data:");  
    //Serial.write(payload, length);
    //Serial.println(payload);
    Serial.println();
      int i = 0;
      char strPayload[300];
  for ( i; i < length; i++)
  {
    strPayload[i] = ((char)payload[i]);
  }
  strPayload[i] = NULL;
  MQTTparser(topic,strPayload);
}

void setup() {

  Serial.begin(115200);
  // Set time out for
  Serial.setTimeout(500);
  delay(5000); 

   MQTT_ConnectListen = xSemaphoreCreateBinary();
   InternetConnection = xSemaphoreCreateBinary();
   InternetStatus = xSemaphoreCreateBinary();
    
                   
   xTaskCreatePinnedToCore(InternetConnectionCode,"InternetConnection",5000,NULL,2,&InternetConnection,1);
   xTaskCreatePinnedToCore(MQTT_ConnectListenCode,"MQTT_ConnectListen",30000,NULL,2,&MQTT_ConnectListen,1);  
   xTaskCreatePinnedToCore(InternetStatusCode,"InternetStatus",5000,NULL,2,&InternetStatus,1);                   
                                    
   delay(2000);


}


void loop() {

}

void MQTT_ConnectListenCode( void * pvParameters ){
  MQTT_client.setServer(mqtt_server, mqtt_port);
  MQTT_client.setCallback(MQTT_callback);  
  for(;;){
       if(isonline = false){
            vTaskDelay(10000 / portTICK_PERIOD_MS);
            continue;
        } 
       if (!MQTT_client.connected()) {
       // Loop until we're reconnected
         while (!MQTT_client.connected()) {
         Serial.print("Attempting MQTT connection...");
     // Create a random client ID
          String clientId = "user1";
    //clientId += String(random(0xffff), HEX);
    // Attempt to connect
           if (MQTT_client.connect(clientId.c_str(),MQTT_USER,MQTT_PASSWORD)) {
               Serial.println("connected");
               //vTaskDelay(1000/portTICK_PERIOD_MS);
      //Once connected, publish an announcement...
     
      // ... and resubscribe
               MQTT_client.subscribe(MQTT_SERIAL_RECEIVER_CH,1);
           } else {
               Serial.print("failed, rc=");
               Serial.print(MQTT_client.state());
               Serial.println(" try again in 5 secondssss");
               vTaskDelay(5000/portTICK_PERIOD_MS);
              continue;
             }
        }
      }
      else{
        xSemaphoreTake(MQTT_ConnectListen,portMAX_DELAY);
        MQTT_client.loop();
        xSemaphoreGive(MQTT_ConnectListen);
      }       
  }
   
}

void InternetConnectionCode( void * pvParameters ){
int first=0;
    for(;;){
      if(first==0){
            Serial.println("initiallising");
            first=1;
            vTaskDelay(1000 / portTICK_PERIOD_MS);
            continue;
      }
        if(WiFi.status() == WL_CONNECTED){
            vTaskDelay(10000 / portTICK_PERIOD_MS);
            continue;
        }

        Serial.println("[WIFI] Connecting");
        WiFi.mode(WIFI_STA);
        WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);

        unsigned long startAttemptTime = millis();

        // Keep looping while we're not connected and haven't reached the timeout
        while (WiFi.status() != WL_CONNECTED && 
                millis() - startAttemptTime < WIFI_TIMEOUT_MS){}

        // When we couldn't make a WiFi connection (or the timeout expired)
      // sleep for a while and then retry.
        if(WiFi.status() != WL_CONNECTED){
            Serial.println("[WIFI] FAILED");
            vTaskDelay(WIFI_RECOVER_TIME_MS / portTICK_PERIOD_MS);
        continue;
        }  
    }
    
}
void InternetStatusCode( void * pvParameters ){
    for(;;){
        if(Ping.ping("google.com")) {
           isonline=true;
           Serial.println("hi");
           vTaskDelay(250/portTICK_PERIOD_MS);
           continue;
        } 
        else {
           isonline=false;
           Serial.println("Error connecting to wifi);
           vTaskDelay(10000/portTICK_PERIOD_MS);
           continue;
        }
    }
}

void MQTT_parser(char * ttopic, char* ppayload)
{
  //print message just for test
  Serial.print(ppayload);
}

Code was working untill i tried the semaphore things:

        xSemaphoreTake(MQTT_ConnectListen,portMAX_DELAY);
        MQTT_client.loop();
        xSemaphoreGive(MQTT_ConnectListen);

instead of:

MQTT_client.loop();

error:

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8
initiallising
Attempting MQTT connection...failed, rc=-2 try again in 5 secondssss
Error connecting to wifi
[WIFI] Connecting
Attempting MQTT connection...connected
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c:1443 (xQueueGenericReceive)- assert failed!
abort() was called at PC 0x40088885 on core 1

Backtrace: 0x4008c434:0x3ffd0ae0 0x4008c665:0x3ffd0b00 0x40088885:0x3ffd0b20 0x400d137b:0x3ffd0b60 0x40088b7d:0x3ffd0ba0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:9720
ho 0 tail 12 room 4
load:0x40080400,len:6352
entry 0x400806b8

What am i missing here? I only tried to use semaphores for first time and only in one place of the code

Try installing and running the Exception Decoder.

Im trying to install it but doesnt seem to work. i have a java file instead of jar. tried to run the script but it seems like a unix script which doesnt work

EDIT:
i beg your pardon i had downloaded the source

[i]Decoding stack results[/i]
[color=green]0x4008c434: [/color][b][color=blue]invoke_abort[/color][/b] at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/[b]panic.c[/b] line [b]155[/b]
[color=green]0x4008c665: [/color][b][color=blue]abort[/color][/b] at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/[b]panic.c[/b] line [b]170[/b]
[color=green]0x40088885: [/color][b][color=blue]xQueueGenericReceive[/color][/b] at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/[b]queue.c[/b] line [b]1443[/b]
[color=green]0x400d137f: [/color][b][color=blue]MQTT_ConnectListenCode(void*)[/color][/b] at C:\Users\CT\Documents\Arduino\myproj\myproj/[b]myproj.ino[/b] line [b]146[/b]
[color=green]0x40088b7d: [/color][b][color=blue]vPortTaskWrapper[/color][/b] at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/[b]port.c[/b] line [b]143[/b]

From the FreeRTOS doc:

The semaphore is created in the ’empty’ state, meaning the semaphore must first be given using the xSemaphoreGive() API function before it can subsequently be taken (obtained) using the xSemaphoreTake() function.

 xSemaphoreTake(MQTT_ConnectListen,portMAX_DELAY);[color=#222222]

How can the semaphore take when a semaphore is never given? At that point portMax_DELAY will time out and cause a WDT or GURU meditation error.
There are way to bypass the take on timeout of portMax_Delay but you've not coded for it.

Again how can a take be done when a give has not been done?

Idahowalker:
Again how can a take be done when a give has not been done?

That's clearly a problem but it's not very intuitive for a binary semaphore. Before reading the doc, I assumed that just creating it would make it ready to be taken. Clearly that's not the case, but I don't understand why.

This is needless/useless and stops the entire CPU from running

 delay(2000);

wildbill:
That's clearly a problem but it's not very intuitive for a binary semaphore. Before reading the doc, I assumed that just creating it would make it ready to be taken. Clearly that's not the case, but I don't understand why.

How can a semaphore token be taken if a semaphore token is not given?

You like candy, I have candy. When I put a candy on a table, you take it. If I do not put candy on the table for you to take then how can you take candy that is not there for you to take?

What's so difficult to understand about that?

The difficulty is that a binary semaphore can conceptually have two states - given or taken. But it seems here that it actually has three states - given, taken and unintialized. I'm sure there is a good reason for it, I just can't see what it is.

A binary semaphore has 2 states, given (0) or taken(1). The default is not given(0). The semaphore is initialized to not given(0) as explained in the documentation, freeRTOS, The incorrect assumption is that when the semaphore is assigned a handle the semaphore is already given a token of 1; which is not the case.

A binary semaphore token is either 1 or 0. When created its a zero.

bool IamTrue; <<< What's the default value of of that declared variable? Not true, 0. To make it true a one/true is assigned; such as bool IamTRue = true; Just like the semaphore.

Of course a semaphore can be uninitialized SemaphoreHandle_t MQTT_ConnectListen; is an declared semaphore with a semaphore handle of null.

Here InternetConnection = xSemaphoreCreateBinary(); the semaphore is initialized with a handle and is created with a token of 0.

Here xSemaphoreGive(MQTT_ConnectListen); the semaphore si being assigned a value of not 0.

Idahowalker:
A binary semaphore has 2 states, given (0) or taken(1). The default is not given(0).

Makes sense - thanks.

    MQTT_ConnectListen = xSemaphoreCreateBinary();
    InternetConnection = xSemaphoreCreateBinary();
    InternetStatus = xSemaphoreCreateBinary();
    xSemaphoreGive(MQTT_ConnectListen);
    xSemaphoreGive(InternetConnection);
    xSemaphoreGive(InternetStatus);

Im not sure how exactly semaphores work thats why i didnt "give". Im trying to learn it through tests on my code.

I used xSemaphoreGive now for all but still doesnt seem to work.. What do i miss now?

What does it does not work mean?

Do you expect me to figure out why it does not work with just a code snippet?

Why not start all over with the code I had posted that works?

Post your does not work code and explain what you mean it does not work.

What does this InternetConnection = xSemaphoreCreateBinary(); do? Why do you need it? Where is the code?

What does this InternetStatus = xSemaphoreCreateBinary(); do? Why do you need it? Where is the code?

This works:

#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
//#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
////
Adafruit_BME280 bme280( GPIO_NUM_5 ); // hardware SPI
////
WiFiClient   wifiClient;
PubSubClient MQTTclient( mqtt_server, mqtt_port, wifiClient );
////
SemaphoreHandle_t sema_MQTT_KeepAlive;
////
byte mac[6];
////
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
      break;
    default: break;
  }
}
////
void setup()
{
  sema_MQTT_KeepAlive   = xSemaphoreCreateBinary();
  xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
  ////
  SPI.begin();
  bme280.begin();
  xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 20000, NULL, 3, NULL, 1 );
  xTaskCreatePinnedToCore( DoTheBME280Thing, "DoTheBME280Thing", 20000, NULL, 4, NULL, 1);
} //void setup()
//
void DoTheBME280Thing( void *pvParameters )
{
  float temperature = 0.0f;
  float pressure    = 0.0f;
  float humidity    = 0.0f;
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  for (;;)
  {
    temperature = ( 1.8f * bme280.readTemperature() ) +32.0f;
    pressure    = bme280.readPressure() / 133.3223684f; // mmHg
    humidity    = bme280.readHumidity();
    log_i( " temperature %f, Pressure %f, Humidity %f", temperature, pressure, humidity);
    xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
    if ( MQTTclient.connected() )
    {
      MQTTclient.publish( topicInsideTemp, String(temperature).c_str() );
      vTaskDelay( 2 ); // gives the Raspberry Pi 4 time to receive the message and process
      MQTTclient.publish( topicInsideHumidity, String(humidity).c_str() );
      vTaskDelay( 2 ); // no delay and RPi is still processing previous message
      MQTTclient.publish( topicInsidePressure, String(pressure).c_str() );
    }
    xSemaphoreGive( sema_MQTT_KeepAlive );
    vTaskDelay( 1000 * 15 );
    log_i( "DoTheBME280Thing high watermark %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete ( NULL );
}
////
/*
    Important to not set vTaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
    makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
  // setting must be set before a mqtt connection is made
  MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
  for (;;)
  {
    //check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
    if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
    {
      xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
      MQTTclient.loop();
      xSemaphoreGive( sema_MQTT_KeepAlive );
    }
    else {
      log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
      if ( !(WiFi.status() == WL_CONNECTED) )
      {
        connectToWiFi();
      }
      connectToMQTT();
    }
    vTaskDelay( 250 ); //task runs approx every 250 mS
  }
  vTaskDelete ( NULL );
}
////
void connectToMQTT()
{
  // create client ID from mac address
  String clientID = String(mac[0]) + String(mac[5]) ;
  log_i( "connect to mqtt as client %s", clientID );
  while ( !MQTTclient.connected() )
  {
    MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
    log_i( "connecting to MQTT" );
    vTaskDelay( 250 );
  }
  log_i("MQTT Connected");
}
//
void connectToWiFi()
{
  log_i( "connect to wifi" );
  while ( WiFi.status() != WL_CONNECTED )
  {
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    log_i(" waiting on wifi connection" );
    vTaskDelay( 4000 );
  }
  log_i( "Connected to WiFi" );
  WiFi.macAddress(mac);
  log_i( "mac address %d.%d.%d.%d.%d", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]  );
  WiFi.onEvent( WiFiEvent );
}
////
void loop() { }

Hi,
it doesnt work i mean i get the errors like before:

[WIFI] Connecting
Attempting MQTT connection...connected
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c:1443 (xQueueGenericReceive)- assert failed!
abort() was called at PC 0x40088885 on core 1

Backtrace: 0x4008c434:0x3ffd0a50 0x4008c665:0x3ffd0a70 0x40088885:0x3ffd0a90 0x400d137f:0x3ffd0ad0 0x40088b7d:0x3ffd0b10

Rebooting...
ets Jun  8 2016 00:22:57

im only trying to use take and give in one task just to test it and understand how it works..but it wont run..

thank you!

PS im trying to implant your code into my code. thanks :slight_smile:

Why do you need the other semaphores? What resource do they protect? Where is your don't work code?

So far, from your posted code #0, you only need one semaphore and that is to prevent client loop from running when there is a publish and to prevent a publish from happening when client loop is running.

Idahowalker:
Why do you need the other semaphores? What resource do they protect? Where is your don't work code?

So far, from your posted code #0, you only need one semaphore and that is to prevent client loop from running when there is a publish and to prevent a publish from happening when client loop is running.

I am not using the other semaphores atm.i Just registered them in the sketch. is that an issue you think?
btw im trying to run a sample code from a tutorial online but it only causes reboots(FreeRTOS Binary Semaphore Tasks Interrupt Synchronization Arduino):

#include <Arduino_FreeRTOS.h>
#include "semphr.h"
#define  LED  13
SemaphoreHandle_t xBinarySemaphore;
void setup()
{
  Serial.begin(9600);
  pinMode(LED ,OUTPUT);
  xBinarySemaphore = xSemaphoreCreateBinary();
  xTaskCreate(LedOnTask, "LedON",100,NULL,1,NULL);
  xTaskCreate(LedoffTask, "LedOFF", 100,NULL,1,NULL);
  xSemaphoreGive(xBinarySemaphore);
}

void loop(){}
void LedOnTask(void *pvParameters)
{
  while(1)
  {
   xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
   Serial.println("Inside LedOnTask");
   digitalWrite(LED,LOW);
   xSemaphoreGive(xBinarySemaphore);
   vTaskDelay(1);
  }
}
void LedoffTask(void *pvParameters)
{
  while(1)
  {
    xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
    Serial.println("Inside LedffTask");
    digitalWrite(LED,HIGH);
    xSemaphoreGive(xBinarySemaphore);
    vTaskDelay(1);
  }
}

i removed those lines because it wouldnt compile otherwise for ESP32:
#include <Arduino_FreeRTOS.h>
#include "semphr.h"

chris700:
I am not using the other semaphores atm.i Just registered them in the sketch. is that an issue you think?
btw im trying to run a sample code from a tutorial online but it only causes reboots(FreeRTOS Binary Semaphore Tasks Interrupt Synchronization Arduino):

#include <Arduino_FreeRTOS.h>

#include "semphr.h"
#define  LED  13
SemaphoreHandle_t xBinarySemaphore;
void setup()
{
 Serial.begin(9600);
 pinMode(LED ,OUTPUT);
 xBinarySemaphore = xSemaphoreCreateBinary();
 xTaskCreate(LedOnTask, "LedON",100,NULL,1,NULL);
 xTaskCreate(LedoffTask, "LedOFF", 100,NULL,1,NULL);
 xSemaphoreGive(xBinarySemaphore);
}

void loop(){}
void LedOnTask(void *pvParameters)
{
 while(1)
 {
  xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
  Serial.println("Inside LedOnTask");
  digitalWrite(LED,LOW);
  xSemaphoreGive(xBinarySemaphore);
  vTaskDelay(1);
 }
}
void LedoffTask(void *pvParameters)
{
 while(1)
 {
   xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);
   Serial.println("Inside LedffTask");
   digitalWrite(LED,HIGH);
   xSemaphoreGive(xBinarySemaphore);
   vTaskDelay(1);
 }
}



i removed those lines because it wouldnt compile otherwise for ESP32:
#include <Arduino_FreeRTOS.h>
#include "semphr.h"

PS im not using the other semaphores at the moment but i read somewhere that i need semaphores for all tasks to sychronize them.. thats why i registered them all. i thought later i need to write more code to sychronize them

**errors during compiling the sketch from the tutorial:
exit status 1
Error compiling for board ESP32 Dev Module.

Also when i go to the examples freertos is replaced by "INCOMPATIBLE" :confused:

Are you seriously using this #include <Arduino_FreeRTOS.h> on an ESP32?