GNU Radio's RTP Package
misc.h
Go to the documentation of this file.
1// Miscellaneous constants, macros and function prototypes for ka9q-radio
2// Copyright 2018-2023 Phil Karn, KA9Q
3#ifndef _MISC_H
4#define _MISC_H 1
5
6// Note: files that include <math.h> before us must define _GNU_SOURCE prior to including math.h
7// or Linux will generate warnings about a lack of declarations for sincos and sincosf.
8// Apparently they are defined in math.h only when _GNU_SOURCE is defined.
9// Our re-defining _GNU_SOURCE and re-including math.h doesn't help if it has already been included
10#ifndef _GNU_SOURCE
11#define _GNU_SOURCE 1
12#endif
13
14#include <pthread.h>
15#include <stdint.h>
16#include <limits.h>
17#include <complex.h>
18#include <math.h> // Get M_PI
19#include <stdlib.h> // for ldiv(), free()
20#include <stdbool.h>
21#include <sys/errno.h>
22#ifdef __linux__
23#include <bsd/string.h>
24#endif
25#include <assert.h>
26#include <sys/types.h>
27
28#if 0
29// Must be a macro so __FILE__ and __TIMESTAMP__ will substitute correctly
30#define VERSION() { fprintf(stderr,"KA9Q Multichannel SDR %s last modified %s\n",__FILE__,__TIMESTAMP__); \
31 fprintf(stderr,"Copyright 2026, Phil Karn, KA9Q. May be used under the terms of the GNU Public License\n"); \
32 fprintf(stderr," Repo: %s\n",GIT_REMOTE_URL); \
33 fprintf(stderr," Commit: %s\n",GIT_HASH); \
34 fprintf(stderr," Date: %s\n",GIT_TIME); \
35 fprintf(stderr," Branch:%s\n",GIT_BRANCH); \
36 fprintf(stderr,"Version: %s\n",GIT_VERSION); \
37 fprintf(stderr,"Summary: %s\n",GIT_SUMMARY); \
38}
39#else
40#define VERSION() { fprintf(stderr,"KA9Q Multichannel SDR %s last modified %s\n",__FILE__,__TIMESTAMP__); \
41 fprintf(stderr,"Copyright 2026, Phil Karn, KA9Q. May be used under the terms of the GNU Public License\n"); \
42 fprintf(stderr," Repo: %s\n",GIT_REMOTE_URL); \
43 fprintf(stderr," Commit: %s\n",GIT_HASH); \
44}
45#endif
46#define ASSERT_ZEROED(ptr, size) assert(memcmp(ptr, &(typeof(*(ptr))){0}, size) == 0)
47
48static inline void ASSERT_UNLOCKED(pthread_mutex_t *mutex){
49#ifndef NDEBUG
50 int rc = pthread_mutex_trylock(mutex);
51 assert(rc != EBUSY);
52 pthread_mutex_unlock(mutex);
53#else
54 (void)mutex;
55#endif
56}
57// 16-bit floating point is not consistent across platforms
58#ifdef __arm__ // ARM platform
59 #if defined(__ARM_FP16_FORMAT_IEEE)
60 typedef __fp16 float16_t; // ARM-specific half-precision support
61 #else
62 typedef float float16_t; // Fallback on older ARM CPUs
63 #endif
64 #define HAS_FLOAT16 = 1
65#else // Non-ARM platforms
66 #if defined(__FLT16_MAX__) // Check if _Float16 is natively supported
67 typedef _Float16 float16_t;
68 #define HAS_FLOAT16 = 1
69 #endif
70#endif
71
72#define DEGPRA (180./M_PI)
73#define RAPDEG (M_PI/180.)
74#define TAI_GPS_OFFSET (19) // TAI is always and forever 19 seconds ahead of GPS
75#define GPS_UTC_OFFSET (18) // GPS ahead of utc by 18 seconds - make this a table!
76#define TAI_UTC_OFFSET (TAI_GPS_OFFSET+GPS_UTC_OFFSET)
77#define UNIX_EPOCH ((time_t)315964800) // GPS epoch on unix time scale
78
79#define BOLTZMANN (1.380649e-23) // Boltzmann's constant, J/K
80
81static float const SCALE16 = 1.f/INT16_MAX;
82static float const SCALE12 = 1.f/2048.;
83static float const SCALE8 = 1.f/INT8_MAX; // Scale signed 8-bit int to float in range -1, +1
84
85
86#define FULL_SAMPRATE (48000)
87
88int default_prio(void);
89void realtime(int prio);
90int norealtime(void);
91void stick_core(void);
92// Custom version of malloc that aligns to a cache line
93void *lmalloc(size_t size);
94
95// I *hate* this sort of pointless, stupid, gratuitous incompatibility that
96// makes a lot of code impossible to read and debug
97
98#ifdef __APPLE__
99// OSX doesn't have pthread_barrier_*
100#include <pthread.h>
101
102typedef int pthread_barrierattr_t;
103typedef struct
104{
105 pthread_mutex_t mutex;
106 pthread_cond_t cond;
107 int count;
108 int tripCount;
109} pthread_barrier_t;
110int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count);
111int pthread_barrier_destroy(pthread_barrier_t *barrier);
112int pthread_barrier_wait(pthread_barrier_t *barrier);
113
114// The Linux version of pthread_setname_np takes two args, the OSx version only one
115// The GNU malloc_usable_size() does exactly the same thing as the BSD/OSX malloc_size()
116// except that the former is defined in <malloc.h>, the latter is in <malloc/malloc.h>
117
118#define pthread_setname(x) pthread_setname_np(x)
119#include <malloc/malloc.h>
120#define malloc_usable_size(x) malloc_size(x)
121#define sincos(x,s,c) __sincos((x),(s),(c))
122#define sincosf(x,s,c) __sincosf((x),(s),(c))
123
124#else // !__APPLE__
125// Not apple (Linux, etc)
126
127#include <malloc.h>
128#define pthread_setname(x) pthread_setname_np(pthread_self(),(x))
129
130#endif // ifdef __APPLE__
131
132// Portable mutex initializer for recursive mutexes
133static inline int init_recursive_mutex(pthread_mutex_t *m){
134 pthread_mutexattr_t attr;
135 pthread_mutexattr_init(&attr);
136 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
137 return pthread_mutex_init(m,&attr);
138}
139
140
141// Stolen from the Linux kernel -- enforce type matching of arguments
142#define min(x,y) ({ \
143 typeof(x) _x = (x); \
144 typeof(y) _y = (y); \
145 (void) (&_x == &_y); \
146 _x < _y ? _x : _y; })
147
148#define max(x,y) ({ \
149 typeof(x) _x = (x); \
150 typeof(y) _y = (y); \
151 (void) (&_x == &_y); \
152 _x > _y ? _x : _y; })
153
154
155// power2dB and voltage2dB pass NAN to log10(), for debug trapping
156// They do avoid the divide-by-zero exception for the common case of 0 -> -infinity dB
157static inline double dB2power(double x){
158 return pow(10.0,x/10.0);
159}
160static inline double power2dB(double x){
161 if(x <= 0.0)
162 return -INFINITY;
163 return 10.0 * log10(x);
164}
165static inline double dB2voltage(double x){
166 return pow(10.0,x/20.0);
167}
168static inline double voltage2dB(double x){
169 if(x <= 0.0)
170 return -INFINITY;
171 return 20.0 * log10(x);
172}
173
174// Does anyone implement these natively for Linux?
175// (I just did - KA9Q Jan 2026 -- see sincospi.c and sincospif.c)
176// It's a big win in DSP to keep phases as rotations (or half rotations),
177// rather than radians, to make phase wrap reduction really easy and accurate
178void sincospi(double x, double *s, double *c);
179void sincospif(float x, float *s, float *c);
180
181// How many names can people dream up for the same operation?
182// (I know, I'm an EE so I should say 'j', not 'i')
183// exp(i*x) = Cos(x) + i*sin(x)
184// "cosine plus i sine" -- heard a lot in grad school
185#define cisf(x) csincosf(x)
186#define cispif(x) csincospif(x)
187#define cis(x) csincos(x)
188#define cispi(x) csincospi(x)
189
190
191static inline double sinc(double x){
192 if(x == 0)
193 return 1;
194 return sin(M_PI * x) / (M_PI * x);
195}
196
197
198extern const char *App_path;
199extern int Verbose;
200extern char const *Months[12];
201extern bool Affinity;
202
203int dist_path(char *path,int path_len,const char *fname);
204char *format_gpstime(char *result,int len,int64_t t);
205char *format_gpstime_iso8601(char *result,int len,int64_t t);
206char *format_utctime(char *result,int len,int64_t t);
207char *format_utctime_iso8601(char *result,int len,int64_t t);
208char *ftime(char *result,int size,int64_t t);
209void normalize_time(struct timespec *x);
210double parse_frequency(char const *,bool);
211uint32_t nextfastfft(uint32_t n);
212ssize_t pipefill(int,void *,size_t);
213void chomp(char *);
214char *ensure_suffix(char const *str, char const *suffix);
215uint32_t ElfHash(uint8_t const *s,size_t length);
216uint32_t ElfHashString(char const *s);
217uint32_t fnv1hash(const uint8_t *s,size_t length);
218
219// Modified Bessel functions
220double i0(double const z); // 0th kind
221double i1(double const z); // 1st kind
222
223double xi(double thetasq);
224double fm_snr(double r);
225
226// Convert floating point sample to 16-bit integer, with clipping
227inline static int16_t scaleclip(float const x){
228 return (x >= 1.0) ? INT16_MAX : (x <= -1.0) ? -INT16_MAX : (int16_t)(INT16_MAX * x);
229}
230static inline float complex csincosf(float const x){
231 float s,c;
232
233 sincosf(x,&s,&c);
234 return CMPLXF(c,s);
235}
236static inline float complex csincospif(float const x){
237 float s,c;
238 sincospif(x,&s,&c);
239 return CMPLXF(c,s);
240}
241// return unit magnitude complex number with given phase x
242static inline double complex csincos(double const x){
243 double s,c;
244
245 sincos(x,&s,&c);
246 return CMPLX(c,s);
247}
248static inline double complex csincospi(double const x){
249 double s,c;
250 sincospi(x,&s,&c);
251 return CMPLX(c,s);
252}
253// Complex norm (sum of squares of real and imaginary parts)
254static inline float cnrmf(float complex const x){
255 return crealf(x)*crealf(x) + cimagf(x) * cimagf(x);
256}
257static inline double cnrm(double complex const x){
258 return creal(x)*creal(x) + cimag(x) * cimag(x);
259}
260// Fast approximate square root, for signal magnitudes
261// https://dspguru.com/dsp/tricks/magnitude-estimator/
262static inline double approx_magf(double complex x){
263 static double const Alpha = 0.947543636291;
264 static double const Beta = 0.392485425092;
265
266 double absr = fabs(__real__ x);
267 double absi = fabs(__imag__ x);
268
269 return Alpha * max(absr,absi) + Beta * min(absr,absi);
270}
271
272// Result = a - b
273static inline void time_sub(struct timespec *result,struct timespec const *a, struct timespec const *b){
274 result->tv_sec = a->tv_sec - b->tv_sec;
275 result->tv_nsec = a->tv_nsec - b->tv_nsec;
276 normalize_time(result);
277}
278// Result = a + b
279static inline void time_add(struct timespec *result,struct timespec const *a, struct timespec const *b){
280 result->tv_sec = a->tv_sec + b->tv_sec;
281 result->tv_nsec = a->tv_nsec + b->tv_nsec;
282 normalize_time(result);
283}
284
285// Compare two timespec structures, assuming normalized
286// a > b: +1
287// a < b: -1
288// a == b: 0
289static inline int time_cmp(struct timespec const *a,struct timespec const *b){
290 // Will this long conditional help the optimizer?
291 return (a->tv_sec > b->tv_sec) ? 1
292 : (a->tv_sec < b->tv_sec) ? -1
293 : (a->tv_nsec > b->tv_nsec) ? +1
294 : (a->tv_nsec < b->tv_nsec) ? -1
295 : 0;
296}
297static int64_t const BILLION = 1000000000LL;
298static int const MILLION = 1000000;
299static int const THOUSAND = 1000;
300
301// Convert timespec (seconds, nanoseconds) to integer nanoseconds
302// Integer nanoseconds overflows past 584.94242 years. That's probably long enough
303static inline int64_t ts2ns(struct timespec const *ts){
304 return ts->tv_sec * BILLION + ts->tv_nsec;
305}
306// Convert integer nanosec count to timspec
307static inline void ns2ts(struct timespec *ts,int64_t ns){
308 lldiv_t r = lldiv(ns,BILLION);
309 ts->tv_sec = r.quot;
310 ts->tv_nsec = r.rem;
311}
312
313// Return time of day as seconds (truncated) from UTC epoch
314static inline time_t utc_time_sec(void){
315 struct timespec now;
316 clock_gettime(CLOCK_REALTIME,&now);
317 return (time_t)now.tv_sec;
318}
319// Same from GPS epoch
320static inline time_t gps_time_sec(void){
322}
323
324// Return time of day as nanosec from UTC epoch
325static inline int64_t utc_time_ns(void){
326 struct timespec now;
327 clock_gettime(CLOCK_REALTIME,&now);
328 return ts2ns(&now);
329}
330
331// Return time of day as nanosec from GPS epoch
332// Note: assumes fixed leap second offset
333// Could be better derived direct from a GPS receiver without applying the leap second offset
334int64_t gps_time_ns(void);
335
336// How the free() library routine should have been all along: null the pointer after freeing!
337#define FREE(p) (free(p), p = NULL)
338
339// Create allocation followed immediately by its mirror, useful for ring buffers
340// size is rounded up to next page boundary
341void *mirror_alloc(size_t size);
342void mirror_free(void **p,size_t size);
343
344// Wrap pointer p to keep it in range (base, base + size), where size is in bytes
345// The callers use C casts in a somewhat dodgy fashion, but is OK because size is always a multiple of the page size,
346// and there's an integral number of the objects we're pointing to in a page (we hope!!)
347static inline void mirror_wrap(void const **p, void const * const base,size_t const size){
348 assert(*p >= base); // Shouldn't be THIS low
349 assert(*p < base + 2 * size); // Or this high
350
351 if((uint8_t *)*p >= (uint8_t *)base + size)
352 *p = (uint8_t *)*p - size;
353}
354
355// round argument up to an even number of system pages
356size_t round_to_page(size_t size);
357
358uint32_t round2(uint32_t v);
359
360void drop_cache(void *mem,size_t bytes);
361
362// Gaussian (normal) RV generation
363typedef struct {
364 uint64_t s[4];
366
367void xoshiro256ss_seed(xoshiro256ss_state *st, uint64_t seed);
370void rand_init(void);
371double real_gauss(void);
372static inline double complex complex_gauss(void){
373 double r = real_gauss();
374 double i = real_gauss();
375 return CMPLX(r,i);
376}
377
378#endif // _MISC_H
static void mirror_wrap(void const **p, void const *const base, size_t const size)
Definition misc.h:347
#define UNIX_EPOCH
Definition misc.h:77
static int const MILLION
Definition misc.h:298
bool Affinity
static void ASSERT_UNLOCKED(pthread_mutex_t *mutex)
Definition misc.h:48
static int16_t scaleclip(float const x)
Definition misc.h:227
uint32_t nextfastfft(uint32_t n)
char * format_gpstime(char *result, int len, int64_t t)
static void time_add(struct timespec *result, struct timespec const *a, struct timespec const *b)
Definition misc.h:279
char const * Months[12]
char * format_gpstime_iso8601(char *result, int len, int64_t t)
static float cnrmf(float complex const x)
Definition misc.h:254
uint32_t round2(uint32_t v)
static double dB2voltage(double x)
Definition misc.h:165
uint32_t ElfHash(uint8_t const *s, size_t length)
int default_prio(void)
uint32_t fnv1hash(const uint8_t *s, size_t length)
char * format_utctime_iso8601(char *result, int len, int64_t t)
void * lmalloc(size_t size)
static int64_t const BILLION
Definition misc.h:297
static double dB2power(double x)
Definition misc.h:157
int norealtime(void)
static double cnrm(double complex const x)
Definition misc.h:257
void sincospif(float x, float *s, float *c)
double real_gauss(void)
static double voltage2dB(double x)
Definition misc.h:168
static double complex csincospi(double const x)
Definition misc.h:248
void chomp(char *)
static double sinc(double x)
Definition misc.h:191
static int time_cmp(struct timespec const *a, struct timespec const *b)
Definition misc.h:289
void stick_core(void)
static float const SCALE8
Definition misc.h:83
char * ensure_suffix(char const *str, char const *suffix)
int64_t gps_time_ns(void)
void * mirror_alloc(size_t size)
static float complex csincosf(float const x)
Definition misc.h:230
static void ns2ts(struct timespec *ts, int64_t ns)
Definition misc.h:307
void sincospi(double x, double *s, double *c)
char * format_utctime(char *result, int len, int64_t t)
static double complex csincos(double const x)
Definition misc.h:242
void realtime(int prio)
double xi(double thetasq)
static int64_t ts2ns(struct timespec const *ts)
Definition misc.h:303
static int64_t utc_time_ns(void)
Definition misc.h:325
int Verbose
ssize_t pipefill(int, void *, size_t)
char * ftime(char *result, int size, int64_t t)
static time_t utc_time_sec(void)
Definition misc.h:314
uint32_t ElfHashString(char const *s)
static double complex complex_gauss(void)
Definition misc.h:372
static double approx_magf(double complex x)
Definition misc.h:262
static int init_recursive_mutex(pthread_mutex_t *m)
Definition misc.h:133
const char * App_path
void xoshiro256ss_jump(xoshiro256ss_state *st)
static void time_sub(struct timespec *result, struct timespec const *a, struct timespec const *b)
Definition misc.h:273
void rand_init(void)
double i1(double const z)
#define min(x, y)
Definition misc.h:142
static float const SCALE12
Definition misc.h:82
int dist_path(char *path, int path_len, const char *fname)
double fm_snr(double r)
static time_t gps_time_sec(void)
Definition misc.h:320
static float const SCALE16
Definition misc.h:81
#define max(x, y)
Definition misc.h:148
void normalize_time(struct timespec *x)
void mirror_free(void **p, size_t size)
static int const THOUSAND
Definition misc.h:299
static float complex csincospif(float const x)
Definition misc.h:236
uint64_t xoshiro256ss_next(xoshiro256ss_state *st)
#define GPS_UTC_OFFSET
Definition misc.h:75
double i0(double const z)
void drop_cache(void *mem, size_t bytes)
static double power2dB(double x)
Definition misc.h:160
void xoshiro256ss_seed(xoshiro256ss_state *st, uint64_t seed)
size_t round_to_page(size_t size)
Definition misc.h:363
uint64_t s[4]
Definition misc.h:364