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

Automatic DST support #3072

Merged
merged 12 commits into from
May 20, 2018
Prev Previous commit
Next Next commit
DST presets for EU and USA, new tz_dst_country config
  • Loading branch information
nmaggioni committed Apr 19, 2018
commit d861ee805c4a22c0a429bc9962f796615e25a84e
1 change: 1 addition & 0 deletions docs/Cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ Re-apply any new defaults as desired.
| airspeed_adc_channel | - | ADC channel to use for analog pitot tube (airspeed) sensor. If board doesn't have a dedicated connector for analog airspeed sensor will default to 0 |
| tz_offset | 0 | Time zone offset from UTC, in minutes. This is applied to the GPS time for logging and time-stamping of Blackbox logs |
| tz_automatic_dst | OFF | Automatically add Daylight Saving Time to the GPS time when needed or simply ignore it |
| tz_dst_country | EU | Country to use for DST calculations, presets are given for either EU or USA. If you live outside this areas it is suggested to disable automatic handling of DST (`tz_automatic_dst` = OFF) and manage `tz_offset` by yourself |

This Markdown table is made by MarkdwonTableMaker addon for google spreadsheet.
Original Spreadsheet used to make this table can be found here https://docs.google.com/spreadsheets/d/1ubjYdMGmZ2aAMUNYkdfe3hhIF7wRfIjcuPOi_ysmp00/edit?usp=sharing
68 changes: 61 additions & 7 deletions src/main/common/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include "drivers/time.h"

#define UNIX_REFERENCE_YEAR 1970
#define UNIX_REFERENCE_DOW 3
#define MILLIS_PER_SECOND 1000

// rtcTime_t when the system was started.
Expand All @@ -53,6 +52,7 @@ PG_REGISTER_WITH_RESET_TEMPLATE(timeConfig_t, timeConfig, PG_TIME_CONFIG, 1);
PG_RESET_TEMPLATE(timeConfig_t, timeConfig,
.tz_offset = 0,
.tz_automatic_dst = false,
.tz_dst_country = DST_EU,
);

static rtcTime_t dateTimeToRtcTime(dateTime_t *dt)
Expand Down Expand Up @@ -122,15 +122,69 @@ static bool rtcIsDateTimeValid(dateTime_t *dateTime)
(dateTime->millis <= 999);
}

