diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-01-08 11:49:26 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-01-10 20:32:49 +0100 |
commit | 70c5ba0867945bb097f466262ce03470b690518f (patch) | |
tree | c7b14e7e5debdad25778d18559d42f5306289e67 /src/ClockTAI.cpp | |
parent | 3bcda54518c4914c1b934d7d12b7219d1ee7d941 (diff) | |
download | dabmux-70c5ba0867945bb097f466262ce03470b690518f.tar.gz dabmux-70c5ba0867945bb097f466262ce03470b690518f.tar.bz2 dabmux-70c5ba0867945bb097f466262ce03470b690518f.zip |
Add TAI handling for EDI with TIST
Diffstat (limited to 'src/ClockTAI.cpp')
-rw-r--r-- | src/ClockTAI.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/ClockTAI.cpp b/src/ClockTAI.cpp new file mode 100644 index 0000000..1b2d4ef --- /dev/null +++ b/src/ClockTAI.cpp @@ -0,0 +1,220 @@ +/* + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Her Majesty the Queen in Right of Canada (Communications + Research Center Canada) + + Copyright (C) 2016 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://www.opendigitalradio.org + */ +/* + This file is part of ODR-DabMux. + + ODR-DabMux 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, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMux 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. + + You should have received a copy of the GNU General Public License + along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ClockTAI.h" + +#include <stdio.h> +#include <errno.h> +#include <sys/timex.h> +#include <curl/curl.h> +#include <string> +#include <iostream> +#include <algorithm> +#include <regex> + +/* Last line from bulletin, example: + 2015 JUL 1 =JD 2457204.5 TAI-UTC= 36.0 S + (MJD - 41317.) X 0.0 S + */ + +ClockTAI::ClockTAI() +{ + m_offset = 0; + m_bulletin_download_time.tv_nsec = 0; + m_bulletin_download_time.tv_sec = 0; +} + +int ClockTAI::get_offset() +{ + struct timespec time_now; + + int err = clock_gettime(CLOCK_REALTIME, &time_now); + if (err) { + throw std::runtime_error("ClockTAI::get_offset() clock_gettime failed"); + } + + if (time_now.tv_sec - m_bulletin_download_time.tv_sec > + 3600 * 24 * 31) { + // Refresh if it's older than one month. Leap seconds are + // announced several months in advance + + if (download_tai_utc_bulletin(tai_data_url1) == 0) { + m_offset = parse_tai_offset(); + } + else if (download_tai_utc_bulletin(tai_data_url2) == 0) { + m_offset = parse_tai_offset(); + } + } + + return m_offset; + + throw std::runtime_error("Could not fetch TAI-UTC offset"); +} + +#if SUPPORT_SETTING_CLOCK_TAI +int ClockTAI::update_local_tai_clock(int offset) +{ + struct timex timex_request; + timex_request.modes = ADJ_TAI; + timex_request.constant = offset; + + int err = adjtimex(&timex_request); + if (err == -1) { + perror("adjtimex"); + } + + printf("adjtimex: %d, tai %d\n", err, timex_request.tai); + + return err; +} +#endif + +int ClockTAI::parse_tai_offset() +{ + std::regex regex_offset("TAI-UTC= *([0-9.]+)"); + + int tai_utc_offset = 0; + + int linecount = 0; + + for (std::string line; std::getline(m_bulletin, line); ) { + linecount++; + auto words_begin = + std::sregex_token_iterator( + line.begin(), line.end(), regex_offset, 1); + auto words_end = std::sregex_token_iterator(); + + for (auto w = words_begin; w != words_end; ++w) { + std::string s(*w); + tai_utc_offset = std::atoi(s.c_str()); + } + + } + + if (linecount == 0) { + throw std::runtime_error("No data in TAI bulletin"); + } + + // With the current evolution of the offset, we're probably going + // to reach 500 long after DAB gets replaced by another standard. + if (tai_utc_offset < 0 or tai_utc_offset > 500) { + std::stringstream ss; + ss << "TAI offset " << tai_utc_offset << " out of range"; + throw std::range_error(ss.str()); + } + + return tai_utc_offset; +} + +size_t ClockTAI::fill_bulletin(char *ptr, size_t size, size_t nmemb) +{ + size_t len = size * nmemb; + for (size_t i = 0; i < len; i++) { + m_bulletin << ptr[i]; + } + return len; +} + +size_t ClockTAI::fill_bulletin_cb( + char *ptr, size_t size, size_t nmemb, void *ctx) +{ + return ((ClockTAI*)ctx)->fill_bulletin(ptr, size, nmemb); +} + +int ClockTAI::download_tai_utc_bulletin(const char* url) +{ + int r = 0; + + CURL *curl; + CURLcode res; + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url); + /* example.com is redirected, so we tell libcurl to follow redirection */ + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ClockTAI::fill_bulletin_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + r = 1; + } + else { + // Save the download time of the bulletin + int err = clock_gettime(CLOCK_REALTIME, &m_bulletin_download_time); + if (err) { + perror("REALTIME clock_gettime failed"); + r = 1; + } + } + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return r; +} + +#if 0 +// Example testing code +void debug_tai_clk() +{ + struct timespec rt_clk; + + int err = clock_gettime(CLOCK_REALTIME, &rt_clk); + if (err) { + perror("REALTIME clock_gettime failed"); + } + + struct timespec tai_clk; + + err = clock_gettime(CLOCK_TAI, &tai_clk); + if (err) { + perror("TAI clock_gettime failed"); + } + + printf("RT - TAI = %ld\n", rt_clk.tv_sec - tai_clk.tv_sec); + + + struct timex timex_request; + timex_request.modes = 0; // Do not set anything + + err = adjtimex(&timex_request); + if (err == -1) { + perror("adjtimex"); + } + + printf("adjtimex: %d, tai %d\n", err, timex_request.tai); +} +#endif + |