Advice on UDP.write and char* command

Hi All

I have some code I've grabbed for WiFi and I'm changing the data being sent.

I've successfully changed the struct command to what I now want it to be, this is on the Master.

Next I need to send this data over wifi, I have commented out the line I'm struggling with as I don't understand it and how to change it to now be correct.

Could somebody please explain this:-

UDP.write((char*)&send_data,sizeof(struct led_command));

It is writing data to UDP, I understand the last bit where it sends the length of the string.
I do not understand the char* bit and what it does and more importantly how I change it for my new struct.
I am wanting to send 2 values, which are in the new struct. First value 0-255 is the DMX value for the channel I am working with. The second value is the brightness for that value, 0-255.
Apologies if you need the whole code, I was trying to keep it simple.

The error I'm getting when I uncomment this line is:-

exit status 1
invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]

void sendLedData(uint8_t send_dmx_value, uint8_t send_dmx_brightness) 
{

  struct led_command send_data;
  send_data.value = send_dmx_value; 
  send_data.brightness = send_dmx_brightness; 
  
// struct led_command send_data;
//send_data.opmode = op_mode; 
// send_data.data = data; 

 for (int i = 0; i < NUMBER_OF_CLIENTS; i++) 
 {
    IPAddress ip(192,168,4,2 + i);
    UDP.beginPacket(ip, 7001); 
    Serial.print("Send DMX Value:");
    Serial.print(send_dmx_value);
    Serial.print(": Send DMX Brightness:");
    Serial.print(send_dmx_brightness);
    Serial.println();
//    UDP.write((char*)&send_data,sizeof(struct led_command));
    UDP.endPacket();
 }
}

You failed to include enough code for me to determine exactly which libraries you're using. But, looking in 'Ethernet.h' under the EthernetUDP class, I see:

virtual size_t write(const uint8_t *buffer, size_t size);

So, I'd try casting your struct's address to a 'const uint8_t *' rather than a 'char *'.

gfvalvo:
You failed to include enough code for me to determine exactly which libraries you're using. But, looking in 'Ethernet.h' under the EthernetUDP class, I see:

virtual size_t write(const uint8_t *buffer, size_t size);

So, I'd try casting your struct's address to a 'const uint8_t *' rather than a 'char *'.

Apologies, I was trying to keep the post concise.
I have commented out the old code I have changed, it was previously sending opMode and data.

Here's the full code.

//From https://github.com/luksal/ESP32-DMX-RX

#include <dmx.h>
#include <FastLED.h>
#include <WiFi.h>
#include <WiFiUDP.h>
#include "reactive_common.h"

#define NUMBER_OF_CLIENTS 1

int dmx_start = 10; //DMX starting channel, channel+1 = Brightness

int dmx_value = 0;
int dmx_brightness = 50; //up to 255

int readcycle = 0;
const int checkDelay = 5000;
const int numOpModes = 11;

unsigned long lastChecked;

WiFiUDP UDP;


//struct led_command send_data;
//  send_data.value = send_dmx_value; 
//  send_data.brightness = send_dmx_brightnes; 

struct led_command {
  uint8_t value;
  uint8_t brightness;
};

bool heartbeats[NUMBER_OF_CLIENTS];

static int opMode = 4; //pre-set number to send to slave (for testing)
int old_opMode = 0;


void setup() {
  /* WiFi Part */
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print("------------------------------------------------");
  Serial.println();
  Serial.print("Setting soft-AP ... ");
  WiFi.persistent(false);
  WiFi.mode(WIFI_AP);
  WiFi.softAP("DMX_WiFi", "123456789");
  Serial.print("Soft-AP IP address = ");
  Serial.println(WiFi.softAPIP());
  UDP.begin(7171); 
  resetHeartBeats();
  waitForConnections(); //wait here until we have a connection, then resume
  lastChecked = millis();


  /* DMX part */ 
  Serial.begin(115200);
  DMX::Initialize();
}


