I'm trying to modify the pings example from the EtherCard library so I can ping multiple hosts. The end result should be a small device which monitors other devices on my network.
Here is the modified code I have in my loop
#include <EtherCard.h>
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
void setup () {
Serial.begin(57600);
Serial.println("\n[pings]");
if (ether.begin(sizeof Ethernet::buffer, mymac, SS) == 0)
Serial.println(F("Failed to access Ethernet controller"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.parseIp(ether.hisip, "192.168.123.150");
ether.printIp("SRV: ", ether.hisip);
timer = -9999999;
Serial.println();
}
void loop()
{
word len = ether.packetReceive(); // go receive new packets
word pos = ether.packetLoop(len); // respond to incoming pings
// report whenever a reply to our outgoing ping comes back
if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip))
{
Serial.print(" ");
Serial.print((micros() - timer) * 0.001, 3);
Serial.println(" ms");
}
// ping a remote server once every few seconds
if (micros() - timer >= 5000000)
{
if (ether.parseIp(ether.hisip, "192.168.123.150") == 0)
{
Serial.println("Address parsed");
}
ether.printIp("Pinging: ", ether.hisip);
timer = micros();
ether.clientIcmpRequest(ether.hisip);
}
}
When I look at the serial monitor, I see
Address parsed
Pinging: 192.168.123.150
but this happens only on the first iteration.
Every following iteration, I see Pinging: 0.0.0.0
.
I've added a variable to check the value of parseIP, which is 0 the first time, but always 1 after that.
I've tried to swap out ether.hisip completely, but that did not work, which is why I'm trying to parse the IP inside the loop (so I can swap addresses).
Why does parseIP only parse the IP correctly the first time?
1 Answer 1
The most recent version of Ethercard in library manager is v1.1.0.
In that version the parseIp
function is destructive to the input string.
uint8_t EtherCard::parseIp (uint8_t *bytestr,char *str)
If you turn the warning level up in your IDE, you should see the compiler complain about passing a pointer to const
thing (your string literal) into the non-const
input parameter (str
). Technically, modifying a string literal isn't allowed by the standard. Often in something like the Arduino the strings are in flash and attempting to write to them silently fails. For the AVR based Arduino Nano they are kept in RAM for reasons that have to do with the ATmega328/168 AVR's architecture.
parseIp
was written to replace the dots in your dotted-quad with null terminators.
During the second and subsequent calls to parseIp
the string literal has already been effectively changed to "192"
which then fails to parse.
You can see here that they've changed parseIp
to now accept const char *
and to not insert null terminators, but this code hasn't made it into a release.
So, you can try downloading to the main branch from github into your sketchbook/libraries directory, because it seems to allow your current usage of parseIp
.
Otherwise you'd need to make a temporary copy of your dotted quad string that parseIp
is then allowed to destroy:
uint8_t set_ether_hisip_from_dotted_quad(const char *dotted_quad) {
char destructable_dotted_quad[sizeof "aaa.bbb.ccc.ddd"];
strncpy(destructable_dotted_quad, dotted_quad, sizeof destructable_dotted_quad);
return ether.parseIp(ether.hisip, destructable_dotted_quad);
}
Then your calls can then take the form: if (set_ether_hisip_from_dotted_quad("192.168.123.150") == 0) {
Compilers can and usually do combine instances of string literals in memory ("coalescing") so if you corrupt "192.168.123.150"
from one place in your code you may see it in all places in your code. So if you test with this set_ether_hisip_from_dotted_quad
, make sure you replace all of your calls that are corrupting the string literal, otherwise the literal going into set_ether_hisip_from_dotted_quad
will also have changed to "192"
.
-
Thank you, that explains it! I have also figured out that I can set the octets of ether.hisip separately by accessing them as an array. I'm going to check the main branch as you suggested, and I'll use that if it doesn't give me any errors or side effects. Otherwise I'll use your other suggestion - either way, I think you've solved my problem. Thanks again!Deekay– Deekay2025年07月21日 20:27:01 +00:00Commented Jul 21 at 20:27
Strange, it compiled when I posted it
... you didn't post all of your code at first ... thesetup ()
function was missing