/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) Copyright (C) 2022 Matthias P. Braendli, matthias.braendli@mpb.li http://opendigitalradio.org */ /* This file is part of ODR-DabMod. ODR-DabMod 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-DabMod 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-DabMod. If not, see . */ #pragma once #include #include #include #include #include #include "RemoteControl.h" struct frame_timestamp { // Which frame count does this timestamp apply to int32_t fct; uint8_t fp; // Frame Phase uint32_t timestamp_sec; // seconds in unix epoch uint32_t timestamp_pps; // In units of 1/16384000 s bool timestamp_valid = false; bool offset_changed = false; frame_timestamp& operator+=(const double& diff); const frame_timestamp operator+(const double diff) const { frame_timestamp ts = *this; ts += diff; return ts; } double pps_offset() const { return timestamp_pps / 16384000.0; } double offset_to_system_time() const; double get_real_secs() const { double t = timestamp_sec; t += pps_offset(); return t; } long long int get_ns() const { long long int ns = timestamp_sec * 1000000000ull; ns += llrint((double)timestamp_pps / 0.016384); return ns; } void set_ns(long long int time_ns) { timestamp_sec = time_ns / 1000000000ull; const long long int subsecond = time_ns % 1000000000ull; timestamp_pps = lrint(subsecond * 16384000.0); } std::string to_string() const; void print(const char* t) const { etiLog.log(debug, "%s \n", t, this->timestamp_valid ? "valid" : "invalid", this->timestamp_sec, pps_offset(), this->fct); } }; /* This module decodes MNSC time information from an ETI source and * EDI time information*/ class TimestampDecoder : public RemoteControllable { public: /* offset_s: The modulator adds this offset to the TIST to define time of * frame transmission */ TimestampDecoder(double& offset_s); frame_timestamp getTimestamp(void); /* Update timestamp data from ETI */ void updateTimestampEti( uint8_t framephase, uint16_t mnsc, uint32_t pps, // In units of 1/16384000 s int32_t fct); /* Update timestamp data from EDI */ void updateTimestampEdi( uint32_t seconds_utc, uint32_t pps, // In units of 1/16384000 s int32_t fct, uint8_t framephase); /*********** REMOTE CONTROL ***************/ /* Base function to set parameters. */ 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; const char* name() { return "TS"; } protected: /* Push a new MNSC field into the decoder */ void pushMNSCData(uint8_t framephase, uint16_t mnsc); /* Each frame contains the TIST field with the PPS offset. * For each frame, this function must be called to update * the timestamp. * * pps is in units of 1/16384000 s * * This function also takes care of updating the second when * the pps rolls over. */ void updateTimestampPPS(uint32_t pps); /* Update the timestamp when a full set of MNSC data is * known. This function can be called at most every four * frames when the data is transferred using the MNSC. */ void updateTimestampSeconds(uint32_t secs); struct tm temp_time; uint32_t time_secs = 0; int32_t latestFCT = 0; uint32_t latestFP = 0; uint32_t time_pps = 0; double& timestamp_offset; int inhibit_second_update = 0; bool offset_changed = false; uint32_t time_secs_of_frame0 = 0; uint32_t time_pps_of_frame0 = 0; /* When the type or identifier don't match, the decoder must * be disabled */ bool enableDecode = false; /* Disable timstamps until full time has been received */ bool full_timestamp_received = false; };