/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /* * Affine maps from master TSF to each radio TSF: t_radio ≈ α·t_master + β. * One master among N radios → (N−1) fitted maps + identity for the master. */ #ifndef TSF_AFFINE_H #define TSF_AFFINE_H #include #include #include #define TSF_AFFINE_MAX_RADIOS 32 struct tsf_affine_map { double alpha; double beta; uint64_t anchor_master; uint64_t anchor_radio; int have_anchor; /* Window of (dm, dr) with dm = master - anchor_master, dr = radio - anchor_radio */ int64_t *dm; int64_t *dr; size_t win_cap; size_t win_count; size_t win_pos; /* next write index */ }; struct tsf_affine_pool { unsigned int n_radios; unsigned int master_idx; struct tsf_affine_map maps[TSF_AFFINE_MAX_RADIOS]; }; int tsf_affine_pool_init(struct tsf_affine_pool *p, unsigned int n_radios, unsigned int master_idx, size_t window_cap); void tsf_affine_pool_fini(struct tsf_affine_pool *p); /* Push one simultaneous pair (same physical instant). Ignored for master_idx. */ void tsf_affine_pool_sample(struct tsf_affine_pool *p, unsigned int radio_idx, uint64_t master_tsf, uint64_t radio_tsf); /* * Given master TSF, fill out_radio[i] for all i. * Master index: out_radio[master_idx] == master_tsf exactly. */ void tsf_affine_pool_master_to_all(const struct tsf_affine_pool *p, uint64_t master_tsf, uint64_t out_radio[TSF_AFFINE_MAX_RADIOS]); /* Single radio; returns false if radio_idx invalid or map not yet usable. */ bool tsf_affine_pool_master_to_radio(const struct tsf_affine_pool *p, unsigned int radio_idx, uint64_t master_tsf, uint64_t *out_radio_tsf); bool tsf_affine_map_ready(const struct tsf_affine_map *m); #endif