如何将 this 指针传递给 class 中的任务?
How to pass the this pointer to a task inside a class?
我正在创建一个库来管理我们在许多 ESP32 设备上的 wifi 网络连接。
在我的库中,我有一个循环任务,暂停 1 秒,从我的 .begin() 函数中的 xTaskCreate 开始。问题是,如果我没有在我的 .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);
}
}
您已经在这样做了,只是您没有意识到而已。看一下 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();
...
PS。另请注意(在您从不同线程访问同一对象之前,可能会导致难以发现的错误)FreeRTOS 提供了出色的线程间通信工具 - queues and task notifications often being the most useful ones. Check out their tutorial/book 进行了解释。
我正在创建一个库来管理我们在许多 ESP32 设备上的 wifi 网络连接。
在我的库中,我有一个循环任务,暂停 1 秒,从我的 .begin() 函数中的 xTaskCreate 开始。问题是,如果我没有在我的 .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);
}
}
您已经在这样做了,只是您没有意识到而已。看一下 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();
...
PS。另请注意(在您从不同线程访问同一对象之前,可能会导致难以发现的错误)FreeRTOS 提供了出色的线程间通信工具 - queues and task notifications often being the most useful ones. Check out their tutorial/book 进行了解释。