void loop()
{
  if(millis() - readcycle > 1000)
  {
    readcycle = millis();

    Serial.print(readcycle);
      
    if(DMX::IsHealthy())
    {
      Serial.print(": ok - ");
    }
    else
    {
      Serial.print(": fail - ");
    }


    dmx_value = DMX::Read(dmx_start);
    dmx_brightness = DMX::Read(dmx_start+1);
    
    Serial.print("DMX Value:");
    Serial.print(dmx_value);
    Serial.print(": DMX Brightness:");
    Serial.print(dmx_brightness);
    Serial.println();
    //Serial.print(" - ");
    //Serial.print(DMX::Read(dmx_start+2));
    //Serial.print(" - ");
    //Serial.println(DMX::Read(dmx_start+3));

    sendLedData(dmx_value, dmx_brightness);
    delay(10);
  }
}




void sendLedData(uint8_t send_dmx_value, uint8_t send_dmx_brightness) 
{

  struct led_command send_data;
  send_data.value = send_dmx_value; 
  send_data.brightness = send_dmx_brightness; 
  
// struct led_command send_data;
//send_data.opmode = op_mode; 
// send_data.data = data; 

 for (int i = 0; i < NUMBER_OF_CLIENTS; i++) 
 {
    IPAddress ip(192,168,4,2 + i);
    UDP.beginPacket(ip, 7001); 
    Serial.print("Send DMX Value:");
    Serial.print(send_dmx_value);
    Serial.print(": Send DMX Brightness:");
    Serial.print(send_dmx_brightness);
    Serial.println();
    UDP.write((char*)&send_data,sizeof(struct led_command));
    UDP.endPacket();
 }
}


void waitForConnections() {
  while(true) {
      readHeartBeat();
      if (checkHeartBeats()) {
        return;
      }
      delay(checkDelay);
      resetHeartBeats();
  }
}


void resetHeartBeats() {
  for (int i = 0; i < NUMBER_OF_CLIENTS; i++) {
   heartbeats[i] = false;
  }
}


void readHeartBeat() {
  struct heartbeat_message hbm;
 while(true) {
  int packetSize = UDP.parsePacket();
  if (!packetSize) {
    break;
  }
  UDP.read((char *)&hbm, sizeof(struct heartbeat_message));
  if (hbm.client_id > NUMBER_OF_CLIENTS) {
    Serial.println("Error: invalid client_id received");
    continue;
  }
  heartbeats[hbm.client_id - 1] = true;
 }
}


bool checkHeartBeats() {
  for (int i = 0; i < NUMBER_OF_CLIENTS; i++) {
   if (!heartbeats[i]) {
    return false;
   }
  }
  resetHeartBeats();
  return true;
}

OK, same thing as Ethernet.h. Function prototype from WiFiUDP.h:

virtual size_t write(const uint8_t *buffer, size_t size);

Like I said:

gfvalvo:
So, I'd try casting your struct's address to a 'const uint8_t *' rather than a 'char *'.

BTW, this skeletal (and obviously non-functional) code compiles error-free in Arduino 1.8.12. Target board is an Uno:

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiUDP.h>

struct led_command {
  uint8_t value;
  uint8_t brightness;
};

WiFiUDP UDP;
led_command send_data;

void setup() {
  UDP.write((char*) &send_data, sizeof(send_data));
}

void loop() {
}

gfvalvo:
BTW, this skeletal (and obviously non-functional) code compiles error-free in Arduino 1.8.12. Target board is an Uno:

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiUDP.h>

struct led_command {
  uint8_t value;
  uint8_t brightness;
};

WiFiUDP UDP;
led_command send_data;

void setup() {
  UDP.write((char*) &send_data, sizeof(send_data));
}

void loop() {
}

Thank you for taking the time to put this together.
Weirdly, on my IDE 1.8.12 installation I get a compiler error still with this code.

invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]

gfvalvo:
BTW, this skeletal (and obviously non-functional) code compiles error-free in Arduino 1.8.12. Target board is an Uno:

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiUDP.h>

struct led_command {
  uint8_t value;
  uint8_t brightness;
};

WiFiUDP UDP;
led_command send_data;

void setup() {
  UDP.write((char*) &send_data, sizeof(send_data));
}

void loop() {
}

Apologies, I should have been clearer.

Yes, this compiles against a UNO.

However, it still fails for me against a ESP32 Dev Module. I would have hoped for better compatibility.

Can anyone advise?

Anybody?