Converting message types from one kind to another.

In a bit of code I have this command:

  Serial.println("");
  Serial.println("=================");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("=================");

Nice.

I want to access this "WiFi.localIP()" and put it in to (I think they are called arrays) for instance:

message[]

I'm reading but as I am not having any luck.

I have some code already written and it takes it's input from that kind of variable.

So I can either re-write my routine to accept what that command gives, or change it from what it gives to be stored in "message[]".

The array is a bit nicer because I can step through and look at each letter/character individually.

lost_and_confused:
So I can either re-write my routine to accept what that command gives, or change it from what it gives to be stored in "message[]".

Can you explain a bit more, what you are trying to accomplish? Can you show us the routine, you have written?

WiFi.localIP() I guess that returns a String.
So, use the c_str() method.

AWOL:

WiFi.localIP()

I guess that returns a String.
So, use the c_str() method.

It returns the address as 'IPAddress'. This class does have a toString() method, which returns String. So you could do (EDIT: As gfvalvo correctly pointed out, the temporary String object would get destroyed after the ';'. So this expression can only be used as a parameter to a function. Then the expression would end after the call.)

WiFi.localIP().toString().c_str();

You need to use this instead:

String strLocalIp = WiFi.localIP().toString();
const char* cstrIp = strLocalIp.c_str();

This way the String instance lifes until the name goes out of scope. You need to make sure, that you don't use cstrIp after the String has gone out of scope. [/EDIT]

It would be better however, to do the conversion on your own, since it is pretty easy and doesn't fragment your ram. I think there is more to the question than simply converting an IPAddress to string.

Thanks all.

