/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 2014, 2015
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
#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)
{
boost::shared_ptr ts_queued =
boost::make_shared();
/* 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() <= m_tist_delay_stages) {
//fprintf(stderr, "* %zu %u ", queue_timestamps.size(), m_tist_delay_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);*/
}
MDEBUG("Timestamp queue size %zu, delay_calc %u\n",
queue_timestamps.size(),
m_tist_delay_stages);
if (queue_timestamps.size() > m_tist_delay_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;
}
void TimestampDecoder::set_parameter(
const std::string& parameter,
const std::string& value)
{
using namespace std;
stringstream ss(value);
ss.exceptions ( stringstream::failbit | stringstream::badbit );
if (parameter == "offset") {
ss >> timestamp_offset;
offset_changed = true;
}
else {
stringstream ss;
ss << "Parameter '" << parameter
<< "' is not exported by controllable " << get_rc_name();
throw ParameterError(ss.str());
}
}
const std::string TimestampDecoder::get_parameter(
const std::string& parameter) const
{
using namespace std;
stringstream ss;
if (parameter == "offset") {
ss << timestamp_offset;
}
else {
ss << "Parameter '" << parameter <<
"' is not exported by controllable " << get_rc_name();
throw ParameterError(ss.str());
}
return ss.str();
}