Time Library added to Playground

I'm not sure that I understand what your problem is, but, the first value that you print is done this way:
There will be truncation as a result of the division, ...
Would you try again to explain what your problem is, if this is not the culprit?

Thanks for looking at it. That's not the problem, I understand the variable type and rounding but that part is working fine.

The code waits for you to type "~" then sets the clock to 13:22:00, then immediately prints out the time once a second for 5 seconds. It also prints the millis counter (divided by 1000) as a reference. I expect the time printout to look like 13:22:00, 13:22:01, 13:22:02...13:22:05. I understand that with excecution times etc it might miss a second every now and then and am not worried about that either.

What I consistently get is the clock set to the 13:22:00 plus the time difference between the last clock print time from millis() and the current time from millis(). For example, the first set of data ends with a millis of 10e3, and the second set starts with millis of 19e3 (10 and 19 in the left column), and the second clock printouts are 9 seconds fast. Further down the there is a printout at 32 seconds then a clock setting at 75 seconds, and the clock is set 43 seconds fast (to 13:22:43). You can subtract the number on the left below the ----- from the number on the left above the ----- and predict how far off the clock setting will be.

I seem to be missing an activate/set/do it now!!! sort of command; my clock setting using setTime doesn't happen until sometime later.

I did switch to the old DateTime library and got this working just fine. Are there any bugs with the DateTime library or was it abandoned because there are more features in Time?

Thanks,
-Mike

Is it just me or does this library not work under IDE 0021? The NTP example is throwing up all kinds of errors.

It's not just you, Mike. I've been trying to sort through this as well.

