Conversion of MAC Addresses String to uint8_t array for ESP Now

Dear experts

I am still a beginner and I have created an (MIT) Android App where I select/configure the ESP32 MAC addresses for my ESP NOW (one to many) broadcast network. The App is connected using Bluetooth Classic to one ESP Now Sender Module.

The App sends a string (in variable lengths) with multiple MAC addresses (from none to a total of twelve MAC addresses).
Example of a transmitted string with three MAC addresses: <3F4C5D026611, 3F4C5D026622, 3F4C5D026633>

With this code I am receiving the string:

void recPeerList() // Reveive MAC Address from APP
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial_BT.available() > 0 && newData_Peer == false)
  {
    rc = Serial_BT.read();

    if (recvInProgress == true)
    {
      if (rc != endMarker)
      {
        receivedChars_Peer[ndx] = rc;
        ndx++;
        if (ndx >= numChars_Peer)
        {
          ndx = numChars_Peer - 1;
        }
      }
      else
      {
        receivedChars_Peer[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData_Peer = true;
      }
    }
    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

According to the Serial Monitor the sting is received correctly in receivedChars_Peer. I am trying now to convert and assign the received string to variables respectively arrays.

Examples for desired format required for ESP Now transmission:

broadcastAddress1 = {0x3F, 0x4C, 0x5D, 0x02, 0x66, 0x11}

broadcastAddress2 = {0x3F, 0x4C, 0x5D, 0x02, 0x66, 0x22}

etc.

Now I am trying to change the format and assign each MAC address to a variable/array as described above but how I don’t know how to achieve this?

if (new_Peer_List_rcvd == (true))
  {
    
    Serial.println(receivedChars_Peer);

    uint8_t bytes[6];
    int values[6];
    int i;

    if (6 == sscanf(receivedChars_Peer, "%x:%x:%x:%x:%x:%x%*c",
                    &values[0], &values[1], &values[2],
                    &values[3], &values[4], &values[5]))
    {
      /* convert to uint8_t */
      for (i = 0; i < 6; ++i)
        bytes[i] = (uint8_t)values[i];
    }
    else
    {
      /* invalid mac */
    }

Thank you very much for your help, hints and tips.

Victor

your sscanf() format is not correct. It currently states you are looking for hex digits separated by ‘:’ but the string you received is not in that format. Instead of a separator, you need to specify to only use 2 digits ‘%2x%2x%2x%2x%2x%2x’
If you want to capture all the addresses returned, you will need to deal with the leading/trailing markers and break the string up (strtok) at the commas and then process each address

Thanks a lot.
I fixed the “:” issue as I intended to reduce the characters transmitted. I will look into the strtok concept, but for now I even have no clue how I can assign just one single (transmitted) MAC address to an array?

Example String:
<3F4C5D026611> to be assigned to array:
broadcastAddress = {0x3F, 0x4C, 0x5D, 0x02, 0x66, 0x11}
Unfortunately, I do not understand how to “feed” the array:

uint8_t broadcastAddress[6];


void loop()
{
if (new_Peer_List_rcvd == (true))
  {
    
    Serial.println(receivedChars_Peer);

    uint8_t bytes[6];
    char bytes[6];
    int values[6];
    int i;

    if (6 == sscanf(receivedChars_Peer, "%x%x%x%x%x%x%*c",
                    &values[0], &values[1], &values[2],
                    &values[3], &values[4], &values[5]))
    {
      /* convert to uint8_t */
      for (i = 0; i < 6; ++i)
        bytes[i] = (uint8_t)values[i];

broadcastAddress = bytes;

    }
    else
    {
      /* invalid mac */
    }

}

Hello,

A better solution (in my opinion) in this case is to use strtoull and a union

Here is a small example : 4JMJUR - Online C++ Compiler & Debugging Tool - Ideone.com

Edit: I forgot that your string doesn’t include < and >. I updated the example so it works without these markers

no error checking…

if (new_Peer_List_rcvd == (true))
{
  Serial.println(receivedChars_Peer);

  int val;
  for ( int i = 0; i < 6; ++i ) {
    int idx = i * 2 + 1; // place in string to start scan
    sscanf(receivedChars_Peer + idx, "%2x", &val);
    broadcastAddress[i] = val;
  }
}

Hello guix

Thank you very much for your help and your example. My questions to that:

  1. How do I use respectively where do I place the int main() structure in my project with setup() and loop()? This seems to be a different concept to compile the code which I am not familiar with.

  2. The format required to register the peer in ESP Now is as follows:
    broadcastAddress = {0x3F, 0x4C, 0x5D, 0x02, 0x66, 0x11}
    can I reformat it in here? printf( “address %hhu = %02X:%02X:%02X:%02X:%02X:%02X**\n**”,

  3. How can I create global variables e.g. broadcastAddress1, broadcastAddress2, etc. in order to use it for ESP Now peer registration (example for peer No3):
    memcpy(peerInfo.peer_addr, broadcastAddress3, 6);

Thank you both once again for your help. As you can easily see this issue is above my programming capability.

Hello blh64

Thanks a lot. How can I display the entire Mac address using broadcastAddress? Like {0x3F, 0x4C, 0x5D, 0x02, 0x66, 0x11}. This is what I require to register my ESP Now Peer (e.g. peer No1):

memcpy(peerInfo.peer_addr, broadcastAddress1, 6);

Thanks once again for your time and effort.

You don’t need main etc, it was just a CPP example demonstrating how to use strtoull :)… And you don’t need a global variable broadcastAddress ( always avoid global variables when possible )

Try something like this:

// This is the input string
char str[] = "3F4C5D026611, 3F4C5D026622, 3F4C5D026633";

esp_now_peer_info_t peerInfo;
peerInfo.channel = 0;
peerInfo.encrypt = false;

char * ptr = str; // pointer to start of string
while( *ptr ) // while end of string not reached
{
  uint64_t addr = strtoull( ptr, &ptr, 16 );
  if ( *ptr ) ptr++; // if end of string not reached, increase pointer to skip ','
  
  // split addr into bytes and store in peerInfo.peer_addr
  for ( uint8_t i = 0; i < 6; i++ )
  {
    peerInfo.peer_addr[ i ] = ( addr >> ( ( 5 - i ) * 8 ) ) & 0xFF;
  }
  
  // try add peer
  if ( esp_now_add_peer( &peerInfo ) != ESP_OK )
  {
    Serial.println( "Error adding peer" );
  }
}

Hi guix

Works like a charm. Thank you very much for all your help!