/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) Copyright (C) 2014 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 . */ #ifndef TIMESTAMP_DECODER_H #define TIMESTAMP_DECODER_H #include #include #include #include #include #include "Eti.h" #include "Log.h" struct modulator_offset_config { bool use_offset_fixed; double offset_fixed; /* These two fields are used when the modulator is run with a fixed offset */ bool use_offset_file; std::string offset_filename; /* These two fields are used when the modulator reads the offset from a file */ unsigned delay_calculation_pipeline_stages; /* Specifies by how many stages the timestamp must be delayed. * (e.g. The FIRFilter is pipelined, therefore we must increase * delay_calculation_pipeline_stages by one if the filter is used */ }; struct frame_timestamp { // Which frame count does this timestamp apply to uint32_t fct; uint32_t timestamp_sec; double timestamp_pps_offset; bool timestamp_valid; bool timestamp_refresh; struct frame_timestamp operator=(const struct frame_timestamp &rhs) { if (this != &rhs) { this->timestamp_sec = rhs.timestamp_sec; this->timestamp_pps_offset = rhs.timestamp_pps_offset; this->timestamp_valid = rhs.timestamp_valid; this->timestamp_refresh = rhs.timestamp_refresh; this->fct = rhs.fct; } return *this; } struct 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_offset += offset_pps; while (this->timestamp_pps_offset > 1) { this->timestamp_pps_offset -= 1.0; this->timestamp_sec += 1; }; return *this; } const struct frame_timestamp operator+(const double diff) { struct frame_timestamp ts = *this; ts += diff; return ts; } void print(const char* t) { fprintf(stderr, "%s \n", t, this->timestamp_valid ? "valid" : "invalid", this->timestamp_sec, this->timestamp_pps_offset); } }; /* This module decodes MNSC time information */ class TimestampDecoder { public: TimestampDecoder( struct modulator_offset_config& config, Logger& logger): myLogger(logger), modconfig(config) { inhibit_second_update = 0; time_pps = 0.0; time_secs = 0; latestFCT = 0; enableDecode = false; full_timestamp_received_mnsc = false; gmtime_r(0, &temp_time); offset_changed = false; myLogger.level(info) << "Setting up timestamp decoder with " << (modconfig.use_offset_fixed ? "fixed" : (modconfig.use_offset_file ? "dynamic" : "none")) << " offset"; }; /* Calculate the timestamp for the current frame. */ void calculateTimestamp(struct frame_timestamp& ts); /* Update timestamp data from data in ETI */ void updateTimestampEti( int framephase, uint16_t mnsc, double pps, uint32_t fct); /* Update the modulator timestamp offset according to the modconf */ bool updateModulatorOffset(); protected: /* Main program logger */ Logger& myLogger; /* Push a new MNSC field into the decoder */ void pushMNSCData(int 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 */ void updateTimestampPPS(double 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; uint32_t latestFCT; double time_pps; double timestamp_offset; int inhibit_second_update; bool offset_changed; /* configuration for the offset management */ struct modulator_offset_config& modconfig; /* When the type or identifier don't match, the decoder must * be disabled */ bool enableDecode; /* Disable timstamps until full time has been received in mnsc */ bool full_timestamp_received_mnsc; /* when pipelining, we must shift the calculated timestamps * through this queue. Otherwise, it would not be possible to * synchronise two modulators if only one uses (for instance) the * FIRFilter (1 stage pipeline) */ std::queue queue_timestamps; }; #endif