I haven't tested the sketch yet, but I finally got it to compile on 0021. I'm not terribly familiar with C/C++ :-[ so I wouldn't mind a few "don't do that; do this" comments from the more elite folks.

Here's what I did:

  1. I previously had these files in an Ethernet directory under the /libraries directory. This works for other libraries but this TimeNTP code seemed to have issues finding the built-in Ethernet library files. I found the built-in Ethernet library directory and moved the library files for the Time stuff all into there.
  2. In all the files (UdpBytewise,UdpString,UdpRaw), change the extern area to:
    // extern "C" {
    // #include "types.h"
    #include "w5100.h"
    #include "socket.h"
    // }
  3. #include <SPI.h> at the top of the sketch
  4. Seems like some string methods got dropped from 0021 so these libraries have a hard time calling cstr or capacity on String. In hardware/arduino/cores/arduino/WString.h add the following to the public defs:
    const char * cstr() const {return _buffer;}
    int capacity() {return _capacity;}
  5. This one I'm the least sure about what's the best thing to do about the W5100 class - where/how it ought to be instantiated. The below will at least fix the compilation issues... so it's a naive start.
    UdpRaw.cpp:
    W5100Class wizzy;
    int UdpRawClass::available() {
    return wizzy.getRXReceivedSize(_sock);
    }
    and UdpString
    W5100Class wizzyForUdpString;
    int UdpStringClass::available() {
    return wizzyForUdpString.getRXReceivedSize(_sock);
    }

I forgot to mention that references in the Udp code to SnMR need to be updated to SnMR::UDP

I just tried the TimeNTP sketch (with 0021) on my Arduino and I'm successfully getting timestamps outputted to Serial every second.

I don't know a whole lot about arduino programming ect. but i downloaded the libary(the latestest version, download a few minutes ago) extacted it, copied and pasted it into the libraries file, load a example into arduino and try to compile and get the following errors in red at the bottom:

TimeSerial.cpp:12:20: error: Time.h: No such file or directory
TimeSerial:16: error: 'time_t' does not name a type
TimeSerial.cpp: In function 'void setup()':
TimeSerial:19: error: 'requestSync' was not declared in this scope
TimeSerial:19: error: 'setSyncProvider' was not declared in this scope
TimeSerial.cpp: In function 'void loop()':
TimeSerial:28: error: 'timeStatus' was not declared in this scope
TimeSerial:28: error: 'timeNotSet' was not declared in this scope
TimeSerial:30: error: 'timeSet' was not declared in this scope
TimeSerial.cpp: In function 'void digitalClockDisplay()':
TimeSerial:38: error: 'hour' was not declared in this scope
TimeSerial:39: error: 'minute' was not declared in this scope
TimeSerial:40: error: 'second' was not declared in this scope
TimeSerial:42: error: 'day' was not declared in this scope
TimeSerial:44: error: 'month' was not declared in this scope
TimeSerial:46: error: 'year' was not declared in this scope
TimeSerial.cpp: In function 'void processSyncMessage()':
TimeSerial:64: error: 'time_t' was not declared in this scope
TimeSerial:64: error: expected `;' before 'pctime'
TimeSerial:68: error: 'pctime' was not declared in this scope
TimeSerial:71: error: 'pctime' was not declared in this scope
TimeSerial:71: error: 'setTime' was not declared in this scope
TimeSerial.cpp: At global scope:
TimeSerial:76: error: 'time_t' does not name a type

I may be doing something wrong, if i am let me know, its the TimeSerial example sketch all i did was load the example(from the file, examples list) and hit compile. If it matters I am running the IDE 0021 on Windows 7 64 bit. Due to these errors i haven't even got to try loading it to an arduino (i have an uno and duemilanove)

Open the IDE, with a blank sketch. Use the Sketch + Import Library... menu item to try to import the Time library. You will probably find that you can't.

This indicates that you did not put the library in the correct place, or correctly in the place that you put it.

Make note of the name of one of the libraries that you CAN import. Use your computer's search capability to find that name. Look at where that name occurs, as opposed to where you put the time library. Look at the structure of that library, as opposed to the time library structure that you created.

The difference should be obvious. If not, post what you find, and we'll help you get it straightened out.

Hi, I propose a different way to set the date / time for the library. I implemented this because I get the time information out of a HTTP response. Here we find an UTC string where the month is encoded as 3 letter string.

Wed, 27 Oct 2010 18:18:04 GMT

I have an example code which works for me:

First define the months as PROGMEM variables.

prog_char m_jan[] PROGMEM = "Jan";   // The months for UTC Date conversion
prog_char m_feb[] PROGMEM = "Feb";
prog_char m_mar[] PROGMEM = "Mar";
prog_char m_apr[] PROGMEM = "Apr";
prog_char m_may[] PROGMEM = "May";
prog_char m_jun[] PROGMEM = "Jun";
prog_char m_jul[] PROGMEM = "Jul";
prog_char m_aug[] PROGMEM = "Aug";
prog_char m_sep[] PROGMEM = "Sep";
prog_char m_oct[] PROGMEM = "Oct";
prog_char m_nov[] PROGMEM = "Nov";
prog_char m_dec[] PROGMEM = "Dec";

PROGMEM const char *MONTHS[] =          // as an array
{   
  m_jan, m_feb, m_mar, m_apr, m_may, m_jun, m_jul, m_aug, m_sep, m_oct, m_nov, m_dec
};

Then just iterate over them until it could be matched. datebuf helds a string as shown above.

    int h,m,s,y,d,mo = 0;
    char mon[2];
    sscanf(datebuf,"%*s %d %s %d %d:%d:%d",&d,&mon,&y,&h,&m,&s); //split the UTC Date string
  
    while (strcmp_P(mon, (char*)pgm_read_word(&(MONTHS[mo]))) != 0) //decode the month
        mo++;

    // NOTICE: the actual month is mo+1 !!
    setTime(h,m,s,d,mo+1,y); // to set with the time library

I hope this helps.. Who do I best contact to integrate this in the Time Library?

Hope this helps someone
Michael

Syncing time is not precise. I am using the timeserial example with a little addition. Just after the setTime(pctime); command I've added two commands to print both the pctime (that was just set) and the now() internal time. I suppose they should be the same, but they never are.

The output is like this:

1288477507
1288477511

1288477507
1288477510

1288477507
1288477610

1288477507
1288477516

I think this is the same problem Breezetrees is referring to. Any idea how to sync the time with more precision?

Just after the setTime(pctime); command I've added two commands to print both the pctime (that was just set) and the now() internal time. I suppose they should be the same, but they never are.

Let's see the code. There is, of course, some time taken to set the time and some time taken to get the time. There may also, depending on your code, be time taken to print the time to the serial port.

Just send T1262347200 a couple of times via serial, and see the result...

/* 
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */ 
 
#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() ) 
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)   
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  /* // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); */
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    Serial.print(c);  
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
      Serial.print("timeStatus() = ");
      Serial.print(timeStatus());
      Serial.print(", pctime = ");
      Serial.print(pctime);
      Serial.print(" and now() = ");
      Serial.println(now());
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST,BYTE);  
  return 0; // the time will be sent later in response to serial mesg
}

Try calling now() immediately after setTime(), and storing the value returned. Print that value, where you now print now().

I've tried that, no difference, still quite large discrepancies in the synced time (now()) with the original time send via serial (pctime). The older DateTime library doesn't have this behaviour in the same situation.

The example below is what happens when the time T1288477507 was send 4 times to sync via serial.

\0x07Waiting for sync message

TtimeStatus() = 2, pctime = 1288477507 and now() = 1288477512

TtimeStatus() = 2, pctime = 1288477507 and now() = 1288477513

TtimeStatus() = 2, pctime = 1288477507 and now() = 1288477516

TtimeStatus() = 2, pctime = 1288477507 and now() = 1288477515

/*
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */

#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message
unsigned long timeStorage = 0;

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() )
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)  
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  /* // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println(); */
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ;
    Serial.print(c);  
    if( c == TIME_HEADER ) {      
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){  
        c = Serial.read();          
        if( c >= '0' && c <= '9'){  
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }  
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
      timeStorage = now();
      Serial.print("timeStatus() = ");
      Serial.print(timeStatus());
      Serial.print(", pctime = ");
      Serial.print(pctime);
      Serial.print(" and now() = ");
      Serial.println(timeStorage);
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST,BYTE);  
  return 0; // the time will be sent later in response to serial mesg
}

There may be a weakness in setTime(). Try to call now() right before you call setTime(). If that solves the problem, let us know it, then we can have it fixed.

Korman

Try to call now() right before you call setTime().

If the value returned by now() is supposed to be set by the call to setTime(), how in the heck is calling now() first going to accomplish anything?

No, I mean something like:

[glow]now();[/glow]
setTime(pctime);
timeStorage = now();

And no, that's not voodoo, it might prevent a potential problem from happening. If everything works fine with the additional now(), we have discovered a bug which will be easy to solve. If it doesn't the thing I imagined to be a problem isn't one and we're barking up the wrong tree.

Korman

That indeed solves the problem. So if I understand it right, to get a precise sync, for the moment, you need to call now() just before setTime() ?

\0x07Waiting for sync message

\0x07
now() time before syncing = 3
pctime, time that was synced with
= 1288477507
timeStatus() after syncing = 2
now() time after syncing = 1288477507

now() time before syncing = 1288477549
pctime, time that was synce
d with = 1288477507
timeStatus() after syncing = 2
now() time after syncing = 1288477507

now() time before syncing = 1288477534
pctime, time that was sy
nced with = 1288477507
timeStatus() after syncing = 2
now() time after syncing = 1288477507

/*
 * TimeSerial.pde
 * example code illustrating Time library set through serial port messages.
 *
 * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970)
 * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010
 T1262347200  
 *
 * A Processing example sketch to automatically send the messages is inclided in the download
 */

#include <Time.h>  

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message
unsigned long timeStorage = 0;

void setup()  {
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
}

void loop(){    
  if(Serial.available() )
  {
    processSyncMessage();
  }
  if(timeStatus()!= timeNotSet)  
  {
    digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh  
    digitalClockDisplay();  
  }
  delay(1000);
}

void digitalClockDisplay(){
  /* // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println(); */
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ; 
    if( c == TIME_HEADER ) {      
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){  
        c = Serial.read();          
        if( c >= '0' && c <= '9'){  
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }  
      timeStorage = now();
      Serial.println();
      Serial.print("now() time before syncing = ");
      Serial.println(timeStorage);
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
      timeStorage = now();
      Serial.print("pctime, time that was synced with = ");
      Serial.println(pctime);
      Serial.print("timeStatus() after syncing = ");
      Serial.println(timeStatus());
      Serial.print("now() time after syncing = ");
      Serial.println(timeStorage);
    }  
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST,BYTE);  
  return 0; // the time will be sent later in response to serial mesg
}

That indeed solves the problem.

Ok, the bug in the setTime function is that it doesn't reset prevMillis to the value of millis(). So the next time you call now(), the difference between the last call to now() and the current value of millis() will be added to the time you just adjusted with setTime(). If now is called often enough, that isn't a visible problem. However if you call now() only every 5 seconds and use setTime() directly, you get that weird offset you saw.

Next step: Finding out who maintains the Time library and where to post a patch...

Korman

Thanks Korman.

I have added the fix and uploaded it to the Playground.
Give it a go and let me know how you get on.

Wow, that is a quick bugfix! :slight_smile:

It's working just fine now.

Mem,

it looks good now. Thank you for the quick response. For completeness here's my test program which fails with the old library and works with the new one:

#include <Time.h>
void setup () {
      Serial.begin (9600);
      delay (10000);
      Serial.println (now());
      delay (10000);
      setTime (123456789);
      Serial.println (now());
}
void loop(){
}

Results with old Time library - highlight is wrong:

10
123456799

Results with new Time library - highlight is ok now:

10
123456789

Korman