[RESOLU] Soucis pour transposition d'un fichier C vers C++

Hello la commu !

J'ai un petit souci pour passer d'un fichier d'exemple en C vers mon fichier C++ sur mon projet.

Fichier d'origine:

request.onReadyStateChange(requestCB);
void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState) 
{
  (void) optParm;
  
  if (readyState == readyStateDone) 
  {
    Serial.println("\n**************************************");
    Serial.println(request->responseText());
    Serial.println("**************************************");
    
    request->setDebug(false);
  }
}

Passé dans mon fichier:

en .h: void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);
this->request.onReadyStateChange(this->requestCB);
void ASYNC_HTTP::requestCB(void* optParm, AsyncHTTPRequest* this->request, int readyState) 
{
  (void) optParm;
  
  if (readyState == readyStateDone) 
  {
    Serial.println("\n**************************************");
    Serial.println(request->responseText());
    Serial.println("**************************************");
    
    request->setDebug(false);
  }
}

Et le compilateur qui me crache à la tête avec ces paroles insensées :

sketch\asyncHTTP.cpp: In constructor 'ASYNC_HTTP::ASYNC_HTTP()':

asyncHTTP.cpp:7:51: error: no matching function for call to 'ASYNC_HTTP::requestCB()'

  this->request.onReadyStateChange(this->requestCB());

                                                   ^

sketch\asyncHTTP.cpp:7:51: note: candidate is:

In file included from sketch\asyncHTTP.cpp:1:0:

sketch\asyncHTTP.h:42:8: note: void ASYNC_HTTP::requestCB(void*, AsyncHTTPRequest*, int)

   void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);

        ^

sketch\asyncHTTP.h:42:8: note:   candidate expects 3 arguments, 0 provided

sketch\asyncHTTP.cpp: At global scope:

asyncHTTP.cpp:31:61: error: expected ',' or '...' before 'this'

 void ASYNC_HTTP::requestCB(void* optParm, AsyncHTTPRequest* this->request, int readyState) 

                                                             ^

asyncHTTP.cpp:31:6: error: prototype for 'void ASYNC_HTTP::requestCB(void*, AsyncHTTPRequest*)' does not match any in class 'ASYNC_HTTP'

 void ASYNC_HTTP::requestCB(void* optParm, AsyncHTTPRequest* this->request, int readyState) 

      ^

In file included from sketch\asyncHTTP.cpp:1:0:

asyncHTTP.h:42:8: error: candidate is: void ASYNC_HTTP::requestCB(void*, AsyncHTTPRequest*, int)

   void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);

        ^

exit status 1
no matching function for call to 'ASYNC_HTTP::requestCB()'

Que dois-je faire ? Corriger le code avec votre aide ou appeler un exorciste ?_?
Vous avez dans ce cas des numéros de tél à me proposer pour pas cher xD ??

J'ai un petit souci pour passer d'un fichier d'exemple en C vers mon fichier C++ sur mon projet.

Le C++ englobe le C. Si un code fonctionne en C, il marche en C++, l'inverse n'est pas forcément vrai.
Comme le code n'est pas complet, on ne peut pas vraiment savoir pourquoi il y a une erreur.

Ca je sais que si ca fonctionne en C ca fonctionne en C++ (quoi que .... +_+ )

Moi je veux bien poster le code, mais ca va rien changer le souci vient de ce que j'ai indiqué dans mon premier post.

CODE D'ORIGINE:

#if !( defined(ESP8266) ||  defined(ESP32) )
  #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
#endif

// Level from 0-4
#define ASYNC_HTTP_DEBUG_PORT     Serial
#define _ASYNC_HTTP_LOGLEVEL_     0    

// 300s = 5 minutes to not flooding
#define HTTP_REQUEST_INTERVAL     10  //300

// 10s
#define HEARTBEAT_INTERVAL        10

int status;     // the Wifi radio's status

const char* ssid        = "RAX40_EXT";
const char* password    = "Thi$GreatPa$word";

#if (ESP8266)
  #include <ESP8266WiFi.h>
#elif (ESP32)
  #include <WiFi.h>
#endif

#include <AsyncHTTPRequest_Generic.h>           // https://github.com/khoih-prog/AsyncHTTPRequest_Generic
#include <Ticker.h>

AsyncHTTPRequest request;
Ticker ticker;
Ticker ticker1;

void sendRequest() 
{
  static bool requestOpenResult;
  
  if (request.readyState() == readyStateUnsent || request.readyState() == readyStateDone)
  {
    //requestOpenResult = request.open("GET", "http://worldtimeapi.org/api/timezone/Europe/London.txt");
    requestOpenResult = request.open("GET", "http://10.0.0.45/MOOBOX/?e=EaTcB*hr2aTN2auM*aYrr*9oB**_ki*Akv}ZE5TZocN91**ao2*Mnia5N2z5N2l6yM{Jjv{LhMjD");
    
    if (requestOpenResult)
    {
      // Only send() if open() returns true, or crash
      request.send();
    }
    else
    {
      Serial.println("Can't send bad request");
    }
  }
  else
  {
    Serial.println("Can't send request");
  }
}

