/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Her Majesty
the Queen in Right of Canada (Communications Research Center Canada)
Copyright (C) 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 "TII.h"
#include "PcDebug.h"
#include
#include
#include
typedef std::complex complexf;
/* TII pattern for TM I, II, IV */
const int pattern_tm1_2_4[][8] = { // {{{
{0,0,0,0,1,1,1,1},
{0,0,0,1,0,1,1,1},
{0,0,0,1,1,0,1,1},
{0,0,0,1,1,1,0,1},
{0,0,0,1,1,1,1,0},
{0,0,1,0,0,1,1,1},
{0,0,1,0,1,0,1,1},
{0,0,1,0,1,1,0,1},
{0,0,1,0,1,1,1,0},
{0,0,1,1,0,0,1,1},
{0,0,1,1,0,1,0,1},
{0,0,1,1,0,1,1,0},
{0,0,1,1,1,0,0,1},
{0,0,1,1,1,0,1,0},
{0,0,1,1,1,1,0,0},
{0,1,0,0,0,1,1,1},
{0,1,0,0,1,0,1,1},
{0,1,0,0,1,1,0,1},
{0,1,0,0,1,1,1,0},
{0,1,0,1,0,0,1,1},
{0,1,0,1,0,1,0,1},
{0,1,0,1,0,1,1,0},
{0,1,0,1,1,0,0,1},
{0,1,0,1,1,0,1,0},
{0,1,0,1,1,1,0,0},
{0,1,1,0,0,0,1,1},
{0,1,1,0,0,1,0,1},
{0,1,1,0,0,1,1,0},
{0,1,1,0,1,0,0,1},
{0,1,1,0,1,0,1,0},
{0,1,1,0,1,1,0,0},
{0,1,1,1,0,0,0,1},
{0,1,1,1,0,0,1,0},
{0,1,1,1,0,1,0,0},
{0,1,1,1,1,0,0,0},
{1,0,0,0,0,1,1,1},
{1,0,0,0,1,0,1,1},
{1,0,0,0,1,1,0,1},
{1,0,0,0,1,1,1,0},
{1,0,0,1,0,0,1,1},
{1,0,0,1,0,1,0,1},
{1,0,0,1,0,1,1,0},
{1,0,0,1,1,0,0,1},
{1,0,0,1,1,0,1,0},
{1,0,0,1,1,1,0,0},
{1,0,1,0,0,0,1,1},
{1,0,1,0,0,1,0,1},
{1,0,1,0,0,1,1,0},
{1,0,1,0,1,0,0,1},
{1,0,1,0,1,0,1,0},
{1,0,1,0,1,1,0,0},
{1,0,1,1,0,0,0,1},
{1,0,1,1,0,0,1,0},
{1,0,1,1,0,1,0,0},
{1,0,1,1,1,0,0,0},
{1,1,0,0,0,0,1,1},
{1,1,0,0,0,1,0,1},
{1,1,0,0,0,1,1,0},
{1,1,0,0,1,0,0,1},
{1,1,0,0,1,0,1,0},
{1,1,0,0,1,1,0,0},
{1,1,0,1,0,0,0,1},
{1,1,0,1,0,0,1,0},
{1,1,0,1,0,1,0,0},
{1,1,0,1,1,0,0,0},
{1,1,1,0,0,0,0,1},
{1,1,1,0,0,0,1,0},
{1,1,1,0,0,1,0,0},
{1,1,1,0,1,0,0,0},
{1,1,1,1,0,0,0,0} }; // }}}
TII::TII(unsigned int dabmode, unsigned int comb, unsigned int pattern) :
ModCodec(ModFormat(0), ModFormat(0)),
m_dabmode(dabmode),
m_comb(comb),
m_pattern(pattern),
m_insert(true)
{
PDEBUG("TII::TII(%u) @ %p\n", dabmode, this);
std::stringstream ss;
ss << "TII(comb:" << m_comb << ", pattern:" << m_pattern << ")";
m_name = ss.str();
switch (m_dabmode) {
case 1:
m_carriers = 1536;
if (not(0 <= m_pattern and m_pattern <= 69) ) {
throw std::runtime_error(
"TII::TII pattern not valid!");
}
break;
case 2:
m_carriers = 384;
if (not(0 <= m_pattern and m_pattern <= 69) ) {
throw std::runtime_error(
"TII::TII pattern not valid!");
}
break;
/* unsupported
case 3:
m_carriers = 192;
break;
case 4:
d_dabmode = 0;
case 0:
*/
default:
std::stringstream ss_exception;
ss_exception <<
"TII::TII DAB mode " << m_dabmode << " not valid!";
throw std::runtime_error(ss_exception.str());
}
if (not(0 < m_comb and m_comb <= 23) ) {
throw std::runtime_error(
"TII::TII comb not valid!");
}
m_dataIn.clear();
m_dataIn.resize(m_carriers);
prepare_pattern();
myOutputFormat.size(m_carriers * sizeof(complexf));
}
TII::~TII()
{
PDEBUG("TII::~TII() @ %p\n", this);
}
int TII::process(Buffer* const dataIn, Buffer* dataOut)
{
PDEBUG("TII::process(dataIn: %p, dataOut: %p)\n",
dataIn, dataOut);
if ((dataIn != NULL) && (dataIn->getLength() != 0)) {
throw std::runtime_error(
"TII::process input size not valid!");
}
if (m_insert) {
dataOut->setData(&m_dataIn[0], m_carriers * sizeof(complexf));
}
else {
dataOut->setLength(m_carriers * sizeof(complexf));
bzero(dataOut->getData(), dataOut->getLength());
}
// TODO wrong! Must align with frames containing the right data
m_insert = not m_insert;
return 1;
}
void TII::enable_carrier(int k) {
int ix = m_carriers/2 + k;
if (ix < 0 or ix+1 >= (ssize_t)m_dataIn.size()) {
throw std::runtime_error(
"TII::enable_carrier invalid k!");
}
// TODO power of the carrier ?
m_dataIn.at(ix) = 1.0;
m_dataIn.at(ix+1) = 1.0; // TODO verify if +1 is really correct
}
void TII::prepare_pattern() {
int comb = m_comb; // Convert from unsigned to signed
// This could be written more efficiently, but since it is
// not performance-critial, it makes sense to write it
// in the same way as the specification in
// ETSI EN 300 401 Clause 14.8
if (m_dabmode == 1) {
for (int k = -768; k < -384; k++) {
for (int b = 0; b < 8; b++) {
if ( k == -768 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
}
for (int k = -384; k < -0; k++) {
for (int b = 0; b < 8; b++) {
if ( k == -384 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
}
for (int k = 1; k <= 384; k++) {
for (int b = 0; b < 8; b++) {
if ( k == 1 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
}
for (int k = 384; k <= 768; k++) {
for (int b = 0; b < 8; b++) {
if ( k == 385 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
}
}
else if (m_dabmode == 2) {
for (int k = -192; k <= 192; k++) {
for (int b = 0; b < 4; b++) {
if ( k == -192 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
for (int b = 4; b < 8; b++) {
if ( k == -191 + 2 * comb + 48 * b and
pattern_tm1_2_4[m_pattern][b]) {
enable_carrier(k);
}
}
}
}
else {
throw std::runtime_error(
"TII::TII DAB mode not valid!");
}
}
#ifdef TII_TEST
int main(int argc, char** argv)
{
const unsigned int mode = 2;
const unsigned int comb = 4;
const unsigned int pattern = 16;
TII tii(mode, comb, pattern);
return 0;
}
#endif