// sntp.h

#ifndef _SNTP_h
#define _SNTP_h
//  Notes on NTP packet format from IETF RFC-2030, SNTP Specification (http://www.ietf.org/rfc/rfc2030.txt?number=2030) :
//
//NTP Timestamp Format
//
//   SNTP uses the standard NTP timestamp format described in RFC-1305 and
//   previous versions of that document. In conformance with standard
//   Internet practice, NTP data are specified as integer or fixed-point
//   quantities, with bits numbered in big-endian fashion from 0 starting
//   at the left, or high-order, position. Unless specified otherwise, all
//   quantities are unsigned and may occupy the full field width with an
//   implied 0 preceding bit 0.
//
//   Since NTP timestamps are cherished data and, in fact, represent the
//   main product of the protocol, a special timestamp format has been
//   established. NTP timestamps are represented as a 64-bit unsigned
//   fixed-point number, in seconds relative to 0h on 1 January 1900. The
//   integer part is in the first 32 bits and the fraction part in the
//   last 32 bits. In the fraction part, the non-significant low order can
//   be set to 0.
//
//      It is advisable to fill the non-significant low order bits of the
//      timestamp with a random, unbiased bitstring, both to avoid
//      systematic roundoff errors and as a means of loop detection and
//      replay detection (see below). One way of doing this is to generate
//      a random bitstring in a 64-bit word, then perform an arithmetic
//      right shift a number of bits equal to the number of significant
//      bits of the timestamp, then add the result to the original
//      timestamp.
//
//
//
//
//Mills                        Informational                      [Page 6]
//
//RFC 2030             SNTPv4 for IPv4, IPv6 and OSI          October 1996
//
//
//   This format allows convenient multiple-precision arithmetic and
//   conversion to UDP/TIME representation (seconds), but does complicate
//   the conversion to ICMP Timestamp message representation, which is in
//   milliseconds. The maximum number that can be represented is
//   4,294,967,295 seconds with a precision of about 200 picoseconds,
//   which should be adequate for even the most exotic requirements.
//
//                        1                   2                   3
//    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                           Seconds                             |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//   |                  Seconds Fraction (0-padded)                  |
//   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//   Note that, since some time in 1968 (second 2,147,483,648) the most
//   significant bit (bit 0 of the integer part) has been set and that the
//   64-bit field will overflow some time in 2036 (second 4,294,967,296).
//   Should NTP or SNTP be in use in 2036, some external means will be
//   necessary to qualify time relative to 1900 and time relative to 2036
//   (and other multiples of 136 years). There will exist a 200-picosecond
//   interval, henceforth ignored, every 136 years when the 64-bit field
//   will be 0, which by convention is interpreted as an invalid or
//   unavailable timestamp.
//
//      As the NTP timestamp format has been in use for the last 17 years,
//      it remains a possibility that it will be in use 40 years from now
//      when the seconds field overflows. As it is probably inappropriate
//      to archive NTP timestamps before bit 0 was set in 1968, a
//      convenient way to extend the useful life of NTP timestamps is the
//      following convention: If bit 0 is set, the UTC time is in the
//      range 1968-2036 and UTC time is reckoned from 0h 0m 0s UTC on 1
//      January 1900. If bit 0 is not set, the time is in the range 2036-
//      2104 and UTC time is reckoned from 6h 28m 16s UTC on 7 February
//      2036. Note that when calculating the correspondence, 2000 is not a
//      leap year. Note also that leap seconds are not counted in the
//      reckoning.
//
//4. NTP Message Format
//
//   Both NTP and SNTP are clients of the User Datagram Protocol (UDP)
//   [POS80], which itself is a client of the Internet Protocol (IP)
//   [DAR81]. The structure of the IP and UDP headers is described in the
//   cited specification documents and will not be detailed further here.
//   The UDP port number assigned to NTP is 123, which should be used in
//   both the Source Port and Destination Port fields in the UDP header.
//   The remaining UDP header fields should be set as described in the
//   specification.
//
//
//
//Mills                        Informational                      [Page 7]
//
//RFC 2030             SNTPv4 for IPv4, IPv6 and OSI          October 1996
//
//
//   Below is a description of the NTP/SNTP Version 4 message format,
//   which follows the IP and UDP headers. This format is identical to
//   that described in RFC-1305, with the exception of the contents of the
//   reference identifier field. The header fields are defined as follows:
//
//                           1                   2                   3
//       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                          Root Delay                           |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                       Root Dispersion                         |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                     Reference Identifier                      |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                                                               |
//      |                   Reference Timestamp (64)                    |
//      |                                                               |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                                                               |
//      |                   Originate Timestamp (64)                    |
//      |                                                               |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                                                               |
//      |                    Receive Timestamp (64)                     |
//      |                                                               |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                                                               |
//      |                    Transmit Timestamp (64)                    |
//      |                                                               |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                 Key Identifier (optional) (32)                |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                                                               |
//      |                                                               |
//      |                 Message Digest (optional) (128)               |
//      |                                                               |
//      |                                                               |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//   As described in the next section, in SNTP most of these fields are
//   initialized with pre-specified data. For completeness, the function
//   of each field is briefly summarized below.
//
//
//   Leap Indicator (LI): This is a two-bit code warning of an impending
//   leap second to be inserted/deleted in the last minute of the current
//   day, with bit 0 and bit 1, respectively, coded as follows:
//
//      LI       Value     Meaning
//      -------------------------------------------------------
//      00       0         no warning
//      01       1         last minute has 61 seconds
//      10       2         last minute has 59 seconds)
//      11       3         alarm condition (clock not synchronized)
//
//   Version Number (VN): This is a three-bit integer indicating the
//   NTP/SNTP version number. The version number is 3 for Version 3 (IPv4
//   only) and 4 for Version 4 (IPv4, IPv6 and OSI). If necessary to
//   distinguish between IPv4, IPv6 and OSI, the encapsulating context
//   must be inspected.
//
//   Mode: This is a three-bit integer indicating the mode, with values
//   defined as follows:
//
//      Mode     Meaning
//      ------------------------------------
//      0        reserved
//      1        symmetric active
//      2        symmetric passive
//      3        client
//      4        server
//      5        broadcast
//      6        reserved for NTP control message
//      7        reserved for private use
//
//   In unicast and anycast modes, the client sets this field to 3
//   (client) in the request and the server sets it to 4 (server) in the
//   reply. In multicast mode, the server sets this field to 5
//   (broadcast).
//
//   Stratum: This is a eight-bit unsigned integer indicating the stratum
//   level of the local clock, with values defined as follows:
//
//      Stratum  Meaning
//      ----------------------------------------------
//      0        unspecified or unavailable
//      1        primary reference (e.g., radio clock)
//      2-15     secondary reference (via NTP or SNTP)
//      16-255   reserved
//
//
//   Poll Interval: This is an eight-bit signed integer indicating the
//   maximum interval between successive messages, in seconds to the
//   nearest power of two. The values that can appear in this field
//   presently range from 4 (16 s) to 14 (16284 s); however, most
//   applications use only the sub-range 6 (64 s) to 10 (1024 s).
//
//   Precision: This is an eight-bit signed integer indicating the
//   precision of the local clock, in seconds to the nearest power of two.
//   The values that normally appear in this field range from -6 for
//   mains-frequency clocks to -20 for microsecond clocks found in some
//   workstations.
//
//   Root Delay: This is a 32-bit signed fixed-point number indicating the
//   total roundtrip delay to the primary reference source, in seconds
//   with fraction point between bits 15 and 16. Note that this variable
//   can take on both positive and negative values, depending on the
//   relative time and frequency offsets. The values that normally appear
//   in this field range from negative values of a few milliseconds to
//   positive values of several hundred milliseconds.
//
//   Root Dispersion: This is a 32-bit unsigned fixed-point number
//   indicating the nominal error relative to the primary reference
//   source, in seconds with fraction point between bits 15 and 16. The
//   values that normally appear in this field range from 0 to several
//   hundred milliseconds.
//
//   Reference Identifier: This is a 32-bit bitstring identifying the
//   particular reference source. In the case of NTP Version 3 or Version
//   4 stratum-0 (unspecified) or stratum-1 (primary) servers, this is a
//   four-character ASCII string, left justified and zero padded to 32
//   bits. In NTP Version 3 secondary servers, this is the 32-bit IPv4
//   address of the reference source. In NTP Version 4 secondary servers,
//   this is the low order 32 bits of the latest transmit timestamp of the
//   reference source. NTP primary (stratum 1) servers should set this
//   field to a code identifying the external reference source according
//   to the following list. If the external reference is one of those
//   listed, the associated code should be used. Codes for sources not
//   listed can be contrived as appropriate.
//
//
//      Code     External Reference Source
//      ----------------------------------------------------------------
//      LOCL     uncalibrated local clock used as a primary reference for
//               a subnet without external means of synchronization
//      PPS      atomic clock or other pulse-per-second source
//               individually calibrated to national standards
//      ACTS     NIST dialup modem service
//      USNO     USNO modem service
//      PTB      PTB (Germany) modem service
//      TDF      Allouis (France) Radio 164 kHz
//      DCF      Mainflingen (Germany) Radio 77.5 kHz
//      MSF      Rugby (UK) Radio 60 kHz
//      WWV      Ft. Collins (US) Radio 2.5, 5, 10, 15, 20 MHz
//      WWVB     Boulder (US) Radio 60 kHz
//      WWVH     Kaui Hawaii (US) Radio 2.5, 5, 10, 15 MHz
//      CHU      Ottawa (Canada) Radio 3330, 7335, 14670 kHz
//      LORC     LORAN-C radionavigation system
//      OMEG     OMEGA radionavigation system
//      GPS      Global Positioning Service
//      GOES     Geostationary Orbit Environment Satellite
//
//   Reference Timestamp: This is the time at which the local clock was
//   last set or corrected, in 64-bit timestamp format.
//
//   Originate Timestamp: This is the time at which the request departed
//   the client for the server, in 64-bit timestamp format.
//
//   Receive Timestamp: This is the time at which the request arrived at
//   the server, in 64-bit timestamp format.
//
//   Transmit Timestamp: This is the time at which the reply departed the
//   server for the client, in 64-bit timestamp format.
//
//   Authenticator (optional): When the NTP authentication scheme is
//   implemented, the Key Identifier and Message Digest fields contain the
//   message authentication code (MAC) information defined in Appendix C
//   of RFC-1305.