void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState) 
{
  (void) optParm;
  
  if (readyState == readyStateDone) 
  {
    Serial.println("\n**************************************");
    Serial.println(request->responseText());
    Serial.println("**************************************");
    
    request->setDebug(false);
  }
}

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial);
  
  Serial.println("\nStarting AsyncHTTPRequest_ESP using " + String(ARDUINO_BOARD));
  Serial.println(ASYNC_HTTP_REQUEST_GENERIC_VERSION);

  WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
  
  Serial.println("Connecting to WiFi SSID: " + String(ssid));

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  Serial.print(F("\nHTTP WebServer is @ IP : "));
  Serial.println(WiFi.localIP());
 
  request.setDebug(false);
  
  request.onReadyStateChange(requestCB);
  sendRequest();  
}

void loop()
{ 
static unsigned long ms = millis();
Serial.println((String)millis() + ">loop");
if (millis() - ms > 5000UL) {
		sendRequest();
		ms = millis();
	}
	delay(100);
}

Mon fichier .h:

#ifndef ASYNCHTTP_h
#define ASYNCHTTP_h

#include <Arduino.h>

#if !( defined(ESP8266) ||  defined(ESP32) )
  #error This code is intended to run on the ESP8266 or ESP32 platform! Please check your Tools->Board setting.
#endif

// Level from 0-4
#define ASYNC_HTTP_DEBUG_PORT     Serial
#define _ASYNC_HTTP_LOGLEVEL_     0    

// 300s = 5 minutes to not flooding
#define HTTP_REQUEST_INTERVAL     10  //300

// 10s
#define HEARTBEAT_INTERVAL        10

#if (ESP8266)
  #include <ESP8266WiFi.h>
#elif (ESP32)
  #include <WiFi.h>
#endif

#include <AsyncHTTPRequest_Generic.h>           // https://github.com/khoih-prog/AsyncHTTPRequest_Generic
#include <Ticker.h>
#include "mstring.h"

class ASYNC_HTTP {
	public:
		ASYNC_HTTP();
		void setWifiByConfigFile(String _rawConfigFile);
		bool isConnected();
	private:
		AsyncHTTPRequest request;
		Ticker ticker;
		Ticker ticker1;
		String SSID, password;;
		MSTRING mstring;
		void clientSetup();
		void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);
};







#endif

Mon fichier .cpp:

#include "asyncHTTP.h"

ASYNC_HTTP::ASYNC_HTTP() {
	this->request.setDebug(false);
	this->SSID = "";
	this->password = "";
	this->request.onReadyStateChange(this->requestCB);
	//WiFi.disconnect(false);
}

void ASYNC_HTTP::clientSetup() {
	// Démarrage de la connection WIFI
	WiFi.begin(this->SSID.c_str(), this->password.c_str());
	delay(100);
}

bool ASYNC_HTTP::isConnected() {
	static unsigned long lastQuery = millis();
	static int lastState = WiFi.status();
	if (millis() - lastQuery > 500UL) {lastState = WiFi.status();}
	if (lastState == WL_CONNECTED) {return true;} else {return false;}
	//if (WiFiMulti.run() == WL_CONNECTED) {return true;} else {return false;}
}

void ASYNC_HTTP::setWifiByConfigFile(String _rawConfigFile) {
	this->SSID = mstring.extractString(_rawConfigFile, "SSID");
	this->password = mstring.extractString(_rawConfigFile, "SSIDPWD");
	this->clientSetup();
}

void ASYNC_HTTP::requestCB(void* optParm, AsyncHTTPRequest* this->request, int readyState) 
{
  (void) optParm;
  
  if (readyState == readyStateDone) 
  {
    Serial.println("\n**************************************");
    Serial.println(request->responseText());
    Serial.println("**************************************");
    
    request->setDebug(false);
  }
}

