/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
Includes modifications for which no copyright is claimed
2012, Matthias P. Braendli, matthias.braendli@mpb.li
*/
/*
This file is part of CRC-DADMOD.
CRC-DADMOD 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.
CRC-DADMOD 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 CRC-DADMOD. If not, see .
*/
#include "EtiReader.h"
#include "Log.h"
#include "PcDebug.h"
#include "TimestampDecoder.h"
#include
#include
#include
#include
enum ETI_READER_STATE {
EtiReaderStateNbFrame,
EtiReaderStateFrameSize,
EtiReaderStateSync,
EtiReaderStateFc,
EtiReaderStateNst,
EtiReaderStateEoh,
EtiReaderStateFic,
EtiReaderStateSubch,
EtiReaderStateEof,
EtiReaderStateTist,
EtiReaderStatePad
};
EtiReader::EtiReader(struct modulator_offset_config& modconf,
Logger& logger) :
myLogger(logger),
state(EtiReaderStateSync),
myFicSource(NULL)
{
PDEBUG("EtiReader::EtiReader()\n");
myCurrentFrame = 0;
myTimestampDecoder = new TimestampDecoder(modconf, myLogger);
}
EtiReader::~EtiReader()
{
PDEBUG("EtiReader::~EtiReader()\n");
// if (myFicSource != NULL) {
// delete myFicSource;
// }
// for (unsigned i = 0; i < mySources.size(); ++i) {
// delete mySources[i];
// }
}
FicSource* EtiReader::getFic()
{
return myFicSource;
}
unsigned EtiReader::getMode()
{
return eti_fc.MID;
}
unsigned EtiReader::getFp()
{
return eti_fc.FP;
}
const std::vector& EtiReader::getSubchannels()
{
return mySources;
}
int EtiReader::process(Buffer* dataIn)
{
PDEBUG("EtiReader::process(dataIn: %p)\n", dataIn);
PDEBUG(" state: %u\n", state);
const unsigned char* in = reinterpret_cast(dataIn->getData());
size_t input_size = dataIn->getLength();
while (input_size > 0) {
switch (state) {
case EtiReaderStateNbFrame:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
nb_frames = *(uint32_t*)in;
input_size -= 4;
in += 4;
state = EtiReaderStateFrameSize;
PDEBUG("Nb frames: %i\n", nb_frames);
break;
case EtiReaderStateFrameSize:
if (input_size < 2) {
return dataIn->getLength() - input_size;
}
framesize = *(uint16_t*)in;
input_size -= 2;
in += 2;
state = EtiReaderStateSync;
PDEBUG("Framesize: %i\n", framesize);
break;
case EtiReaderStateSync:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
framesize = 6144;
memcpy(&eti_sync, in, 4);
input_size -= 4;
framesize -= 4;
in += 4;
state = EtiReaderStateFc;
PDEBUG("Sync.err: 0x%.2x\n", eti_sync.ERR);
PDEBUG("Sync.fsync: 0x%.6x\n", eti_sync.FSYNC);
break;
case EtiReaderStateFc:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
memcpy(&eti_fc, in, 4);
input_size -= 4;
framesize -= 4;
in += 4;
state = EtiReaderStateNst;
PDEBUG("Fc.fct: 0x%.2x\n", eti_fc.FCT);
PDEBUG("Fc.ficf: %u\n", eti_fc.FICF);
PDEBUG("Fc.nst: %u\n", eti_fc.NST);
PDEBUG("Fc.fp: 0x%x\n", eti_fc.FP);
PDEBUG("Fc.mid: %u\n", eti_fc.MID);
PDEBUG("Fc.fl: %u\n", eti_fc.getFrameLength());
if (!eti_fc.FICF) {
throw std::runtime_error("FIC must be present to modulate!");
}
if (myFicSource == NULL) {
myFicSource = new FicSource(eti_fc);
}
break;
case EtiReaderStateNst:
if (input_size < 4 * (size_t)eti_fc.NST) {
return dataIn->getLength() - input_size;
}
if ((eti_stc.size() != eti_fc.NST) ||
(memcmp(&eti_stc[0], in, 4 * eti_fc.NST))) {
PDEBUG("New stc!\n");
eti_stc.resize(eti_fc.NST);
for (unsigned i = 0; i < mySources.size(); ++i) {
delete mySources[i];
}
mySources.resize(eti_fc.NST);
memcpy(&eti_stc[0], in, 4 * eti_fc.NST);
for (unsigned i = 0; i < eti_fc.NST; ++i) {
mySources[i] = new SubchannelSource(eti_stc[i]);
PDEBUG("Sstc %u:\n", i);
PDEBUG(" Stc%i.scid: %i\n", i, eti_stc[i].SCID);
PDEBUG(" Stc%i.sad: %u\n", i, eti_stc[i].getStartAddress());
PDEBUG(" Stc%i.tpl: 0x%.2x\n", i, eti_stc[i].TPL);
PDEBUG(" Stc%i.stl: %u\n", i, eti_stc[i].getSTL());
}
}
input_size -= 4 * eti_fc.NST;
framesize -= 4 * eti_fc.NST;
in += 4 * eti_fc.NST;
state = EtiReaderStateEoh;
break;
case EtiReaderStateEoh:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
memcpy(&eti_eoh, in, 4);
input_size -= 4;
framesize -= 4;
in += 4;
state = EtiReaderStateFic;
PDEBUG("Eoh.mnsc: 0x%.4x\n", eti_eoh.MNSC);
PDEBUG("Eoh.crc: 0x%.4x\n", eti_eoh.CRC);
break;
case EtiReaderStateFic:
if (eti_fc.MID == 3) {
if (input_size < 128) {
return dataIn->getLength() - input_size;
}
PDEBUG("Writting 128 bytes of FIC channel data\n");
Buffer fic = Buffer(128, in);
myFicSource->process(&fic, NULL);
input_size -= 128;
framesize -= 128;
in += 128;
} else {
if (input_size < 96) {
return dataIn->getLength() - input_size;
}
PDEBUG("Writting 96 bytes of FIC channel data\n");
Buffer fic = Buffer(96, in);
myFicSource->process(&fic, NULL);
input_size -= 96;
framesize -= 96;
in += 96;
}
state = EtiReaderStateSubch;
break;
case EtiReaderStateSubch:
for (size_t i = 0; i < eti_stc.size(); ++i) {
unsigned size = mySources[i]->framesize();
PDEBUG("Writting %i bytes of subchannel data\n", size);
Buffer subch = Buffer(size, in);
mySources[i]->process(&subch, NULL);
input_size -= size;
framesize -= size;
in += size;
}
state = EtiReaderStateEof;
break;
case EtiReaderStateEof:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
memcpy(&eti_eof, in, 4);
input_size -= 4;
framesize -= 4;
in += 4;
state = EtiReaderStateTist;
PDEBUG("Eof.crc: %#.4x\n", eti_eof.CRC);
PDEBUG("Eof.rfu: %#.4x\n", eti_eof.RFU);
break;
case EtiReaderStateTist:
if (input_size < 4) {
return dataIn->getLength() - input_size;
}
memcpy(&eti_tist, in, 4);
input_size -= 4;
framesize -= 4;
in += 4;
state = EtiReaderStatePad;
PDEBUG("Tist: 0x%.6x\n", eti_tist.TIST);
break;
case EtiReaderStatePad:
if (framesize > 0) {
--input_size;
--framesize;
++in;
} else {
state = EtiReaderStateSync;
}
break;
default:
// throw std::runtime_error("Invalid state!");
PDEBUG("Invalid state (%i)!", state);
input_size = 0;
}
}
// Update timestamps
myTimestampDecoder->updateTimestampEti(eti_fc.FP & 0x3,
eti_eoh.MNSC,
getPPSOffset());
if (getFCT() % 125 == 0) //every 3 seconds is fine enough
{
myTimestampDecoder->updateModulatorOffset();
}
return dataIn->getLength() - input_size;
}
bool EtiReader::sourceContainsTimestamp()
{
return (ntohl(eti_tist.TIST) & 0xFFFFFF) != 0xFFFFFF;
/* See ETS 300 799, Annex C.2.2 */
}
double EtiReader::getPPSOffset()
{
if (!sourceContainsTimestamp())
return 0.0;
uint32_t timestamp = ntohl(eti_tist.TIST) & 0xFFFFFF;
//fprintf(stderr, "TIST 0x%x\n", timestamp);
double pps = timestamp / 16384000.0; // seconds
return pps;
}
uint32_t EtiReader::getFCT()
{
return eti_fc.FCT;
}