saving and re-broadcasting websocket payload - uint8_t * confusion,

OK, I am a newbie, my first post, I will try to explain carefully. I haven’t used C since my undergrad days, I am now in my 50s and fairly new to Arduino. I have been dabbling mostly in Java in the meantime, Be gentle please! I am fully aware that my understanding of C pointers and arrays has gone awry sometime over the last thirty + years, so I will explain what I think is going on, knowing it is flawed, in the hope that someone can put me right.

I am using an ESP8266 as a websocket server using the server from Links2004 here
I am using it to control WS8218 - type LEDs with a websocket client interface (html). When the server receives a websocket colour change event (as a hex string) I want it to store the value in a global variable, such that if the page reloads or a new browser connects, this value will be sent to the client to preserve the state of the controller and update the web page; it does this by sending the client the value when a new connection event happens on the websocket server (ie all this is being handled by web sockets.)

Now, I can make all this work no problem with Strings, but understand that such profligate waste of resources is frowned upon, so I am trying to do it at a lower level. Here goes with my code and what I think is happening:

uint8_t * colourString = (uint8_t*)"#000000";
size_t payloadLength = 7;

So colourString is a pointer, referencing the first element of a uint8_t type array. The string primitive (as I would call it, sorry) is a const char array? So both data types are one byte but chars are signed, is that right? (When are chars negative?) colourString, as a pointer, can’t know the length of the aray, so I save that in a separate variable.

The method signature of webSocketEvent looks like this:

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {

and when an event bearing a hex string is received I do this:

if (payload[0] == '#') {            // we get RGB data
        if(!gSelected && gProgramMode){
          //do nothing
        }
        else{   //any other situation
            colourString = payload;
            payloadLength = lenght;

And then decode the string to r,g,b and do all the biz, which works fine. ‘payload’ is also a uint8_t * pointer, so after the assignment, colourString takes the value of payload, thus now referencing the first element of the payload array, right? (or wrong?).

In the same method of our server we handle connection events:

case WStype_CONNECTED: {              // if a new websocket connection is established
        //Serial.println("Incoming connection, websocket server arduino");
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
        Serial.printf("colourString sending connected = %s\n", &colourString);
        //webSocket.sendTXT(num, colourString);   //if String
        webSocket.sendTXT(num, colourString, payloadLength);    //if not
      }
      break;

The webserver has the method

bool sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0);

where num is the id of the client.

And a snippet of my serial out:

15:27:22.981 → [0] get Text: Websocket.js Connection opened: Sun Dec 29 2019 16:27:22 GMT+0800 (China Standard Time)
15:27:29.664 → Incoming event
15:27:29.664 → [0] get Text: #70000
15:27:32.555 → Incoming event
15:27:32.555 → [0] get Text: #72a00
15:27:40.408 → handleFileRead: /
15:27:40.446 → Sent file: /index.html
15:27:40.446 → Incoming event
15:27:40.446 → Disconnected
15:27:40.446 →
15:27:40.484 → handleFileRead: /main.css
15:27:40.484 → Sent file: /main.css
15:27:40.625 → handleFileRead: /WebSocket.js
15:27:40.662 → Sent file: /WebSocket.js
15:27:40.771 → Incoming event
15:27:40.771 → [0] Connected from 192.168.4.2 url: /
15:27:40.771 → colourString sending connected = ⸮⸮⸮?⸮⸮⸮?⸮⸮⸮?

So why is the colourString garbled here? The client, decodes it to 0,0,0. I have been trying to work this out for many days now. And barked up an entire forest of wrong trees in the process I think (const char * casts, UTF8 errors, etc etc!!) Also please, point out the flaws in my C-thinking

Many thanks in advance,

Joe

a bit hard to follow. you mention char pointers, char*, but where is the array of bytes used to store the string which a pointer may point to?

colourString = payload;

suggests you want to copy the string in payload to colorString, but all this does is set colorString to the address of payload. If payload is simply the buffer in the message, it will be volatile

it seems that colourString should be an array of bytes (either char or uint8_t) long enough to hold the longest payload string. you can then use a strncpy() to copy the string from payload to colourString if the string is NULL terminated, otherwise you'll need to limit the copy using the length arg to strncpy()

Thanks for the reply... my first code post declares and initialises colourString as a uint8_t *. Payload is the same, as you can see from the method signature, it is passed in. And setting colourString to the address of payload is exactly what I expect, also as I say on the post; which should surely achieve the same end as copying the contents of payload to colourString, ie colourString now references the same data? Or am I missing something here? What I really want to know is why the colourString is garbage when it is finally sent as a payload itself?

do you want to just copy the address of the string or the string? i'm assuming payload is the buffer of the received message and would be overwritten when the next message is received. Otherwise, why not just use payload?

i think you should

#define CSTR_SIZE 20
char colourString [CSTR_SIZE];

and later

strncpy (colourString, payload, CSTR_SIZE)

Aaah, of course! light is dawning… so I am copying the reference to payload, but the buffer to which this points can/will be overwritten with the next event - which is unlikely to be an RGB event etc… got it. I should have spotted that! Thanks.

But why do you suggest char type? The websocket methods need uint8_t at both ends, and as I said I ran into problems trying to cast - ‘loss of precision’.

Thanks again, I will actually try this tomorrow (it is late here now, in E Asia!)

In C the native types are char, short, int and long. I'm not sure that except for char, the number of bits for each is defined. the types in stdint.h, int8_t, int16_t, are more commonly used today.

but char still universally represents an ASCII character. You may need to use uint8_t if that's the type in some function string is being passed to. In most cases a defined string or a string passed to a function is defined as a const char*, implying that it is not changed.

OK, so coming back to this one, I am trying to ‘go Stringless’; you say

#define CSTR_SIZE 20
char colourString [CSTR_SIZE];”

but I do not know the size of every string. Max is 9, but it could be as small as 2.

allocating 9 bytes shouldn't be a problem. extra is good. 20 is fine

if it's only used in a sub-function, it's allocated on the stack and freed when the function returns.

If it were, you can determine the size from payload, malloc a string, use it and free it.