Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide access to left-over milliseconds #93

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ there are also functions to return the hour in 12-hour format
hourFormat12(); // the hour now in 12 hour format
isAM(); // returns true if time now is AM
isPM(); // returns true if time now is PM

now(); // returns the current time as seconds since Jan 1 1970
```

The time and date functions can take an optional parameter for the time. This prevents
Expand All @@ -52,13 +50,24 @@ month(t); // the month for the given time t
year(t); // the year for the given time t
```

There are also two functions that return the number of milliseconds left-over. Care
should be taken when using this value since there are no functions to set the time
with sub-second accuracy and the value may jump when the time is synchronized.
However, it is always consistent with the current time. To access these functions,
you have to `#define TIMELIB_ENABLE_MILLIS` in your sketch.

```c
time_t t = now(uint32_t& m) // store the current time in time variable t and milliseconds in m
millisecond(); // the millisecond now (0-999)
```

Functions for managing the timer services are:

```c
setTime(t); // set the system time to the give time t
setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr
// (2010 or 10 sets year to 2010)
adjustTime(adjustment); // adjust system time by adding the adjustment value
adjustTime(adjustment); // adjust system time by adding the adjustment value (in seconds)
timeStatus(); // indicates if time has been set and recently synchronized
// returns one of the following enumerations:
timeNotSet // the time has never been set, the clock started on Jan 1, 1970
Expand Down
20 changes: 17 additions & 3 deletions Time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <WProgram.h>
#endif

#define TIMELIB_ENABLE_MILLIS

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather do this in Time.h instead of hard-coding it in the compiled .cpp-file and test via #if TIMELIB_ENABLE_MILLIS:

#ifndef TIMELIB_ENABLE_MILLIS
#define TIMELIB_ENABLE_MILLIS true
#endif // #ifndef TIMELIB_ENABLE_MILLIS

This way, it is possible to pass -DTIMELIB_ENABLE_MILLIS=false to the compiler without getting an annoying duplicate-definition warning.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this would work since the later code in Time.cpp relies on all of the declarations in Time.h. I think it would be better to #undef TIMELIB_ENABLE_MILLIS if it's already defined at this point.

Copy link

@nobodyinperson nobodyinperson Apr 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will work, I am doing it in all my projects. The problem is that the .cpp file is compiled in a different translation unit, so to change compiler flags inside it you have to either change it manually in the code (yuck!) or provide a global compiler flag. AFAIK it is not possible to tell the compiler to undo a specific #define, so it is effectively impossible to toggle TIMELIB_ENABLE_MILLIS from outside the code.

Solutions are:

  1. removing any #define TIMELIB_ENABLE_MILLIS from any files, keeping the #ifdef checks and letting the user provide a command-line compiler flag. This however is inconvenient (if not impossible) for the Arduino IDE.
  2. my suggestion: provide a boolean default in the header file (which is #included in the source code file, thus causes a rebuild) and change the checks to #if. This way, a global compiler flag can be used to explicitly enable or disable the feature (vs only being able to enable it as in solution 1). Still, the Arduino IDE problem.
  3. Making this whole library a header-only library and using my suggestion (solution 2). This would enable users of the library to simply #define TIMELIB_ENABLE_MILLIS true/false before #includeing the library to toggle the feature. No need for a global compiler flag, no problem in the IDE. That's what I am mostly doing. Has its own disadvantages. But that would be up to @PaulStoffregen to decide.

Copy link
Author

@jamesmyatt jamesmyatt Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all for avoiding the warning. However, I don't see the problem of forcing TIMELIB_ENABLE_MILLIS to be set in Time.cpp. As you say it's a separate translation unit, so it doesn't change the functions available to the user when they include TimeLib.h.

The purpose of this flag is to enable the declarations involving millis in TimeLib.h so that an advanced user can say "I really want access to the leftover millis. I understand the risks and limitations. I promise I know what I'm doing and I won't complain". So with this solution, you can already just #define TIMELIB_ENABLE_MILLIS in your sketch immediately before #include<TimeLib.h> in your source code (this is what I do). No need for extra compiler flags.

Also I don't see why you would ever want to undefine it. Either you do nothing and the millis aren't available in your sketch, or you use the millis in your sketch so you define it in the sketch. Am I missing something?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You're right.

Funny way of using compiler flags to enable features. I guess, you could ditch all checks for TIMELIB_ENABLE_MILLIS in the .cpp-file altogether then, right? Can't undefine it via compiler command-line flags, hard-coded in the implementation file, feature is only enabled in the header file. So the milliseconds support is always compiled, right?

I guess one could leave it this way. Still, I prefer being explicit than implicit (i.e. being able to explicitly en-/disable some feature). But maybe that's just me. Still up to @PaulStoffregen to merge this into his library.

#include "TimeLib.h"

static tmElements_t tm; // a cache of time elements
Expand Down Expand Up @@ -103,6 +104,12 @@ int second(time_t t) { // the second for the given time
return tm.Second;
}

int millisecond() {
uint32_t ms;
now(ms);
return (int)ms;
}

int day(){
return(day(now()));
}
Expand Down Expand Up @@ -248,9 +255,16 @@ time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync


time_t now() {
// calculate number of seconds passed since last call to now()
while (millis() - prevMillis >= 1000) {
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
uint32_t sysTimeMillis;
return now(sysTimeMillis);
}

time_t now(uint32_t& sysTimeMillis) {
// calculate number of seconds passed since last call to now()
while ((sysTimeMillis = millis() - prevMillis) >= 1000) {
// millis() and prevMillis are both unsigned ints thus the subtraction will
// always result in a positive difference. This is OK since it corrects for
// wrap-around and millis() is monotonic.
sysTime++;
prevMillis += 1000;
#ifdef TIME_DRIFT_INFO
Expand Down
6 changes: 6 additions & 0 deletions TimeLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ int minute(); // the minute now
int minute(time_t t); // the minute for the given time
int second(); // the second now
int second(time_t t); // the second for the given time
#ifdef TIMELIB_ENABLE_MILLIS
int millisecond(); // the millisecond now
#endif
int day(); // the day now
int day(time_t t); // the day for the given time
int weekday(); // the weekday now (Sunday is day 1)
Expand All @@ -118,6 +121,9 @@ int year(); // the full four digit year: (2009, 2010 etc)
int year(time_t t); // the year for the given time

time_t now(); // return the current time as seconds since Jan 1 1970
#ifdef TIMELIB_ENABLE_MILLIS
time_t now(uint32_t& sysTimeMillis); // return the current time as seconds and milliseconds since Jan 1 1970
#endif
void setTime(time_t t);
void setTime(int hr,int min,int sec,int day, int month, int yr);
void adjustTime(long adjustment);
Expand Down
1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ time_t KEYWORD1
# Methods and Functions (KEYWORD2)
#######################################
now KEYWORD2
millisecond KEYWORD2
second KEYWORD2
minute KEYWORD2
hour KEYWORD2
Expand Down