Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

udp.available() returning -1 x bytes available #105

Closed
MrWFoulkes opened this issue Feb 19, 2020 · 0 comments · Fixed by #107
Closed

udp.available() returning -1 x bytes available #105

MrWFoulkes opened this issue Feb 19, 2020 · 0 comments · Fixed by #107

Comments

@MrWFoulkes
Copy link

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);
}
Rocketct added a commit to Rocketct/MKRGSM that referenced this issue Mar 4, 2020
This changefix the  negative value returned by GSMUDP::available()

fix: arduino-libraries#105  arduino-libraries#106
Rocketct added a commit to Rocketct/MKRGSM that referenced this issue Mar 4, 2020
This changefix the  negative value returned by GSMUDP::available()

fix: arduino-libraries#105 and arduino-libraries#106
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant