Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
Revision 31:f6ff7fdb9c67, committed 2018-11-29
- Comitter:
- andrewboyson
- Date:
- Thu Nov 29 16:51:19 2018 +0000
- Parent:
- 30:212ca42b8779
- Child:
- 32:f915ccb1ece3
- Commit message:
- Changed time.c to tm.c
Changed in this revision
--- a/clock.c Fri Feb 16 17:30:46 2018 +0000
+++ b/clock.c Thu Nov 29 16:51:19 2018 +0000
@@ -1,11 +1,11 @@
#include <stdint.h>
#include <stdio.h>
-#include "log.h"
-#include "tick.h"
-#include "sync.h"
-#include "time.h"
-#include "rtc.h"
+#include "log.h"
+#include "tick.h"
+#include "sync.h"
+#include "tm.h"
+#include "rtc.h"
#include "timer.h"
#define ONE_BILLION 1000000000
@@ -24,7 +24,7 @@
static time_t nowT = 0;
static void calculateTimes()
{
- nowTicks = Ticks();
+ nowTicks = TicksNow();
nowT = nowTicks >> TICK_ONE_SECOND_SHIFT;
}
@@ -44,17 +44,17 @@
void ClockTmLocal(struct tm* ptm)
{
- TimeToTmLocal(nowT, ptm);
+ TmLocalFromTimeT(nowT, ptm);
}
void ClockTmUtc(struct tm* ptm)
{
- TimeToTmUtc(nowT, ptm);
+ TmUtcFromTimeT(nowT, ptm);
}
void ClockAscii(char* p)
{
struct tm tm;
- TimeToTmUtc(nowT, &tm);
+ TmUtcFromTimeT(nowT, &tm);
sprintf(p, "%d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
void ClockInit()
@@ -74,13 +74,13 @@
{
//Establish this scan time
static uint32_t lastCount = 0;
-
+
bool firstScan = !lastCount;
-
+
uint32_t elapsed = TimerIntervalCount(&lastCount);
-
+
if (firstScan) return;
-
+
//Average the scan time
if (elapsed > ClockScanAverage) ClockScanAverage++;
if (elapsed < ClockScanAverage) ClockScanAverage--;
@@ -93,32 +93,32 @@
{
TimerMain();
TickMain();
-
+
//Establish the scan times
establishScanTimes();
-
+
//Calculate ns and time_t
calculateTimes();
-
+
static int lastSyncedRate = 0;
static int lastSyncedTime = 0;
-
+
if ( SyncedRate && !lastSyncedRate) LogTimeF("Rate sync acquired\r\n");
if (!SyncedRate && lastSyncedRate) LogTimeF("Rate sync lost\r\n");
if ( SyncedTime && !lastSyncedTime) LogTimeF("Time sync acquired\r\n");
if (!SyncedTime && lastSyncedTime) LogTimeF("Time sync lost\r\n");
-
+
lastSyncedRate = SyncedRate;
lastSyncedTime = SyncedTime;
-
+
//Record the time the clock started
if (SyncedTime && SyncedRate) refTicks = nowTicks;
-
+
//Set a one shot memory for having had a tick
static time_t lastT = 0;
ClockTicked = lastT > 0 && lastT != nowT;
lastT = nowT;
-
+
if (TickIsSet())
{
//Save the time to the RTC on the second
@@ -139,7 +139,7 @@
RtcGetTm(&tm);
if (lastRtcSecond > 0 && tm.tm_sec != lastRtcSecond)
{
- time_t t = TimeFromTmUtc(&tm);
+ time_t t = TmUtcToTimeT(&tm);
TickSet((int64_t)t << TICK_ONE_SECOND_SHIFT);
calculateTimes();
LogTimeF("Clock set from RTC\r\n");
--- a/clock.txt Fri Feb 16 17:30:46 2018 +0000 +++ b/clock.txt Thu Nov 29 16:51:19 2018 +0000 @@ -1,17 +1,39 @@ -Clock era is 1970 -Ntp era is 1900 +Clock +===== +clock.c contains +* settings +* functions to save and restore the time to the RTC. -Clock time is a 64 bit signed int counting ns since 1970 ==> 1970 +/- 292 years ==> 1678 --> 2262 -Ntp time is a 32 bit unsigned int (with a 32 bit fraction) counting seconds since 1900 ==> 1900 + 136 years ==> 1900 --> 2036 - -To eliminate the need to do multiplication and division by a billion we need to use a binary fraction with bit shifts +High resolution timer +======================= +timer.c uses TIM0 as a 32bit timer which counts at the cpu frequency 96MHz and rolls over after 44s. +It is used for three purposes: +* A general purpose high resolution timer with a (1/96MHz) 10nS resolution and a maximum interval of 44 seconds +* A one second pulse for use by governed time (see time.c) +* A general purpose low resolution elapsed time of about 20mS -36bits for seconds 28bits for fraction -ie SSSS SSSS S.FFF FFFF -would give +/- 1089 years with a resolution of 3ns +Governed time +============= +tick.c receives a tick each second from timer.c. It increments the governed time using the ppb and slew (see by sync.c). +When the governed time is requested it uses its count and a proportion of the elapsed second from the high resolution timer to calculate the exact time. +See time-formats.text for the governed time format. +PPB is stored in GPREG0 whenever it is set and retrieved during initialisation. + +time_t and struct tm utilities +============================== +time.c contains a number of functions for manipulating time_t and struct tm times. It contains nothing for governed time or the high resolution count. -34bits for seconds 30bits for fraction -would give +/- 272 years with a resolution of 1ns +Synchronisation to an external source +===================================== +sync.c takes external time from either: +* a long term source such as NTP +* a pulse per second (PPS) +It adjusts the governed time ppb and slew to synchronise the external source and the governed time. -44 bits for seconds 20 bits for fraction -would give +/- 278,731 years with a resolution of 1us \ No newline at end of file +Backup over power down +====================== +rtc.c contains routines to save and restore the time in the battery backed real time clock. + +NTP utilities +============= +Converts governed time to NTP time and vice versa. \ No newline at end of file
--- a/text.txt Fri Feb 16 17:30:46 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -Current system counts ns from 1970. It needs much arithmetic o convert between NTP and time_t. - -To eliminate the need to replace multiplication and division by a billion with bit shifts we need to use a binary fraction - -1 bit sign, 43 bits for seconds, 20 bits for fraction -would give +/- 278,731 years at 1us or 1 ppm per second or 3 ppb per hour -Advantages: a wide coverage - simple transformation to NTP and time_t -Disadvantage: not able to reflect the freq adjustments for pps. - -1 bit sign, 35bits for seconds, 28bits for fraction -would give +/- 1089 years at 3ns or 3ppb per second -ie SSSS SSSS S.FFF FFFF -Advantages: easily represented in hex - a wide coverage - simple transformation to NTP and time_t -Disadvantage: borderline to reflect the freq adjustments for pps. - -1 bit sign, 33 bits for seconds, 30 bits for fraction -would give +/- 272 years at 1ns or 1 ppb per second -Advantages: adequately representing the freq adjustments for pps - simple transformation to NTP and time_t - can use a bitwise shift to give an approximation to ns, us or ms - adequately covers the next two centuries -Disadvantage: none - -Use 96MHz int64 count -would give +/- 3044 years with a resolution of 10ns or 10ppm per second -Advantages: a wide coverage -Disadvantage: not able to reflect the freq adjustments for pps. - -Use a count of ns -would give +/- 292 years at 1ns or 1ppb per second -Advantages: adequately representing the freq adjustments for pps - easily usable with ppb and ns - a wide coverage -Disadvantage: 2^32 / 96MHz = 44s so 1 tick will be 44s
--- a/tick.c Fri Feb 16 17:30:46 2018 +0000
+++ b/tick.c Thu Nov 29 16:51:19 2018 +0000
@@ -2,7 +2,7 @@
#include <stdbool.h>
#include "rtc.h"
-#include "time.h"
+#include "tm.h"
#include "tick.h"
#include "timer.h"
#include "led.h"
@@ -20,7 +20,7 @@
bool TickIsSet() { return countIsSet; }
bool Ticked() { return ticked; }
-int64_t Ticks() { return ticksThisScan; } //30th bit is one second
+int64_t TicksNow() { return ticksThisScan; } //30th bit is one second
int32_t TickGetSlew() { return slew; }
void TickSetSlew(int32_t value) { slew = value; }
@@ -32,16 +32,16 @@
void TicksToTmUtc (int64_t ticks, struct tm* ptm)
{
time_t t = ticks >> TICK_ONE_SECOND_SHIFT;
- TimeToTmUtc(t, ptm);
+ TmUtcFromTimeT(t, ptm);
}
int64_t TicksFromTmUtc(struct tm* ptm)
{
- time_t t = TimeFromTmUtc(ptm);
+ time_t t = TmUtcToTimeT(ptm);
return t << TICK_ONE_SECOND_SHIFT;
}
-/*
+/* Timer counts like this:
+---------+---------------+
| Seconds | Base count |
+---------+---------------+
@@ -53,6 +53,9 @@
| 45 | 25,032,704 |
| ... | ... |
+---------+---------------+
+Tick counts as a signed 64 bit integer
+1 bit sign, 33 bits for seconds, 30 bits for fraction
+giving +/- 272 years with a resolution of around approximately 1ns or 1 ppb per second (2^30 == 1024x1024x1024)
*/
void TickSet(int64_t extClock)
@@ -73,7 +76,7 @@
void TickMain()
{
//Update the times whenever there has been a system second
- if (TimerTicked)
+ if (TimerHadSecond)
{
__disable_irq();
tickCount += TICK_ONE_SECOND + ppb;
--- a/tick.h Fri Feb 16 17:30:46 2018 +0000 +++ b/tick.h Thu Nov 29 16:51:19 2018 +0000 @@ -14,7 +14,7 @@ extern int32_t TickGetPpb (void); extern void TickSetPpb (int32_t value); extern void TickAddPpb(int32_t value); extern bool TickIsSet(void); extern bool Ticked(void); -extern int64_t Ticks(void); +extern int64_t TicksNow(void); extern void TickInit(void); extern void TickMain(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/time-formats.txt Thu Nov 29 16:51:19 2018 +0000 @@ -0,0 +1,49 @@ +Current system counts ns from 1970. It needs much arithmetic o convert between NTP and time_t. + +To eliminate the need to replace multiplication and division by a billion with bit shifts we need to use a binary fraction + +NTP time +======== +Ntp era is 1900 +Ntp time is a 32 bit unsigned int (with a 32 bit fraction) counting seconds since 1900 ==> 1900 + 136 years ==> 1900 --> 2036 + +Governed time - the version chosen +================================== +Clock era is 1970 +1 bit sign, 33 bits for seconds, 30 bits for fraction + +Governed time - alternatives considered +======================================= +1 bit sign, 43 bits for seconds, 20 bits for fraction +would give +/- 278,731 years at 1us or 1 ppm per second or 3 ppb per hour +Advantages: a wide coverage + simple transformation to NTP and time_t +Disadvantage: not able to reflect the freq adjustments for pps. + +1 bit sign, 35bits for seconds, 28bits for fraction +would give +/- 1089 years at 3ns or 3ppb per second +ie SSSS SSSS S.FFF FFFF +Advantages: easily represented in hex + a wide coverage + simple transformation to NTP and time_t +Disadvantage: borderline to reflect the freq adjustments for pps. + +1 bit sign, 33 bits for seconds, 30 bits for fraction +would give +/- 272 years at 1ns or 1 ppb per second +Advantages: adequately representing the freq adjustments for pps + simple transformation to NTP and time_t + can use a bitwise shift to give an approximation to ns, us or ms + adequately covers the next two centuries +Disadvantage: none + +Use 96MHz int64 count +would give +/- 3044 years with a resolution of 10ns or 10ppm per second +Advantages: a wide coverage +Disadvantage: not able to reflect the freq adjustments for pps. + +Use a count of ns +would give +/- 292 years at 1ns or 1ppb per second +Advantages: adequately representing the freq adjustments for pps + easily usable with ppb and ns + a wide coverage +Disadvantage: 2^32 / 96MHz = 44s so 1 tick will be 44s
--- a/time.c Fri Feb 16 17:30:46 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-#include <stdlib.h>
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-
-#define STD_OFFSET 0
-#define DST_OFFSET 1
-
-static bool isLeapYear(int year)
-{
- year += 1900;
- bool leapYear = !(year & 0x3);
- if (year >= 2100)
- {
- if (year % 100 == 0) leapYear = false;
- if (year % 400 == 0) leapYear = true;
- }
- return leapYear;
-
-}
-static int monthLength(int year, int month)
-{
- static char monthlengths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- int daysInMonth = monthlengths[month];
- if (month == 1 && isLeapYear(year)) daysInMonth++; //February is month 1 of months 0 to 11
- return daysInMonth;
-}
-static bool isDst(int year, int month, int dayOfMonth, int dayOfWeek, int hours)
-{
- //Find the last Sunday in the month
- int lastDayOfMonth = monthLength(year, month);
- int daysToEndOfMonth = lastDayOfMonth - dayOfMonth;
- int dayOfWeekOfLastDayOfMonth = (dayOfWeek + daysToEndOfMonth) % 7;
- int lastSundayDayOfMonth = lastDayOfMonth - dayOfWeekOfLastDayOfMonth;
-
- //Check each month
- if (month <= 1) return false; //Jan, Feb
- if (month == 2) //Mar - DST true after 1am UTC on the last Sunday in March
- {
- if (dayOfMonth < lastSundayDayOfMonth) return false;
- if (dayOfMonth == lastSundayDayOfMonth) return hours >= 1;
- if (dayOfMonth > lastSundayDayOfMonth) return true;
- }
- if (month >= 3 && month <= 8) return true; //Apr, May, Jun, Jul, Aug, Sep
- if (month == 9) //Oct - DST false after 1am UTC on the last Sunday in October
- {
- if (dayOfMonth < lastSundayDayOfMonth) return true;
- if (dayOfMonth == lastSundayDayOfMonth) return hours < 1;
- if (dayOfMonth > lastSundayDayOfMonth) return false;
- }
- if (month >= 10) return false; //Nov, Dec
- return false;
-}
-static void calculateDayOfYearAndWeek(int thisYear, int thisMonth, int thisMonthDay, int* pDayOfYear, int* pDayOfWeek)
-{
- int dayOfYear = 0; //1 Jan is day 0
- int dayOfWeek = 4; //1 Jan 1970 is a Thursday
-
- //Add days of each whole year
- for (int y = 70; y < thisYear; y++)
- {
- int lengthOfYear = isLeapYear(y) ? 366 : 365;
- dayOfWeek += lengthOfYear;
- }
-
- //Add days of each whole month
- for (int m = 0; m < thisMonth; m++)
- {
- int lengthOfMonth = monthLength(thisYear, m);
- dayOfYear += lengthOfMonth;
- dayOfWeek += lengthOfMonth;
- }
-
- //Add days of part month
- thisMonthDay--; //thisMonthDay is 01 to 31 where we need 00 to 30
- dayOfYear += thisMonthDay;
- dayOfWeek += thisMonthDay;
-
- //Update the day of year and day of week parts of the struct tm
- *pDayOfYear = dayOfYear; // 0 --> 365
- *pDayOfWeek = dayOfWeek % 7; // 0 --> 6
-}
-void TimeIncrement(struct tm* ptm)
-{
- ptm->tm_sec++;
- if (ptm->tm_sec > 59)
- {
- ptm->tm_sec = 0;
- ptm->tm_min++;
- }
- if (ptm->tm_min > 59)
- {
- ptm->tm_min = 0;
- ptm->tm_hour++;
- }
- if (ptm->tm_hour > 23)
- {
- ptm->tm_hour = 0;
- ptm->tm_wday++;
- if (ptm->tm_wday > 6) ptm->tm_wday = 0;
- ptm->tm_yday++;
- ptm->tm_mday++;
- if (ptm->tm_mday > monthLength(ptm->tm_year, ptm->tm_mon))
- {
- ptm->tm_mon++;
- if (ptm->tm_mon > 11)
- {
- ptm->tm_year++;
- ptm->tm_yday = 0;
- ptm->tm_mon = 0;
- }
- ptm->tm_mday = 1;
- }
- }
-}
-static void normalise(int* pHours, int* pDayOfWeek, int* pDayOfMonth, int* pMonth, int * pDayOfYear, int* pYear)
-{
- if (*pHours > 23)
- {
- *pHours -= 24;
- ++*pDayOfWeek;
- if (*pDayOfWeek > 6) *pDayOfWeek = 0;
- ++*pDayOfYear;
- ++*pDayOfMonth;
- if (*pDayOfMonth > monthLength(*pYear, *pMonth))
- {
- ++*pMonth;
- if (*pMonth > 11)
- {
- ++*pYear;
- *pDayOfYear = 0;
- *pMonth = 0;
- }
- *pDayOfMonth = 1;
- }
- }
-
- if (*pHours < 0)
- {
- *pHours += 24;
- --*pDayOfWeek;
- if (*pDayOfWeek < 0) *pDayOfWeek = 6;
- --*pDayOfYear;
- --*pDayOfMonth;
- if (*pDayOfMonth < 1)
- {
- --*pMonth;
- if (*pMonth < 0)
- {
- --*pYear;
- *pDayOfYear = isLeapYear(*pYear) ? 365 : 364;
- *pMonth = 11;
- }
- *pDayOfMonth = monthLength(*pYear, *pMonth);
- }
- }
-}
-static void addYears(int* pYear, int* pDayOfWeek, int* pDaysLeft)
-{
- while(1)
- {
- //See if it is a leap year
- int leapYear = isLeapYear(*pYear);
-
- //Find the number of days in this year
- int daysInYear = leapYear ? 366 : 365;
-
- //Stop if this is the final year
- if (*pDaysLeft < daysInYear) break;
-
- //Calculate the current day of the week at the start of the year
- *pDayOfWeek += leapYear ? 2 : 1;
- if (*pDayOfWeek >= 7) *pDayOfWeek -= 7;
-
- //Move on to the next year
- *pDaysLeft -= daysInYear;
- ++*pYear;
- }
-}
-static void addMonths(int year, int* pMonth, int* pDaysLeft)
-{
- while(1)
- {
- int daysInMonth = monthLength(year, *pMonth);
-
- //Stop if this is the last month
- if (*pDaysLeft < daysInMonth) break;
-
- //Move onto next month
- *pDaysLeft -= daysInMonth;
- ++*pMonth;
- }
-}
-static void timeToTm(time_t t, struct tm* ptm, bool local)
-{
- //Extract the seconds, minutes, hours and days from the time_t t
- div_t divres;
- divres = div( t, 60); int seconds = divres.rem;
- divres = div(divres.quot, 60); int minutes = divres.rem;
- divres = div(divres.quot, 24); int hours = divres.rem;
- int daysLeft = divres.quot;
-
- //Add a year at a time while there is more than a year of days left
- int year = 70; //Unix epoch is 1970
- int dayOfWeek = 4; //1 Jan 1970 is a Thursday
- addYears(&year, &dayOfWeek, &daysLeft);
-
- //Days left contains the days left from the start (1 Jan) of the current year
- int dayOfYear = daysLeft;
- dayOfWeek += daysLeft;
- dayOfWeek %= 7;
-
- //Add a month at a time while there is more than a month of days left
- int month = 0;
- addMonths(year, &month, &daysLeft);
-
- //Days left contains the days left from the start (1st) of the current month
- int dayOfMonth = daysLeft + 1;
-
- //Deal with local time offsets
- int dst;
- if (local)
- {
- //Work out if Daylight Saving Time applies
- dst = isDst(year, month, dayOfMonth, dayOfWeek, hours);
-
- //Adjust for the timezone
- hours += dst ? DST_OFFSET : STD_OFFSET;
- normalise(&hours, &dayOfWeek, &dayOfMonth, &month, &dayOfYear, &year);
- }
- else
- {
- dst = -1;
- }
-
- //Set up the broken time TM structure
- ptm->tm_sec = seconds; // 00 --> 59
- ptm->tm_min = minutes; // 00 --> 59
- ptm->tm_hour = hours; // 00 --> 23
- ptm->tm_mday = dayOfMonth; // 01 --> 31
- ptm->tm_mon = month; // 00 --> 11
- ptm->tm_year = year; // Years since 1900
- ptm->tm_wday = dayOfWeek; // 0 --> 6 where 0 == Sunday
- ptm->tm_yday = dayOfYear; // 0 --> 365
- ptm->tm_isdst = dst; // +ve if DST, 0 if not DSTime, -ve if the information is not available. Note that 'true' evaluates to +1.
-}
-void TimeToTmUtc(time_t time, struct tm* ptm)
-{
- timeToTm(time, ptm, false);
-}
-void TimeToTmLocal(time_t time, struct tm* ptm)
-{
- timeToTm(time, ptm, true);
-}
-time_t TimeFromTmUtc(struct tm* ptm)
-{
- int days = 0;
-
- for (int y = 70; y < ptm->tm_year; y++) days += isLeapYear(y) ? 366 : 365;
-
- days += ptm->tm_yday;
-
- return days * 86400 +
- ptm->tm_hour * 3600 +
- ptm->tm_min * 60 +
- ptm->tm_sec;
-}
-int TimePeriodBetween(struct tm* ptmLater, struct tm* ptmEarlier)
-{
- int days = 0;
-
- if (ptmLater->tm_year > ptmEarlier->tm_year) for (int y = ptmEarlier->tm_year; y < ptmLater->tm_year; y++) days += isLeapYear(y) ? 366 : 365;
- else for (int y = ptmEarlier->tm_year; y > ptmLater->tm_year; y--) days -= isLeapYear(y) ? 366 : 365;
-
- days += ptmLater->tm_yday - ptmEarlier->tm_yday;
-
- return days * 86400 +
- (ptmLater->tm_hour - ptmEarlier->tm_hour) * 3600 +
- (ptmLater->tm_min - ptmEarlier->tm_min ) * 60 +
- (ptmLater->tm_sec - ptmEarlier->tm_sec );
-}
-
-void TimeTmUtcToLocal(struct tm* ptm)
-{
- //Establish DST
- ptm->tm_isdst = isDst(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, ptm->tm_wday, ptm->tm_hour);
-
- //Adjust for the timezone
- ptm->tm_hour += ptm->tm_isdst ? DST_OFFSET : STD_OFFSET;
- normalise(&ptm->tm_hour, &ptm->tm_wday, &ptm->tm_mday, &ptm->tm_mon, &ptm->tm_yday, &ptm->tm_year);
-}
-
-void TimeAsciiDateTimeToTm(const char* pDate, const char* pTime, struct tm* ptm) // Convert compile time to system time
-{
- //__DATE__ The string constant contains eleven characters and looks like "Feb 12 1996". If the day of the month is less than 10, it is padded with a space on the left.
- char month[5];
- sscanf(pDate, "%s %d %d", month, &ptm->tm_mday, &ptm->tm_year); ptm->tm_year -= 1900;
-
- // Find where month is in month_names. Deduce month value.
- static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
- ptm->tm_mon = (strstr(month_names, month) - month_names) / 3;
-
- //__TIME__ The string constant contains eight characters and looks like "23:59:01".
- sscanf(pTime, "%2d %*c %2d %*c %2d", &ptm->tm_hour, &ptm->tm_min, &ptm->tm_sec);
-
- //Fill the day of week and the day of year part of the tm structure
- calculateDayOfYearAndWeek(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, &ptm->tm_yday, &ptm->tm_wday);
-}
--- a/time.h Fri Feb 16 17:30:46 2018 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -#include <time.h> -#include <stdint.h> - -extern void TimeTmUtcToLocal(struct tm* ptm); - -extern void TimeAsciiDateTimeToTm(const char* pDate, const char* pTime, struct tm* ptm); -extern void TimeToTmLocal(uint32_t time, struct tm* ptm); -extern void TimeToTmUtc(uint32_t time, struct tm* ptm); - -extern time_t TimeFromTmUtc(struct tm* ptm); -extern int TimePeriodBetween(struct tm* ptmLater, struct tm* ptmEarlier); \ No newline at end of file
--- a/timer.c Fri Feb 16 17:30:46 2018 +0000
+++ b/timer.c Thu Nov 29 16:51:19 2018 +0000
@@ -47,13 +47,25 @@
return (value * fraction) >> 32;
}
-bool TimerTicked = false;
+bool TimerHadSecond = false;
+
+//Counts from zero to 2^32 and wraps around after:
+// 13.7 years if 10 per second - scan time must be less than 100mS
+// 1.37 years if 100 per second - scan time must be less than 10mS
+uint32_t TimerTicks = 0;
void TimerMain()
{
- TimerTicked = TimerCountSinceLastSecond() > TIMER_COUNT_PER_SECOND;
+ TimerHadSecond = TimerCountSinceLastSecond() > TIMER_COUNT_PER_SECOND;
+ if (TimerHadSecond) secondsBaseCount += TIMER_COUNT_PER_SECOND;
+
+ static uint32_t tickBaseCount = 0;
- if (TimerTicked) secondsBaseCount += TIMER_COUNT_PER_SECOND;
+ if (TC - tickBaseCount > TIMER_COUNT_PER_SECOND / TIMER_TICKS_PER_SECOND)
+ {
+ TimerTicks++;
+ tickBaseCount += TIMER_COUNT_PER_SECOND / TIMER_TICKS_PER_SECOND;
+ }
}
void TimerInit()
{
--- a/timer.h Fri Feb 16 17:30:46 2018 +0000 +++ b/timer.h Thu Nov 29 16:51:19 2018 +0000 @@ -8,10 +8,11 @@ extern uint32_t TimerCountSinceLastSecond(void); extern int32_t TimerMultiplyFractionalPart(int32_t value, uint32_t timerCountSinceLastSecond); -extern bool TimerTicked; +extern bool TimerHadSecond; extern void TimerMain(void); extern void TimerInit(void); #define TIMER_COUNT_PER_SECOND 96000000UL #define TIMER_COUNT_PER_MS (TIMER_COUNT_PER_SECOND / 1000); #define TIMER_COUNT_PER_US (TIMER_COUNT_PER_MS / 1000); +#define TIMER_TICKS_PER_SECOND 50
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tm.c Thu Nov 29 16:51:19 2018 +0000
@@ -0,0 +1,309 @@
+#include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define STD_OFFSET 0
+#define DST_OFFSET 1
+
+static bool isLeapYear(int year)
+{
+ year += 1900;
+ bool leapYear = !(year & 0x3);
+ if (year >= 2100)
+ {
+ if (year % 100 == 0) leapYear = false;
+ if (year % 400 == 0) leapYear = true;
+ }
+ return leapYear;
+
+}
+static int monthLength(int year, int month)
+{
+ static char monthlengths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int daysInMonth = monthlengths[month];
+ if (month == 1 && isLeapYear(year)) daysInMonth++; //February is month 1 of months 0 to 11
+ return daysInMonth;
+}
+static bool isDst(int year, int month, int dayOfMonth, int dayOfWeek, int hours)
+{
+ //Find the last Sunday in the month
+ int lastDayOfMonth = monthLength(year, month);
+ int daysToEndOfMonth = lastDayOfMonth - dayOfMonth;
+ int dayOfWeekOfLastDayOfMonth = (dayOfWeek + daysToEndOfMonth) % 7;
+ int lastSundayDayOfMonth = lastDayOfMonth - dayOfWeekOfLastDayOfMonth;
+
+ //Check each month
+ if (month <= 1) return false; //Jan, Feb
+ if (month == 2) //Mar - DST true after 1am UTC on the last Sunday in March
+ {
+ if (dayOfMonth < lastSundayDayOfMonth) return false;
+ if (dayOfMonth == lastSundayDayOfMonth) return hours >= 1;
+ if (dayOfMonth > lastSundayDayOfMonth) return true;
+ }
+ if (month >= 3 && month <= 8) return true; //Apr, May, Jun, Jul, Aug, Sep
+ if (month == 9) //Oct - DST false after 1am UTC on the last Sunday in October
+ {
+ if (dayOfMonth < lastSundayDayOfMonth) return true;
+ if (dayOfMonth == lastSundayDayOfMonth) return hours < 1;
+ if (dayOfMonth > lastSundayDayOfMonth) return false;
+ }
+ if (month >= 10) return false; //Nov, Dec
+ return false;
+}
+static void calculateDayOfYearAndWeek(int thisYear, int thisMonth, int thisMonthDay, int* pDayOfYear, int* pDayOfWeek)
+{
+ int dayOfYear = 0; //1 Jan is day 0
+ int dayOfWeek = 4; //1 Jan 1970 is a Thursday
+
+ //Add days of each whole year
+ for (int y = 70; y < thisYear; y++)
+ {
+ int lengthOfYear = isLeapYear(y) ? 366 : 365;
+ dayOfWeek += lengthOfYear;
+ }
+
+ //Add days of each whole month
+ for (int m = 0; m < thisMonth; m++)
+ {
+ int lengthOfMonth = monthLength(thisYear, m);
+ dayOfYear += lengthOfMonth;
+ dayOfWeek += lengthOfMonth;
+ }
+
+ //Add days of part month
+ thisMonthDay--; //thisMonthDay is 01 to 31 where we need 00 to 30
+ dayOfYear += thisMonthDay;
+ dayOfWeek += thisMonthDay;
+
+ //Update the day of year and day of week parts of the struct tm
+ *pDayOfYear = dayOfYear; // 0 --> 365
+ *pDayOfWeek = dayOfWeek % 7; // 0 --> 6
+}
+void TimeIncrement(struct tm* ptm)
+{
+ ptm->tm_sec++;
+ if (ptm->tm_sec > 59)
+ {
+ ptm->tm_sec = 0;
+ ptm->tm_min++;
+ }
+ if (ptm->tm_min > 59)
+ {
+ ptm->tm_min = 0;
+ ptm->tm_hour++;
+ }
+ if (ptm->tm_hour > 23)
+ {
+ ptm->tm_hour = 0;
+ ptm->tm_wday++;
+ if (ptm->tm_wday > 6) ptm->tm_wday = 0;
+ ptm->tm_yday++;
+ ptm->tm_mday++;
+ if (ptm->tm_mday > monthLength(ptm->tm_year, ptm->tm_mon))
+ {
+ ptm->tm_mon++;
+ if (ptm->tm_mon > 11)
+ {
+ ptm->tm_year++;
+ ptm->tm_yday = 0;
+ ptm->tm_mon = 0;
+ }
+ ptm->tm_mday = 1;
+ }
+ }
+}
+static void normalise(int* pHours, int* pDayOfWeek, int* pDayOfMonth, int* pMonth, int * pDayOfYear, int* pYear)
+{
+ if (*pHours > 23)
+ {
+ *pHours -= 24;
+ ++*pDayOfWeek;
+ if (*pDayOfWeek > 6) *pDayOfWeek = 0;
+ ++*pDayOfYear;
+ ++*pDayOfMonth;
+ if (*pDayOfMonth > monthLength(*pYear, *pMonth))
+ {
+ ++*pMonth;
+ if (*pMonth > 11)
+ {
+ ++*pYear;
+ *pDayOfYear = 0;
+ *pMonth = 0;
+ }
+ *pDayOfMonth = 1;
+ }
+ }
+
+ if (*pHours < 0)
+ {
+ *pHours += 24;
+ --*pDayOfWeek;
+ if (*pDayOfWeek < 0) *pDayOfWeek = 6;
+ --*pDayOfYear;
+ --*pDayOfMonth;
+ if (*pDayOfMonth < 1)
+ {
+ --*pMonth;
+ if (*pMonth < 0)
+ {
+ --*pYear;
+ *pDayOfYear = isLeapYear(*pYear) ? 365 : 364;
+ *pMonth = 11;
+ }
+ *pDayOfMonth = monthLength(*pYear, *pMonth);
+ }
+ }
+}
+static void addYears(int* pYear, int* pDayOfWeek, int* pDaysLeft)
+{
+ while(1)
+ {
+ //See if it is a leap year
+ int leapYear = isLeapYear(*pYear);
+
+ //Find the number of days in this year
+ int daysInYear = leapYear ? 366 : 365;
+
+ //Stop if this is the final year
+ if (*pDaysLeft < daysInYear) break;
+
+ //Calculate the current day of the week at the start of the year
+ *pDayOfWeek += leapYear ? 2 : 1;
+ if (*pDayOfWeek >= 7) *pDayOfWeek -= 7;
+
+ //Move on to the next year
+ *pDaysLeft -= daysInYear;
+ ++*pYear;
+ }
+}
+static void addMonths(int year, int* pMonth, int* pDaysLeft)
+{
+ while(1)
+ {
+ int daysInMonth = monthLength(year, *pMonth);
+
+ //Stop if this is the last month
+ if (*pDaysLeft < daysInMonth) break;
+
+ //Move onto next month
+ *pDaysLeft -= daysInMonth;
+ ++*pMonth;
+ }
+}
+static void timeToTm(time_t t, struct tm* ptm, bool local)
+{
+ //Extract the seconds, minutes, hours and days from the time_t t
+ div_t divres;
+ divres = div( t, 60); int seconds = divres.rem;
+ divres = div(divres.quot, 60); int minutes = divres.rem;
+ divres = div(divres.quot, 24); int hours = divres.rem;
+ int daysLeft = divres.quot;
+
+ //Add a year at a time while there is more than a year of days left
+ int year = 70; //Unix epoch is 1970
+ int dayOfWeek = 4; //1 Jan 1970 is a Thursday
+ addYears(&year, &dayOfWeek, &daysLeft);
+
+ //Days left contains the days left from the start (1 Jan) of the current year
+ int dayOfYear = daysLeft;
+ dayOfWeek += daysLeft;
+ dayOfWeek %= 7;
+
+ //Add a month at a time while there is more than a month of days left
+ int month = 0;
+ addMonths(year, &month, &daysLeft);
+
+ //Days left contains the days left from the start (1st) of the current month
+ int dayOfMonth = daysLeft + 1;
+
+ //Deal with local time offsets
+ int dst;
+ if (local)
+ {
+ //Work out if Daylight Saving Time applies
+ dst = isDst(year, month, dayOfMonth, dayOfWeek, hours);
+
+ //Adjust for the timezone
+ hours += dst ? DST_OFFSET : STD_OFFSET;
+ normalise(&hours, &dayOfWeek, &dayOfMonth, &month, &dayOfYear, &year);
+ }
+ else
+ {
+ dst = -1;
+ }
+
+ //Set up the broken time TM structure
+ ptm->tm_sec = seconds; // 00 --> 59
+ ptm->tm_min = minutes; // 00 --> 59
+ ptm->tm_hour = hours; // 00 --> 23
+ ptm->tm_mday = dayOfMonth; // 01 --> 31
+ ptm->tm_mon = month; // 00 --> 11
+ ptm->tm_year = year; // Years since 1900
+ ptm->tm_wday = dayOfWeek; // 0 --> 6 where 0 == Sunday
+ ptm->tm_yday = dayOfYear; // 0 --> 365
+ ptm->tm_isdst = dst; // +ve if DST, 0 if not DSTime, -ve if the information is not available. Note that 'true' evaluates to +1.
+}
+void TmUtcFromTimeT(time_t time, struct tm* ptm)
+{
+ timeToTm(time, ptm, false);
+}
+void TmLocalFromTimeT(time_t time, struct tm* ptm)
+{
+ timeToTm(time, ptm, true);
+}
+time_t TmUtcToTimeT(struct tm* ptm)
+{
+ int days = 0;
+
+ for (int y = 70; y < ptm->tm_year; y++) days += isLeapYear(y) ? 366 : 365;
+
+ days += ptm->tm_yday;
+
+ return days * 86400 +
+ ptm->tm_hour * 3600 +
+ ptm->tm_min * 60 +
+ ptm->tm_sec;
+}
+int TmSecondsBetween(struct tm* ptmLater, struct tm* ptmEarlier)
+{
+ int days = 0;
+
+ if (ptmLater->tm_year > ptmEarlier->tm_year) for (int y = ptmEarlier->tm_year; y < ptmLater->tm_year; y++) days += isLeapYear(y) ? 366 : 365;
+ else for (int y = ptmEarlier->tm_year; y > ptmLater->tm_year; y--) days -= isLeapYear(y) ? 366 : 365;
+
+ days += ptmLater->tm_yday - ptmEarlier->tm_yday;
+
+ return days * 86400 +
+ (ptmLater->tm_hour - ptmEarlier->tm_hour) * 3600 +
+ (ptmLater->tm_min - ptmEarlier->tm_min ) * 60 +
+ (ptmLater->tm_sec - ptmEarlier->tm_sec );
+}
+
+void TmUtcToLocal(struct tm* ptm)
+{
+ //Establish DST
+ ptm->tm_isdst = isDst(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, ptm->tm_wday, ptm->tm_hour);
+
+ //Adjust for the timezone
+ ptm->tm_hour += ptm->tm_isdst ? DST_OFFSET : STD_OFFSET;
+ normalise(&ptm->tm_hour, &ptm->tm_wday, &ptm->tm_mday, &ptm->tm_mon, &ptm->tm_yday, &ptm->tm_year);
+}
+
+void TmFromAsciiDateTime(const char* pDate, const char* pTime, struct tm* ptm) // Convert compile time to system time
+{
+ //__DATE__ The string constant contains eleven characters and looks like "Feb 12 1996". If the day of the month is less than 10, it is padded with a space on the left.
+ char month[5];
+ sscanf(pDate, "%s %d %d", month, &ptm->tm_mday, &ptm->tm_year); ptm->tm_year -= 1900;
+
+ // Find where month is in month_names. Deduce month value.
+ static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+ ptm->tm_mon = (strstr(month_names, month) - month_names) / 3;
+
+ //__TIME__ The string constant contains eight characters and looks like "23:59:01".
+ sscanf(pTime, "%2d %*c %2d %*c %2d", &ptm->tm_hour, &ptm->tm_min, &ptm->tm_sec);
+
+ //Fill the day of week and the day of year part of the tm structure
+ calculateDayOfYearAndWeek(ptm->tm_year, ptm->tm_mon, ptm->tm_mday, &ptm->tm_yday, &ptm->tm_wday);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tm.h Thu Nov 29 16:51:19 2018 +0000 @@ -0,0 +1,11 @@ +#include <time.h> +#include <stdint.h> + +extern void TmUtcToLocal(struct tm* ptm); + +extern void TmFromAsciiDateTime(const char* pDate, const char* pTime, struct tm* ptm); +extern void TmLocalFromTimeT(uint32_t time, struct tm* ptm); +extern void TmUtcFromTimeT(uint32_t time, struct tm* ptm); + +extern time_t TmUtcToTimeT(struct tm* ptm); +extern int TmSecondsBetween(struct tm* ptmLater, struct tm* ptmEarlier); \ No newline at end of file