NTP Client Hello World application.

18 Oct 2015

Hi,

This is a new post regarding the https://developer.mbed.org/questions/61217/How-stable-is-lwIP/#answer8809 question.

I narrowed the problems I've been having down to the NTP Client using the code below:

#include "mbed.h"
#include "EthernetInterface.h"
#include "NTPClient.h"

EthernetInterface eth;
NTPClient ntp;

int main() 
{
    int cnt = 0;
    
    printf ("\r\r");
    
    eth.init(); //Use DHCP
    eth.connect();
    while(1) {
        if (ntp.setTime("be.pool.ntp.org") == 0)
        {
          time_t ctTime;
          ctTime = time(NULL);
          printf("% 5u: Time is set to (UTC): %s\r", cnt ++, ctime(&ctTime));
        }
        else
        {
          printf("Error\r\n");
        }          
        wait(1);
    }
}

This program tries to set the RTC every second, yeah I know very demanding but in the interest of finding a bug very time saving.

I've set the DBG option in the NTPCLient.cpp source and just waited, it sometimes takes 20 tries sometimes about a 500, but it will hang eventually in the do loop in the snippet from NTPClient.cpp below.

  DBG("Pong");
  do
  {
    ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
    if(ret < 0)
    {
      ERR("Could not receive packet");
      m_sock.close();
      return NTP_CONN;
    }
    DBG(".");
  } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 );

As it turns out ... In the case at hand ... after 279 successful attempts, the NTPClient software is hung in the loop revealing no errors whatsoever.

 278: Time is set to (UTC): Sun Oct 18 17:48:49 2015
[NTPClient : DBG]Time is set to (UTC): Sun Oct 18 17:48:50 2015

[NTPClient : DBG]Binding socket
[NTPClient : DBG]Ping
[NTPClient : DBG]Pong
[NTPClient : DBG].
[NTPClient : DBG]All is good here!
[NTPClient : DBG]Sent @3654179330l
[NTPClient : DBG]Offset: 0
[NTPClient : DBG]Time is now (UTC): Sun Oct 18 17:48:50 2015

  279: Time is set to (UTC): Sun Oct 18 17:48:50 2015
[NTPClient : DBG]Time is set to (UTC): Sun Oct 18 17:48:51 2015

[NTPClient : DBG]Binding socket
[NTPClient : DBG]Ping
[NTPClient : DBG]Pong
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].
[NTPClient : DBG].

I need some help to get this solved ...

Thanks,

Koen.

20 Oct 2015

Nobody ? Why am I not surprised ? Well ... I deed some more digging. Seems that MBED gets stuck in the loop because the received endpoint stays blank

    4: Time is set to (UTC): Tue Oct 20 05:23:50 2015
[NTPClient : DBG]Time is set to (UTC): Tue Oct 20 05:23:51 2015

[NTPClient : DBG]Binding socket
[NTPClient : DBG]Ping
[NTPClient : DBG]Output Endpoint = 87.238.165.168
[NTPClient : DBG]Pong
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =
[NTPClient : DBG].
[NTPClient : DBG]Input Endpoint =

I believe this is caused by a lost UDP packet either transmitted or received. If i recall my CCNA or P whatever correctly UDP offers best effort so lost packets are a possibility. Furthermore when reading http://doc.ntp.org/4.1.1/accopt.htm the server may drop requests rather than sending a kiss of death.

The do loop therefor can wait forever for the inEndpoint and outEndpoint IP addresses to match. Without a re-transmission it will *most likely* never happen ;-) I removed the do loop from the NTPClient.cpp file, allowing the process to continue when no packet is received. The first if clause will trap socket binding error the second will trap the event where the number of bytes received doesn't match.

Modified snippet from NTPClient.cpp

  ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); 
  if(ret < 0)
  {
    ERR("Could not receive packet");
    m_sock.close();
    return NTP_CONN;
  }

  if(ret < sizeof(NTPPacket)) //TODO: Accept chunks
  {
    ERR("Receive packet size does not match");
    ERR("Received only: %u bytes of %u total", ret, sizeof(NTPPacket)); 
    m_sock.close();
    return NTP_PRTCL;
  }

  if( pkt.stratum == 0)  //Kiss of death message : Not good !
  {
    ERR("Kissed to death!");
    m_sock.close();
    return NTP_PRTCL;
  }