dans le fichier .h il y a:
void requestCB(....

Dans le .cpp il indique une erreur:
this->request.onReadyStateChange(this->requestCB);

Je ne sais pas ou elle est défini, mais tu passes en paramètre le résultat d'une fonction qui n'en a pas (elle est void!)

J'ai beau retourner le truc dans tous les sens, je vois pas +_+

Précises ce qui ne va pas.

En gros c'est comme si je te demandes "combien fait 2 à la puissance?", ou "quelle est la moyenne?".

ce code d'originerequest.onReadyStateChange(requestCB);donne en paramètre un pointeur sur la fonction requestCB(). ça déclare un callback.

La fonction n'étant je suppose pas liée à l'instance en cours (sinon vous aurez des soucis, il faudrait qu'elle soit static), il suffit de passer encore le pointeur sur la fonctionthis->request.onReadyStateChange(requestCB);
il faut bien sûr que requestCB soit connue.

vileroi:
Précises ce qui ne va pas.

En gros c'est comme si je te demandes "combien fait 2 à la puissance?", ou "quelle est la moyenne?".

Dans mon premier post, j'indique ce qui ne va pas avec la réponse du compilateur.
Merci de la réponse J-M-L :slight_smile:
Mais le compilo gueule avec

asyncHTTP.cpp:7:44: error: no matching function for call to 'AsyncHTTPRequest::onReadyStateChange(<unresolved overloaded function type>)'

Et autant d'habitude ca va avec les erreurs, autant là j'ai jamais été confronté à ça et je sais pas comment le résoudre....

j'avais pas regardé votre code. vous n'avez pas une fonction globale requestCB mais c'est une méthode de votre classe void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);dans la partie privée

	private:
		AsyncHTTPRequest request;
		Ticker ticker;
		Ticker ticker1;
		String SSID, password;;
		MSTRING mstring;
		void clientSetup();
		void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState);

comme dit ci dessus, vous ne pouvez pas passer un pointeur sur cette méthode, ça ne veut rien dire puisque la méthode n'a pas d'intérêt sans son contexte, l'instance sur laquelle elle doit s'exécuter.

Oui ça je me doute.

Le code suivant fonctionne pour le moment:

fichier .cpp
void requestCB(void* optParm, AsyncHTTPRequest* request, int readyState)
{
  (void) optParm;
  
  if (readyState == readyStateDone) 
  {
    Serial.println("\n**************************************");
    Serial.println(request->responseText());
    Serial.println("**************************************");
    
    request->setDebug(false);
  }
}
ASYNC_HTTP::ASYNC_HTTP() {
	this->request.setDebug(false);
	this->SSID = "";
	this->password = "";
	this->request.onReadyStateChange(&requestCB);
	//WiFi.disconnect(false);
}

Donc il n'y a vraiment pas moyen d'appeler un callback dans un objet ?

on peut, mais il faut que la fonction soit static ou globale, ie qu'elle existe indépendamment de toute instance.
Si vous voulez retrouvez quelle instance a déclenché le trigger, il faut se débrouiller pour qu'un paramètre (un index dans un tableau d'instances, un pointeur vers l'instance,...) soit passé au callback pour rétablir un contexte d'appel correct.

OOOKKKKK c'est plus clair.
Vais essayer de me débrouiller pour faire ça mais je sens que je vais en chier ^^

Oui mais en fait euh... nan xD
Il faut que je passe "this" du coup en paramètre si je veux retrouver mon objet; c'est ca ?

Oui mais this c’est compliqué à passer

En prenant un pas de recul pourquoi avez vous besoin d’encapsuler votre machin dans une classe? Vous allez avoir plusieurs instances dans une app? Si non, faites juste une bibliothèque de fonctions

Plusieurs instances oui. Et c'est une methode de cette classe qui appelle une requete et je voulais que cette requete réponde au bon objet. Mais j'ai réussi au final avec le code plus haut, et un objet global (HOU ! honte, rejet, haine !!!) qui gère les ID des requetes. Car passer le this effectivement.... Et de plus ça demandais de modifier la librairy d'origine.
En gros, ma solution: j'effectue une requete et je lui attribue une ID. Et je check dans le loop (pas vraiment mais c'est c'est l'idée ^^) si la requete ID est aboutie et si oui je vais chercher les résultats. Obligé de passer l'id au serveur par contre qui la renvoie dans la réponse pour que ça passe dans le bon tuyau à la reception :slight_smile:
C'est barbare, mais ça fonctionne encore mieux que je ne l'espérai car du coup ça facilite un morceau que je devais faire après ^^

Merci J-M-L en tout cas :slight_smile:

Ninnin:
Plusieurs instances oui.

vous comptez faire tourner plusieurs serveurs HTTP sur votre arduino?

Non, disons que chaque objet a son propre appel serveur. C'est compliqué ^^
Et c'est un client, pas un serveur :-p

oui l'approche retenue correspond à une façon de faire.

L'autre solution, si vous voulez cacher tout cela dans la classe, c'est d'avoir un tableau/liste/vecteur static (variable de classe) qui mémorise tous les pointeurs vers les instances (qu'on maintient lors du constructeur et destructeur). On rajoute aussi une fonction static (méthode de classe) qui sert de callback général et c'est elle qui fait l'analyse pour décider à quelle instance de sa liste envoyer le callback.

Et c'est un client, pas un serveur :-p

et donc vous voulez gérer plusieurs URL émises en simultané c'est ça ?

J-M-L:
oui l'approche retenue correspond à une façon de faire.

Oui mais ça me plait pas plus que ça de passer par une var global. J'aime pas ça car j''estime que c'est "dangereux" et pas propre, du moins pas autant que du local. Mais ça a le mérite de fonctionner :slight_smile:
Ensuite, en simultanée non, pas possible puisque monothread, mais à la suite les unes des autres oui, et surtout aussi en asynchrone.