#if defined(ARDUINO) && ARDUINO >= 100
	#include "Arduino.h"
#else
	#include "WProgram.h"
#endif

#include "utility/socket.h"
#include "utility/netapp.h"

//#define CLOCK_DEBUG
//#define CLOCK_DEEP_DEBUG
//
#define SNTP_PORT	  ((uint16_t)123)   /* well-known NTP port number, assigned by IANA */

#define	MAX_URL_NAME		 31

#define MAX_NTP_SERVERS		  2

#define NUMBER_OF_TIME_ZONES 34


typedef enum SNTP_LI_t	{	no_warning = 0,
							sixty_One,
							fifty_Nine,
							alarm
						} SNTP_LI_t;

typedef enum SNTP_Mode_t {	reserved = 0,
							sym_active,
							sym_passive,
							client,
							server,
							broadcast,
							reserved_control,
							reserved_private
						 } SNTP_Mode_t;

typedef struct SNTP_Stratum_t
{
	uint8_t primary       : 1;
	uint8_t secondary     : 3;
	uint8_t reserved      : 4;
}SNTP_Stratum_t;

typedef struct SNTP_Timestamp_t
{
	uint32_t  seconds;
	int32_t  fraction;
}SNTP_Timestamp_t;

typedef struct SNTP_Message_t
{
	SNTP_Mode_t          mode          : 3;
	uint8_t              VN            : 3;
	SNTP_LI_t            LI            : 2;
	SNTP_Stratum_t       stratum;
	char                 poll;
	char                 precision;
	long                 delay;
	uint32_t             dispersion;
	uint32_t             referenceID;
	SNTP_Timestamp_t     tsReference;
	SNTP_Timestamp_t     tsOriginate;
	SNTP_Timestamp_t     tsReceive;
	SNTP_Timestamp_t     tsTransmit;
	//   uint32_t               key;                  //optional field - ignore
	//   uint8_t                messageDigest[128];   //optional field - ignore
}SNTP_Message_t;