Lets see what happens if one takes a closer look at the amount of bytes received ... It must be zero if no packet is received.

   70: Time is set to (UTC): Tue Oct 20 12:47:33 2015
[NTPClient : DBG]Time is set to (UTC): Tue Oct 20 12:47:34 2015

[NTPClient : DBG]Binding socket
[NTPClient : DBG]Ping
[NTPClient : DBG]Pong
[NTPClient : ERR]Receive packet size does not match
[NTPClient : ERR]Received only: 0 bytes of 48 total

I think this confirms my conjecture. Also the Wireshark capture that was running did not capture a return packet from the NTP Server.

Can somebody proof me wrong or share some other insights?

KK

22 Oct 2015

Hi Koen, I think you are right. I can confirm the problems with NTPClient, hanging or receiving a date like 1 Jan 2066. I made a nice digital clock with date (and temperature using TMP102) on a Adafruit 64x32 RGB LED matrix. It connects to my WiFi and should reliable get the time right from an NTP server. Since that doesn't work, instead of using NTPClient, I started to use a 5-way button to set the date and time. But I would like to see NTPClient working too. :-) I haven't looked at it so deep, as I have a 2.5 year old boy at home who's getting most of my attention. :-) So only some late hours are left, if I'm unwilling to sleep...

22 Oct 2015

Hi Koen,

have you checked this?

Invalid IPAddress for Incoming EndPoint: https://developer.mbed.org/forum/repo-42768-PicoTCP-community/topic/16612/

Regards, Jack.

22 Oct 2015

Jack,

No i didn't, but I just did ... It seems like that is a related topic.

I understand the bugfix Martin suggests. However I do not understand why the loop should stay in place in the first place. I just finished some tests with my test program. It recovers fine from dropped request, keeping the RTC at its original setting and signalling the calling application a error occured.

I've committed my proposal for a bugfix, pending approval.

Koen.

22 Oct 2015

Hi Koen,

thank you very much for your contribution. I'm also interested in your fix.

Jack.

23 Oct 2015

On the other hand ... It might be safer to initialize the inEndpoint's address property on the count of network security. This is what I cooked up:

https://developer.mbed.org/users/KKempeneers/code/NTPClient/

It works fine for me, let me know if this works for you.

Koen.

23 Oct 2015

Hi Koen, it seems not to work for me, it only gets date 1 Jan 2066. I tried several times, after I reverted, it works again. Regards, Jack.

24 Oct 2015

May I have a peek at your application code?

KK

24 Oct 2015

Sure.

most is original.

main.cpp

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "mbed.h"
#include "cc3000.h"
#include "main.h"
#include "NTPClient.h"

#define CC3000_IRQ   D3  // (D3)
#define CC3000_EN    D5  // (D5)
#define CC3000_CS    D10 // (D10)
#define CC3000_MOSI  D11 // (D11)
#define CC3000_MISO  D12 // (D12)
#define CC3000_SCLK  D13 // (D13)

#define SSID         "Prakjaroen"
#define PHRASE       "A4B5C6D7E8F9"
#define SECURITY     WPA2

#define IP           "192.168.2.165"
#define MASK         "255.255.255.0"
#define GW           "192.168.2.1"
#define DHCP         1

using namespace mbed_cc3000;

#if defined TARGET_NUCLEO_F446RE
//cc3000 wifi(IRQ, EN, CS, SPI(MOSI, MISO, SCLK), SSID, PHRASE, SECURITY, false);
cc3000 wifi(D3, D5, D10, SPI(D11, D12, D13), "Prakjaroen", "A4B5C6D7E8F9", WPA2, false);
Serial pc(USBTX, USBRX);
#endif

/**
 *  \brief NTP client demo
 *  \param  none
 *  \return int
 */
