diff --git a/openrtx/include/core/datetime.h b/openrtx/include/core/datetime.h index a2996225..c003ac02 100644 --- a/openrtx/include/core/datetime.h +++ b/openrtx/include/core/datetime.h @@ -35,14 +35,13 @@ extern "C" { */ typedef struct { - uint8_t hour : 5; // Hours (0-23) - uint8_t minute : 6; // Minutes (0-59) - uint8_t second : 6; // Seconds (0-59) - uint8_t day : 3; // Day of the week (1-7) - uint8_t date : 5; // Day of the month (1-31) - uint8_t month : 4; // Month (1-12) - uint8_t year : 7; // Year (0-99) - uint8_t : 4; // Padding to 40 bits + int8_t hour; // Hours (0-23) + int8_t minute; // Minutes (0-59) + int8_t second; // Seconds (0-59) + int8_t day; // Day of the week (1-7) + int8_t date; // Day of the month (1-31) + int8_t month; // Month (1-12) + uint8_t year; // Year (0-99) } datetime_t; @@ -64,6 +63,14 @@ datetime_t utcToLocalTime(const datetime_t utc_time, const int8_t timezone); */ datetime_t localTimeToUtc(const datetime_t local_time, const int8_t timezone); +/** + * Adjust the values of the members of datetime_t if they are off-range or if + * they have values that do not match the date described by the other members. + * + * @param time: pointer to a datetime_t struct. + */ +void realignTimeInfo(datetime_t *time); + #ifdef __cplusplus } #endif diff --git a/openrtx/include/core/settings.h b/openrtx/include/core/settings.h index 7a42ae9a..f9046199 100644 --- a/openrtx/include/core/settings.h +++ b/openrtx/include/core/settings.h @@ -51,14 +51,14 @@ typedef struct uint8_t contrast; // Display contrast uint8_t sqlLevel; // Squelch level uint8_t voxLevel; // Vox level - int8_t utc_timezone; // Timezone + int8_t utc_timezone; // Timezone, in units of half hours bool gps_enabled; // GPS active char callsign[10]; // Plaintext callsign, for future use - uint8_t display_timer : 4, // Standby timer - not_in_use : 4; - uint8_t vpLevel : 3, - vpPhoneticSpell : 1, - vpReserved : 4; // reserved for voice rate on the fly. + uint8_t display_timer : 4, // Standby timer + _ununsed : 4; + uint8_t vpLevel : 3, // Voice prompt level + vpPhoneticSpell : 1, // Phonetic spell enabled + _reserved : 4; } __attribute__((packed)) settings_t; @@ -78,10 +78,10 @@ static const settings_t default_settings = false, // GPS enabled "", // Empty callsign TIMER_30S, // 30 seconds - 0, // not in use - 0, // vpOff, - 0, // phonetic spell off, - 0 // not in use. + 0, // not used + 0, // Voice prompts off + 0, // Phonetic spell off + 0 // not used }; #endif /* SETTINGS_H */ diff --git a/openrtx/src/core/datetime.c b/openrtx/src/core/datetime.c index f6a2ac59..8eb7638d 100644 --- a/openrtx/src/core/datetime.c +++ b/openrtx/src/core/datetime.c @@ -19,26 +19,42 @@ ***************************************************************************/ #include +#include +#include + +static const int DAYS_IN_MONTH[12] = +{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +#define _DAYS_IN_MONTH(x) ((x == 2) ? days_in_feb : DAYS_IN_MONTH[x - 1]) + +/** + * \internal + * Return the number of days in a year by checking wheter the current year is + * a leap one or not. + * + * @param year: current year, ranging from 0 to 99. + * @return number of days in the year. + */ +static inline uint16_t daysInYear(uint16_t year) +{ + year += 2000; + if( ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))) + { + return 366; + } + + return 365; +} + datetime_t utcToLocalTime(const datetime_t utc_time, const int8_t timezone) { datetime_t local_time = utc_time; - if(local_time.hour + timezone >= 24) - { - local_time.hour = local_time.hour - 24 + timezone; - local_time.date += 1; - } - else if(local_time.hour + timezone < 0) - { - local_time.hour = local_time.hour + 24 + timezone; - local_time.date -= 1; - } - else - { - local_time.hour += timezone; - } + local_time.hour += (timezone / 2); + local_time.minute += (timezone % 2) * 30; + realignTimeInfo(&local_time); return local_time; } @@ -47,20 +63,103 @@ datetime_t localTimeToUtc(const datetime_t local_time, const int8_t timezone) { datetime_t utc_time = local_time; - if(utc_time.hour - timezone >= 24) - { - utc_time.hour = utc_time.hour - 24 - timezone; - utc_time.date += 1; - } - else if(utc_time.hour - timezone < 0) - { - utc_time.hour = utc_time.hour + 24 - timezone; - utc_time.date -= 1; - } - else - { - utc_time.hour -= timezone; - } + utc_time.minute -= (timezone % 2) * 30; + utc_time.hour -= (timezone / 2); + realignTimeInfo(&utc_time); return utc_time; } + +/* + * Function borrowed from newlib implementation of mktime, see + * https://github.com/bminor/newlib/blob/master/newlib/libc/time/mktime.c + * + * Slightly modified to remove the _DAYS_IN_YEAR macro and to handle month + * with range 1-12 instead of 0-11. + */ +void realignTimeInfo(datetime_t *time) +{ + div_t res; + int days_in_feb = 28; + + if((time->second < 0) || (time->second > 59)) + { + res = div(time->second, 60); + time->minute += res.quot; + + if ((time->second = res.rem) < 0) + { + time->second += 60; + time->minute -= 1; + } + } + + if((time->minute < 0) || (time->minute > 59)) + { + res = div(time->minute, 60); + time->hour += res.quot; + + if((time->minute = res.rem) < 0) + { + time->minute += 60; + time->hour -= 1; + } + } + + if((time->hour < 0) || (time->hour > 23)) + { + res = div(time->hour, 24); + time->date += res.quot; + + if((time->hour = res.rem) < 0) + { + time->hour += 24; + time->date -= 1; + } + } + + if((time->month < 0) || (time->month > 12)) + { + res = div (time->month, 12); + time->year += res.quot; + + if((time->month = res.rem) < 0) + { + time->month += 12; + time->year -= 1; + } + } + + if(daysInYear(time->year) == 366) + days_in_feb = 29; + + if(time->date <= 0) + { + while(time->date <= 0) + { + time->month -= 1; + if(time->month == -1) + { + time->year -= 1; + time->month = 12; + days_in_feb = ((daysInYear(time->year) == 366) ? 29 : 28); + } + + time->date += _DAYS_IN_MONTH (time->month); + } + } + else + { + while(time->date > _DAYS_IN_MONTH (time->month)) + { + time->date -= _DAYS_IN_MONTH (time->month); + time->month += 1; + if (time->month > 12) + { + time->year += 1; + time->month = 1; + days_in_feb = ((daysInYear (time->year) == 366) ? 29 : 28); + } + } + } +} diff --git a/openrtx/src/ui/ui.c b/openrtx/src/ui/ui.c index f9798de1..38cc0ef6 100644 --- a/openrtx/src/ui/ui.c +++ b/openrtx/src/ui/ui.c @@ -1893,10 +1893,10 @@ void ui_updateFSM(bool *sync_rtx) state.gps_set_time); break; case G_TIMEZONE: - if(msg.keys & KEY_LEFT || msg.keys & KEY_UP || + if(msg.keys & KEY_LEFT || msg.keys & KEY_DOWN || msg.keys & KNOB_LEFT) state.settings.utc_timezone -= 1; - else if(msg.keys & KEY_RIGHT || msg.keys & KEY_DOWN || + else if(msg.keys & KEY_RIGHT || msg.keys & KEY_UP || msg.keys & KNOB_RIGHT) state.settings.utc_timezone += 1; vp_announceSettingsInt(¤tLanguage->UTCTimeZone, diff --git a/openrtx/src/ui/ui_menu.c b/openrtx/src/ui/ui_menu.c index 55643193..50eb2357 100644 --- a/openrtx/src/ui/ui_menu.c +++ b/openrtx/src/ui/ui_menu.c @@ -296,17 +296,34 @@ int _ui_getSettingsGPSValueName(char *buf, uint8_t max_len, uint8_t index) switch(index) { case G_ENABLED: - snprintf(buf, max_len, "%s", (last_state.settings.gps_enabled) ? currentLanguage->on : currentLanguage->off); + snprintf(buf, max_len, "%s", (last_state.settings.gps_enabled) ? + currentLanguage->on : + currentLanguage->off); break; case G_SET_TIME: - snprintf(buf, max_len, "%s", (last_state.gps_set_time) ? currentLanguage->on : currentLanguage->off); + snprintf(buf, max_len, "%s", (last_state.gps_set_time) ? + currentLanguage->on : + currentLanguage->off); break; case G_TIMEZONE: - // Add + prefix to positive numbers + { + int8_t tz_hr = (last_state.settings.utc_timezone / 2); + int8_t tz_mn = (last_state.settings.utc_timezone % 2) * 5; + char sign = ' '; + if(last_state.settings.utc_timezone > 0) - snprintf(buf, max_len, "+%d", last_state.settings.utc_timezone); - else - snprintf(buf, max_len, "%d", last_state.settings.utc_timezone); + { + sign = '+'; + } + else if(last_state.settings.utc_timezone < 0) + { + sign = '-'; + tz_hr *= (-1); + tz_mn *= (-1); + } + + snprintf(buf, max_len, "%c%d.%d", sign, tz_hr, tz_mn); + } break; } return 0;