Hello,
yes, as far as I have understood yet (but still reading the linked document, read a book about FreeRTOS before), the watch dogs are there, but they aren't my problem.
Since I try to cut down a sketch into a part just for asking on support for a logical question or in other words an algorithm, my sketch seems to not make sense anyway.
The task "xTaskSwitchScan" can be understood as a user pressing a button to start the WiFi scans, also another press of the button will stop them. But as written before, I do not like to just disable them if the user presses the button the second time, the loop should be finish its work. So telling a task to start somehow (using a variable like I've done here or using task notification or explicitly a semaphore does not solve my issue: between the detection for start the loop again and setting the variable, that a scan is now in progress it is possible that the FreeRTOS scheduler just cut the process here and switches to the main loop. The main loop may just then tell the scan task to not start a new scan, but detects that the bool variable (or another notification like a semaphore) has not been changed. This has nothing to do with the understanding of multi tasking.
I have two ideas:
a) change the check in the scan loop from "while(x){...}" to a "do{...portENTER_CRITICAL(&mux);...portEXIT_CRITICAL(&mux);...}while(x)"
b) chaning the task priority for the scan task in the main loop while the status is checked - but this only works if the main loop and the scan task run on the same core
For idea a) the scan task woo be changed to:
void xTaskWiFiScan(void* pvParameters) {
Serial.println("xTaskWiFiScan(): Executing on core " + String(xPortGetCoreID()));
Serial.println("B: xTaskWiFiScan started.");
int16_t n;
while (1) {
Serial.println("B: Scan allowed?");
do {
vTaskDelay(100 / portTICK_PERIOD_MS);
Serial.println("B: a) bWiFiScanStart=" + String(bWiFiScanStart) + ", bWiFiScanRunning=" + String(bWiFiScanRunning));
Serial.println("B: portENTER_CRITICAL.");
Serial.flush();
portENTER_CRITICAL(&mux);
if (bWiFiScanStart == true) {
Serial.println("B: vTaskDelay start.");
delay(5000);
Serial.println("B: vTaskDelay finished.");
bWiFiScanRunning = true;
}
portEXIT_CRITICAL(&mux);
Serial.println("B: portEXIT_CRITICAL.");
Serial.println("B: b) bWiFiScanStart=" + String(bWiFiScanStart) + ", bWiFiScanRunning=" + String(bWiFiScanRunning));
vTaskDelay(20000 / portTICK_PERIOD_MS);
Serial.println("B: after vTaskDelay");
Serial.println("B: c) bWiFiScanStart=" + String(bWiFiScanStart) + ", bWiFiScanRunning=" + String(bWiFiScanRunning));
} while (!bWiFiScanRunning);
Serial.println("B: WiFi status: " + String(WiFi.status()));
Serial.println("B: Start WiFi scan.");
WiFi.scanNetworks(true);
n = WiFi.scanComplete();
while (n < 0) {
Serial.print(".");
vTaskDelay(500 / portTICK_PERIOD_MS);
n = WiFi.scanComplete();
}
Serial.println(".");
Serial.println("B: " + String(n) + " network(s) found.");
WiFi.scanDelete();
bWiFiScanRunning = false;
Serial.println("B: Finished WiFi scan.");
vTaskDelay(WIFI_SCAN_PERIOD / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
I think this solution for just making sure that bWiFiScanStart is checked to be true and then bWiFiScanRunning is set to true seems to be a good solution. However, using a notification to wait for execution would be the next step.
Additional, the while loop can be simplified to
do {
vTaskDelay(100 / portTICK_PERIOD_MS);
portENTER_CRITICAL(&mux);
bWiFiScanRunning = bWiFiScanStart;
portEXIT_CRITICAL(&mux);
} while (!bWiFiScanRunning);
(and removed all testing code). I'm not sure if the critical commands are needed here because I don't know how the setting of the variable is done internally.
So with these changes and also using vTaskSuspend/vTaskResume the scan task can be controlled.
This also allows to skip the usage of notifications since the benefit for blocking a task without cpu consumption can be ignored.
The complete short sketch:
/*
* Using Arduino IDE v2.2.1
* Settings:
* Board: ESP32 / Wemos D1 Mini ESP32
* CPU frequency: 240 MHz (WiFi/BT)
* Core Debung Level: "verbose"
* Erase all Flash before sketch upload: disabled
* Flash Frequency: 80MHz
* Partition Scheme: Default
* Upload Speed: 921600
*
* Hardware:
* Wemos D1 Mini ESP32
*/
#include <WiFi.h>
#include <esp_wifi.h>
#define WIFI_SCAN_PERIOD 1000
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
bool bWiFiScanStart = false; // modified only in loop
bool bWiFiScanRunning = false; // modified only in xTaskWiFiScan
bool bEnableWiFi = false;
bool bWiFiEnabled = false; // WiFi on or off
bool bAskForDisablingWiFi = false;
TaskHandle_t hWiFiScanHandle;
TaskHandle_t hSwitchScanHandle;
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n\n\n");
xTaskCreatePinnedToCore(xTaskWiFiScan, "xTaskWiFiScan", 10000, NULL, 0, &hWiFiScanHandle, 0);
vTaskSuspend(hWiFiScanHandle);
xTaskCreatePinnedToCore(xTaskSwitchScan, "xTaskSwitchScan", 10000, NULL, 0, &hSwitchScanHandle, 1);
}
void enableWiFi() {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
if (esp_wifi_init(&cfg) == ESP_OK)
Serial.println("ok");
else
Serial.println("not ok");
Serial.print("D: esp_wifi_set_ps(WIFI_PS_NONE)=");
if (esp_wifi_set_ps(WIFI_PS_NONE) == ESP_OK)
Serial.println("ok");
else
Serial.println("not ok");
Serial.println("C: WiFi.setSleep(false)=" + String(WiFi.setSleep(false)));
esp_wifi_start();
Serial.println("C: WiFi.disconnect()=" + String(WiFi.disconnect()));
Serial.println("C: WiFi.mode(WIFI_STA)=" + String(WiFi.mode(WIFI_STA)));
bWiFiEnabled = true; // WiFi is enabled
bEnableWiFi = false; // do not enable again
Serial.println("C: WiFi turned on");
}
void disableWiFi() {
esp_err_t wifiStop = esp_wifi_stop();
Serial.print("D: esp_wifi_stop()=");
if (wifiStop == ESP_OK)
Serial.println("ok");
else if (wifiStop == ESP_ERR_WIFI_NOT_INIT)
Serial.println("ESP_ERR_WIFI_NOT_INIT");
else
Serial.println("not ok");
Serial.print("D: WiFi.setSleep(true)=");
if (WiFi.setSleep(true))
Serial.println("ok");
else
Serial.println("not ok");
Serial.print("D: esp_wifi_set_ps(WIFI_PS_MAX_MODEM)=");
if (esp_wifi_set_ps(WIFI_PS_MAX_MODEM) == ESP_OK)
Serial.println("ok");
else
Serial.println("not ok");
Serial.print("D: esp_wifi_deinit()=");
if (esp_wifi_deinit() == ESP_OK)
Serial.println("ok");
else
Serial.println("not ok");
bWiFiEnabled = false; // WiFi is disabled now
bAskForDisablingWiFi = false; // WiFi is disabled, do not disable again
Serial.println("D: WiFi turned off");
}
void loop() {
// do some other stuff
if (!bWiFiEnabled) // WiFi off?
{
if (bEnableWiFi) // should be turned on?
{
enableWiFi();
bWiFiScanStart = true; // Notification: start scans
vTaskResume(hWiFiScanHandle);
}
} else {
if (bAskForDisablingWiFi) // should be turned off?
{
bWiFiScanStart = false; // Notification: start no new scan
if (!bWiFiScanRunning) {
// no scan currently running
vTaskSuspend(hWiFiScanHandle);
disableWiFi();
} else {
Serial.print("#");
}
}
}
// continue with other stuff
delay(20);
}
void xTaskWiFiScan(void* pvParameters) {
Serial.println("B: xTaskWiFiScan started.");
int16_t n;
while (1) {
Serial.println("B: Scan allowed?");
do {
vTaskDelay(100 / portTICK_PERIOD_MS);
portENTER_CRITICAL(&mux);
bWiFiScanRunning = bWiFiScanStart;
portEXIT_CRITICAL(&mux);
} while (!bWiFiScanRunning);
Serial.println("B: WiFi status: " + String(WiFi.status()));
Serial.println("B: Start WiFi scan.");
WiFi.scanNetworks(true);
n = WiFi.scanComplete();
while (n < 0) {
Serial.print(".");
vTaskDelay(500 / portTICK_PERIOD_MS);
n = WiFi.scanComplete();
}
Serial.println(".");
Serial.println("B: " + String(n) + " network(s) found.");
WiFi.scanDelete();
bWiFiScanRunning = false;
Serial.println("B: Finished WiFi scan.");
vTaskDelay(WIFI_SCAN_PERIOD / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
// Dummy task, just for enabling and disabling WiFi
void xTaskSwitchScan(void* pvParameters) {
Serial.println("A: xTaskSwitchScan started.");
vTaskDelay(5000 / portTICK_PERIOD_MS);
bEnableWiFi = true;
Serial.println("A: Enable WiFi scan.");
vTaskDelay(60000 / portTICK_PERIOD_MS);
if (bWiFiEnabled) {
bAskForDisablingWiFi = true;
Serial.println("A: Start no more WiFi scan.");
}
while (bWiFiScanRunning) {
Serial.println("A: Check for running WiFi scan.");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
Serial.println("A: WiFi scan finished, WiFi can be turned off.");
vTaskDelay(30000 / portTICK_PERIOD_MS);
bEnableWiFi = true;
Serial.println("A: Enable WiFi scan.");
vTaskDelay(60000 / portTICK_PERIOD_MS);
if (bWiFiEnabled) {
bAskForDisablingWiFi = true;
Serial.println("A: Start no more WiFi scan.");
}
while (bWiFiScanRunning) {
Serial.println("A: Check for running WiFi scan.");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
Serial.println("A: WiFi scan finished, WiFi can be turned off.");
while (1) {
vTaskDelay(20000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
What do you think about??