int main() {
    init(); /* board dependent init */
    pc.baud(230400);
    
    printf("\r\n--------------------------------------------------------------------------------\r\n");
    printf("cc3000 NTP client demo for Nucleo F446RE.\r\n");
#if (DHCP == 1)
    printf("Initialize the interface using DHCP...\r\n");
    printf("wifi.init() ");
    wifi.init();
#else
    const char IP_ADDR[4] = {192,168,2,165};
    const char IP_MASK[4] = {255,255,255,0};
    const char IP_GWAY[4] = {192,168,2,1};
    printf("Initialize the interface using a static IP address...\r\n");
    printf("wifi.init(IP, MASK, GW) ");
    wifi.init(IP_ADDR, IP_MASK, IP_GWAY);
#endif
    printf("done.\r\n");
    printf("wifi.connect() ");
    if (wifi.connect() == -1) {
        printf("failed.\r\n");
        printf("Failed to connect. Please verify connection details and try again. \r\n");
    } else {
        printf("done.\r\n");
        printf("IP address: %s \r\n", wifi.getIPAddress());
    }

    NTPClient ntp_client;
    time_t ct_time;
    char time_buffer[80];    
    char time_buffer_old[80];    
    wait(1);

    strcpy(time_buffer_old, "");

    // Parameters
    char* domain_name = "0.uk.pool.ntp.org";
    int   port_number = 123;
    
    // Read time from server
    printf("Reading time...\r\n");
    ntp_client.setTime(domain_name, port_number, 2);

//    ct_time = time(NULL);
//    strftime(time_buffer, 80, "%a %b %d %T %p %z %Z\n", localtime(&ct_time));
//    printf("UTC/GMT: %s\n", time_buffer);
//    printf("UTC %s\n", ctime(&ct_time));

    // Choose standard or daylight savings time, comment out other
//    ct_time= time(NULL) + 3600; // Winter time - Convert to Europe/Amsterdam Time
    ct_time = time(NULL) + 7200; // Summer time - Convert to Europe/Amsterdam Time
    set_time(ct_time);

//    ct_time = time(NULL);
//    strftime(time_buffer, 80, "%a %d-%b-%Y %T", localtime(&ct_time));
//    printf("%s\r\n", time_buffer);

    strftime(time_buffer, 80, "%Y", localtime(&ct_time));
    printf("Year: %s\r\n", time_buffer);
    while (strcmp(time_buffer, "2066") == 0) {
        ntp_client.setTime(domain_name, port_number, 2);
        ct_time = time(NULL);
        strftime(time_buffer, 80, "%Y", localtime(&ct_time));
        printf("Year: %s\r\n", time_buffer);
    }
    while (1) {
        ct_time = time(NULL);
        strftime(time_buffer, 80, "%S", localtime(&ct_time));
        if (strcmp(time_buffer, time_buffer_old) != 0) {
            strcpy(time_buffer_old, time_buffer);

            // Sync once a day
            strftime(time_buffer, 80, "%T", localtime(&ct_time));
            if (strcmp(time_buffer, "00:00:00") == 0) {
                ntp_client.setTime(domain_name, port_number, 2);
                ct_time = time(NULL) + 7200;
            }

            strftime(time_buffer, 80, "%a %d-%b-%Y %T", localtime(&ct_time));
            printf("%s\r\n", time_buffer);
        }
        wait(0.01);
    }
}

ntpclient.cpp It has only these modifications

- m_sock.bind(123); Bind to a random port)

- MaxLoop in the do/while loop

