【问题标题】:How to pass the this pointer to a task inside a class?如何将this指针传递给类内的任务?
【发布时间】:2021-12-06 13:06:17
【问题描述】:

我正在创建一个库来管理我们在许多 ESP32 设备上的 wifi 网络连接。

在我的库中,我有一个以 .begin() 函数内部的 xTaskCreate 开始的 1 秒暂停循环的任务。问题是如果我没有在我的 .h 文件中将其设为静态,我将无法启动该任务。因此,一旦任务被声明为静态,我就无法访问此任务中的 this-> 指针。无论如何我可以在我的任务中发送 this-> 指针,比如在参数或类似的东西中?

这里有一些代码:

class EraWiFi{
    public:
        EraWiFi();
        /*!
        * @brief Initialize WiFi
        * @return Returns true if successful
        */

        bool begin(fs::FS &fs);
        /*!
        * @brief Start EraWiFi service
        * @return Returns true if successful
        */

        void downloadWiFi();

    private:
        static void wifiTask(void * parameter);
};


bool EraWiFi::begin(fs::FS &fs){
    File file = fs.open("/WiFi.json", FILE_READ);
    if(file){
        DynamicJsonDocument wifi(2048);
        DeserializationError error = deserializeJson(wifi, file);
        file.close();
        if (!error){
            Serial.println("We have a VALID WiFi.json configurations file!");
            Serial.println("Adding wifi networks:");
            for (JsonArray arr : wifi.as<JsonArray>()){
                Serial.print("SSID: ");
                Serial.print(arr[0].as<char*>());
                Serial.print(", KEY: ");
                Serial.println(arr[1].as<char*>());
                wifiMulti.addAP(arr[0].as<char*>(), arr[1].as<char*>());
            }
        }else{
            Serial.println("We don't have a VALID WiFi.json configurations file!");
        }
    }else{
        Serial.println("There is no WiFi.json configurations file!");
    }
    wifiMulti.addAP("Testing", "1234");
    xTaskCreate(
        this->wifiTask,    // Function that should be called
        "WiFiTask",   // Name of the task (for debugging)
        10000,            // Stack size (bytes)
        (void*)&this,            // Parameter to pass
        1,               // Task priority
        NULL   // Task handle
    );
    return true;
}



void EraWiFi::downloadWiFi(){
    Serial.println("Downloading WiFi.json from ErabliTEK Server.");
    HTTPClient http;
    // Send request
    http.useHTTP10(true);
    String url = "https://testing.testing.com/wifis/getWiFi/";
    http.begin(url);
    int httpResponseCode =  http.GET();
    if(httpResponseCode == HTTP_CODE_OK){
        // Parse response
        DynamicJsonDocument doc(2048);
        DeserializationError error = deserializeJson(doc, http.getStream());
        // Disconnect
        http.end();
        if (!error){
        File file = fs.open("/WiFi.json", FILE_WRITE);
        if(file){
            // Serialize JSON to file
            if (serializeJson(doc, file) == 0) {
            Serial.println("Error saving WiFi.json!");
            Serial.println(http.getString());
            }else{
            Serial.println("Succesfully saved WiFi.json!");
            }
        }
        // Close the file
        file.close();
        }else{
        Serial.println("Error downloading WiFi.json");
        }
    }else{
        Serial.println("Problem connecting to " + url + " with http code: " + String(httpResponseCode));
    }
}



void EraWiFi::wifiTask(void * parameters){
    bool wifiConnected = false;
    for(;;){
        uint8_t wifiStatus = wifiMulti.run();
        if((wifiStatus != WL_CONNECTED) and wifiConnected) {
            wifiConnected = false;
            Serial.println("WiFi not connected!");
        }else if((wifiStatus == WL_CONNECTED) and !wifiConnected){
            wifiConnected = true;
            Serial.println("WiFi Connected.");
            Serial.print("SSID: ");
            Serial.println(WiFi.SSID());
            Serial.print("KEY: ");
            Serial.println(WiFi.psk());
            Serial.print("IP Address: ");
            Serial.println(WiFi.localIP());
            EraWiFi::downloadWiFi();
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

【问题讨论】:

  • 请分享实际代码来演示问题。您的描述可能对您有意义,但对我们没有意义。编辑问题以包含有效但未执行您需要的代码,以及您尝试执行的代码,以及您尝试构建或运行时遇到的错误文本它。
  • 您可以将类的实例作为参数传递并使用 -> 访问成员,但这可能不是最佳解决方案。请发布一些代码或提供有关您的情况的更多详细信息。
  • 我已经用代码编辑了帖子。我的问题出在 EraWiFi::wifiTask 中,当我尝试调用 downloadWiFi() 函数时,我无法使用 this->downloadWiFi() 因为我必须将 wifiTask 声明为静态才能将其作为任务启动。
  • 您能否将 EraWiFi 的实例作为参数传递?您的函数声明可能类似于: static void wifiTask(EraWiFi* eraWifiObject, void * parameter);在函数中,您的 downloadWiFi() 调用看起来像 eraWifiObject->downloadWiFi();。不过,我觉得可能有更好的方法来处理这个问题。这个类之外的静态对象怎么样?唯一的私有成员是这个静态函数,因此将这个功能完全分开可能会更清楚。

标签: arduino wifi esp32 multitasking


【解决方案1】:

你已经在这样做了,只是你没有意识到。看看FreeRTOS documentation on xTaskCreate(),它解释了第四个参数pvParameters 是一个空指针,它作为其(唯一的)输入参数传递给新任务。

此处注释的行表示您正在获取 EraWiFi 对象的地址并将其传递给任务:

    xTaskCreate(
        this->wifiTask,
        "WiFiTask",
        10000,
        (void*)&this,  //< Pointer gets forwarded to the task
        1,
        NULL
    );

要在你的任务中使用指针,你只需要将它从void* 转换回来:

void EraWiFi::wifiTask(void * parameters){
    EraWifi* p = static_cast<EraWifi*>(parameters); //< That's the same pointer
    p->someMethod();
...

附言。另请注意(在您从不同线程戳同一对象之前,可能会导致难以发现的错误)FreeRTOS 提供了出色的线程间通信设施 - queuestask notifications 通常是最有用的。查看他们的tutorial/book 以获得解释。

【讨论】:

    猜你喜欢
    • 2016-07-20
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多