Due compatible Time library?

I recently ported the Time library for Teensy 3.0. This doesn't directly support the Due RTC, but it's meant to work together with the library mentioned above.

Michael Margolis (author of this Time library) and I talked about the time_t compatibility issue. His preference was to rename it to atime_t. Probably "a" for Arduino?

Here's the modified code:

~~http://www.pjrc.com/teensy/beta/Time.zip~~ (edit: do not use this old beta copy)

This is the final, well tested Time library:
http://www.pjrc.com/teensy/td_libs_Time.html

I really should have followed up by updating the playground page.

Can anyone here please test this on Due and then update the playground page? The original code has a TimeAlarms library in the same file, which I haven't used (I did start on it... contact me for the code). It probably needs to be split into a separate download, ported and tested. The page also mentions "time_t", which needs to be edited to "atime_t". I simply ran out of time to update the page.

Yuck! That seems like a dreadful solution.
Please, please don't go down that route. That is such a Windows-fix-of-the-moment type of fix.
That really breaks compatibility especially for those writing code that will use the time type for
things like calculating time intervals.
Why not use the __time_t_defined define to determine whether or not the system has already typed time_t ?
The define could be tested to see if time_t needs to be typed in the library Time.h file.
This seems like a proper fix.

Add this to the Time library Time.h header file:

#ifndef __time_t_defined
typedef unsigned long time_t;
#endif

Then the STUPID IDE also has an issue that rears it ugly head again that breaks this.
The IDE inserts its prologue which includes

#include "Arduino.h"

in the middle of the sketch .cpp file so it ends up after the

#include <Time.h>

So the system version of time_t doesn't get typed before the library Time.h looks at the define.
You have to insert some dummy code to coerce the silly IDE to put the prologue at the top of the .cpp file
I added this to the example sketch:

int dummy = 0;

right at the top of the sketch.

(Can't the IDE be fixed to avoid this silly wrong location prologue insertion????)

One thing that is concerning to me is that since Windows is doesn't handle mixed case
on its file names, #include <Time.h> might end up pulling in the system time.h since it is earlier on the include path
(I don't do Windows so I'm not sure about that).

--- bill

Hello Paul Stoffregen,

I have tested your version of Time and it's remotely to be ported for Due. Actually I already did the time_t variable name change, but that is not the only thing that need to be modified (I did it as bperrybap suggest thought).

#include <machine/types.h>

#ifndef __time_t_defined
//typedef unsigned long time_t;			// original library typedef.
typedef _TIME_T_ time_t;				
#define __time_t_defined
#endif

After that I have been through several compiling errors I would like to bring them here.
First with setTime function, it seems that overloading that function bothers the compiler
previous declaration 'void setTime(atime_t)' here

I decide to remove (comment out) the version with more arguments as you can use the makeTime to have time_t from individual values.
I also have to remove from Time Folder the file DateStrings.cpp.

After all that I make a simple test file like this

#include <Wire.h>  
#include <Time.h>  

void setup()  {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("setup RTC test");

  tmElements_t t;
  t.Second = 0;
  t.Minute = 30;
  t.Hour = 19;
  t.Wday = 3;
  t.Day = 16;
  t.Month = 1;
  t.Year = y2kYearToTm(13);
  Serial.println("setup makeTime");
  makeTime(t);
//  setTime(makeTime(t));
  Serial.println("how come  ");

  
}
void loop()
{
   digitalClockDisplay();  
   delay(1000);
}



void digitalClockDisplay(){
  // digital clock display of the time
  time_t t = now();
  Serial.print(hour(t));
  printDigits(minute(t));
  printDigits(second(t));
  Serial.print(" ");
  Serial.print(day(t));
  Serial.print(" ");
  Serial.print(month(t));
  Serial.print(" ");
  Serial.print(year(t)); 
  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);
}

the good thing is that it compiles but the bad is that a warning appears