/* NTPClient.cpp */
/* Copyright (C) 2012 mbed.org, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//Debug is disabled by defaulta
#if 0
//Enable debug
#define __DEBUG__
#include <cstdio>
#define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 
#define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 
#define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 

#else
//Disable debug
#define DBG(x, ...) 
#define WARN(x, ...)
#define ERR(x, ...) 

#endif

#include "NTPClient.h"

#include "UDPSocket.h"

#include "mbed.h" //time() and set_time()

#define NTP_PORT 123
#define NTP_CLIENT_PORT 0 //Random port
#define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)

NTPClient::NTPClient() : m_sock()
{


}

NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
{
#ifdef __DEBUG__
  time_t ctTime;
  ctTime = time(NULL);
  DBG("Time is set to (UTC): %s", ctime(&ctTime));
#endif

  //Create & bind socket
  DBG("Binding socket");
  m_sock.bind(123); //Bind to a random port
  
  m_sock.set_blocking(false, timeout); //Set not blocking

  struct NTPPacket pkt;

  //Now ping the server and wait for response
  DBG("Ping");
  //Prepare NTP Packet:
  pkt.li = 0; //Leap Indicator : No warning
  pkt.vn = 4; //Version Number : 4
  pkt.mode = 3; //Client mode
  pkt.stratum = 0; //Not relevant here
  pkt.poll = 0; //Not significant as well
  pkt.precision = 0; //Neither this one is

  pkt.rootDelay = 0; //Or this one
  pkt.rootDispersion = 0; //Or that one
  pkt.refId = 0; //...

  pkt.refTm_s = 0;
  pkt.origTm_s = 0;
  pkt.rxTm_s = 0;
  pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE

  pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;

  Endpoint outEndpoint;
  
  if( outEndpoint.set_address(host, port) < 0)
  {
    m_sock.close();
    return NTP_DNS;
  }
  
  //Set timeout, non-blocking and wait using select
  int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
  if (ret < 0 )
  {
    ERR("Could not send packet");
    m_sock.close();
    return NTP_CONN;
  }

  //Read response
  Endpoint inEndpoint;

  DBG("Pong");
  int MaxLoop = 100;
  do
  {
    MaxLoop--;
//    if (MaxLoop == 0)
//      printf("Pong\r\n");

  DBG("m_sock.receiveFrom() start");
    ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
  DBG("m_sock.receiveFrom() ended");
    if(ret < 0)
    {
      ERR("Could not receive packet");
      m_sock.close();
      return NTP_CONN;
    }
  } while( (strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 ) && (MaxLoop > 0));

//    printf(" - %d ", MaxLoop);

  if(ret < sizeof(NTPPacket)) //TODO: Accept chunks
  {
    ERR("Receive packet size does not match");
    m_sock.close();
    return NTP_PRTCL;
  }

  if( pkt.stratum == 0)  //Kiss of death message : Not good !
  {
    ERR("Kissed to death!");
    m_sock.close();
    return NTP_PRTCL;
  }

  //Correct Endianness
  pkt.refTm_s = ntohl( pkt.refTm_s );
  pkt.refTm_f = ntohl( pkt.refTm_f );
  pkt.origTm_s = ntohl( pkt.origTm_s );
  pkt.origTm_f = ntohl( pkt.origTm_f );
  pkt.rxTm_s = ntohl( pkt.rxTm_s );
  pkt.rxTm_f = ntohl( pkt.rxTm_f );
  pkt.txTm_s = ntohl( pkt.txTm_s );
  pkt.txTm_f = ntohl( pkt.txTm_f );

  //Compute offset, see RFC 4330 p.13
  uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
  int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
  DBG("Sent @%ul", pkt.txTm_s);
  DBG("Offset: %lld", offset);
  //Set time accordingly
  set_time( time(NULL) + offset );

#ifdef __DEBUG__
  ctTime = time(NULL);
  DBG("Time is now (UTC): %s", ctime(&ctTime));
#endif

  m_sock.close();

  return NTP_OK;
}
24 Oct 2015

Hi Jack:

the unit of timeout in setTime() is mini-seconds. Setting it at 2 will always result in timeout. Try to change 2 to 7000 and see if it works.

24 Oct 2015

Hi Koen, thank you very much, I changed 2 into 7000. It works, it first got 2066, but then 2015, which would not happen otherwise, I believe. I tried your version of NTPClient above with this setting, but that gets dates in 2066. It's maybe because of the combination with the cc3000.

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "mbed.h"
#include "cc3000.h"
#include "main.h"
#include "NTPClient.h"

#define CC3000_IRQ   D3  // (D3)
#define CC3000_EN    D5  // (D5)
#define CC3000_CS    D10 // (D10)
#define CC3000_MOSI  D11 // (D11)
#define CC3000_MISO  D12 // (D12)
#define CC3000_SCLK  D13 // (D13)

#define SSID         "Prakjaroen"
#define PHRASE       "A4B5C6D7E8F9"
#define SECURITY     WPA2

#define IP           "192.168.2.165"
#define MASK         "255.255.255.0"
#define GW           "192.168.2.1"
#define DHCP         1

using namespace mbed_cc3000;

#if defined TARGET_NUCLEO_F446RE
//cc3000 wifi(IRQ, EN, CS, SPI(MOSI, MISO, SCLK), SSID, PHRASE, SECURITY, false);
cc3000 wifi(D3, D5, D10, SPI(D11, D12, D13), "Prakjaroen", "A4B5C6D7E8F9", WPA2, false);
Serial pc(USBTX, USBRX);
#endif

/**
 *  \brief NTP client demo
 *  \param  none
 *  \return int
 */
