Losing a character when converting from String toCharArray

I am using this routine to send a String via UDP:

void sendWiegandIDtoServer(String id) {
  if (checkWiegandIDforErrors(id))
    return;
  logOutput("Access Code '" + id + "' has been entered.");
  ws.textAll("access_code");

  String key = "multicontroller, key=" + id;
  uint8_t bufferLengh = key.length();
  uint8_t buffer[bufferLengh];
  key.toCharArray((char *)buffer, bufferLengh);

  Serial.print("To be sent to server: ");
  Serial.println(key);

  if (!wiegand_udp_on || wiegand_state.ip_wiegand == "not set" ||
      wiegand_state.ip_wiegand.length() == 0) {
    logOutput("ERROR ! Invalid IP Address for Wiegand. Please enter a valid IP.");
    return;
  }

  // send packet to server
  wiegand_udp.beginPacket(wiegand_state.ip_wiegand.c_str(),
                          wiegand_state.port_wiegand.toInt());
  wiegand_udp.write(buffer, sizeof(buffer));
  delay(30);
  logOutput(wiegand_udp.endPacket()
                ? (String) "Wiegand ID: " + id + " was sent over UDP."
                : "WARNING: Wiegand ID not sent.");
  memset(buffer, 0, bufferLengh);
}

// for context:
void logOutput(String string1)
{
    circle.push(string1);
    Serial.println(string1);
}

I have String key, which I place in a buffer uint8_t buffer[bufferLengh]; using key.toCharArray((char *)buffer, bufferLengh); and then I send it with wiegand_udp.write(buffer, sizeof(buffer));.

The issue is that even if logOutput(wiegand_udp.endPacket() ? (String) "Wiegand ID: " + id + " was sent over UDP." : "WARNING: Wiegand ID not sent."); logs a correct id, which is a 6 digit code, wiegand_udp.write(buffer, sizeof(buffer)); only sends "multicontroller, key=" + id with 5 digit instead of 6.

Where could I be losing a digit ?

Why is the key a String rather than a string ?

You need to add one extra byte than the length to store the trailing null char

There is no need to duplicate - just use the underlying cString

Your function should pass Strings by reference - as it stands you duplicate Strings all over the place and increase the RAM pressure needlessly

So, basically uint8_t bufferLength = key.length() + 1; // Add 1 for null terminator ?

yes, if you want to keep abusing RAM :slight_smile:

when you do

  key.toCharArray((char *)buffer, bufferLengh);

the function copies bufferLengh-1 bytes from the key into the buffer and then add a trailing null. So that's why you lose one character.

but my recommendation would be to use the c_str() method directly on the id and not use the String class so much

instead of

void sendWiegandIDtoServer(String id) {
...
  String key = "multicontroller, key=" + id;
  uint8_t bufferLengh = key.length();
  uint8_t buffer[bufferLengh];
  key.toCharArray((char *)buffer, bufferLengh);
...
  // send packet to server
  wiegand_udp.beginPacket(wiegand_state.ip_wiegand.c_str(),
                          wiegand_state.port_wiegand.toInt());
  wiegand_udp.write(buffer, sizeof(buffer));

just do

void sendWiegandIDtoServer(String& id) { // <== add & to pass the parameter by reference instead of copy
...
  // send packet to server
  const char * header = "multicontroller, key=";
  wiegand_udp.beginPacket(wiegand_state.ip_wiegand.c_str(), wiegand_state.port_wiegand.toInt());
  wiegand_udp.write(header, strlen(header) ); 
  wiegand_udp.write(id.c_str(), id.length()); // or id.length() + 1 if you want to send the trailing null char

and if you could use a const char * for your id instead of a String, that would be even better for the memory

 wiegand_udp.write(header, strlen(header) ); 
 wiegand_udp.write(id.c_str(), id.length());

Both write () functions return : no instance of overloaded function "WiFiUDP::write" matches the argument listC/C++(304)

As write is:


size_t WiFiUDP::write(const uint8_t *buffer, size_t size){
  size_t i;
  for(i=0;i<size;i++)
    write(buffer[i]);
  return i;
}
write(buffer[i]);

Should there be an object name in front of the write() function ?

cast to const uint8_t * (otherwise it's a const char * and it seems the developers of the library did not plan for that)

  wiegand_udp.write((const uint8_t * ) header, strlen(header) ); 
  wiegand_udp.write((const uint8_t * ) id.c_str(), id.length()); // or id.length() + 1 if you want to send the trailing null char

that was an extract from the class, so write() was referring to the local function in the class

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.