Go Down

Topic: Using pointers to strip values out of an UDP array returned by time server (Read 318 times) previous topic - next topic

book_woorm

Hi,
I'm trying to reduce the amount of SRAM and stack space used by the conventional method of getting the 4 bit NTP time returned by a UDP request by using pointers but it is failing to compile. Given that the 4 bytes required are at ofsets 40-43 of the array that is returned and that they are in the right order high to low we should be able to just point to them as an 'unsigned long' rather than go through the rigmarol of making a high word and a low word then combining these.

I've also added a bit of code designed to pole through three possible NTP servers in case there is a null return

Code: [Select]
void sendNTPpacket()
{
  Udp.begin(localPort);

  const byte NTP_PACKET_SIZE= 48;      // NTP time stamp is in the first 48 bytes of the message
  byte packetBuffer[NTP_PACKET_SIZE];  //buffer to hold incoming and outgoing packets
  byte * NTP_POINTER = packetBuffer;   // pointer to start of packet buffer )
  unsigned long ntpEpoch = 0;                // to hold number of seconds returned by time server
  unsigned long * ntpEpoch_POINTER;     // pointer to NTP Epoch need this to ensure we pick up all 4 bytes and not just the first one
  ntpEpoch_POINTER = NTP_POINTER + 40; pointer to osition of the 4 required bytes in the array

  byte i =0;                            // we have 3 NTP addresses so cycle through them if needs be
  while (!ntpEpoch && (i<3)){           // if ntpEpoch comes back with zero try one of the others
    // set all bytes in the inputBuffer 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(ntp_servers[i], 123); //NTP requests are to port 123
    Udp.write(packetBuffer,NTP_PACKET_SIZE);
    Udp.endPacket();
 
    delay(1000);
    if (Udp.parsePacket() !=0 ) { 
      // We've received a packet, read the data from it
      //Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
      Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
      //the timestamp starts at byte 40 of the received packet and is four bytes,
     
      ntpEpoch = *(ntpEpoch_POINTER) - 2208988800UL;
 
    }  //end 'If ( Udp.parsePacket() )' if we didnt have a time ntpEpoch is still zero
 
  i++;  // try another address it could still come back with zero but its unlikely
  }//end while
  if (ntpEpoch) { // figure is not zero so we've to reset
    timeError = systime-ntpEpoch;
    systime   = ntpEpoch; 
  }
  else {
    ReStart =3;//No return from NTP therfor systime is not updated
  }
  Udp.stop();
} //end 'sendNTPpacket'


the IDE is returning 'error: cannot convert 'byte*' to 'long unsigned int*' in assignment'.
Using pointers seems a neat idea but I'm not getting very far with it at the moment I'm sure somebody else has done this already but I havent found it in the playground or forum yet

pYro_65

If this is the line you are concerned about:
Code: [Select]
ntpEpoch_POINTER = NTP_POINTER + 40;

The error is due to the types being incompatible, strict aliasing rules are broken if you attempt to dereference a punned type:
Code: [Select]
ntpEpoch_POINTER = ( unsigned long* ) ( NTP_POINTER + 40 );

It may work for now, but is not good practice.

Also ensure your endianess is correct:
Code: [Select]

unsigned int i = 0x1234;
Serial.print( *( byte* )&i, HEX ); // = 0x34



Go Up