libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
delay_line.h
Go to the documentation of this file.
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license in the file COPYING
10 * or http://www.opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file COPYING.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2023 Saso Kiselkov. All rights reserved.
24 */
34#ifndef _ACF_UTILS_DELAY_LINE_H_
35#define _ACF_UTILS_DELAY_LINE_H_
36
37#include <string.h>
38#include <stdint.h>
39
40#include "assert.h"
41#include "core.h"
42#include "crc64.h"
43#include "time.h"
44
45#ifdef __cplusplus
46extern "C" {
47#endif
48
55typedef uint64_t (*delay_line_time_func_t)(void *userinfo);
56
57typedef struct {
58 union {
59 int64_t i64;
60 uint64_t u64;
61 double f64;
62 };
63 union {
64 int64_t i64_new;
65 uint64_t u64_new;
66 double f64_new;
67 };
68 uint64_t changed_t;
69 uint64_t delay_us;
70 uint64_t delay_base_us;
71 double delay_rand_fract;
72#ifndef _MSC_VER
73 int __serialize_marker[0];
74#else
75 /* MSVC really hates a zero-length array */
76 int __serialize_marker[1];
77#endif
78 delay_line_time_func_t time_func;
79 void *time_func_userinfo;
81
88static inline void
89delay_line_init(delay_line_t *line, uint64_t delay_us)
90{
91 ASSERT(line != NULL);
92 memset(line, 0, sizeof (*line));
93 line->delay_us = delay_us;
94 line->delay_base_us = delay_us;
95 line->delay_rand_fract = 0;
96}
97
109static inline void
111 delay_line_time_func_t time_func, void *time_func_userinfo)
112{
113 ASSERT(line != NULL);
114 memset(line, 0, sizeof (*line));
115 line->delay_us = delay_us;
116 line->delay_base_us = delay_us;
117 line->delay_rand_fract = 0;
118 line->time_func = time_func;
119 line->time_func_userinfo = time_func_userinfo;
120}
121
127static inline void
129{
130 ASSERT(line != NULL);
131 if (line->delay_rand_fract == 0) {
132 line->delay_us = line->delay_base_us;
133 } else {
134 uint64_t rand_us = line->delay_rand_fract * line->delay_base_us;
135 line->delay_us = line->delay_base_us +
136 (uint64_t)((crc64_rand_fract() - 0.5) * rand_us);
137 }
138}
139
143static inline void
144delay_line_set_delay(delay_line_t *line, uint64_t delay_us)
145{
146 ASSERT(line != NULL);
147 if (line->delay_base_us != delay_us) {
148 line->delay_base_us = delay_us;
150 }
151}
152
158static inline uint64_t
160{
161 ASSERT(line != NULL);
162 return (line->delay_base_us);
163}
164
171static inline uint64_t
173{
174 ASSERT(line != NULL);
175 return (line->delay_us);
176}
177
191static inline void
192delay_line_set_rand(delay_line_t *line, double rand_fract)
193{
194 ASSERT(line != NULL);
195 ASSERT3F(rand_fract, >=, 0);
196 ASSERT3F(rand_fract, <=, 1);
197 line->delay_rand_fract = rand_fract;
199}
200
206static inline double
208{
209 return (line->delay_rand_fract);
210}
211
212#define DEF_DELAY_LINE_PULL(typename, abbrev_type) \
213static inline typename \
214delay_line_pull_ ## abbrev_type(delay_line_t *line) \
215{ \
216 uint64_t now; \
217 ASSERT(line != NULL); \
218 now = (line->time_func != NULL ? \
219 line->time_func(line->time_func_userinfo) : microclock()); \
220 if (line->abbrev_type ## _new != line->abbrev_type && \
221 now - line->changed_t >= line->delay_us) { \
222 line->abbrev_type = line->abbrev_type ## _new; \
223 delay_line_refresh_delay(line); \
224 } \
225 return (line->abbrev_type); \
226}
227
234DEF_DELAY_LINE_PULL(int64_t, i64)
238DEF_DELAY_LINE_PULL(uint64_t, u64)
242DEF_DELAY_LINE_PULL(double, f64)
243
244#define DEF_DELAY_LINE_PEEK(typename, abbrev_type) \
245static inline typename \
246delay_line_peek_ ## abbrev_type(const delay_line_t *line) \
247{ \
248 ASSERT(line != NULL); \
249 return (line->abbrev_type); \
250}
257DEF_DELAY_LINE_PEEK(int64_t, i64)
261DEF_DELAY_LINE_PEEK(uint64_t, u64)
265DEF_DELAY_LINE_PEEK(double, f64)
266
272DEF_DELAY_LINE_PEEK(int64_t, i64_new)
276DEF_DELAY_LINE_PEEK(uint64_t, u64_new)
280DEF_DELAY_LINE_PEEK(double, f64_new)
281
282#define DEF_DELAY_LINE_PUSH(typename, abbrev_type) \
283static inline typename \
284delay_line_push_ ## abbrev_type(delay_line_t *line, typename value) \
285{ \
286 uint64_t now; \
287 ASSERT(line != NULL); \
288 now = (line->time_func != NULL ? \
289 line->time_func(line->time_func_userinfo) : microclock()); \
290 if (line->abbrev_type == line->abbrev_type ## _new && \
291 value != line->abbrev_type ## _new) { \
292 line->changed_t = now; \
293 delay_line_refresh_delay(line); \
294 } \
295 line->abbrev_type ## _new = value; \
296 return (delay_line_pull_ ## abbrev_type(line)); \
297}
306DEF_DELAY_LINE_PUSH(int64_t, i64)
310DEF_DELAY_LINE_PUSH(uint64_t, u64)
314DEF_DELAY_LINE_PUSH(double, f64)
315
316#define DEF_DELAY_LINE_PUSH_IMM(typename, abbrev_type) \
317static inline typename \
318delay_line_push_imm_ ## abbrev_type(delay_line_t *line, typename value) \
319{ \
320 ASSERT(line != NULL); \
321 line->abbrev_type = value; \
322 line->abbrev_type ## _new = value; \
323 return (line->abbrev_type); \
324}
329DEF_DELAY_LINE_PUSH_IMM(int64_t, i64)
333DEF_DELAY_LINE_PUSH_IMM(uint64_t, u64)
337DEF_DELAY_LINE_PUSH_IMM(double, f64)
338
352/*
353 * Generics require at least C11.
354 */
355#if __STDC_VERSION__ >= 201112L
356#define DELAY_LINE_PUSH(line, value) \
357 _Generic((value), \
358 float: delay_line_push_f64((line), (value)), \
359 double: delay_line_push_f64((line), (value)), \
360 uint32_t: delay_line_push_u64((line), (value)), \
361 uint64_t: delay_line_push_u64((line), (value)), \
362 default: delay_line_push_i64((line), (value)))
363#define DELAY_LINE_PUSH_IMM(line, value) \
364 _Generic((value), \
365 float: delay_line_push_imm_f64((line), (value)), \
366 double: delay_line_push_imm_f64((line), (value)), \
367 uint32_t: delay_line_push_imm_u64((line), (value)), \
368 uint64_t: delay_line_push_imm_u64((line), (value)), \
369 default: delay_line_push_imm_i64((line), (value)))
370#else /* __STDC_VERSION__ < 201112L */
371#define DELAY_LINE_PUSH(line, value) \
372 DELAY_LINE_PUSH_macro_requires_C11_or_greater
373#define DELAY_LINE_PUSH_IMM(line, value) \
374 DELAY_LINE_PUSH_IMM_macro_requires_C11_or_greater
375#endif /* __STDC_VERSION__ < 201112L */
376
387static inline uint64_t
389{
390 uint64_t now;
391 ASSERT(line != NULL);
392 now = (line->time_func != NULL ?
393 line->time_func(line->time_func_userinfo) : microclock());
394 return (now - line->changed_t);
395}
396
397#ifdef __cplusplus
398}
399#endif
400
401#endif /* _ACF_UTILS_DELAY_LINE_H_ */
#define ASSERT(x)
Definition assert.h:208
#define ASSERT3F(x, op, y)
Definition assert.h:211
API_EXPORT double crc64_rand_fract(void)
Definition crc64.c:135
static uint64_t delay_line_get_delay(const delay_line_t *line)
Definition delay_line.h:159
static void delay_line_set_rand(delay_line_t *line, double rand_fract)
Definition delay_line.h:192
static void delay_line_refresh_delay(delay_line_t *line)
Definition delay_line.h:128
uint64_t(* delay_line_time_func_t)(void *userinfo)
Definition delay_line.h:55
static double delay_line_get_rand(const delay_line_t *line)
Definition delay_line.h:207
static uint64_t delay_line_get_delay_act(const delay_line_t *line)
Definition delay_line.h:172
static void delay_line_init(delay_line_t *line, uint64_t delay_us)
Definition delay_line.h:89
static uint64_t delay_line_get_time_since_change(const delay_line_t *line)
Definition delay_line.h:388
static void delay_line_init_time_func(delay_line_t *line, uint64_t delay_us, delay_line_time_func_t time_func, void *time_func_userinfo)
Definition delay_line.h:110
static void delay_line_set_delay(delay_line_t *line, uint64_t delay_us)
Definition delay_line.h:144