1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
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) 2018
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/>.
*/
/* The EDI output needs TAI clock, according to ETSI TS 102 693 Annex F
* "EDI Timestamps". This module can set the local CLOCK_TAI clock by
* setting the TAI-UTC offset using adjtimex.
*
* This functionality requires Linux 3.10 (30 Jun 2013) or newer.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <sstream>
#include <chrono>
#include <future>
#include <mutex>
#include "RemoteControl.h"
// EDI needs to know UTC-TAI, but doesn't need the CLOCK_TAI to be set.
// We can keep this code, maybe for future use
#define SUPPORT_SETTING_CLOCK_TAI 0
/* Loads, parses and represents TAI-UTC offset information from the IETF bulletin */
class ClockTAI : public RemoteControllable {
public:
ClockTAI();
// Fetch the bulletin from the IETF website and return the current
// TAI-UTC offset.
// Throws runtime_error on failure.
int get_offset(void);
#if SUPPORT_SETTING_CLOCK_TAI
// Update the local TAI clock according to the TAI-UTC offset
// return 0 on success
int update_local_tai_clock(int offset);
#endif
private:
class download_failed {};
// Either retrieve the bulletin from the cache or if necessarly
// download it, and calculate the TAI-UTC offset.
// Returns the offset or throws download_failed or a range_error
// if the offset is out of bounds.
int get_valid_offset(void);
// Download of new bulletin is done asynchronously
std::future<int> m_offset_future;
// Protect all data members, as RC functions are in another thread
mutable std::mutex m_data_mutex;
// The currently used TAI-UTC offset
int m_offset = 0;
int m_offset_valid = false;
mutable std::stringstream m_bulletin;
std::chrono::system_clock::time_point m_bulletin_download_time;
// Load bulletin into m_bulletin from the cache file
void load_bulletin_from_file(const char* cache_filename);
// Update the cache file with the current m_bulletin
void update_cache(const char* cache_filename);
// Verifies the expiration date in the m_bulletin. Returns
// true if the bulletin is valid.
bool bulletin_is_valid(void);
// In how much time will the bulletin expire?
// returns a value in seconds, or -1 if it is expired or invalid
int64_t bulletin_expiry_delay(void) const;
// Load bulletin into m_bulletin from the URL
void download_tai_utc_bulletin(const char* url);
// read TAI offset from m_bulletin in IETF format
int parse_ietf_bulletin(void);
// callback that receives data from cURL
size_t fill_bulletin(char *ptr, size_t size, size_t nmemb);
// static callback wrapper for cURL
static size_t fill_bulletin_cb(
char *ptr, size_t size, size_t nmemb, void *ctx);
/* Remote control */
virtual void set_parameter(const std::string& parameter,
const std::string& value);
/* Getting a parameter always returns a string. */
virtual const std::string get_parameter(const std::string& parameter) const;
};
|