Go Down

Topic: Convert String to Mac Address (Read 168 times) previous topic - next topic

Stupidav

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!

zoomkat

Perhaps you should show your code, using code tags </> in the upper left, to better understand what you are trying to do.
Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

Stupidav

#2
Dec 08, 2019, 02:02 pm Last Edit: Dec 08, 2019, 02:04 pm by Stupidav
This was just the last attempt that I made, there were quite a few variations prior to that:

Code: [Select]

#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

J-M-L

#3
Dec 08, 2019, 04:10 pm Last Edit: Dec 08, 2019, 04:13 pm by J-M-L
as said in another post, don't use the String class...

instead of
Code: [Select]
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 
Code: [Select]
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
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

johnwasser

Code: [Select]
      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.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

J-M-L

#5
Dec 08, 2019, 04:13 pm Last Edit: Dec 08, 2019, 04:23 pm by J-M-L
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
Code: [Select]
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() {}
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Stupidav

Thank you John! That works perfectly.

Quote
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?

Code: [Select]
char* endPtr;
while (*endPtr)
What does the * do or mean?

Here is the latest trial code that works:

Code: [Select]
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);
}





J-M-L

#7
Dec 08, 2019, 06:34 pm Last Edit: Dec 08, 2019, 06:36 pm by J-M-L
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).

Code: [Select]
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 


Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

J-M-L

#8
Dec 08, 2019, 06:42 pm Last Edit: Dec 08, 2019, 07:30 pm by J-M-L
Quote
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
Code: [Select]
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:

Code: [Select]
#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()
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

johnwasser

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.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Go Up