Convert String to Mac Address

After hours of searching and trials.....

So I have my MAC Address for the ethernet card in a String, and I am stuck on converting it.

Apparently the newer versions of the IDE have shut down many of the ways to accomplish this and after hours I am stuck.

Any ideas are much appreciated!

Perhaps you should show your code, using code tags </> in the upper left, to better understand what you are trying to do.

This was just the last attempt that I made, there were quite a few variations prior to that:

#include <SD.h>
#include <SPI.h>


String val;
String trash;
byte myMac[6];
byte myIP[4];
byte myNM[4];
byte myGW[4];
byte myDNS[4];
char cstrprs[32];

void setup() {
  Serial.begin(9600);           // Start Serial for Debugging

  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  if(!SD.begin(4)) Serial.println("SD fail");
  else Serial.println("SD ok");

  File cfg = SD.open("cfg.ini", FILE_READ);
  int i = 0;
  while (cfg.available()) {
    
    val = cfg.readStringUntil(';');
    trash =  cfg.readStringUntil('\n');
    Serial.println(i);
    Serial.println(val); //Printing for debugging purpose 
    switch(i) {
      case 0:
        const char * str = val;
        sscanf(str,"%2x:%2x:%2x:%2x:%2x:%2x",&myMac[0],&myMac[1],&myMac[2],&myMac[3],&myMac[4],&myMac[5]);  
      break;
      case 1:
        const char * str = val;
        sscanf(str, "%u.%u.%u.%u", &myIP[0], &myIP[1], &myIP[2], &myIP[3]);
      break;
        case 2:
      break;
        case 3:
      break;
        case 4:
      break;
        case 5:
      break;

    }


    
    i++;        
  }

  cfg.close();
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

Heres the error:
cannot convert ‘String’ to ‘const char*’ in initialization

as said in another post, don't use the String class...

instead of

const char * str = val;
sscanf(str,"%2x:%2x:%2x:%2x:%2x:%2x",&myMac[0],&myMac[1],&myMac[2],&myMac[3],&myMac[4],&myMac[5]);

try sscanf(val.c_str(),"%2x:%2x:%2x:%2x:%2x:%2x",&myMac[0],&myMac[1],&myMac[2],&myMac[3],&myMac[4],&myMac[5]);
(same would go for the IP)

The c_str() method gives you the cString pointer that is at the back of the String object

Note that in a switch/case if you want to declare local scoped variable you need to use {} in the case

      case 0:
        sscanf(val.c_str(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 
          &myMac[0], &myMac[1], &myMac[2], &myMac[3], &myMac[4], &myMac[5]);
        break;

      case 1:
        sscanf(val.c_str(), "%hhu.%hhu.%hhu.%hhu", 
          &myIP[0], &myIP[1], &myIP[2], &myIP[3]);
        break;

Without the 'hh' specifiers it's going to treat your data pointer as 'unsigned int' pointers and store each value as two bytes.

Good point, I did not look at the format

have a look at this code otherwise if you don't want to go heavy duty with sscanf

char myMacStr[] = "8d:75:92:6a:40:e6";

void setup()
{
  Serial.begin(115200);
  
  char* endPtr;
  Serial.print(F("0x"));
  Serial.println(strtol(myMacStr, &endPtr, 16), HEX);
  
  while (*endPtr) {
    Serial.print(F("0x"));
    Serial.println(strtol(endPtr + 1, &endPtr, 16), HEX);
  }
}

void loop() {}

Thank you John! That works perfectly.

Without the 'hh' specifiers it's going to treat your data pointer as 'unsigned int' pointers and store each value as two bytes.

I obviously am searching with the wrong terminology, but what do I need to search for or where can I find out about the "specifiers" or "format" as J-M-L referred to it?

J-M-L, I have read many times and seen at least a couple of your things on staying away from the String class (and I would like to), and I have tried, but I keep running into the same hiccup. Unfortunately you code won't work in my deal because your code is starting off with a "char" not a "string". Unfortunately I am reading the MAC Address from an SD Card, so it comes in as a String, so I am stuck having to try to convert that. Is there another way that your method works starting with a string?

Another question for you J-M-L, I have seen it in several samples, and am trying to fully understand how your code does it, but have not been able to determine what it means or does, *. Where can I find out about that, or can you explain it?

char* endPtr;
while (*endPtr)

What does the * do or mean?

Here is the latest trial code that works:

byte myMac[6];
String val = "8d:75:92:6a:40:e6";

void setup() {
  Serial.begin(9600); 

  sscanf(val.c_str(), "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 
    &myMac[0], &myMac[1], &myMac[2], &myMac[3], &myMac[4], &myMac[5]);

  Serial.print(myMac[0],HEX);
  Serial.print(":");
  Serial.print(myMac[1], HEX);
  Serial.print(":");
  Serial.print(myMac[2], HEX);
  Serial.print(":");
  Serial.print(myMac[3], HEX);
  Serial.print(":");
  Serial.print(myMac[4], HEX);
  Serial.print(":");
  Serial.print(myMac[5], HEX);
}

read about strings and the String class

The strtol() function reads a number in a certain base from a cString. read the doc.

here is a version starting from a String (you just need to call the c_str() method to access the buffer and it’s the same as my other code).

byte myMac[6];
String val = "8d:75:92:6a:40:e6";

void setup()
{
  char* endPtr;
  Serial.begin(115200);
  myMac[0] = strtol(val.c_str(), &endPtr, 16); // read the first starting at the beginning of the buffer. this initializes endPtr as a pointer to the ':' after the first number 
  for (int i = 1;  (*endPtr) && (i < 6); i++) {
    myMac[i] = strtol(endPtr + 1, &endPtr, 16); // using +1 for the pointer as we want to skip the ':'
  }

  for (int i = 0; i < 6; i++) {
    Serial.print(myMac[i], HEX);
    if (i != 5) Serial.print(F(":"));
  }
}

void loop() {}

you can find more functions working with cStrings in stdlib.h and string.h

Unfortunately I am reading the MAC Address from an SD Card, so it comes in as a String, so I am stuck having to try to convert that. Is there another way that your method works starting with a string?

you are stuck with a String class because you use cfg.readStringUntil(';');
if you were to use readBytesUntil() then you could form a cString directly

Not tested as I typed that here based on your code, but you could try this out:

#include <SD.h>
#include <SPI.h>

const byte maxBufferSize = 32; // make sure it's large enough
char val[maxBufferSize + 1]; // +1 to accomodate the NULL terminating char for the cString

byte myMac[6];
byte myIP[4];
byte myNM[4];
byte myGW[4];
byte myDNS[4];
char cstrprs[32];

void setup() {
  Serial.begin(115200);           // Start Serial for Debugging

  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);

  if (!SD.begin(4)) Serial.println("SD fail");
  else Serial.println("SD ok");

  File cfg = SD.open("cfg.ini", FILE_READ);
  int i = 0;
  while (cfg.available()) {
    int l = cfg.readBytesUntil(';', val, maxBufferSize); // https://www.arduino.cc/reference/en/language/functions/communication/stream/streamreadbytesuntil/
    val[l] = '\0'; // terminate the cString
    Serial.println(i);
    Serial.println(val); //Printing for debugging purpose

    // skip the rest of the line
    while (cfg.available())
      if (cfg.read() == '\n') break;

    switch (i) {
      case 0: // MAC ADDRESS, in HEX
        {
          char* endPtr;
          myMac[0] = strtol(val, &endPtr, 16); // read the first starting at the beginning of the buffer. this initializes endPtr as a pointer to the ':' after the first number
          for (int i = 1;  (*endPtr) && (i < 6); i++) {
            myMac[i] = strtol(endPtr + 1, &endPtr, 16); // using +1 for the pointer as we want to skip the ':'
          }

          for (int i = 0; i < 6; i++) {
            Serial.print(myMac[i], HEX);
            if (i != 5) Serial.print(F(":"));
          }
        }
        break;

      case 1: // IP ADDRESS, in DECIMAL
        {
          char* endPtr;
          myIP[0] = strtol(val, &endPtr, 10); // read the first starting at the beginning of the buffer. this initializes endPtr as a pointer to the ':' after the first number
          for (int i = 1;  (*endPtr) && (i < 4); i++) {
            myIP[i] = strtol(endPtr + 1, &endPtr, 10); // using +1 for the pointer as we want to skip the ':'
          }

          for (int i = 0; i < 4; i++) {
            Serial.print(myIP[i], DEC);
            if (i != 3) Serial.print(F("."));
          }
        }
        break;

      case 2:
        break;
      case 3:
        break;
      case 4:
        break;
      case 5:
        break;
    }
    i++;
  }

  cfg.close();

}

void loop() {}

Note that I used the console @115200 bauds. no reason to go slow

as mentioned above, Note that in a switch/case if you want to declare local scoped variable you need to use {} in the case

I also assumed your IP address was expressed in decimal, not Hexa hence the 16 to convert the MAC address and the 10 for the IP address in strtol()

Stupidav:
I obviously am searching with the wrong terminology, but what do I need to search for or where can I find out about the "specifiers" or "format" as J-M-L referred to it?

I did a Google search for 'scanf' and the first result included a table of format specifiers:
http://www.cplusplus.com/reference/cstdio/scanf/
Don't ask me why there isn't a "b" length specifier for 8-bit pointers.