Do all time calculations in uint64_t
This prevents loss of precision that occurs with double-precision floats if timestamps become very large. Timestamps are already large if they contain a UNIX time value (requires 60 bits; double has 53 bit resolution).
This commit is contained in:
parent
ec9e893c73
commit
a0623668a7
|
@ -50,7 +50,7 @@
|
||||||
static int m_tunfd = -1;
|
static int m_tunfd = -1;
|
||||||
static bool m_running = true;
|
static bool m_running = true;
|
||||||
|
|
||||||
static double next_tx_switch_time = 0.0;
|
static uint64_t next_tx_switch_time = 0;
|
||||||
|
|
||||||
static rx_stats_t m_rx_stats;
|
static rx_stats_t m_rx_stats;
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
||||||
|
|
||||||
static void block_tx_for(unsigned offset_ms)
|
static void block_tx_for(unsigned offset_ms)
|
||||||
{
|
{
|
||||||
next_tx_switch_time = get_hires_time() + (double)offset_ms * 0.001;
|
next_tx_switch_time = get_hires_time() + HRTIME_MS(offset_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_complex_array(const char *varname, float complex const *array, size_t len)
|
void print_complex_array(const char *varname, float complex const *array, size_t len)
|
||||||
|
@ -186,7 +186,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
bool on_air = true;
|
bool on_air = true;
|
||||||
|
|
||||||
srand((int)(get_hires_time() * 1e6));
|
srand(get_hires_time());
|
||||||
|
|
||||||
// ** Initialize **
|
// ** Initialize **
|
||||||
|
|
||||||
|
@ -233,18 +233,18 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
unsigned rx_retries = 0;
|
unsigned rx_retries = 0;
|
||||||
|
|
||||||
double old = get_hires_time();
|
uint64_t old = get_hires_time();
|
||||||
size_t total_samples = 0;
|
size_t total_samples = 0;
|
||||||
double next_stats_print_time = old + 0.5;
|
uint64_t next_stats_print_time = old + HRTIME_MS(500);
|
||||||
|
|
||||||
double retransmit_time = 0.0;
|
uint64_t retransmit_time = 0;
|
||||||
|
|
||||||
while(m_running) {
|
while(m_running) {
|
||||||
double now = get_hires_time();
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
if(retransmit_time != 0.0 && now >= retransmit_time) {
|
if(retransmit_time != 0 && now >= retransmit_time) {
|
||||||
LOG(LVL_INFO, "Retransmit triggered.");
|
LOG(LVL_INFO, "Retransmit triggered.");
|
||||||
retransmit_time = 0.0;
|
retransmit_time = 0;
|
||||||
layer2_tx_restart(&l2tx);
|
layer2_tx_restart(&l2tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ int main(int argc, char **argv)
|
||||||
RESULT_CHECK(sdr_start_rx(&sdr));
|
RESULT_CHECK(sdr_start_rx(&sdr));
|
||||||
on_air = false;
|
on_air = false;
|
||||||
|
|
||||||
retransmit_time = get_hires_time() + 1.0 + 1.0 * rand() / RAND_MAX;
|
retransmit_time = get_hires_time() + HRTIME_SEC(1) + HRTIME_SEC(1.0 * rand() / RAND_MAX);
|
||||||
|
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
||||||
}
|
}
|
||||||
|
@ -360,9 +360,9 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
total_samples += n_rf_samples;
|
total_samples += n_rf_samples;
|
||||||
|
|
||||||
double new = get_hires_time();
|
uint64_t new = get_hires_time();
|
||||||
if(new >= next_stats_print_time) {
|
if(new >= next_stats_print_time) {
|
||||||
double rate = total_samples / (new - old);
|
double rate = total_samples * 1e9 / (new - old);
|
||||||
LOG(LVL_INFO, "\nEstimated rate: %.3f MS/s", rate / 1e6);
|
LOG(LVL_INFO, "\nEstimated rate: %.3f MS/s", rate / 1e6);
|
||||||
LOG(LVL_INFO, "Receiver statistics:");
|
LOG(LVL_INFO, "Receiver statistics:");
|
||||||
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
||||||
|
|
|
@ -99,9 +99,9 @@ static int tx_callback(hackrf_transfer *transfer)
|
||||||
return HACKRF_ERROR_OTHER;
|
return HACKRF_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sdr_ctx->tx_start_time == 0.0) {
|
if(sdr_ctx->tx_start_time == 0) {
|
||||||
sdr_ctx->tx_start_time = get_hires_time();
|
sdr_ctx->tx_start_time = get_hires_time();
|
||||||
sdr_ctx->tx_duration = 10e-3; // give a little headroom
|
sdr_ctx->tx_duration = HRTIME_MS(10); // give a little headroom
|
||||||
LOG(LVL_INFO, "TX time tracking reset: start = %.3f.", sdr_ctx->tx_start_time);
|
LOG(LVL_INFO, "TX time tracking reset: start = %.3f.", sdr_ctx->tx_start_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ static int tx_callback(hackrf_transfer *transfer)
|
||||||
|
|
||||||
if(samples_read != 0) {
|
if(samples_read != 0) {
|
||||||
// only add time if any actual samples were transmitted
|
// only add time if any actual samples were transmitted
|
||||||
sdr_ctx->tx_duration += (double)samples_requested / SDR_TX_SAMPLING_RATE;
|
sdr_ctx->tx_duration += HRTIME_SEC((double)samples_requested / SDR_TX_SAMPLING_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LVL_DEBUG, "copied %u samples to HackRF.", samples_read);
|
LOG(LVL_DEBUG, "copied %u samples to HackRF.", samples_read);
|
||||||
|
@ -377,8 +377,8 @@ result_t sdr_flush_tx_buffer(sdr_ctx_t *ctx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double now = get_hires_time();
|
uint64_t now = get_hires_time();
|
||||||
double end = ctx->tx_start_time + ctx->tx_duration;
|
uint64_t end = ctx->tx_start_time + ctx->tx_duration;
|
||||||
|
|
||||||
if(sem_post(&ctx->buf_sem) < 0) {
|
if(sem_post(&ctx->buf_sem) < 0) {
|
||||||
LOG(LVL_ERR, "sem_post: %s", strerror(errno));
|
LOG(LVL_ERR, "sem_post: %s", strerror(errno));
|
||||||
|
|
|
@ -76,11 +76,23 @@ err_close:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_hires_time(void)
|
uint64_t get_hires_time(void)
|
||||||
{
|
{
|
||||||
struct timespec clk;
|
struct timespec clk;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &clk);
|
clock_gettime(CLOCK_MONOTONIC, &clk);
|
||||||
return clk.tv_sec + 1e-9 * clk.tv_nsec;
|
return clk.tv_sec * 1000000000ULL + (uint64_t)clk.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep_until(uint64_t hires_time)
|
||||||
|
{
|
||||||
|
struct timespec tv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tv.tv_sec = hires_time / 1000000000ULL;
|
||||||
|
tv.tv_nsec = hires_time % 1000000000ULL;
|
||||||
|
do {
|
||||||
|
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tv, NULL);
|
||||||
|
} while(ret == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsleep(double d)
|
void fsleep(double d)
|
||||||
|
@ -93,18 +105,6 @@ void fsleep(double d)
|
||||||
nanosleep(&ts, NULL);
|
nanosleep(&ts, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sleep_until(double hires_time)
|
|
||||||
{
|
|
||||||
struct timespec tv;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
tv.tv_sec = hires_time;
|
|
||||||
tv.tv_nsec = (uint64_t)(1e9 * hires_time) % 1000000000;
|
|
||||||
do {
|
|
||||||
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tv, NULL);
|
|
||||||
} while(ret == EINTR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hexdump(const uint8_t *data, size_t len)
|
void hexdump(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
static const char lut[16] = "0123456789ABCDEF";
|
static const char lut[16] = "0123456789ABCDEF";
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <liquid/liquid.h>
|
#include <liquid/liquid.h>
|
||||||
|
|
||||||
|
#define HRTIME_US(x) ((uint64_t)(1000ULL * (x)))
|
||||||
|
#define HRTIME_MS(x) ((uint64_t)(1000000ULL * (x)))
|
||||||
|
#define HRTIME_SEC(x) ((uint64_t)(1000000000ULL * (x)))
|
||||||
|
|
||||||
/*! Dump a array of complex numbers.
|
/*! Dump a array of complex numbers.
|
||||||
*
|
*
|
||||||
* \param data Pointer to the data to dump.
|
* \param data Pointer to the data to dump.
|
||||||
|
@ -30,9 +34,26 @@ bool dump_array_cf(const float complex *data, size_t n, float T, const char *fil
|
||||||
*/
|
*/
|
||||||
bool dump_array_f(const float *data, size_t n, float T, const char *filename);
|
bool dump_array_f(const float *data, size_t n, float T, const char *filename);
|
||||||
|
|
||||||
void sleep_until(double hires_time);
|
|
||||||
|
/*! Sleep until the given absolute timestamp in ns.
|
||||||
|
*
|
||||||
|
* The current timestamp can be retrieved using \ref get_hires_time().
|
||||||
|
*
|
||||||
|
* \param hires_time The resume timestamp in ns.
|
||||||
|
*/
|
||||||
|
void sleep_until(uint64_t hires_time);
|
||||||
|
|
||||||
|
|
||||||
|
/*! Returns the current high-resulution timestamp.
|
||||||
|
*
|
||||||
|
* This timestamp comes from the CLOCK_MONOTONIC source and has no defined relation to the wall-clock time. It can be used to calculate intervals, though.
|
||||||
|
*
|
||||||
|
* \returns A timestamp in nanosecond resolution.
|
||||||
|
*/
|
||||||
|
uint64_t get_hires_time(void);
|
||||||
|
|
||||||
|
|
||||||
void fsleep(double d);
|
void fsleep(double d);
|
||||||
double get_hires_time(void);
|
|
||||||
|
|
||||||
void hexdump(const uint8_t *data, size_t len);
|
void hexdump(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ static bool m_running = true;
|
||||||
|
|
||||||
static int m_bcast_sock = -1;
|
static int m_bcast_sock = -1;
|
||||||
|
|
||||||
static double next_tx_switch_time = 0.0;
|
static uint64_t next_tx_switch_time = 0;
|
||||||
|
|
||||||
static rx_stats_t m_rx_stats;
|
static rx_stats_t m_rx_stats;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
||||||
|
|
||||||
static void block_tx_for(unsigned offset_ms)
|
static void block_tx_for(unsigned offset_ms)
|
||||||
{
|
{
|
||||||
next_tx_switch_time = get_hires_time() + (double)offset_ms * 0.001;
|
next_tx_switch_time = get_hires_time() + HRTIME_MS(offset_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
bool on_air = true;
|
bool on_air = true;
|
||||||
|
|
||||||
srand((int)(get_hires_time() * 1e6));
|
srand(get_hires_time());
|
||||||
|
|
||||||
// ** Initialize **
|
// ** Initialize **
|
||||||
|
|
||||||
|
@ -218,18 +218,18 @@ int main(int argc, char **argv)
|
||||||
pfd_bcast.fd = m_bcast_sock;
|
pfd_bcast.fd = m_bcast_sock;
|
||||||
pfd_bcast.events = POLLIN;
|
pfd_bcast.events = POLLIN;
|
||||||
|
|
||||||
double old = get_hires_time();
|
uint64_t old = get_hires_time();
|
||||||
size_t total_bytes = 0;
|
size_t total_bytes = 0;
|
||||||
double next_stats_print_time = old + 0.5;
|
uint64_t next_stats_print_time = old + HRTIME_MS(500);
|
||||||
|
|
||||||
double retransmit_time = 0.0;
|
uint64_t retransmit_time = 0;
|
||||||
|
|
||||||
while(m_running) {
|
while(m_running) {
|
||||||
double now = get_hires_time();
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
if(retransmit_time != 0.0 && now >= retransmit_time) {
|
if(retransmit_time != 0 && now >= retransmit_time) {
|
||||||
LOG(LVL_INFO, "Retransmit triggered.");
|
LOG(LVL_INFO, "Retransmit triggered.");
|
||||||
retransmit_time = 0.0;
|
retransmit_time = 0;
|
||||||
connection_restart_tx(&l2conn);
|
connection_restart_tx(&l2conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ int main(int argc, char **argv)
|
||||||
LOG(LVL_INFO, "TX -> RX");
|
LOG(LVL_INFO, "TX -> RX");
|
||||||
on_air = false;
|
on_air = false;
|
||||||
|
|
||||||
retransmit_time = get_hires_time() + 1.0 + 1.0 * rand() / RAND_MAX;
|
retransmit_time = get_hires_time() + HRTIME_SEC(1) + HRTIME_SEC(1.0 * rand() / RAND_MAX);
|
||||||
|
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
||||||
}
|
}
|
||||||
|
@ -334,9 +334,9 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
total_bytes += ret;
|
total_bytes += ret;
|
||||||
|
|
||||||
double new = get_hires_time();
|
uint64_t new = get_hires_time();
|
||||||
if(new >= next_stats_print_time) {
|
if(new >= next_stats_print_time) {
|
||||||
double rate = total_bytes / (new - old);
|
double rate = total_bytes * 1e9 / (new - old);
|
||||||
LOG(LVL_INFO, "\nEstimated rate: %.3f kB/s", rate / 1e3);
|
LOG(LVL_INFO, "\nEstimated rate: %.3f kB/s", rate / 1e3);
|
||||||
LOG(LVL_INFO, "Receiver statistics:");
|
LOG(LVL_INFO, "Receiver statistics:");
|
||||||
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
||||||
|
@ -346,7 +346,7 @@ int main(int argc, char **argv)
|
||||||
m_rx_stats.header_errors, m_rx_stats.header_errors * 100.0f / m_rx_stats.preambles_found);
|
m_rx_stats.header_errors, m_rx_stats.header_errors * 100.0f / m_rx_stats.preambles_found);
|
||||||
LOG(LVL_INFO, " Failed decodes: %8zd (%6.2f %%)",
|
LOG(LVL_INFO, " Failed decodes: %8zd (%6.2f %%)",
|
||||||
m_rx_stats.failed_decodes, m_rx_stats.failed_decodes * 100.0f / m_rx_stats.preambles_found);
|
m_rx_stats.failed_decodes, m_rx_stats.failed_decodes * 100.0f / m_rx_stats.preambles_found);
|
||||||
next_stats_print_time += 0.5;
|
next_stats_print_time += HRTIME_MS(500);
|
||||||
|
|
||||||
total_bytes = 0;
|
total_bytes = 0;
|
||||||
old = new;
|
old = new;
|
||||||
|
|
|
@ -50,7 +50,7 @@ static bool m_running = true;
|
||||||
|
|
||||||
static int m_bcast_sock = -1;
|
static int m_bcast_sock = -1;
|
||||||
|
|
||||||
static double next_tx_switch_time = 0.0;
|
static uint64_t next_tx_switch_time = 0;
|
||||||
|
|
||||||
static rx_stats_t m_rx_stats;
|
static rx_stats_t m_rx_stats;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ static void signal_handler(int signal, siginfo_t *info, void *ctx)
|
||||||
|
|
||||||
static void block_tx_for(unsigned offset_ms)
|
static void block_tx_for(unsigned offset_ms)
|
||||||
{
|
{
|
||||||
next_tx_switch_time = get_hires_time() + (double)offset_ms * 0.001;
|
next_tx_switch_time = get_hires_time() + HRTIME_MS(offset_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
bool on_air = true;
|
bool on_air = true;
|
||||||
|
|
||||||
srand((int)(get_hires_time() * 1e6));
|
srand(get_hires_time());
|
||||||
|
|
||||||
// ** Initialize **
|
// ** Initialize **
|
||||||
|
|
||||||
|
@ -218,18 +218,18 @@ int main(int argc, char **argv)
|
||||||
pfd_bcast.fd = m_bcast_sock;
|
pfd_bcast.fd = m_bcast_sock;
|
||||||
pfd_bcast.events = POLLIN;
|
pfd_bcast.events = POLLIN;
|
||||||
|
|
||||||
double old = get_hires_time();
|
uint64_t old = get_hires_time();
|
||||||
size_t total_bytes = 0;
|
size_t total_bytes = 0;
|
||||||
double next_stats_print_time = old + 0.5;
|
uint64_t next_stats_print_time = old + HRTIME_MS(500);
|
||||||
|
|
||||||
double retransmit_time = 0.0;
|
uint64_t retransmit_time = 0;
|
||||||
|
|
||||||
while(m_running) {
|
while(m_running) {
|
||||||
double now = get_hires_time();
|
uint64_t now = get_hires_time();
|
||||||
|
|
||||||
if(retransmit_time != 0.0 && now >= retransmit_time) {
|
if(retransmit_time != 0 && now >= retransmit_time) {
|
||||||
LOG(LVL_INFO, "Retransmit triggered.");
|
LOG(LVL_INFO, "Retransmit triggered.");
|
||||||
retransmit_time = 0.0;
|
retransmit_time = 0;
|
||||||
connection_restart_tx(&l2conn);
|
connection_restart_tx(&l2conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ int main(int argc, char **argv)
|
||||||
LOG(LVL_INFO, "TX -> RX");
|
LOG(LVL_INFO, "TX -> RX");
|
||||||
on_air = false;
|
on_air = false;
|
||||||
|
|
||||||
retransmit_time = get_hires_time() + 1.0 + 1.0 * rand() / RAND_MAX;
|
retransmit_time = get_hires_time() + HRTIME_SEC(1) + HRTIME_SEC(1.0 * rand() / RAND_MAX);
|
||||||
|
|
||||||
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON);
|
||||||
}
|
}
|
||||||
|
@ -334,9 +334,9 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
total_bytes += ret;
|
total_bytes += ret;
|
||||||
|
|
||||||
double new = get_hires_time();
|
uint64_t new = get_hires_time();
|
||||||
if(new >= next_stats_print_time) {
|
if(new >= next_stats_print_time) {
|
||||||
double rate = total_bytes / (new - old);
|
double rate = total_bytes * 1e9 / (new - old);
|
||||||
LOG(LVL_INFO, "\nEstimated rate: %.3f kB/s", rate / 1e3);
|
LOG(LVL_INFO, "\nEstimated rate: %.3f kB/s", rate / 1e3);
|
||||||
LOG(LVL_INFO, "Receiver statistics:");
|
LOG(LVL_INFO, "Receiver statistics:");
|
||||||
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
LOG(LVL_INFO, " Preambles found: %8zd", m_rx_stats.preambles_found);
|
||||||
|
@ -346,7 +346,7 @@ int main(int argc, char **argv)
|
||||||
m_rx_stats.header_errors, m_rx_stats.header_errors * 100.0f / m_rx_stats.preambles_found);
|
m_rx_stats.header_errors, m_rx_stats.header_errors * 100.0f / m_rx_stats.preambles_found);
|
||||||
LOG(LVL_INFO, " Failed decodes: %8zd (%6.2f %%)",
|
LOG(LVL_INFO, " Failed decodes: %8zd (%6.2f %%)",
|
||||||
m_rx_stats.failed_decodes, m_rx_stats.failed_decodes * 100.0f / m_rx_stats.preambles_found);
|
m_rx_stats.failed_decodes, m_rx_stats.failed_decodes * 100.0f / m_rx_stats.preambles_found);
|
||||||
next_stats_print_time += 0.5;
|
next_stats_print_time += HRTIME_MS(500);
|
||||||
|
|
||||||
total_bytes = 0;
|
total_bytes = 0;
|
||||||
old = new;
|
old = new;
|
||||||
|
|
Loading…
Reference in a new issue