1 /** @file
2  * @brief Network timer with wrap around
3  *
4  * Timer that runs longer than about 49 days needs to calculate wraps.
5  */
6 
7 /*
8  * Copyright (c) 2018 Intel Corporation
9  * Copyright (c) 2020 Nordic Semiconductor ASA
10  *
11  * SPDX-License-Identifier: Apache-2.0
12  */
13 
14 #ifndef ZEPHYR_INCLUDE_NET_NET_TIMEOUT_H_
15 #define ZEPHYR_INCLUDE_NET_NET_TIMEOUT_H_
16 
17 /**
18  * @brief Network long timeout primitives and helpers
19  * @defgroup net_timeout Network long timeout primitives and helpers
20  * @since 1.14
21  * @version 0.8.0
22  * @ingroup networking
23  * @{
24  */
25 
26 #include <string.h>
27 #include <stdbool.h>
28 #include <limits.h>
29 #include <zephyr/types.h>
30 #include <zephyr/sys/slist.h>
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 /** @brief Divisor used to support ms resolution timeouts.
37  *
38  * Because delays are processed in work queues which are not invoked
39  * synchronously with clock changes we need to be able to detect timeouts
40  * after they occur, which requires comparing "deadline" to "now" with enough
41  * "slop" to handle any observable latency due to "now" advancing past
42  * "deadline".
43  *
44  * The simplest solution is to use the native conversion of the well-defined
45  * 32-bit unsigned difference to a 32-bit signed difference, which caps the
46  * maximum delay at INT32_MAX.  This is compatible with the standard mechanism
47  * for detecting completion of deadlines that do not overflow their
48  * representation.
49  */
50 #define NET_TIMEOUT_MAX_VALUE ((uint32_t)INT32_MAX)
51 
52 /** Generic struct for handling network timeouts.
53  *
54  * Except for the linking node, all access to state from these objects must go
55  * through the defined API.
56  */
57 struct net_timeout {
58 	/** Used to link multiple timeouts that share a common timer infrastructure.
59 	 *
60 	 * For examples a set of related timers may use a single delayed work
61 	 * structure, which is always scheduled at the shortest time to a
62 	 * timeout event.
63 	 */
64 	sys_snode_t node;
65 
66 	/** Time at which the timer was last set.
67 	 *
68 	 * This usually corresponds to the low 32 bits of k_uptime_get().
69 	 */
70 	uint32_t timer_start;
71 
72 	/** Portion of remaining timeout that does not exceed
73 	 * NET_TIMEOUT_MAX_VALUE.
74 	 *
75 	 * This value is updated in parallel with timer_start and wrap_counter
76 	 * by net_timeout_evaluate().
77 	 */
78 	uint32_t timer_timeout;
79 
80 	/** Timer wrap count.
81 	 *
82 	 * This tracks multiples of NET_TIMEOUT_MAX_VALUE milliseconds that
83 	 * have yet to pass.  It is also updated along with timer_start and
84 	 * wrap_counter by net_timeout_evaluate().
85 	 */
86 	uint32_t wrap_counter;
87 };
88 
89 /** @brief Configure a network timeout structure.
90  *
91  * @param timeout a pointer to the timeout state.
92  *
93  * @param lifetime the duration of the timeout in seconds.
94  *
95  * @param now the time at which the timeout started counting down, in
96  * milliseconds.  This is generally a captured value of k_uptime_get_32().
97  */
98 void net_timeout_set(struct net_timeout *timeout,
99 		     uint32_t lifetime,
100 		     uint32_t now);
101 
102 /** @brief Return the 64-bit system time at which the timeout will complete.
103  *
104  * @note Correct behavior requires invocation of net_timeout_evaluate() at its
105  * specified intervals.
106  *
107  * @param timeout state a pointer to the timeout state, initialized by
108  * net_timeout_set() and maintained by net_timeout_evaluate().
109  *
110  * @param now the full-precision value of k_uptime_get() relative to which the
111  * deadline will be calculated.
112  *
113  * @return the value of k_uptime_get() at which the timeout will expire.
114  */
115 int64_t net_timeout_deadline(const struct net_timeout *timeout,
116 			     int64_t now);
117 
118 /** @brief Calculate the remaining time to the timeout in whole seconds.
119  *
120  * @note This function rounds the remaining time down, i.e. if the timeout
121  * will occur in 3500 milliseconds the value 3 will be returned.
122  *
123  * @note Correct behavior requires invocation of net_timeout_evaluate() at its
124  * specified intervals.
125  *
126  * @param timeout a pointer to the timeout state
127  *
128  * @param now the time relative to which the estimate of remaining time should
129  * be calculated.  This should be recently captured value from
130  * k_uptime_get_32().
131  *
132  * @retval 0 if the timeout has completed.
133  * @retval positive the remaining duration of the timeout, in seconds.
134  */
135 uint32_t net_timeout_remaining(const struct net_timeout *timeout,
136 			       uint32_t now);
137 
138 /** @brief Update state to reflect elapsed time and get new delay.
139  *
140  * This function must be invoked periodically to (1) apply the effect of
141  * elapsed time on what remains of a total delay that exceeded the maximum
142  * representable delay, and (2) determine that either the timeout has
143  * completed or that the infrastructure must wait a certain period before
144  * checking again for completion.
145  *
146  * @param timeout a pointer to the timeout state
147  *
148  * @param now the time relative to which the estimate of remaining time should
149  * be calculated.  This should be recently captured value from
150  * k_uptime_get_32().
151  *
152  * @retval 0 if the timeout has completed
153  * @retval positive the maximum delay until the state of this timeout should
154  * be re-evaluated, in milliseconds.
155  */
156 uint32_t net_timeout_evaluate(struct net_timeout *timeout,
157 			      uint32_t now);
158 
159 #ifdef __cplusplus
160 }
161 #endif
162 
163 /**
164  * @}
165  */
166 
167 
168 #endif /* ZEPHYR_INCLUDE_NET_NET_TIMEOUT_H_ */
169