test_time.cpp.o: In function setup':* *C:\...\arduino-1.5.1r2/test_time.ino:24: warning: undefined reference to makeTime(tmElements_t&)'
Binary sketch size: 25,856 bytes (of a 524,288 byte maximum)

I recently discover that if you put the Time.h include at the beginning of the import section it produces the above error and the Due hangs before it can print "how come".

If you put any other import before Time.h it compiles cleanly and run without problems.

Maybe it have to do with

Then the STUPID IDE also has an issue that rears it ugly head again that breaks this.
The IDE inserts its prologue which includes
Code:
#include "Arduino.h"
in the middle of the sketch .cpp file so it ends up after the
Code:
#include <Time.h>
So the system version of time_t doesn't get typed before the library Time.h looks at the define.
You have to insert some dummy code to coerce the silly IDE to put the prologue at the top of the .cpp file
I added this to the example sketch:
Code:
int dummy = 0;
right at the top of the sketch.

I found another issue, in file Time.h the line

typedef time_t(*getExternalTime)();

should be

typedef time_t(*getExternalTime)(void);

Best,

Hello, I'm trying to compile this libs on Arduino due for use an external TinyRTC

#include <Wire.h>
#include <Time.h> // lib with updates from this post
#include <DS1307RTC.h> //lib from http://www.pjrc.com/teensy/td_libs_DS1307RTC.html

void setup() {
  // put your setup code here, to run once:
}
void loop() {
  // put your main code here, to run repeatedly:
}