typedef const char** NTP_Pool_t;							//Name of NTP server pool
typedef uint32_t  NTP_Server_List_t[MAX_NTP_SERVERS];   //list of ntp server addresses (as returned by NTP server pool)

/**
* Structure for NTP calendar time.
*
*/
typedef struct NetTime_t
{
	uint16_t millis; ///< Milliseconds after the second (0..999)
	uint8_t	 sec;    ///< Seconds after the minute (0..59)
	uint8_t	 min;    ///< Minutes after the hour (0..59)
	uint8_t	 hour;   ///< Hours since midnight (0..23)
	uint8_t	 mday;   ///< Day of the month (1..31)
	uint8_t	 mon;    ///< Months since January (0..11)
	uint16_t year;   ///< Year.
	uint8_t	 wday;	 ///< Days since Sunday (0..6)
	uint16_t yday;   ///< Days since January 1 (0..365)
	bool	 isdst;  ///< Daylight savings time flag, currently not supported
}NetTime_t;


class sntp
{
  public:
	sntp();
 	sntp(char* ntp_server_url1, short local_utc_offset);
 	sntp(char* ntp_server_url1, char* ntp_server_url2, short local_utc_offset);
 	sntp(char* ntp_server_url1, short local_utc_offset, short dst_utc_offset, bool enable_dst);
	sntp(char* ntp_server_url1, char* ntp_server_url2, short local_utc_offset, short dst_utc_offset, bool enable_dst);
	
