/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 2017
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;
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;
}
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
*
* tist_delay_stages: Specifies by how many stages the timestamp must
* be delayed. (e.g. The FIRFilter is pipelined, therefore we must
* increase tist_delay_stages by one if the filter is used
*/
TimestampDecoder(double& offset_s, unsigned tist_delay_stages);
/* Calculate the timestamp for the current frame. */
void calculateTimestamp(frame_timestamp& ts);
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;
unsigned m_tist_delay_stages;
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;
/* 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;
};