How create a String from an 'unsigned char' array?

I'm working on a mesh where every node take a picture, encode it in base64 and send the result to the root node. The encoded array is 'unsigned char' but the function used to send the data to the root node via mesh accepts a String. And if I try to create a String from the 'unsigned char' array I get the error: invalid conversion from 'unsigned char' to 'const char*'*.

unsigned char* base64 = (unsigned char*)heap_caps_malloc(4*(_jpg_buf_len/3)+1, MALLOC_CAP_8BIT);
if (base64 == NULL)
  Serial.println("Can not malloc memory");
unsigned int base64_length = encode_base64(_jpg_buf, _jpg_buf_len, base64); //unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]);

String to = bridgeNodeName;
mesh.sendSingle(to, base64); //bool painlessMesh::sendSingle(uint32_t dest, String &msg)

What's the best method to avoid this problem?

Don't post snippets (Snippets R Us!)

what is bridgeNodeName? why is it a String? did you extend the sendSingle() method?

assuming this works, you could try

mesh.sendSingle(to, String(base64));

that's a pretty heavy / bad use of the memory...

Try this

{ //start block
  String base64str;
  if (!base64str.reserve(4*(_jpg_buf_len/3)+1)) {
      Serial.println("Can not malloc memory");
  } else {
    unsigned int base64_length = encode_base64((unsigned char*)base64str.c_str(), 
    base64str.length(), base64); //unsigned int encode_base64(unsigned char input[], unsigned int   input_length, unsigned char output[]);
    // clean up the string 
    base64str[base64_length] = '\0';  // this is a bit naughty as the base64str.length() is no longer correct, but it should work.
    mesh.sendSingle(to, base64str);
  }
} // end block to recover base64str memory

Are you sure?

No not tested, but seems OK.
What problem can you see?

What are you base64 encoding? How much is base64str.length() worth straight out of reserve?

Thanks you caught my stuff up, again :slight_smile:
How about this


{ //start block
  String base64str;
  if (!base64str.reserve(4*(_jpg_buf_len/3)+1)) {
      Serial.println("Can not malloc memory");
  } else {
    unsigned int base64_length = encode_base64(_jpg_buf, 
    _jpg_buf_len, (unsigned char*)base64str.c_str()); //unsigned int encode_base64(unsigned char input[], unsigned int   input_length, unsigned char output[  ]);
    // clean up the string 
    base64str[base64_length] = '\0';  // this is a bit naughty as the base64str.length() is no longer correct, but it should work.
    mesh.sendSingle(to, base64str);
  }
}

// end block to recover base64str memory

Better :wink:

The null terminator is added by the call to encode_base64() so it’s not required to add one manually

Just to be picky - Technically in c++ you should usually try to stay clear from c style casting and casting a const char * back into a char* should be a red flag. (And using const_cast to try and modify a read-only object is undefined behavior)

You rely on your understanding of how the String class is working (which breaks the encapsulation rule) and understanding of how gcc deals with the pointers and memory allocation … So this should not be recommended (but will likely work).

I agree entirely. You should not cast const char* to a char* unless you really know what you are doing and what the result will be.

A nasty solution to avoid double memory allocations.
Perhaps there is a better one.
We could look at
mesh.sendSingle( .. ) and see if it can be modified to take the const char* base64 directly.

Yes the library made a “poor” choice not offering other payload types and should be modified. (Not easy)