	virtual ~sntp() {};
		
	NetTime_t			*ExtractNTPTime(/*in*/ SNTP_Timestamp_t *ntpTime, /*out*/ NetTime_t *extractedTime);

	bool				UpdateNTPTime();
	SNTP_Timestamp_t*	NTPGetTime(SNTP_Timestamp_t* ntpTime, bool local);
	SNTP_Timestamp_t*	NTPSetTime(SNTP_Timestamp_t* ntpTime, bool local);
	int					GetSystemClockAsNTPTime(SNTP_Timestamp_t* ntpSystemTime);
	
  private:
	char				GetNTPServerList(const char** ntp_pool_list, uint32_t* addrBuffer, int maxServerCount);
	bool				SNTP_GetTime(int sntpSocket, uint32_t *ntpServerAddr);

	NetTime_t			m_timeStruct;

	uint8_t				m_change_DST;					// 0 if no daylight savings time change, +1 if spring change, -1 if fall change

	SNTP_Timestamp_t	m_NTPReferenceTime;				//base time for real-time clock real time = this + millisecond ticker
	SNTP_Timestamp_t	m_std_UTC_offset;				//Local standard-time offset from UTC. Example: Eastern Standard is UTC - 5 hours
	SNTP_Timestamp_t	m_dst_UTC_offset;				//Local daylight-savings-time offset from UTC. Ex: Eastern Daylght is UTC - 4 hours
	SNTP_Timestamp_t*	m_cur_UTC_offset;				//Current offset from UTC. Pointer to either std_UTC_offset or dst_UTC_offset
	bool				m_twelveHour;					//use 12-hour time when true, 24-hour time when false
	bool  		        m_enable_dst;					//enable daylight savings time
	SNTP_Timestamp_t	m_dst_start;					// next date when DST starts
	SNTP_Timestamp_t	m_dst_end;						// next date when DST ends
	uint32_t			m_pollTime;						// in seconds, how often to poll NTP to update clock
	NTP_Pool_t			m_localPool;					//list of pool servers for current geographical location
	NTP_Pool_t			m_globalPool;					//list of global pool servers if no local servers respond
	uint8_t				m_userServerCount;				//number of NTP servers provded by user (not pool servers)
	const char*			m_userServers[MAX_NTP_SERVERS];	//list of NTP or NTP pool servers provided by user (pointers to userServerStrings)
	char				m_userServerStrings[MAX_NTP_SERVERS][MAX_URL_NAME+1]; //storage for user's NTP server URL strings

    bool				m_timeIsSet;					//false = current time is not set

};

//extern sntp SNTP;
extern Print* CC3KPrinter;

#endif

