/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) Copyright (C) 2018 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 #include "Eti.h" #include "Log.h" #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; uint32_t timestamp_pps; // In units of 1/16384000 s bool timestamp_valid = false; bool timestamp_refresh; frame_timestamp() = default; frame_timestamp(const frame_timestamp& other) = default; frame_timestamp& operator=(const frame_timestamp &rhs) { if (this != &rhs) { this->timestamp_sec = rhs.timestamp_sec; this->timestamp_pps = rhs.timestamp_pps; this->timestamp_valid = rhs.timestamp_valid; this->timestamp_refresh = rhs.timestamp_refresh; this->fct = rhs.fct; this->fp = rhs.fp; } return *this; } frame_timestamp& operator+=(const double& diff) { double offset_pps, offset_secs; offset_pps = modf(diff, &offset_secs); this->timestamp_sec += lrintf(offset_secs); this->timestamp_pps += lrintf(offset_pps * 16384000.0); while (this->timestamp_pps >= 16384000) { this->timestamp_pps -= 16384000; this->timestamp_sec += 1; }; return *this; } const frame_timestamp operator+(const double diff) { frame_timestamp ts = *this; ts += diff; return ts; } double pps_offset() const { return timestamp_pps / 16384000.0; } double get_real_secs() const { double t = timestamp_sec; t += timestamp_pps; 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 print(const char* t) { fprintf(stderr, "%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); std::shared_ptr 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; /* 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; };