I was working on a sketch where my Arduino is both a server, a web client and reads time from a NTP-server. It worked, but only for a while. After a couple of hours either the server stopped responding or the client did not get the data. I searched the forums and found some interesting stuff from SurferTim where he implements a timeout-function in case something goes wrong. So I started with the web-client from the playground, added my own addresses and let it get data (a simple xml file containing some setup data) from my (Apache) server for a couple of hours without crashes. Then I added the NTP code from my other sketch. This works fine on startup, but once in loop the Arduino resets itself every time the NTP code is called. This did not happen in my other (much larger) sketch. I understand that auto-rebooting is usually caused by a buffer overflow or memory shortage. So I also added code to check the amount of free memory. This reports 1280 bytes free and never changes.
When I out-comment the 'getPage' line from loop I get a new NTP-IP every 5 seconds. So the NTP code on its own works, the client code also works but together they cause havoc.
Note that I poll an NTP server very 5 seconds only for testing. In my first try I had not set this interval which means it polls every 5 minutes. The Arduino would reboot after 86 loops (with the loop set to 3 seconds that's about 5 minutes, also the syncInterval time when not set with setSyncInterval() if you call now() often enough). I set it to 5 seconds to check if polling the NTP server was what caused the crash. In real life my sketch can do with a poll once every 6 hours or longer.
Also note I xxx-ed out my server address. Also not I use port 6960 for my client. That is not a mistake, my Apache server is configured to also listen on that port.
/*
Web client sketch for IDE v1.0.1 and w5100/w5200
Uses GET method.
Posted October 2012 by SurferTim
*/
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Dns.h>
// this must be unique
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// change to your network settings
IPAddress ip(192,168,0,177);
IPAddress dnsIP(8,8,8,8); // google dns
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress server(1xx,1xx,xx,1xx); // server IP-number
// change to your server's port
int serverPort = 6960;
EthernetClient client;
int totalCount = 0;
int loopCount = 0;
char pageAdd[32];
/* Timeserver setups */
IPAddress timeServer; //
EthernetUDP Udp;
unsigned int localPort = 8888; // local port to listen for UDP packets
const int timeZone = 2; // Central European Time
void setup() {
Serial.begin(9600);
// disable SD SPI
pinMode(4,OUTPUT);
digitalWrite(4,HIGH);
// Start ethernet
Serial.println(F("Starting ethernet..."));
Ethernet.begin(mac, ip, dnsIP, gateway, subnet);
Serial.println(Ethernet.localIP());
delay(2000);
setSyncProvider(getNtpTime);
setSyncInterval(5);
//digitalClockDisplay();
Serial.println(F("Ready"));
}
void loop()
{
if(loopCount < 4)
{
// if loopCount is less than 30, just delay a second
delay(1000);
}
else
{
// every thirty seconds this runs
loopCount = 0;
// Modify next line to load different page
// or pass values to server
//sprintf(pageAdd,"/",totalCount);
sprintf(pageAdd,"http://www.xxx.xxx/xxx.xml",totalCount);
if(!getPage(server,serverPort,pageAdd)) Serial.print(F("Fail "));
else Serial.print(F("Pass "));
totalCount++;
Serial.println(totalCount,DEC);
printRAM();
}
loopCount++;
}
byte getPage(IPAddress ipBuf,int thisPort, char *page)
{
int inChar;
char outBuf[128];
Serial.print(F("connecting..."));
if(client.connect(ipBuf,thisPort))
{
Serial.println(F("connected"));
sprintf(outBuf,"GET %s HTTP/1.0\r\n\r\n",page);
client.write(outBuf);
}
else
{
Serial.println(F("failed"));
return 0;
}
// connectLoop controls the hardware fail timeout
int connectLoop = 0;
while(client.connected())
{
while(client.available())
{
inChar = client.read();
Serial.write(inChar);
// set connectLoop to zero if a packet arrives
connectLoop = 0;
}
connectLoop++;
// if more than 10000 milliseconds since the last packet
if(connectLoop > 10000)
{
// then close the connection from this end.
Serial.println();
Serial.println(F("Timeout"));
client.stop();
}
// this is a delay for the connectLoop timing
delay(1);
}
Serial.println();
Serial.println(F("disconnecting."));
// close client end
client.stop();
return 1;
}
/*-------- NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
time_t getNtpTime()
{
Udp.begin(localPort);
DNSClient dns;
dns.begin(Ethernet.dnsServerIP());
if(dns.getHostByName("pool.ntp.org",timeServer)) {
Serial.print(F("NTP server ip: "));
Serial.println(timeServer);
}
else Serial.print(F("dns lookup failed"));
while (Udp.parsePacket() > 0) ; // discard any previously received packets
//Serial.println("Transmit NTP Request");
sendNTPpacket(timeServer);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
//Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response :-(");
return 0; // return 0 if unable to get the time
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void digitalClockDisplay(){
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}
void printDigits(int digits){
// utility for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
void printRAM()
{
Serial.print("Free RAM = ");
Serial.println(freeRam());
digitalClockDisplay();
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
What could be wrong with this code?