NTP over UDP?

Anyone have any luck receiving NTP packets via UDP? I’m using the official Ether shield, and the UDP libraries written by Bjorn Hartmann.

I can send the request, but all I get back is a single question mark…

#include <Ethernet.h>
#include <UdpString.h>
#include <WString.h>

/* Attempt to get NTP time from NIST
 * Based on examples of how to send and receive packets over UDP 
 * using the UdpString library by bjoern@cs.stanford.edu 12/30/2008
 */

/* ETHERNET CONFIGURATION 
 * ARDUINO: set MAC, IP address of Ethernet shield, its gateway,
 * and local port to listen on for incoming packets */
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //MAC address to use
byte ip[] = { 192, 168, 1, 175 }; // Arduino's IP address
byte gw[] = { 192, 168, 1, 1 };   // Gateway IP address
int localPort = 123; //local port to listen on

/* TARGET: set this to IP/Port of computer that will receive
 * UDP messages from Arduino */
byte targetIp[] = { 192, 43, 244, 18}; //time.nist.gov
int targetPort = 123;

/* Strings hold the packets we want to send */
String asciiString;

String packet(32); //packet can be max 32 bytes long
byte remoteIp[4]; // holds recvieved packet's originating IP
unsigned int remotePort[1]; // holds received packet's originating port

int i;

void setup() {
  Serial.begin(9600); 
  Serial.print("Starting Ethernet, UDP...  ");
  Ethernet.begin(mac,ip,gw);
  UdpString.begin(localPort);
  
  asciiString = "/n";
  // send a normal, zero-terminated string.
  Serial.println("Sending packet...");
  UdpString.sendPacket(asciiString,targetIp,targetPort);
  delay(1000);

  if (UdpString.available()) {
    int packetSize = UdpString.readPacket(packet,remoteIp,remotePort);

    Serial.print("Received packet of size ");
    Serial.println(packetSize);

    Serial.print("From IP ");
    for(i=0; i<3; i++) {
      Serial.print(remoteIp[i],DEC);
      Serial.print(".");
    }
    Serial.print(remoteIp[3],DEC);

    Serial.print(" Port ");
    Serial.println(remotePort[0]); 

    Serial.println("Contents:");
    Serial.println(packet);


  }
  
}

void loop() {


}

The result (in 'packet') will not be a null-terminated string as the print/println routines expect. You need to loop through the bytes in the packet and print the values individually.

--Phil.

I dove into this today and ended up making a smallish library that will fetch a timestamp from an NTP server.

I ended up using the Bytewise part of Bjorn's library and I had to modify the header to allow me to send larger packets (you need to send 48 bytes, and the default limit is 32).

It's not really polished (or even finished) but it works for getting a timestamp.

Github link coming up in the next post...

http://github.com/cynshard/arduino-ntp/tree/master

I am trying to make work NTP. But I am a beginner and I have never coded in C, so the syntax is still something I need to get accustomed yet.

My problem right now is that I get Error message from compiler:

\arduino\arduino-0017\hardware\libraries\time\UdpBytewise.cpp:118: error: 'sendto' was not declared in this scope

It seem like compiler can not find some files or those are unknown to compiler where 'sendto' is defined. Does anybody know what should I check?

The sendto function is part of the Ethernet library.

You may have installed the UdpBytewise files in the wrong place. They belong in the same directory as the Arduino Ethernet files (arduino\arduino-0017\hardware\libraries\Ethernet)

Thanks! That helped when I copied all the UDP files there. But now there is another syntax related error message:
\arduino-0017\hardware\libraries\Ethernet\UdpString.cpp:70: error: expected ‘,’ or ‘;’ before ‘{’ token

cpp file itself is following:

extern “C” {
#include “types.h”
#include “w5100.h”
#include “socket.h”
}

#include “Ethernet.h”
#include “UdpString.h”

/* Start UDP socket, listening at local port PORT */
void UdpStringClass::begin(uint16_t port) {
_port = port;
_sock = 0; //TODO: should not be hardcoded
socket(_sock,Sn_MR_UDP,_port,0);
}

/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. */
int UdpStringClass::available() {
return getSn_RX_RSR(_sock);
}

/////////////////////////////////////////
//Wstring functions
int UdpStringClass::sendPacket(String str, byte * ip, unsigned int port) {
return (int)sendto(_sock,(const uint8_t *)str.cstr(),str.length(),ip,port);
}

int UdpStringClass::sendPacket(String str, int length, byte * ip, unsigned int port) {
return (int)sendto(_sock,(const uint8_t *)str.cstr(),length,ip,port);
}

int UdpStringClass::readPacket(String &str) {
uint8_t ip[4];
uint16_t port[1];
return readPacket(str,ip,port);
}

/* read packet into String str - if str is too short, expand its capacity */
int UdpStringClass::readPacket(String &str, byte * ip, unsigned int *port) {
int len = available() -8; //skip UDP header
if(len <= 0) return 0;
if(len > str.capacity()) {
//packet is longer than string capacity -
//resize string - this is very implementation dependent on WString
str = String(len);
//fall through to read which should be ok now
}
return (int)recvfrom(_sock,(byte *)(str.cstr()),(uint16_t)str.capacity(),ip,port);
}

/* Create one global object */
UdpStringClass UdpString;

I can’t see anything wrong here. Or am I wrong?

are you using the bytewise or string functions? if you want to use UDPBytewise functions, try deleting the other UDP files.

Yes, as much as I understand I need only UDP Bytewise function. And when I delete other UDP files it starts to give me former errormessage about 'sendto'.

The message you posted was for UdpString.cpp are you sure you deleted that file and the UdpString.h file?

Try deleting all the files in the Ethernet directory that begin: Udp... except the files that begin UdbBytewise

I am not sure that will get everything working but it should eliminate the error message you had before. If you do still get errors, post the message

good luck!

Thank you for your help! I feel myself as a total newbie as I continue to get strange messages. It seem to me that I am in trouble with understanding where to copy what library. And which directory is used for which purpose.

Never the less, I managed to make it to work! And thats what counts :)