From 7bdb7b6c6d2623361bd8e7b83565e269750540bb Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Fri, 12 May 2023 11:43:26 -0400 Subject: [PATCH] add support code for future modifications; --- src/Clock.cpp | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/Clock.h | 77 ++++++++++++++++++ 2 files changed, 289 insertions(+) create mode 100644 src/Clock.cpp create mode 100644 src/Clock.h diff --git a/src/Clock.cpp b/src/Clock.cpp new file mode 100644 index 00000000..ea974cac --- /dev/null +++ b/src/Clock.cpp @@ -0,0 +1,212 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2023 Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#include "Defines.h" +#include "Clock.h" + +using namespace system_clock; + +#include + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +static const uint64_t EPOCH = 2208988800ULL; +static const uint64_t NTP_SCALE_FRAC = 4294967296ULL; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/// +/// +/// +/// +/// +/// +static inline uint32_t ntpDiffMS(uint64_t older, uint64_t newer) +{ + if (older > newer) { + // LOG_ERROR("Older timestamp is actually newer"); + } + + uint32_t s1 = (older >> 32) & 0xffffffff; + uint32_t s2 = (newer >> 32) & 0xffffffff; + uint64_t us1 = ((older & 0xffffffff) * 1000000UL) / NTP_SCALE_FRAC; + uint64_t us2 = ((newer & 0xffffffff) * 1000000UL) / NTP_SCALE_FRAC; + + uint64_t r = (((uint64_t)(s2 - s1) * 1000000) + ((us2 - us1))) / 1000; + + if (r > UINT32_MAX) { + // LOG_ERROR("NTP difference is too large: %llu. Limiting value", r); + r = UINT32_MAX; + } + + return (uint32_t)r; +} + +/// +/// Get current time in NTP units. +/// +/// NTP timestamp. +uint64_t ntp::now() +{ + struct timeval tv; +#ifdef _WIN32 + gettimeofday(&tv, NULL); +#else + gettimeofday(&tv, NULL); +#endif + + uint64_t tv_ntp = tv.tv_sec + EPOCH; + uint64_t tv_usecs = (uint64_t)((float)(NTP_SCALE_FRAC * tv.tv_usec) / 1000000.f); + + return (tv_ntp << 32) | tv_usecs; +} + +/// +/// Calculate the time difference of two NTP times. +/// +/// First NTP timestamp +/// Second NTP timestamp +/// Difference of the timestamps in milliseconds. +uint64_t ntp::diff(uint64_t ntp1, uint64_t ntp2) +{ + return ntpDiffMS(ntp1, ntp2); +} + +/// +/// Calculate the time difference of two NTP times. +/// +/// This function calls clock::ntp::now() and then subtracts the input +/// parameter from that timestamp value. +/// +/// NTP timestamp +/// Difference of the timestamps in milliseconds. +uint64_t ntp::diffNow(uint64_t then) +{ + uint64_t now = ntp::now(); + return ntpDiffMS(then, now); +} + +/// +/// Get current time in HRC units. +/// +/// NTP timestamp. +hrc::hrc_t hrc::now() +{ + return std::chrono::high_resolution_clock::now(); +} + +/// +/// Calculate the time difference of two HRC times. +/// +/// First HRC timestamp +/// Second HRC timestamp +/// Difference of the timestamps in milliseconds. +uint64_t hrc::diff(hrc::hrc_t hrc1, hrc::hrc_t hrc2) +{ + return std::chrono::duration_cast(hrc1 - hrc2).count(); +} + +/// +/// Calculate the time difference of two HRC times. +/// +/// This function calls clock::hrc::now() and then subtracts the input +/// parameter from that timestamp value. +/// +/// HRC timestamp +/// Difference of the timestamps in milliseconds. +uint64_t hrc::diffNow(hrc::hrc_t then) +{ + return (uint64_t)std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - then).count(); +} + +/// +/// Calculate the time difference of two HRC times. +/// +/// This function calls clock::hrc::now() and then subtracts the input +/// parameter from that timestamp value. +/// +/// HRC timestamp +/// Difference of the timestamps in microseconds. +uint64_t hrc::diffNowUS(hrc::hrc_t& then) +{ + return (uint64_t)std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - then).count(); +} + +/// +/// +/// +/// +/// +uint64_t msToJiffies(uint64_t ms) +{ + return (uint64_t)(((double)ms/1000)* 65536); +} + +/// +/// +/// +/// +/// +uint64_t jiffiesToMs(uint64_t jiffies) +{ + return (uint64_t)(((double)jiffies / 65536) * 1000); +} + +#ifdef _WIN32 +/// +/// +/// +/// +/// +/// +int gettimeofday(struct timeval* tp, struct timezone* tzp) +{ + if (tzp != nullptr) { + // LOG_ERROR("Timezone not supported"); + return -1; + } + + // https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows + + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t epoch = ((uint64_t) 116444736000000000ULL); + + // TODO: Why do we have two epochs defined? + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - epoch) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; +} +#endif \ No newline at end of file diff --git a/src/Clock.h b/src/Clock.h new file mode 100644 index 00000000..2c709c2f --- /dev/null +++ b/src/Clock.h @@ -0,0 +1,77 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2023 Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#if !defined(__CLOCK_H__) +#define __CLOCK_H__ + +#include "Defines.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include + +namespace system_clock +{ + /* + ** Network Time Protocol + */ + namespace ntp + { + /// Get current time in NTP units. + uint64_t now(); + /// Calculate the time difference of two NTP times. + uint64_t diff(uint64_t ntp1, uint64_t ntp2); + /// Calculate the time difference of two NTP times. + uint64_t diffNow(uint64_t then); + } // namespace ntp + + /* + ** High-Resolution Clock + */ + namespace hrc + { + typedef std::chrono::high_resolution_clock::time_point hrc_t; + + /// Get current time in HRC units. + hrc_t now(); + /// Calculate the time difference of two HRC times. + uint64_t diff(hrc_t hrc1, hrc_t hrc2); + /// Calculate the time difference of two HRC times. + uint64_t diffNow(hrc_t then); + /// Calculate the time difference of two HRC times. + uint64_t diffNowUS(hrc_t& then); + } // namespace hrc + + /// + uint64_t msToJiffies(uint64_t ms); + /// + uint64_t jiffiesToMs(uint64_t jiffies); + +#ifdef _WIN32 + /// + int gettimeofday(struct timeval *tp, struct timezone *tzp); +#endif +} // namespace system_clock + +#endif // __CLOCK_H__ \ No newline at end of file