I have the conversion code working now (after a lot of messing around and stupid mistakes.

This is the code:

/*
 *    
 */
void create_bmessage()
{
  //  Uses message[] from outside to construct new array.
  //
  byte data;                  //  Used to read IP address.  Storage of value/s.
  byte input_loop = 0;
  byte output_loop = 0;
  Serial.println("Creating bmessage.   Details below.");
  while (input_loop < message_length)         //    Read message[ data ] into new array.
  {
    data = message[input_loop];
    //Serial.print("Reading in from file ");
    //Serial.println(message[input_loop]);
    if (data == '.')
    {
      //
      //    Decimal point detected.
      //
      Serial.println("**  Decimal place detected  **  Editing this value");
      Serial.println(message[input_loop-1]);
      bmessage[output_loop-1] = (bmessage[output_loop-1] + 128);
      input_loop = input_loop + 1;
    } else
    {
//      data = (data + 48);                   //    Add 48 (ascii table) takes numbers and makes them printable codes.
      data = (data + 16 );                   //    
      bmessage[output_loop] = data;
      input_loop = input_loop + 1;
      output_loop = output_loop + 1;
    }
  }
}
//------------------------------------------------------------

It works and I have sent it "dummy" IP addresses contained in message[]

So yes, thanks. that part works.
I was hoping that I could somehow convert what WiFi.localIP() gives me and make it like message[]

I am looking at c_srt() now. But wanted to post this to keep people up to date.

Can you describe what you want to do in a better way? What is the method create_bmessage doing? Why do you need it to do? What is the purpose of the method? What do you want to do with the local ip address?

The IPAddress class, returned by WiFi.localIP(), can be accessed as an array:

// Assuming the local ip is: 192.168.178.31
IPAddress localIp = WiFi.localIP();

// contains 192
uint8_t firstOctet = localIp[0];

// contains 168
uint8_t secondOctet = localIp[1];

// contains 178
uint8_t thirdOctet = localIp[2];

// contains 31
uint8_t fourthOctet = localIp[3];

LightuC:
Can you describe what you want to do in a better way? What is the method create_bmessage doing? Why do you need it to do? What is the purpose of the method? What do you want to do with the local ip address?

The IPAddress class, returned by WiFi.localIP(), can be accessed as an array:

// Assuming the local ip is: 192.168.178.31

IPAddress localIp = WiFi.localIP();

// contains 192
uint8_t firstOctet = localIp[0];

// contains 168
uint8_t secondOctet = localIp[1];

// contains 178
uint8_t thirdOctet = localIp[2];

// contains 31
uint8_t fourthOctet = localIp[3];

After an initial start of the reply I now realise what you mean buy: describe in a better way.......

I have a WiFi project that connects to my WAP. For the sake of learning I want to display the IP address it gets on a 8 digit 7 segment display I have which connects to the Arduino via SPI.

The display wants REAL NUMBERS to display. So sending the ASCII codes for 1, 2, 3, etc will not really work.

The code I have gets me the IP address in ASCII format.

This method converts from the ASCII code to actual numbers.
It also scans for decimal points and adds them to the digits as required. This is done by setting bit 7 of the digit to the left of the decimal point.

So, the thinking is that I get the IP address from the LocalIP() command and convert it from ASCII to real numbers. Then can send it to the display.

Is that better?

There are two other things I want to do as well, but they are beyond the scope of this thread, so I am conflicted if I should discuss that here or try to work it out myself and then start a new thread when/if I get stuck on that.

lost_and_confused:
Is that better?

Yes.

lost_and_confused:
[...] or try to work it out myself and then start a new thread when/if I get stuck on that.

It's almost always better to try it yourself first.

lost_and_confused:
The code I have gets me the IP address in ASCII format

Look at the code I provided, it'll give you the individual octets of the ip address as real numbers. You can send them directly to your display. Have you tried that?

I only got it about ....... 20 minutes ago. No I haven't tried it yet.

I don't have the arduino plugged in.

I have saved the code and will look at it as soon as I can.

Thanks though.

And on the other things, I think I have it worked out.

Sorry for the slow reply.

LightuC:
There is a slight problem with the code you offered.

It sends the IP number in octets of real numbers - which is nice, but has the drawback (for me at this time), that I can't set the decimal point.

All the values sent are above 128.
As it is I send it a number between 0 and 9.
If I want it to display the decimal point, I add 128 to it. (Set bit 7)

Fine.

That all works.

But as your routine sends digits greater than 128, it all falls over.

Sure: My problem.

Some how it can be done if I go deeper into how to program the display.

There is an included demo but it counts down in INT( ) numbers.
It doesn't go into how to then "cheat" and add decimal points after that number. Which is a long( ) type.

The routine I have written works if the IP address is stored in "message[ ]". Though I guess the name of the variable is not that important.

I could get around that and when I call it I call it with something like:

my_routine(name_of_array)

And in my code I add:

void my_routine(char message[ ])

(Excusing the space between the [ and ]. Included for clarity/visibility.

I am still stuck how to get the IP address into an array.

Reading the c_str( ) command, it doesn't show the "input" and "output" variable names.
I can't understand how the example (which I also can't really see) is formatted.

In your previous posts you said numbers, but it seems you need digits. For digits, having the ip address as a char array is easier, so use DON'T use this. It is just plain wrong, the temporary String will be destroyed after the call to c_str(). strLocalIp will be dangling after this line ends, as gfvalvo pointed out.

const char* strLocalIp = WiFi.localIP().toString().c_str()

You can pass this to your routine, just change the type of your parameter to const char* instead of char [].

Note: this uses big-S Strings, so you might run into memory fragmentation. You can use itoa on the individual octets, which doesn't require dynamic memory allocation.

Ok, we will have to put that down to different interpretation of numbers and digits.

Indulge my ignorance with the code:

const char* strLocalIp = WiFi.localIP().toString().c_str()

But looking at it, I'm confused.
And I get that that is MY problem.

But as the code I have is written it wants the variables in an array. For the sake of consistency: message[ ].

I see you said this:
You can pass this to your routine, just change the type of your parameter to const char* instead of char [].

But I am not getting how it deals with the [] part of it because you even mention at the end to use char* instead of char [].

I'll go away and try to get my head around what char* is/means/does. But as you may see, I'm not getting it.

Luckily on the last part: I am really hoping that the memory fragmentation isn't a problem as it won't/shouldn't be invoked that often.

char [] is an array of characters, while char* is a pointer to a character. There are differences between those two, however all arrays are converted to pointers when passed to a function.

When you define an array, the variable name is used as a placeholder for the first element of the array. By specifying an index in the [] brackets, the compiler can calculate an offset, e.g. first element + two, to get the content of the third element.

A pointer is a variable. It stores the memory address of the first element. By specifying an index in the [] brackets, again an offset can be calculated. However, because a pointer actually holds the memory address and is not a placeholder, the memory access is a little bit different. You can read up on pointers online, there are plenty tutorials who will do a much better job at explaining than I possibly can.

Pointers can be used (in c/c++) just like if they were an array, but arrays can't be used as if they were pointers.

Thanks.

I'll have to sit down and study it.

I hope I get it working soon. But no big deal if it is a while.

I'm just torn between doing it "this way" or starting over and learning a different way of doing it.

For now I think I should stick with this way because if I go off on alternate ways, I will (probably) only further confuse myself.

Sticking with this way I may learn more as I am already using this method and may as well take it to conclusion.

lost_and_confused:
I'm just torn between doing it "this way" or starting over and learning a different way of doing it.

For now I think I should stick with this way because if I go off on alternate ways, I will (probably) only further confuse myself.

Sticking with this way I may learn more as I am already using this method and may as well take it to conclusion.

I'm not quite sure what you mean by "this way", but these two are the same

void my_routine(char message[])
// is the same as
void my_routine(char* message)

To clarify:
I could sit down and re-write the code to read the data from separate octets or work on the code to read it as a series of stuff as it is.

That isn't a slight on what was suggested, but just as it is to me.

Well, here is the complete code:
There are 3 parts:
The main code,
a README tab
and a MISC tab.

The readme is self explanatory.
The MISC tab is where I am messing around with the code to do what I want.

As is the code works if given an IP number. See line 9 on that tab.

But I am at a loss where/how to use this code to give me the output in message[ ]

I can't work out where the output is declared in the line.

const char* strLocalIp = WiFi.localIP().toString().c_str()

Sorry.

Expanded_External_Temperatures_new_5f.ino (29.5 KB)

Misc.ino (3.38 KB)

READ_ME.ino (2.29 KB)

Look at the final method called in this chain:

const char* strLocalIp = WiFi.localIP().toString().c_str()

c_str() gives you the pointer. 'lstrLocalIp' is initialized with the value of this pointer.

Looking at this further, I’m thinking this may not be a good idea:

const char* strLocalIp = WiFi.localIP().toString().c_str();

If you look in the source code for the ‘.localIP()’ method of WiFi, you find this:

IPAddress ESP8266WiFiSTAClass::localIP() {
  struct ip_info ip;
  wifi_get_ip_info(STATION_IF, &ip);
  return IPAddress(ip.ip.addr);
}

So, it returns a temporary object of type IPaddress on the stack.

Then, the ‘toString()’ method of the IPAddress class does this:

String IPAddress::toString()
{
  char szRet[16];
  sprintf(szRet, "%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]);
  return String(szRet);
}

So, it returns a temporary object of type String on the stack.

Finally, the ‘c_str()’ method of the String does this:

const char * c_str() const {
  return buffer;
}

So, it returns a pointer to that String’s internal buffer.

Seems to me, when it’s all said and done, that temporary String object will be popped off the stack and deleted. Now, that char * that you worked so hard to get will be pointing to invalid data that will get wiped out once something else is pushed into that stack location.

IMO, @lost_and_confused’s best option is to access the individual octets as advised way back in Reply #5 and then learn how to convert them into whatever form he/she wants.

Of course, if my analysis above is wrong, I’m sure we’ll hear about it.

gfvalvo:
Looking at this further, I’m thinking this may not be a good idea:
[...]
So, it returns a temporary object of type IPaddress on the stack.

No, it returns a copy of the object on the stack, since it is returned by value.

gfvalvo:
So, it returns a pointer to that String's internal buffer.

That is correct, however the String was previously returned by value, so it is in scope, when you call c_str(). As long as the String is in scope you can use the pointer to the internal buffer.