Function pointer help

Can someone better explain to me what exactly is happening here? I understand first creating function pointer.

AsyncClient* client = reinterpret_cast<AsyncClient*>(arg);

What exactly is happening here client = reinterpret_cast<AsyncClient*>(arg);

why cant i just call replyToServer(client); in the loop when i want to? I would like to set my own timer.

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>

extern "C" {
#include <osapi.h>
#include <os_type.h>
}

#include "config.h"
#define SSID "ESP-TEST"
#define PASSWORD "123456789"
#define SERVER_HOST_NAME "esp_server"
#define TCP_PORT 7050
#define DNS_PORT 53

struct sampleStruct {
  int var1 = 253;
  //byte Array[20];
  float var2 = 5.5;
  unsigned long var3 = 999;
  unsigned long var4 = 1;
  unsigned long var5 = 9999;
  unsigned long var6 = 7777;
  unsigned long var7 = 6666;
  unsigned long var8 = 5555;
  // bool var9;
};
sampleStruct st;

static os_timer_t intervalTimer;

static void replyToServer(void* arg) {
  AsyncClient* client = reinterpret_cast<AsyncClient*>(arg);
  // send reply
  if (client->space() > 32 && client->canSend()) {
    client->add("NODE01", 7); //add verification1
    client->add((char *)&st, sizeof(sampleStruct));
    client->add("NODE01", 7); //add verification2
    client->send();
    Serial.println("sent");
  }
}

/* event callbacks */
static void handleData(void* arg, AsyncClient* client, void *data, size_t len) {
  Serial.printf("\n data received from %s \n", client->remoteIP().toString().c_str());
  Serial.write((uint8_t*)data, len);
  os_timer_arm(&intervalTimer, 500, true); // schedule for reply to server at next 2s
}
void onConnect(void* arg, AsyncClient* client) {
  Serial.printf("\n client has been connected to %s on port %d \n", SERVER_HOST_NAME, TCP_PORT);
  replyToServer(client);
}
void setup() {
  Serial.begin(115200);
  delay(20);
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }

  AsyncClient* client = new AsyncClient;
  client->onData(&handleData, client);
  client->onConnect(&onConnect, client);
  client->connect(SERVER_HOST_NAME, TCP_PORT);

  os_timer_disarm(&intervalTimer);
  os_timer_setfn(&intervalTimer, &replyToServer, client);
}

void loop() {
}

There is a pointer to a void passed to the function. You know, that it really is a pointer to a AsyncClient type. To access the functions from the AsyncClient class, you need to cast the void pointer to a pointer to AsyncClient.

LightuC:
There is a pointer to a void passed to the function. You know, that it really is a pointer to a AsyncClient type. To access the functions from the AsyncClient class, you need to cast the void pointer to a pointer to AsyncClient.

Do you mean like this?

AsyncClient* as;
as->replyToServer(client);

probably not as it didn't work

Look at these conversions:

AsyncClient* client = (AsyncClient*)arg;
client = reinterpret_cast<AsyncClient*>(arg);

Both lines does the same, they are casting an ambiguous void pointer to something else. The difference is that the first line has no error checking, you could cast anything to anything like this. The second line has some compile time error checking which will dissalow most bogus castings from happening.

More info.

I would avoid the casting and just declare the correct method argument like this:

static void replyToServer(AsyncClient* client) {..}

This will eliminate the need for the cast.

Danois90:
Look at these conversions:

AsyncClient* client = (AsyncClient*)arg;

client = reinterpret_cast<AsyncClient*>(arg);




Both lines does the same, they are casting an ambiguous void pointer to something else. The difference is that the first line has no error checking, you could cast anything to anything like this. The second line has some compile time error checking which will dissalow most bogus castings from happening.

[More info](https://en.cppreference.com/w/cpp/language/reinterpret_cast).

I would avoid the casting and just declare the correct method argument like this:



static void replyToServer(AsyncClient* client) {..}




This will eliminate the need for the cast.

I tried the first method but i could not compile it.

AsyncClient* as;

as->replyToServer(client);

complains about async not having function replyToServer

i also tried this but the esp crashed

AsyncClient* client;

void loop() {
if (millis()-now>= 500){
  


  client->add("NODE01", 7); //add verification1
  client->add((char *)&st, sizeof(sampleStruct));
  client->add("NODE01", 7); //add verification2
  client->send();
  now = millis();
  
}
}

Sorry, my bad - I did not inspect the code good enough. In setup you have this call:

os_timer_setfn(&intervalTimer, &replyToServer, client);

Which sets a timer to call the function "replyToServer" with the argument "client". In order to use "client" as an instance of "AsyncClient" the cast in "replyToServer" is required.

EDIT: Btw, the timer is never armed, so it does nothing AFAICT. The code in post #5 fails because "client" is not a valid pointer.

Danois90:
Sorry, my bad - I did not inspect the code good enough. In setup you have this call:

os_timer_setfn(&intervalTimer, &replyToServer, client);

Which sets a timer to call the function "replyToServer" with the argument "client". In order to use "client" as an instance of "AsyncClient" the cast in "replyToServer" is required.

EDIT: Btw, the timer is never armed, so it does nothing AFAICT. The code in post #5 fails because "client" is not a valid pointer.

I'm sorry im trying to follow along i tried this,

void loop() {
 testFunction();
}

void testFunction(){
  if (millis() - now >= 1000) {
    AsyncClient* client;
    replyToServer(client);
    now = millis();
  }
}

but the esp crashes as soon as it connects?

I dont want to break the ASync functionality of the code but for the client i think it would be nice to just be able to send whatever data i need to when i need to.

You are using and unintialized pointer / object:

void testFunction(){
  if (millis() - now >= 1000) {
    AsyncClient* client; //client is NULL, using it will fail
    replyToServer(client);
    now = millis();
  }
}

If you want global access to the "AsyncClient" instance, then you need to declare it as a global variable instead of a local variable in "setup()". The "client" variable in the original code is only valid in "setup()", "handleData(..)" and "onConnect(..)".

Danois90:
You are using and unintialized pointer / object:

void testFunction(){

if (millis() - now >= 1000) {
    AsyncClient* client; //client is NULL, using it will fail
    replyToServer(client);
    now = millis();
  }
}




If you want global access to the "AsyncClient" instance, then you need to declare it as a global variable instead of a local variable in "setup()". The "client" variable in the original code is only valid in "setup()", "handleData(..)" and "onConnect(..)".

Thanks, declaring it globally did the trick for now. Thanks again

I wish there was more documentation on the ESPASyncTCP. the only problem i really have with it is it seems kinda sluggish. 1 message a second tops without lag and freezes. it never crashed but just slow. i dont know if there is a receive buffer to empty or not.