2 * FreeRTOS+TCP V2.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
32 * An example of how to lookup a domain using DNS
\r
33 * And also how to send and receive UDP messages to get the NTP time
\r
37 /* Standard includes. */
\r
43 /* FreeRTOS includes. */
\r
44 #include "FreeRTOS.h"
\r
48 /* FreeRTOS+TCP includes. */
\r
49 #include "FreeRTOS_IP.h"
\r
50 #include "FreeRTOS_Sockets.h"
\r
51 #include "FreeRTOS_DNS.h"
\r
52 #include "FreeRTOS_Stream_Buffer.h"
\r
54 /* Use the date & time functions from +FAT. */
\r
55 #include "ff_time.h"
\r
57 #include "NTPDemo.h"
\r
58 #include "ntpClient.h"
\r
60 #include "date_and_time.h"
\r
69 static struct SNtpPacket xNTPPacket;
\r
71 #if( ipconfigUSE_CALLBACKS == 0 )
\r
72 static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ];
\r
75 static enum EStatus xStatus = EStatusLookup;
\r
77 static const char *pcTimeServers[] = {
\r
78 "0.asia.pool.ntp.org",
\r
79 "0.europe.pool.ntp.org",
\r
80 "0.id.pool.ntp.org",
\r
81 "0.south-america.pool.ntp.org",
\r
82 "0.oceania.pool.ntp.org",
\r
83 "0.north-america.pool.ntp.org"
\r
86 static SemaphoreHandle_t xNTPWakeupSem = NULL;
\r
87 static uint32_t ulIPAddressFound;
\r
88 static Socket_t xUDPSocket = NULL;
\r
89 static TaskHandle_t xNTPTaskhandle = NULL;
\r
90 static TickType_t uxSendTime;
\r
92 static void prvNTPTask( void *pvParameters );
\r
94 static void vSignalTask( void )
\r
96 #if( ipconfigUSE_CALLBACKS == 0 )
\r
97 if( xUDPSocket != NULL )
\r
99 /* Send a signal to the socket so that the
\r
100 FreeRTOS_recvfrom will get interrupted. */
\r
101 FreeRTOS_SignalSocket( xUDPSocket );
\r
105 if( xNTPWakeupSem != NULL )
\r
107 xSemaphoreGive( xNTPWakeupSem );
\r
111 void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority )
\r
113 /* The only public function in this module: start a task to contact
\r
114 some NTP server. */
\r
116 if( xNTPTaskhandle != NULL )
\r
121 xStatus = EStatusAsking;
\r
124 case EStatusLookup:
\r
125 FreeRTOS_printf( ( "NTP looking up server\n" ) );
\r
127 case EStatusAsking:
\r
128 FreeRTOS_printf( ( "NTP still asking\n" ) );
\r
130 case EStatusFailed:
\r
131 FreeRTOS_printf( ( "NTP failed somehow\n" ) );
\r
132 ulIPAddressFound = 0ul;
\r
133 xStatus = EStatusLookup;
\r
140 xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
\r
141 if( xUDPSocket != NULL )
\r
143 struct freertos_sockaddr xAddress;
\r
144 #if( ipconfigUSE_CALLBACKS != 0 )
\r
145 BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 );
\r
147 BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 );
\r
150 xAddress.sin_addr = 0ul;
\r
151 xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
\r
153 FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) );
\r
154 FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
\r
155 xTaskCreate( prvNTPTask, /* The function that implements the task. */
\r
156 ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */
\r
157 usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
\r
158 NULL, /* The task parameter, not used in this case. */
\r
159 uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
\r
160 &xNTPTaskhandle ); /* The task handle. */
\r
164 FreeRTOS_printf( ( "Creating socket failed\n" ) );
\r
168 /*-----------------------------------------------------------*/
\r
170 static void vDNS_callback( const char *pcName, void *pvSearchID, uint32_t ulIPAddress )
\r
174 /* The DNS lookup has a result, or it has reached the time-out. */
\r
175 FreeRTOS_inet_ntoa( ulIPAddress, pcBuf );
\r
176 FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) );
\r
177 if( ulIPAddressFound == 0ul )
\r
179 ulIPAddressFound = ulIPAddress;
\r
181 /* For testing: in case DNS doen't respond, still try some NTP server
\r
182 with a known IP-address. */
\r
183 if( ulIPAddressFound == 0ul )
\r
185 ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 );
\r
186 /* ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242, 70, 4 ); */
\r
188 xStatus = EStatusAsking;
\r
192 /*-----------------------------------------------------------*/
\r
194 static void prvSwapFields( struct SNtpPacket *pxPacket)
\r
196 /* NTP messages are big-endian */
\r
197 pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay );
\r
198 pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion );
\r
200 pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds );
\r
201 pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction );
\r
203 pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds );
\r
204 pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction );
\r
206 pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds );
\r
207 pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction );
\r
209 pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds );
\r
210 pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction );
\r
212 /*-----------------------------------------------------------*/
\r
214 static void prvNTPPacketInit( )
\r
216 memset (&xNTPPacket, '\0', sizeof( xNTPPacket ) );
\r
218 xNTPPacket.flags = 0xDB; /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */
\r
219 xNTPPacket.poll = 10; /* 10 means 1 << 10 = 1024 seconds */
\r
220 xNTPPacket.precision = 0xFA; /* = 250 = 0.015625 seconds */
\r
221 xNTPPacket.rootDelay = 0x5D2E; /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */
\r
222 xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912 seconds */
\r
224 /* use the recorded NTP time */
\r
225 time_t uxSecs = FreeRTOS_time( NULL );/* apTime may be NULL, returns seconds */
\r
227 xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */
\r
228 xNTPPacket.transmitTimestamp.seconds = uxSecs + 3;
\r
230 /* Transform the contents of the fields from native to big endian. */
\r
231 prvSwapFields( &xNTPPacket );
\r
233 /*-----------------------------------------------------------*/
\r
235 static void prvReadTime( struct SNtpPacket * pxPacket )
\r
237 FF_TimeStruct_t xTimeStruct;
\r
238 time_t uxPreviousSeconds;
\r
239 time_t uxPreviousMS;
\r
241 time_t uxCurrentSeconds;
\r
242 time_t uxCurrentMS;
\r
244 const char *pcTimeUnit;
\r
246 TickType_t uxTravelTime;
\r
248 uxTravelTime = xTaskGetTickCount() - uxSendTime;
\r
250 /* Transform the contents of the fields from big to native endian. */
\r
251 prvSwapFields( pxPacket );
\r
253 uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970;
\r
254 uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967;
\r
255 uxCurrentSeconds += uxCurrentMS / 1000;
\r
256 uxCurrentMS = uxCurrentMS % 1000;
\r
258 // Get the last time recorded
\r
259 uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS );
\r
261 // Set the new time with precision in msec. */
\r
262 FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS );
\r
264 if( uxCurrentSeconds >= uxPreviousSeconds )
\r
266 ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds );
\r
270 ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds );
\r
273 if( ( ilDiff < -5 ) || ( ilDiff > 5 ) )
\r
275 /* More than 5 seconds difference. */
\r
276 pcTimeUnit = "sec";
\r
280 /* Less than or equal to 5 second difference. */
\r
282 uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds;
\r
283 int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS;
\r
284 int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS;
\r
285 ilDiff = iCurMS - iPrevMS;
\r
287 uxCurrentSeconds -= iTimeZone;
\r
289 FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct );
\r
292 378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms)
\r
293 379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms)
\r
296 FreeRTOS_printf( ("NTP time: %d/%d/%02d %2d:%02d:%02d.%03u Diff %d %s (%lu ms)\n",
\r
297 xTimeStruct.tm_mday,
\r
298 xTimeStruct.tm_mon + 1,
\r
299 xTimeStruct.tm_year + 1900,
\r
300 xTimeStruct.tm_hour,
\r
301 xTimeStruct.tm_min,
\r
302 xTimeStruct.tm_sec,
\r
303 ( unsigned )uxCurrentMS,
\r
304 ( unsigned )ilDiff,
\r
308 /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
\r
309 ( void ) pcTimeUnit;
\r
310 ( void ) uxTravelTime;
\r
312 /*-----------------------------------------------------------*/
\r
314 #if( ipconfigUSE_CALLBACKS != 0 )
\r
316 static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pvData, size_t xLength,
\r
317 const struct freertos_sockaddr *pxFrom, const struct freertos_sockaddr *pxDest )
\r
319 if( xLength >= sizeof( xNTPPacket ) )
\r
321 prvReadTime( ( struct SNtpPacket *)pvData );
\r
322 if( xStatus != EStatusPause )
\r
324 xStatus = EStatusPause;
\r
328 /* Tell the driver not to store the RX data */
\r
331 /*-----------------------------------------------------------*/
\r
333 #endif /* ipconfigUSE_CALLBACKS != 0 */
\r
335 static void prvNTPTask( void *pvParameters )
\r
337 BaseType_t xServerIndex = 3;
\r
338 struct freertos_sockaddr xAddress;
\r
339 #if( ipconfigUSE_CALLBACKS != 0 )
\r
340 F_TCP_UDP_Handler_t xHandler;
\r
341 #endif /* ipconfigUSE_CALLBACKS != 0 */
\r
343 xStatus = EStatusLookup;
\r
344 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 )
\r
346 xNTPWakeupSem = xSemaphoreCreateBinary();
\r
350 #if( ipconfigUSE_CALLBACKS != 0 )
\r
352 memset( &xHandler, '\0', sizeof( xHandler ) );
\r
353 xHandler.pxOnUDPReceive = xOnUDPReceive;
\r
354 FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) );
\r
357 #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
\r
359 FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) );
\r
366 case EStatusLookup:
\r
367 if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) )
\r
369 if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) )
\r
373 FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) );
\r
374 FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 );
\r
378 xStatus = EStatusAsking;
\r
382 case EStatusAsking:
\r
386 prvNTPPacketInit( );
\r
387 xAddress.sin_addr = ulIPAddressFound;
\r
388 xAddress.sin_port = FreeRTOS_htons( NTP_PORT );
\r
390 FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf );
\r
391 FreeRTOS_printf( ( "Sending UDP message to %s:%u\n",
\r
393 FreeRTOS_ntohs( xAddress.sin_port ) ) );
\r
395 uxSendTime = xTaskGetTickCount( );
\r
396 FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) );
\r
403 case EStatusFailed:
\r
407 #if( ipconfigUSE_CALLBACKS != 0 )
\r
409 xSemaphoreTake( xNTPWakeupSem, 5000 );
\r
413 uint32_t xAddressSize;
\r
414 BaseType_t xReturned;
\r
416 xAddressSize = sizeof( xAddress );
\r
417 xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize );
\r
418 switch( xReturned )
\r
421 case -pdFREERTOS_ERRNO_EAGAIN:
\r
422 case -pdFREERTOS_ERRNO_EINTR:
\r
425 if( xReturned < sizeof( xNTPPacket ) )
\r
427 FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) );
\r
431 prvReadTime( ( struct SNtpPacket *)cRecvBuffer );
\r
432 if( xStatus != EStatusPause )
\r
434 xStatus = EStatusPause;
\r
443 /*-----------------------------------------------------------*/
\r