and I have this errors =(:

In file included from sketch_apr09a.ino:6:
D:\\\Arduino\libraries\DS1307RTC/DS1307RTC.h:45: error: expected ')' before '*' token
D:\\\Arduino\libraries\DS1307RTC/DS1307RTC.h:45: error: expected ')' before '*' token

any idea :disappointed_relieved: I've run this code on Arduino MEGA and I have no error

Could you try using both Time and DS1307RTC from the PJRC site? Maybe you've got an older version?

If that doesn't work, could you also try those 2 with Arduino 1.5.2? Maybe something has changed since they were tested on 1.5.2?

Enrique_SL:
Hello, I'm trying to compile this libs on Arduino due for use an external TinyRTC

#include <Wire.h>

#include <Time.h> // lib with updates from this post
#include <DS1307RTC.h> //lib from DS1307RTC Library, For Accessing Real Time Clock (RTC) Chips

void setup() {
  // put your setup code here, to run once:
}
void loop() {
  // put your main code here, to run repeatedly:
}





and I have this errors =(:




In file included from sketch_apr09a.ino:6:
D:\\Arduino\libraries\DS1307RTC/DS1307RTC.h:45: error: expected ')' before '' token
D:\\Arduino\libraries\DS1307RTC/DS1307RTC.h:45: error: expected ')' before '
' token




any idea :disappointed_relieved: I've run this code on Arduino MEGA and I have no error
[/quote]

DS1307RTC.h


#ifndef DS1307RTC_h
#define DS1307RTC_h
#include <Time.h>
class DS1307RTC
{
public:
 
DS1307RTC();
static time_t get(void);    
static bool set(time_t t);    
static bool read(tmElements_t &tm);  
static bool write(tmElements_t &tm);  
static bool chipPresent(void) {return exists;}

private:

static bool exists;
static uint8_t dec2bcd(uint8_t num);  
static uint8_t bcd2dec(uint8_t num);
};
extern DS1307RTC RTC;
#endif




DS1307RTC.cpp



#include <Wire.h>
#include "DS1307RTC.h"

#define DS1307_CTRL_ID 0x68
DS1307RTC::DS1307RTC()
{
 Wire.begin();
}

// PUBLIC FUNCTIONS
time_t DS1307RTC::get()   // Aquire data from buffer and convert to time_t
{
 tmElements_t tm;
 if (read(tm) == false) return 0;
 return(makeTime(tm));
}
bool DS1307RTC::set(time_t t)
{
 tmElements_t tm;
 breakTime(t, tm);
 tm.Second |= 0x80;  // stop the clock
 write(tm);
 tm.Second &= 0x7f;  // start the clock
 write(tm);
}
// Aquire data from the RTC chip in BCD format
bool DS1307RTC::read(tmElements_t &tm)
{
 uint8_t sec;
 Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100  
 Wire.write((uint8_t)0x00);
#else
 Wire.send(0x00);
#endif  
 if (Wire.endTransmission() != 0) {
   exists = false;
   return false;
 }
 exists = true;
 // request the 7 data fields   (secs, min, hr, dow, date, mth, yr)
 Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);
 if (Wire.available() < tmNbrFields) return false;
#if ARDUINO >= 100
 sec = Wire.read();
 tm.Second = bcd2dec(sec & 0x7f);  
 tm.Minute = bcd2dec(Wire.read() );
 tm.Hour =   bcd2dec(Wire.read() & 0x3f);  // mask assumes 24hr clock
 tm.Wday = bcd2dec(Wire.read() );
 tm.Day = bcd2dec(Wire.read() );
 tm.Month = bcd2dec(Wire.read() );
 tm.Year = y2kYearToTm((bcd2dec(Wire.read())));
#else
 sec = Wire.receive();
 tm.Second = bcd2dec(sec & 0x7f);  
 tm.Minute = bcd2dec(Wire.receive() );
 tm.Hour =   bcd2dec(Wire.receive() & 0x3f);  // mask assumes 24hr clock
 tm.Wday = bcd2dec(Wire.receive() );
 tm.Day = bcd2dec(Wire.receive() );
 tm.Month = bcd2dec(Wire.receive() );
 tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
#endif
 if (sec & 0x80) return false; // clock is halted
 return true;
}
bool DS1307RTC::write(tmElements_t &tm)
{
 Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100  
 Wire.write((uint8_t)0x00); // reset register pointer  
 Wire.write(dec2bcd(tm.Second)) ;  
 Wire.write(dec2bcd(tm.Minute));
 Wire.write(dec2bcd(tm.Hour));      // sets 24 hour format
 Wire.write(dec2bcd(tm.Wday));  
 Wire.write(dec2bcd(tm.Day));
 Wire.write(dec2bcd(tm.Month));
 Wire.write(dec2bcd(tmYearToY2k(tm.Year)));
#else  
 Wire.send(0x00); // reset register pointer  
 Wire.send(dec2bcd(tm.Second)) ;  
 Wire.send(dec2bcd(tm.Minute));
 Wire.send(dec2bcd(tm.Hour));      // sets 24 hour format
 Wire.send(dec2bcd(tm.Wday));  
 Wire.send(dec2bcd(tm.Day));
 Wire.send(dec2bcd(tm.Month));
 Wire.send(dec2bcd(tmYearToY2k(tm.Year)));  
#endif
 if (Wire.endTransmission() != 0) {
   exists = false;
   return false;
 }
 exists = true;
 return true;
}
// PRIVATE FUNCTIONS
// Convert Decimal to Binary Coded Decimal (BCD)
uint8_t DS1307RTC::dec2bcd(uint8_t num)
{
 return ((num/10 * 16) + (num % 10));
}

// Convert Binary Coded Decimal (BCD) to Decimal
uint8_t DS1307RTC::bcd2dec(uint8_t num)
{
 return ((num/16 * 10) + (num % 16));
}
bool DS1307RTC::exists = false;
DS1307RTC RTC = DS1307RTC(); // create an instance for the user

Did you try either of my 2 suggestions?

II have the Arduino IDE 1.5.5 with support for Arduino Due, I just download the IDE 1.5.2 to try, later I'll post the results. thanks for your suggestions

Try the Time library from this page

http://www.pjrc.com/teensy/td_libs_Time.html

The beta copy from reply #6 is old. Do not use it. I have removed it from my server, so that link should no longer work.

:slight_smile: I've tried with your suggestions but I haven't any change with the errors :frowning:

Paul,
The problem is a name collision.
RTC is the DS1307RTC global object name used by the library but is also #define down in:
{IDEinstallDir}/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3s/include/sam3s2a.h
And the define breaks everything.

Bummer....
lots of "ugly" global #define names in that header file.

Not sure how to fix this properly without renaming the DS1307RTC library object.
Although as a temporary kludge/fix you can edit DS1307RTC.h and insert this line:

#undef RTC

Just after

#define DS1307RTC_h

It should be noted that this kludge is not guaranteed to work.
For example, since Wire.h includes the header file above
if Wire.h is included after DS1307RTC.h then this kludge will not work
because sam3s2a.h will simply redefine it.
The examples in DS1307RTC library include <Wire.h> after DS1307RTC.h so
those examples will still break with this kludge inserted.
However, if you change the examples to include <Wire.h> before DS1307RTC.h
the examples will compile.

Like I said this is a temporary kludge and I'm not really sure how to fix
it properly without renaming the library's global RTC object.

--- bill

From the little I've seen of libraries and the core code they are full of non-unique defines like RTC, that's way too generic. What if I rant to use it for Rob's Timer Counter :slight_smile:

I think all libs should use a prefix to their definitions where the prefix is essentially the name of the lib or an appropriate abbreviation.


Rob

Hi, I've tried with bperrybap's solution and the error of D:\\Arduino\libraries\DS1307RTC/DS1307RTC.h:45: error: expected ')' before '*' token disappears.

So I've opened an example of DS130RTC lib.

#include <Time.h>
#include <DS1307RTC.h>
#include <Wire.h>

void setup() {
  Serial.begin(9600);
  while (!Serial) ; // wait for serial
  delay(200);
  Serial.println("DS1307RTC Read Test");
  Serial.println("-------------------");
}

void loop() {
  tmElements_t tm;

  if (RTC.read(tm)) {
    Serial.print("Ok, Time = ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(", Date (D/M/Y) = ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

and a new error appears

Arduino: 1.5.5-r2 (Windows 7), Placa:"Arduino Due (Programming Port)"

ReadTest.ino: In function 'void loop()':
ReadTest:18: error: request for member 'read' in '1074666080u', which is of non-class type 'Rtc*'
ReadTest:33: error: request for member 'chipPresent' in '1074666080u', which is of non-class type 'Rtc*'

Read the rest of my previous post.
--- bill

bperrybap:
Bummer....
lots of "ugly" global #define names in that header file.

Yes, that is particularly ugly. I expect a small and consistent amount of this from Arduino's core library, but not from headers supplied by the semiconductor companies!

If this were Teensy, I'd edit that file. But of course, being Arduino Due, it's really a matter for the Arduino Team to address. Somehow I do not believe they'll have much appetite for editing "system" headers from Atmel, but maybe someone ought to file a bug report anyway?

Although as a temporary kludge/fix you can edit DS1307RTC.h and insert this line:

I've applied the kludge to the DS1307RTC library. This page has the updated code.

http://www.pjrc.com/teensy/td_libs_DS1307RTC.html

Like I said this is a temporary kludge and I'm not really sure how to fix
it properly without renaming the library's global RTC object.

Agreed, but that's more work than I intend to put into this library to support Arduino Due.

Like many other libraries, I sort-of maintain this one. Michael Margolis hasn't completely abandoned it, but he's insanely busy. Of course, if he wants to get involved, I'll sync to whatever he publishes. I'm pretty crazy busy with a lot of Teensy-related stuff, so this is about as much as I'm willing to do.

If anyone wants to step up and become a more active maintainer of this library (and/or many others), the job is open....

Graynomad:
.... RTC, that's way too generic. What if I rant to use it for Rob's Timer Counter :slight_smile:

I'll look forward to trying out the Rob's Timer Counter library. I'm sure it'll be awesome! :wink:

Coming to an Arduino near you :slight_smile:

Actually I just looked at some of my library code and I haven't been following my own advice, might be time for a cleanup.


Rob

Paul,
Simple solution is don't use Due but rather Teensy 3.x instead. :wink:

Here is an option that I think is pretty good that is about the best that can be done
without the major headache of actually changing the object name or requiring the user
to declare the object.

Add this to the top of the DS1307RTC.h header file
just after the guard conditionals so it looks something like this:

#ifndef DS1307RTC_h
#define DS1307RTC_h

// ensure that Wire library header has already been included
#if !defined(TwoWire_h) && !defined(TinyWireM_h)
#error The Wire library header must be included before DS1307RTC.h
#endif

I think that this will catch the guard defines used by the AVR, Teensy, chipkit/pic32, Due and Tiny i2c libraries.
(Why the Tiny library deviated so much is beyond me....)
It is a bit ugly but at least it will ensure that the Wire library header is always included ahead
of DS1307RTC.h so the RTC define can always be undefined.

I'm not sure what happens if somebody actually tries to use the RTC on SAM
but I'm assuming that it isn't an issue in that users will more than likely
not be trying to use the built in RTC when they are using the DS1307RTC library.

Even with this, there still may be other libraries that end up including the sam header
that if the users sketch uses, might create the problem again.
However, I think for the time being, and the effort involved, this kludge/patch
is pretty useful.

Also, could you update the example program on the DS1307RTC page
so that Wire.h is included before DS1307RTC.h
That way the example will compile properly.

--- bill

bperrybap:
Simple solution is don't use Due but rather Teensy 3.x instead. :wink:

Yes, of course, but when posting on Arduino's forum, I generally try to avoid plugging my own products too heavily.

Both Arduino Due and Teensy 3.1 have a built-in RTC, but things are implemented things quite differently. Both boards have a place for the 32 kHz crystal. I believe Due now ships with the crystal. On Teensy 3.x, you have to add it. Due has no easy way to add a battery and Due has its reset signals connected in such a way that the RTC time is not preserved through a hardware reset, which is a very unfortunate design decision that makes Due's built in RTC nearly useless. On Teensy 3.1, there's a pin to add the 3V coin cell. Teensyduino automatically initializes the RTC with your compile time if it's not already running, so things "just work" very nicely, and of course the time is preserved the way you'd expect from a RTC, through hardware resets and reprogramming.

Here is an option that I think is pretty good that is about the best that can be done
without the major headache of actually changing the object name or requiring the user
to declare the object.

Would you like to take over maintaining this library? The position is open, but it doesn't pay very well.....

(Why the Tiny library deviated so much is beyond me....)

I agree. I saw a comment on Adafruit's site about a desire to make the differences from regular Wire clearer. That sounds amazingly similar to the thinking behind several of Arduino's least popular design decisions.

I believe the keepers of Trinket and other ATTINY-based boards could easily change course, and probably still maintain compatibility with all the stuff that's been built up around "TinyWire", by making a Wire.h that includes the old and supports both names using macros, inherited classes, or some other approach. Like so many things, the technology isn't terribly difficult, if you have the will to make it happen. I'm pretty sure they will come around someday.... In the meantime, I'm not planning to add "TinyWire" support to any libraries I maintain. If they want to make things "just work" with the huge number of libraries build on top of Wire.h, they can. It's really that simple.

My philosophy is similar for Arduino Due, Intel Galileo and of course Teensy 3.x. We're all making boards outside the well worn path of ATMEGA328. But how (or even whether) we handle these compatibility issues is a matter of choice.

I personally make Teensy's compatibility a high priority, to the point where I end up maintaining lots of the abandoned Arduino libraries. Often, in cases such as this DS1307RTC libraries, I end up fixing issues for the other boards that people buy instead of Teensy. Maybe that's not the smartest move on my part?