diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/DabModulator.cpp | 4 | ||||
-rw-r--r-- | src/SignalMultiplexer.cpp | 14 | ||||
-rw-r--r-- | src/TII.cpp | 297 | ||||
-rw-r--r-- | src/TII.h | 72 |
5 files changed, 386 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index 5c7c60b..5f73f3b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,6 +165,8 @@ odr_dabmod_SOURCES = src/DabMod.cpp \ src/FormatConverter.h \ src/Utils.cpp \ src/Utils.h \ + src/TII.cpp \ + src/TII.h \ src/zmq.hpp dist_bin_SCRIPTS = src/crc-dwap.py diff --git a/src/DabModulator.cpp b/src/DabModulator.cpp index 667d885..94b6c87 100644 --- a/src/DabModulator.cpp +++ b/src/DabModulator.cpp @@ -46,6 +46,7 @@ #include "Resampler.h" #include "ConvEncoder.h" #include "FIRFilter.h" +#include "TII.h" #include "PuncturingEncoder.h" #include "TimeInterleaver.h" #include "TimestampDecoder.h" @@ -197,6 +198,8 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) cic_ratio)); + shared_ptr<TII> tii(new TII(myDabMode, 3, 16)); + shared_ptr<OfdmGenerator> cifOfdm( new OfdmGenerator((1 + myNbSymbols), myNbCarriers, mySpacing)); @@ -346,6 +349,7 @@ int DabModulator::process(Buffer* const dataIn, Buffer* dataOut) myFlowgraph->connect(cifFreq, cifDiff); myFlowgraph->connect(cifNull, cifSig); myFlowgraph->connect(cifDiff, cifSig); + myFlowgraph->connect(tii, cifSig); if (useCicEq) { myFlowgraph->connect(cifSig, cifCicEq); myFlowgraph->connect(cifCicEq, cifOfdm); diff --git a/src/SignalMultiplexer.cpp b/src/SignalMultiplexer.cpp index c5be552..8edcdc2 100644 --- a/src/SignalMultiplexer.cpp +++ b/src/SignalMultiplexer.cpp @@ -46,6 +46,7 @@ SignalMultiplexer::~SignalMultiplexer() // dataIn[0] -> null symbol // dataIn[1] -> MSC symbols +// dataIn[2] -> (optional) TII symbol int SignalMultiplexer::process(std::vector<Buffer*> dataIn, Buffer* dataOut) { #ifdef DEBUG @@ -60,10 +61,17 @@ int SignalMultiplexer::process(std::vector<Buffer*> dataIn, Buffer* dataOut) fprintf(stderr, ", dataOut: %p, sizeOut: %zu)\n", dataOut, dataOut->getLength()); #endif - assert(dataIn.size() == 2); + assert(dataIn.size() == 2 or dataIn.size() == 3); - *dataOut = *dataIn[0]; - *dataOut += *dataIn[1]; + if (dataIn.size() == 2) { + *dataOut = *dataIn[0]; + *dataOut += *dataIn[1]; + } + else if (dataIn.size() == 3) { + *dataOut = *dataIn[2]; + *dataOut += *dataIn[1]; + } return dataOut->getLength(); } + diff --git a/src/TII.cpp b/src/TII.cpp new file mode 100644 index 0000000..9ccc6e0 --- /dev/null +++ b/src/TII.cpp @@ -0,0 +1,297 @@ +/* + 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 <http://www.gnu.org/licenses/>. + */ + +#include "TII.h" +#include "PcDebug.h" + +#include <stdio.h> +#include <stdexcept> +#include <string.h> + +typedef std::complex<float> 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) { + fprintf(stderr, "k = %d\n", k); + + int ix = m_carriers/2 + k; + + if (ix < 0 or ix > (ssize_t)m_dataIn.size()) { + throw std::runtime_error( + "TII::enable_carrier invalid k!"); + } + + m_dataIn[ix] = 1.0; // TODO power of the carrier ? +} + +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); + enable_carrier(k+1); + } + } + } + + 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); + enable_carrier(k+1); + } + } + } + + 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); + enable_carrier(k+1); + } + } + } + + 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); + enable_carrier(k+1); + } + } + } + } + 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); + enable_carrier(k+1); + } + } + + 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); + enable_carrier(k+1); + } + } + } + } + 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 + diff --git a/src/TII.h b/src/TII.h new file mode 100644 index 0000000..44f37ce --- /dev/null +++ b/src/TII.h @@ -0,0 +1,72 @@ +/* + 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef TII_H +#define TII_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ModCodec.h" + +#include <sys/types.h> +#include <complex> +#include <vector> +#include <string> + +class TII : public ModCodec +{ + public: + TII(unsigned int dabmode, unsigned int comb, unsigned int pattern); + virtual ~TII(); + + int process(Buffer* const dataIn, Buffer* dataOut); + const char* name() { return m_name.c_str(); }; + + protected: + unsigned int m_dabmode; + unsigned int m_comb; + unsigned int m_pattern; + + bool m_insert; + + size_t m_carriers; + + std::string m_name; + std::vector<std::complex<float> > m_dataIn; + + void prepare_pattern(void); + + void enable_carrier(int k); + + private: + TII(const TII&); + TII& operator=(const TII&); +}; + +#endif // TII_H + |