/* 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 . */ #include #include #include #include #include #include #include "PcDebug.h" #include "TimestampDecoder.h" #include "Eti.h" #include "Log.h" //#define MDEBUG(fmt, args...) fprintf (LOG, "*****" fmt , ## args) #define MDEBUG(fmt, args...) PDEBUG(fmt, ## args) void TimestampDecoder::calculateTimestamp(struct frame_timestamp& ts) { struct frame_timestamp* ts_queued = new struct frame_timestamp; /* Push new timestamp into queue */ ts_queued->timestamp_valid = full_timestamp_received_mnsc; ts_queued->timestamp_sec = time_secs; ts_queued->timestamp_pps_offset = time_pps; ts_queued->fct = latestFCT; ts_queued->timestamp_refresh = offset_changed; offset_changed = false; MDEBUG("time_secs=%d, time_pps=%f\n", time_secs, time_pps); *ts_queued += timestamp_offset; queue_timestamps.push(ts_queued); /* Here, the queue size is one more than the pipeline delay, because * we've just added a new element in the queue. * * Therefore, use <= and not < for comparison */ if (queue_timestamps.size() <= modconfig.delay_calculation_pipeline_stages) { //fprintf(stderr, "* %zu %u ", queue_timestamps.size(), modconfig.delay_calculation_pipeline_stages); /* Return invalid timestamp until the queue is full */ ts.timestamp_valid = false; ts.timestamp_sec = 0; ts.timestamp_pps_offset = 0; ts.timestamp_refresh = false; ts.fct = -1; } else { //fprintf(stderr, ". %zu ", queue_timestamps.size()); /* Return timestamp from queue */ ts_queued = queue_timestamps.front(); queue_timestamps.pop(); /*fprintf(stderr, "ts_queued v:%d, sec:%d, pps:%f, ref:%d\n", ts_queued->timestamp_valid, ts_queued->timestamp_sec, ts_queued->timestamp_pps_offset, ts_queued->timestamp_refresh);*/ ts = *ts_queued; /*fprintf(stderr, "ts v:%d, sec:%d, pps:%f, ref:%d\n\n", ts.timestamp_valid, ts.timestamp_sec, ts.timestamp_pps_offset, ts.timestamp_refresh);*/ delete ts_queued; } MDEBUG("Timestamp queue size %zu, delay_calc %u\n", queue_timestamps.size(), modconfig.delay_calculation_pipeline_stages); if (queue_timestamps.size() > modconfig.delay_calculation_pipeline_stages) { etiLog.level(error) << "Error: Timestamp queue is too large : size " << queue_timestamps.size() << "! This should not happen !"; } //ts.print("calc2 "); } void TimestampDecoder::pushMNSCData(int framephase, uint16_t mnsc) { struct eti_MNSC_TIME_0 *mnsc0; struct eti_MNSC_TIME_1 *mnsc1; struct eti_MNSC_TIME_2 *mnsc2; struct eti_MNSC_TIME_3 *mnsc3; switch (framephase) { case 0: mnsc0 = (struct eti_MNSC_TIME_0*)&mnsc; enableDecode = (mnsc0->type == 0) && (mnsc0->identifier == 0); gmtime_r(0, &temp_time); break; case 1: mnsc1 = (struct eti_MNSC_TIME_1*)&mnsc; temp_time.tm_sec = mnsc1->second_tens * 10 + mnsc1->second_unit; temp_time.tm_min = mnsc1->minute_tens * 10 + mnsc1->minute_unit; if (!mnsc1->sync_to_frame) { enableDecode = false; PDEBUG("TimestampDecoder: MNSC time info is not synchronised to frame\n"); } break; case 2: mnsc2 = (struct eti_MNSC_TIME_2*)&mnsc; temp_time.tm_hour = mnsc2->hour_tens * 10 + mnsc2->hour_unit; temp_time.tm_mday = mnsc2->day_tens * 10 + mnsc2->day_unit; break; case 3: mnsc3 = (struct eti_MNSC_TIME_3*)&mnsc; temp_time.tm_mon = (mnsc3->month_tens * 10 + mnsc3->month_unit) - 1; temp_time.tm_year = (mnsc3->year_tens * 10 + mnsc3->year_unit) + 100; if (enableDecode) { full_timestamp_received_mnsc = true; updateTimestampSeconds(mktime(&temp_time)); } break; } MDEBUG("TimestampDecoder::pushMNSCData(%d, 0x%x)\n", framephase, mnsc); MDEBUG(" -> %s\n", asctime(&temp_time)); MDEBUG(" -> %zu\n", mktime(&temp_time)); } void TimestampDecoder::updateTimestampSeconds(uint32_t secs) { if (inhibit_second_update > 0) { MDEBUG("TimestampDecoder::updateTimestampSeconds(%d) inhibit\n", secs); inhibit_second_update--; } else { MDEBUG("TimestampDecoder::updateTimestampSeconds(%d) apply\n", secs); time_secs = secs; } } void TimestampDecoder::updateTimestampPPS(double pps) { MDEBUG("TimestampDecoder::updateTimestampPPS(%f)\n", pps); if (time_pps > pps) // Second boundary crossed { MDEBUG("TimestampDecoder::updateTimestampPPS crossed second\n"); // The second for the next eight frames will not // be defined by the MNSC inhibit_second_update = 2; time_secs += 1; } time_pps = pps; } void TimestampDecoder::updateTimestampEti( int framephase, uint16_t mnsc, double pps, int32_t fct) { updateTimestampPPS(pps); pushMNSCData(framephase, mnsc); latestFCT = fct; } bool TimestampDecoder::updateModulatorOffset() { using namespace std; using boost::lexical_cast; using boost::bad_lexical_cast; if (modconfig.use_offset_fixed) { timestamp_offset = modconfig.offset_fixed; return true; } else if (modconfig.use_offset_file) { bool r = false; double newoffset; std::string filedata; ifstream filestream; try { filestream.open(modconfig.offset_filename.c_str()); if (!filestream.eof()) { getline(filestream, filedata); try { newoffset = lexical_cast(filedata); r = true; } catch (bad_lexical_cast& e) { etiLog.level(error) << "Error parsing timestamp offset from file '" << modconfig.offset_filename << "'"; r = false; } } else { etiLog.level(error) << "Error reading from timestamp offset file: eof reached\n"; r = false; } filestream.close(); } catch (exception& e) { etiLog.level(error) << "Error opening timestamp offset file\n"; r = false; } if (r) { if (timestamp_offset != newoffset) { timestamp_offset = newoffset; etiLog.level(info) << "TimestampDecoder::updateTimestampOffset: new offset is " << timestamp_offset; offset_changed = true; } } return r; } else { return false; } }