int main() {
    init(); /* board dependent init */
    pc.baud(230400);
    
    printf("\r\n--------------------------------------------------------------------------------\r\n");
    printf("cc3000 NTP client demo for Nucleo F446RE.\r\n");
#if (DHCP == 1)
    printf("Initialize the interface using DHCP...\r\n");
    printf("wifi.init() ");
    wifi.init();
#else
    const char IP_ADDR[4] = {192,168,2,165};
    const char IP_MASK[4] = {255,255,255,0};
    const char IP_GWAY[4] = {192,168,2,1};
    printf("Initialize the interface using a static IP address...\r\n");
    printf("wifi.init(IP, MASK, GW) ");
    wifi.init(IP_ADDR, IP_MASK, IP_GWAY);
#endif
    printf("done.\r\n");
    printf("wifi.connect() ");
    if (wifi.connect() == -1) {
        printf("failed.\r\n");
        printf("Failed to connect. Please verify connection details and try again. \r\n");
    } else {
        printf("done.\r\n");
        printf("IP address: %s \r\n", wifi.getIPAddress());
    }

    NTPClient ntp_client;
    time_t ct_time;
    char time_buffer[80];    
    char time_buffer_old[80];    
    wait(1);

    strcpy(time_buffer_old, "");

    // Parameters
    char* domain_name = "0.uk.pool.ntp.org";
    int   port_number = 123;
    uint32_t ntp_timeout = 7000;
    
    // Read time from server
    printf("Reading time...\r\n");
    ntp_client.setTime(domain_name, port_number, ntp_timeout);

//    ct_time = time(NULL);
//    strftime(time_buffer, 80, "%a %b %d %T %p %z %Z\n", localtime(&ct_time));
//    printf("UTC/GMT: %s\n", time_buffer);
//    printf("UTC %s\n", ctime(&ct_time));

    // Choose standard or daylight savings time, comment out other
//    ct_time= time(NULL) + 3600; // Winter time - Convert to Europe/Amsterdam Time
    ct_time = time(NULL) + 7200; // Summer time - Convert to Europe/Amsterdam Time
    set_time(ct_time);

//    ct_time = time(NULL);
//    strftime(time_buffer, 80, "%a %d-%b-%Y %T", localtime(&ct_time));
//    printf("%s\r\n", time_buffer);

    strftime(time_buffer, 80, "%Y", localtime(&ct_time));
    printf("Year: %s\r\n", time_buffer);
    while (strcmp(time_buffer, "2066") == 0) {
        ntp_client.setTime(domain_name, port_number, ntp_timeout);
        ct_time = time(NULL);
        strftime(time_buffer, 80, "%Y", localtime(&ct_time));
        printf("Year: %s\r\n", time_buffer);
    }
    while (1) {
        ct_time = time(NULL);
        strftime(time_buffer, 80, "%S", localtime(&ct_time));
        if (strcmp(time_buffer, time_buffer_old) != 0) {
            strcpy(time_buffer_old, time_buffer);

            // Sync once a day
            strftime(time_buffer, 80, "%T", localtime(&ct_time));
            if (strcmp(time_buffer, "00:00:00") == 0) {
                ntp_client.setTime(domain_name, port_number, ntp_timeout);
                ct_time = time(NULL) + 7200;
            }

            strftime(time_buffer, 80, "%a %d-%b-%Y %T", localtime(&ct_time));
            printf("%s\r\n", time_buffer);
        }
        wait(0.01);
    }
}
25 Oct 2015

I'm glad it works for you ... But the latest post came from Zhiyong, so thanks should go out to him. I myself encountered a new error switching from Daylight Savings Time back to CET. Must be the time of year. :-)

KK