Lazuli
clock_24.c
Go to the documentation of this file.
1 /*
2  * SPDX-License-Identifier: GPL-3.0-only
3  * This file is part of Lazuli.
4  */
5 
14 #include <stdint.h>
15 
16 #include <Lazuli/clock_24.h>
17 #include <Lazuli/common.h>
18 #include <Lazuli/config.h>
19 
20 #include <Lazuli/sys/clock_24.h>
21 #include <Lazuli/sys/memory.h>
22 
26 static volatile Clock24 clock24 = {0};
27 
31 static volatile u_read_write_atomic_t clockVersion = 0;
32 
45 static bool
46 IncrementUntil(volatile uint8_t * const value, const uint8_t comparator)
47 {
48  if (*value >= comparator) {
49  *value = 0;
50 
51  return true;
52  }
53 
54  (*value)++;
55 
56  return false;
57 }
58 
64 static bool
66 {
67  const uint8_t lastSecondInAMinute = 59;
68 
69  return IncrementUntil(&clock24.seconds, lastSecondInAMinute);
70 }
71 
77 static bool
79 {
80  const uint8_t lastMinuteInAnHour = 59;
81 
82  return IncrementUntil(&clock24.minutes, lastMinuteInAnHour);
83 }
84 
88 static void
90 {
91  const uint8_t lastHourInADay = 23;
92 
93  IncrementUntil(&clock24.hours, lastHourInADay);
94 }
95 
96 void
98 {
100  static uint16_t ticksToNewSecond = 0;
101 
102  if (++ticksToNewSecond < ticksInOneSecond) {
103  return;
104  }
105 
106  ticksToNewSecond = 0;
107 
108  /*
109  * The clock version integer will constantly increment from 0 to its maximum
110  * value.
111  * We can let it overflow as it is unsigned. Unsiged overflow is not an
112  * undefined behaviour in C89.
113  */
114  ++clockVersion;
115 
116  if (IncrementSeconds()) {
117  if (IncrementMinutes()) {
118  IncrementHours();
119  }
120  }
121 }
122 
123 /*
124  * The working of this function needs an explanation.
125  *
126  * While a user task reads all the fields of struct Clock24 clock24, the clock
127  * thick interrupt can occur and cause the kernel to update that same fields.
128  * If that happens we will obtain a copy of struct Clock24 clock24 that is
129  * corrupted. e.g. some of the fields with the previous value, and the others
130  * with the updated value.
131  *
132  * To avoid that, we use this kind of "optimistic access":
133  * A version number is associated to struct Clock24. As all of the fields of
134  * struct Clock24 and version number are updated by the kernel at the same time
135  * without being interrupted, the new values of the time fields in the struct
136  * will be associated to a new value of the version field.
137  * We first read the current version number, then read all the time fields, and
138  * finally read the version number again. If the two version numbers differ we
139  * then know that the kernel updated the struct Clock24 clock24 while we were
140  * accessing it.
141  *
142  * This works as long as the version number is declared with a type that is read
143  * and written atomically.
144  */
145 void
146 Lz_Clock24_Get(Clock24 * const userClock24)
147 {
148  u_read_write_atomic_t version;
149 
150  if (NULL == userClock24) {
151  return;
152  }
153 
154  do {
155  version = clockVersion;
156  userClock24->hours = clock24.hours;
157  userClock24->minutes = clock24.minutes;
158  userClock24->seconds = clock24.seconds;
159  } while (version != clockVersion);
160 }
24-Hour clock user interface.
Memory management API.
void Lz_Clock24_Get(Clock24 *const userClock24)
Get the time on a 24-Hour clock.
Definition: clock_24.c:146
Represents the type used to hold the time.
Definition: clock_24.h:26
Include appropriate config file.
uint8_t hours
Hours.
Definition: clock_24.h:27
static bool IncrementMinutes(void)
Increment the minutes of the system 24-Hour clock.
Definition: clock_24.c:78
const unsigned int LZ_CONFIG_SYSTEM_CLOCK_RESOLUTION_FREQUENCY
The operating system clock resolution frequency, in Hertz.
uint8_t seconds
Seconds.
Definition: clock_24.h:29
static volatile Clock24 clock24
The system Clock24.
Definition: clock_24.c:26
unsigned int uint16_t
Represents a unsigned integer type with width of exactly 16 bits.
Definition: stdint.h:94
static bool IncrementSeconds(void)
Increment the seconds of the system 24-Hour clock.
Definition: clock_24.c:65
24-Hour clock kernel interface.
unsigned char uint8_t
Represents a unsigned integer type with width of exactly 8 bits.
Definition: stdint.h:89
static void IncrementHours(void)
Increment the hours of the system 24-Hour clock.
Definition: clock_24.c:89
#define NULL
NULL pointer.
Definition: common.h:68
Basic type definitions and useful macros.
void Clock24_Increment(void)
Increment the 24-Hour clock, taking into the account the resolution of the system clock...
Definition: clock_24.c:97
static bool IncrementUntil(volatile uint8_t *const value, const uint8_t comparator)
Increment an uint8_t value, and reset it if it reaches the value in comparator.
Definition: clock_24.c:46
uint8_t u_read_write_atomic_t
Represents an unsigned integer that can be read and written atomically.
Definition: common.h:107
uint8_t minutes
Minutes.
Definition: clock_24.h:28
static volatile u_read_write_atomic_t clockVersion
The clock version value.
Definition: clock_24.c:31