static int lastSundayOfMonth(int currentYear, int wantedMonth) {
Copy link
Member

Choose a reason for hiding this comment

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

Indentation and formatting need some work in all this function. Opening brace for functions should be in the next line. Indent using 4 spaces and add a space before and after , as well as arithmetic operators.

int days[] = {31,29,31,30,31,30,31,31,30,31,30,31};
int m, y = currentYear, w;
Copy link
Member

Choose a reason for hiding this comment

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

This line seems very hairy. m should be declared in the for, since it's initialised and used only there. y is assigned to w (where is that variable coming from?), but it looks like you could just use currentYear a few lines down without any extra variables.

days[1] -= (y % 4) || (!(y % 100) && (y % 400));
w = y * 365 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + 6;

for(m = 0; m < 12; m++) {
Copy link
Member

Choose a reason for hiding this comment

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

Space between for and (

w = (w + days[m]) % 7;
if (m == wantedMonth - 1) {
return days[m] + (w < 5 ? -2 : 5) - w;
}
}
return 0;
}

static int nthSundayOfMonth(int lastSunday, int nth) {
while (lastSunday > 7 * nth) {
lastSunday -= 7;
}
return lastSunday;
}

static bool isDST(rtcTime_t t) {
dateTime_t dateTime;
rtcTimeToDateTime(&dateTime, t);
if (dateTime.month < 3 || dateTime.month > 11) { return false; }
if (dateTime.month > 3 && dateTime.month < 11) { return true; }
uint8_t dow = (uint8_t) (((t / MILLIS_PER_SECOND) / 86400) + UNIX_REFERENCE_DOW) % 7;
int previousSunday = dateTime.day - dow;
if (dateTime.month == 3) { return previousSunday >= 8; }
return previousSunday <= 0;
int lastSunday;
switch (timeConfig()->tz_dst_country) {
Copy link
Member

Choose a reason for hiding this comment

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

Once you make tz_automatic_dst an uint8_t, cast it here to tz_automatic_dst_e, so the compiler will make sure the checks are exhaustive. i.e.

switch ((tz_automatic_dst_e)timeConfig()-> tz_automatic_dst) {

case DST_USA: // begins at 2:00 a.m. on the second Sunday of March and ends at 2:00 a.m. on the first Sunday of November
if (dateTime.month < 3 || dateTime.month > 11) { return false; }
if (dateTime.month > 3 && dateTime.month < 11) { return true; }
lastSunday = lastSundayOfMonth(dateTime.year, dateTime.month);
if (dateTime.month == 3) {
int secondSunday = nthSundayOfMonth(lastSunday, 2);
if (dateTime.day == secondSunday) {
return dateTime.hours >= 2;
}
return dateTime.day > secondSunday;
}
if (dateTime.month == 11) {
int firstSunday = nthSundayOfMonth(lastSunday, 1);
if (dateTime.day == firstSunday) {
return dateTime.hours < 2;
}
return dateTime.day < firstSunday;
}
break;
case DST_EU: // begins at 1:00 a.m. on the last Sunday of March and ends at 1:00 a.m. on the last Sunday of October
if (dateTime.month < 3 || dateTime.month > 10) { return false; }
if (dateTime.month > 3 && dateTime.month < 10) { return true; }
lastSunday = lastSundayOfMonth(dateTime.year, dateTime.month);
if (dateTime.day < lastSunday) { return !(dateTime.month == 3); }
if (dateTime.day > lastSunday) { return !(dateTime.month == 3); }
if (dateTime.day == lastSunday) {
if (dateTime.month == 3) {
return dateTime.hours >= 1;
}
if (dateTime.month == 10) {
return dateTime.hours < 1;
}
}
break;
}
return false;
}

static void dateTimeWithOffset(dateTime_t *dateTimeOffset, dateTime_t *dateTimeInitial, int16_t minutes, bool automatic_dst)
Expand Down
6 changes: 6 additions & 0 deletions src/main/common/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,15 @@ typedef uint32_t timeUs_t;

static inline timeDelta_t cmpTimeUs(timeUs_t a, timeUs_t b) { return (timeDelta_t)(a - b); }

typedef enum {
DST_EU,
DST_USA,
} tz_dst_country_e;
Copy link
Member

Choose a reason for hiding this comment

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

Name this tz_automatic_dst_e with the following values: TZ_AUTO_DST_OFF, TZ_AUTO_DST_EU, TZ_AUTO_DST_USA. Adjust settings.yaml accordingly.


typedef struct timeConfig_s {
int16_t tz_offset; // Offset from UTC in minutes, might be positive or negative
bool tz_automatic_dst; // Automatically handle DST or ignore it
tz_dst_country_e tz_dst_country;
} timeConfig_t;
Copy link
Member

Choose a reason for hiding this comment

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

Rather than 2 variables, use just one uint8_t named tz_automatic_dst which can take the values OFF (default), US,EU, etc... That way we use a single byte for storage and users just need to change one setting to make it work. Put a comment at the right indicating that the value comes from tz_automatic_dst_e.


PG_DECLARE(timeConfig_t, timeConfig);
Expand Down
6 changes: 6 additions & 0 deletions src/main/fc/settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ tables:
- name: smartport_fuel_unit
values: ["PERCENT", "MAH", "MWH"]
enum: smartportFuelUnit_e
- name: tz_dst_country
values: ["EU", "USA"]
enum: tz_dst_country_e

groups:
- name: PG_GYRO_CONFIG
Expand Down Expand Up @@ -1649,6 +1652,9 @@ groups:
max: 1440
- name: tz_automatic_dst
type: bool
- name: tz_dst_country
table: tz_dst_country
type: uint8_t

- name: PG_DISPLAY_CONFIG
type: displayConfig_t
Expand Down