Calls to udp.available() appear to return -1 x number of bytes available.
My program sends a Network Time Protocol request over UDP and receives a 48 byte response.
Here's the serial output:
Attempting to connect to the modem
Attempting to connect to the GPRS Access Point Name
Packet sent
Awaiting response
udp.parsePacket 0
udp.parsePacket 0
udp.parsePacket 48
udp.available -48 <---expected 48 here
Code (excluding secrets.h) is below. The relevant serial output comes from void loop():
#define LEAP_INDICATOR_NO_WARNING 0
#define LEAP_INDICATOR_61_SECONDS 1
#define LEAP_INDICATOR_59_SECONDS 2
#define LEAP_INDICATOR_UNKNOWN 3
#define LEAP_INDICATOR_Pos 6
#define VERSION_NUMBER_Pos 3
#define MODE_CLIENT 3
#define MODE_Pos 0
#define STRATUM_UNSPECIFIED_OR_INVALID 0
#define NTP_DOMAIN "pool.ntp.org"
const unsigned int NTP_PORT = 123u;
const unsigned int LOCAL_PORT = 2390u;
#include "arduino_secrets.h"
#include <MKRGSM.h>
/*Create the objects needed for internet requests*/
GSM gsm; //class to connect to the modem
GSMClient gsmClient;
GPRS gprs; //class to connect to the internet
GSMUDP udp;
struct NTPPacket {
unsigned int leapIndicator;
unsigned int versionNumber;
unsigned int mode;
unsigned int stratum;
int poll;
int precision;
unsigned long rootDelay;
unsigned long rootDispersion;
unsigned long referenceID;
unsigned long long referenceTimestamp;
unsigned long long originTimestamp;
unsigned long long receiveTimestamp;
unsigned long long transmitTimestamp;
//ignoring the remaining fields for now. The example implementation doesn't use them.
};
void printLongLong(long long value) {
Serial.print((long)(value >> 32), HEX);
Serial.println((unsigned long)(value), HEX);
}
void bigEndian(long long input, int sizeOfOutput, unsigned char output[]) {
for (int i = 0; i < sizeOfOutput; i++) {
int rightShift = (sizeOfOutput - 1 - i) * 8;
char nextByte = (char) (input >> rightShift);
output[i] = nextByte;
}
}
long long bigEndianToLongLong(unsigned char data[], int sizeOfData) {
long long output = 0;
for(int i = 0; i < sizeOfData; i++) {
output = output << 8;
output += data[i];
}
return output;
}
void sendNTPRequest(unsigned long long referenceTimestamp, unsigned long long originTimestamp) {
struct NTPPacket packet;
packet.leapIndicator = LEAP_INDICATOR_UNKNOWN;
packet.versionNumber = 4;
packet.mode = MODE_CLIENT;
packet.stratum = STRATUM_UNSPECIFIED_OR_INVALID;
packet.poll = 0; //presumably this is set by the server?
packet.precision = 0; // ditto
packet.rootDelay = 0;
packet.rootDispersion = 0;
packet.referenceID = 0;
packet.referenceTimestamp = referenceTimestamp;
packet.originTimestamp = originTimestamp;
packet.receiveTimestamp = 0;
packet.transmitTimestamp = 0;
while(!udp.beginPacket(NTP_DOMAIN, NTP_PORT));
udp.write(packet.leapIndicator << LEAP_INDICATOR_Pos
| packet.versionNumber << VERSION_NUMBER_Pos
| packet.mode << MODE_Pos);
udp.write(packet.stratum);
udp.write(packet.poll);
udp.write(packet.precision);
byte byteArray[8]; //byte array to be used for multi-byte fields in big endian format
bigEndian((long long)packet.rootDelay, 4, byteArray);
udp.write(byteArray, 4);
bigEndian((long long)packet.rootDispersion, 4, byteArray);
udp.write(byteArray, 4);
bigEndian((long long)packet.referenceID, 4, byteArray);
udp.write(byteArray, 4);
bigEndian(packet.referenceTimestamp, 8, byteArray);
udp.write(byteArray, 8);
bigEndian(packet.originTimestamp, 8, byteArray);
udp.write(byteArray, 8);
bigEndian(packet.receiveTimestamp, 8, byteArray);
udp.write(byteArray, 8);
bigEndian(packet.transmitTimestamp, 8, byteArray);
udp.write(byteArray, 8);
while(!udp.endPacket());
Serial.println("Packet sent");
}
void receiveNTPPacket() {
struct NTPPacket packet;
byte byteArray[8]; //byte array to be used for multi-byte fields in big endian format
Serial.print((int)udp.available());
Serial.println(" bytes available");
Serial.print("First byte: ");
Serial.println((int)udp.peek(), DEC);
packet.leapIndicator = (udp.peek() >> LEAP_INDICATOR_Pos) & 0b11;
packet.versionNumber = (udp.peek() >> VERSION_NUMBER_Pos) & 0b111;
packet.mode = (udp.read() >> MODE_Pos) & 0b111;
packet.stratum = udp.read();
packet.poll = udp.read();
packet.precision = udp.read();
udp.read(byteArray, 4);
packet.rootDelay = bigEndianToLongLong(byteArray, 4);
udp.read(byteArray, 4);
packet.rootDispersion = bigEndianToLongLong(byteArray, 4);
udp.read(byteArray, 4);
packet.referenceID = bigEndianToLongLong(byteArray, 4);
udp.read(byteArray, 8);
packet.referenceTimestamp = bigEndianToLongLong(byteArray, 8);
udp.read(byteArray, 8);
packet.originTimestamp = bigEndianToLongLong(byteArray, 8);
udp.read(byteArray, 8);
packet.receiveTimestamp = bigEndianToLongLong(byteArray, 8);
udp.read(byteArray, 8);
packet.transmitTimestamp = bigEndianToLongLong(byteArray, 8);
Serial.print("Leap indicator ");
Serial.println(packet.leapIndicator);
Serial.print("Version number ");
Serial.println(packet.versionNumber);
Serial.print("Mode ");
Serial.println(packet.mode);
Serial.print("Stratum ");
Serial.println(packet.stratum);
Serial.print("Poll ");
Serial.println(packet.poll);
Serial.print("Precision ");
Serial.println(packet.precision);
Serial.print("Root delay ");
Serial.println(packet.rootDelay);
Serial.print("Root Dispersion ");
Serial.println(packet.rootDispersion);
Serial.print("Reference ID ");
Serial.println(packet.referenceID);
Serial.print("Reference Timestamp 0x");
printLongLong(packet.referenceTimestamp);
Serial.print("Origin Timestamp 0x");
printLongLong(packet.referenceTimestamp);
Serial.print("Receive Timestamp 0x");
printLongLong(packet.receiveTimestamp);
Serial.print("Transmit Timestamp 0x");
printLongLong(packet.transmitTimestamp);
}
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin(9600);
while(!Serial);
Serial.println("Attempting to connect to the modem");
while(gsm.begin() != GSM_READY) {
Serial.print('.');
delay(100);
}
Serial.println();
Serial.println("Attempting to connect to the GPRS Access Point Name");
while(gprs.attachGPRS(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD) != GPRS_READY) {
Serial.print('.');
delay(100);
}
Serial.println();
while(!udp.begin(LOCAL_PORT));
sendNTPRequest(0,0);
Serial.println("Awaiting response");
int parsePacket;
do {
parsePacket = udp.parsePacket();
Serial.print("udp.parsePacket ");
Serial.println(parsePacket);
delay(100);
} while (parsePacket < 1);
// Serial.println("Response received");
// receiveNTPPacket();
// udp.stop();
}
void loop() {
Serial.print("udp.available ");
Serial.println(udp.available());
Serial.print("udp.peek ");
Serial.println(udp.peek());
Serial.print("udp.available ");
Serial.println(udp.available());
Serial.print("udp.read ");
Serial.println(udp.read());
delay(2000);
}
Calls to
udp.available()
appear to return -1 x number of bytes available.My program sends a Network Time Protocol request over UDP and receives a 48 byte response.
Here's the serial output:
Code (excluding
secrets.h
) is below. The relevant serial output comes fromvoid loop()
: