summaryrefslogtreecommitdiffstats
path: root/src/fig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fig')
-rw-r--r--src/fig/FIG.h96
-rw-r--r--src/fig/FIG0.cpp483
-rw-r--r--src/fig/FIG0.h121
-rw-r--r--src/fig/FIGCarousel.cpp199
-rw-r--r--src/fig/FIGCarousel.h73
5 files changed, 972 insertions, 0 deletions
diff --git a/src/fig/FIG.h b/src/fig/FIG.h
new file mode 100644
index 0000000..4e6c20f
--- /dev/null
+++ b/src/fig/FIG.h
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2015
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FIG_H_
+#define __FIG_H_
+
+#include <boost/shared_ptr.hpp>
+#include "MuxElements.h"
+
+class FIGRuntimeInformation {
+ public:
+ FIGRuntimeInformation(boost::shared_ptr<dabEnsemble> e) :
+ currentFrame(0),
+ ensemble(e),
+ factumAnalyzer(false) {}
+
+ unsigned long currentFrame;
+ boost::shared_ptr<dabEnsemble> ensemble;
+ bool factumAnalyzer;
+};
+
+// Recommended FIG rates according to ETSI TR 101 496-2 Table 3.6.1
+enum class FIG_rate {
+ FIG0_0, /* Special repetition rate for FIG0/0, EN 300 401 Clause 6.4
+ In any 96 ms period, the FIG 0/0 should be transmitted in a fixed time
+ position. In transmission mode I, this should be the first FIB (of the three)
+ associated with the first CIF (of the four) in the transmission frame (see
+ clause 5.1). In transmission modes II and III, this should be the first FIB of
+ every fourth transmission frame. In transmission mode IV, this should be the
+ first FIB (of the three) associated with the first CIF (of the two) in every
+ alternate transmission frame (see clause 5.1). */
+ A, // at least 10 times per second
+ B, // once per second
+ C, // once every 10 seconds
+ D, // less than once every 10 seconds
+ E, // all in two minutes
+};
+
+/* Helper function to calculate the deadline for the next transmission, in milliseconds */
+inline int rate_increment_ms(FIG_rate rate)
+{
+ switch (rate) {
+ case FIG_rate::FIG0_0: return 96; // Is a special case
+ case FIG_rate::A: return 100;
+ case FIG_rate::B: return 1000;
+ case FIG_rate::C: return 10000;
+ case FIG_rate::D: return 30000;
+ case FIG_rate::E: return 120000;
+ }
+ return 1000; //some default value, shouldn't be used
+}
+
+class IFIG
+{
+ public:
+ virtual size_t fill(uint8_t *buf, size_t max_size) = 0;
+
+ virtual FIG_rate repetition_rate(void) = 0;
+
+ virtual const int figtype(void) const = 0;
+ virtual const int figextension(void) const = 0;
+
+ virtual const std::string name(void) const
+ {
+ std::stringstream ss;
+ ss << figtype() << "/" << figextension();
+ return ss.str();
+ }
+
+};
+
+#endif // __FIG_H_
+
diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp
new file mode 100644
index 0000000..458116e
--- /dev/null
+++ b/src/fig/FIG0.cpp
@@ -0,0 +1,483 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2015
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ Implementation of FIG0
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fig/FIG0.h"
+#include "DabMultiplexer.h"
+
+#define PACKED __attribute__ ((packed))
+
+//=========== FIG 0/0 ===========
+
+size_t FIG0_0::fill(uint8_t *buf, size_t max_size)
+{
+ if (max_size < 6) {
+ return 0;
+ }
+
+ FIGtype0_0 *fig0_0;
+ fig0_0 = (FIGtype0_0 *)buf;
+
+ fig0_0->FIGtypeNumber = 0;
+ fig0_0->Length = 5;
+ fig0_0->CN = 0;
+ fig0_0->OE = 0;
+ fig0_0->PD = 0;
+ fig0_0->Extension = 0;
+
+ fig0_0->EId = htons(m_rti->ensemble->id);
+ fig0_0->Change = 0;
+ fig0_0->Al = 0;
+ fig0_0->CIFcnt_hight = (m_rti->currentFrame / 250) % 20;
+ fig0_0->CIFcnt_low = (m_rti->currentFrame % 250);
+
+ return 6;
+}
+
+
+//=========== FIG 0/1 ===========
+
+FIG0_1::FIG0_1(FIGRuntimeInformation *rti) :
+ m_rti(rti),
+ m_initialised(false)
+{
+}
+
+size_t FIG0_1::fill(uint8_t *buf, size_t max_size)
+{
+ size_t remaining = max_size;
+
+ if (not m_initialised) {
+ subchannelFIG0_1 = m_rti->ensemble->subchannels.end();
+ }
+
+ if (max_size < 6) {
+ return 0;
+ }
+
+ auto ensemble = m_rti->ensemble;
+
+ FIGtype0_1 *figtype0_1;
+ figtype0_1 = (FIGtype0_1*)buf;
+
+ figtype0_1->FIGtypeNumber = 0;
+ figtype0_1->Length = 1;
+ figtype0_1->CN = 0;
+ figtype0_1->OE = 0;
+ figtype0_1->PD = 0;
+ figtype0_1->Extension = 1;
+ buf += 2;
+ remaining -= 2;
+
+ // Rotate through the subchannels until there is no more
+ // space in the FIG0/1
+ if (subchannelFIG0_1 == ensemble->subchannels.end()) {
+ subchannelFIG0_1 = ensemble->subchannels.begin();
+ }
+
+ for (; subchannelFIG0_1 != ensemble->subchannels.end();
+ ++subchannelFIG0_1) {
+ dabProtection* protection = &(*subchannelFIG0_1)->protection;
+
+ if ( (protection->form == UEP && remaining < 3) ||
+ (protection->form == EEP && remaining < 4) ) {
+ break;
+ }
+
+ if (protection->form == UEP) {
+ FIG_01_SubChannel_ShortF *fig0_1subchShort =
+ (FIG_01_SubChannel_ShortF*)buf;
+ fig0_1subchShort->SubChId = (*subchannelFIG0_1)->id;
+
+ fig0_1subchShort->StartAdress_high =
+ (*subchannelFIG0_1)->startAddress / 256;
+ fig0_1subchShort->StartAdress_low =
+ (*subchannelFIG0_1)->startAddress % 256;
+
+ fig0_1subchShort->Short_Long_form = 0;
+ fig0_1subchShort->TableSwitch = 0;
+ fig0_1subchShort->TableIndex =
+ protection->uep.tableIndex;
+
+ buf += 3;
+ remaining -= 3;
+ figtype0_1->Length += 3;
+ }
+ else if (protection->form == EEP) {
+ FIG_01_SubChannel_LongF *fig0_1subchLong1 =
+ (FIG_01_SubChannel_LongF*)buf;
+ fig0_1subchLong1->SubChId = (*subchannelFIG0_1)->id;
+
+ fig0_1subchLong1->StartAdress_high =
+ (*subchannelFIG0_1)->startAddress / 256;
+ fig0_1subchLong1->StartAdress_low =
+ (*subchannelFIG0_1)->startAddress % 256;
+
+ fig0_1subchLong1->Short_Long_form = 1;
+ fig0_1subchLong1->Option = protection->eep.GetOption();
+ fig0_1subchLong1->ProtectionLevel =
+ protection->level;
+
+ fig0_1subchLong1->Sub_ChannelSize_high =
+ getSizeCu(*subchannelFIG0_1) / 256;
+ fig0_1subchLong1->Sub_ChannelSize_low =
+ getSizeCu(*subchannelFIG0_1) % 256;
+
+ buf += 4;
+ remaining -= 4;
+ figtype0_1->Length += 4;
+ }
+ }
+
+ return max_size - remaining;
+}
+
+
+//=========== FIG 0/2 ===========
+
+FIG0_2::FIG0_2(FIGRuntimeInformation *rti) :
+ m_rti(rti),
+ m_initialised(false)
+{
+}
+
+size_t FIG0_2::fill(uint8_t *buf, size_t max_size)
+{
+ FIGtype0_2 *fig0_2 = NULL;
+ int cur = 0;
+ ssize_t remaining = max_size;
+
+ if (not m_initialised) {
+ serviceFIG0_2 = m_rti->ensemble->services.end();
+ }
+
+ auto ensemble = m_rti->ensemble;
+
+ // Rotate through the subchannels until there is no more
+ // space
+ if (serviceFIG0_2 == ensemble->services.end()) {
+ serviceFIG0_2 = ensemble->services.begin();
+ }
+
+ for (; serviceFIG0_2 != ensemble->services.end();
+ ++serviceFIG0_2) {
+
+ // filter out services which have no components
+ if ((*serviceFIG0_2)->nbComponent(ensemble->components) == 0) {
+ continue;
+ }
+
+ // Exclude Fidc type services, TODO why ?
+ auto type = (*serviceFIG0_2)->getType(ensemble);
+ if (type == Fidc) {
+ continue;
+ }
+
+ ++cur;
+
+ if (fig0_2 == NULL) {
+ fig0_2 = (FIGtype0_2 *)buf;
+
+ fig0_2->FIGtypeNumber = 0;
+ fig0_2->Length = 1;
+ fig0_2->CN = 0;
+ fig0_2->OE = 0;
+ fig0_2->PD = (type == Audio) ? 0 : 1;
+ fig0_2->Extension = 2;
+ buf += 2;
+ remaining -= 2;
+ }
+
+ if (type == Audio and
+ remaining < 3 + 2 *
+ (*serviceFIG0_2)->nbComponent(ensemble->components)) {
+ break;
+ }
+
+ if (type != Audio and
+ remaining < 5 + 2 *
+ (*serviceFIG0_2)->nbComponent(ensemble->components)) {
+ break;
+ }
+
+ if (type == Audio) {
+ auto fig0_2serviceAudio = (FIGtype0_2_Service*)buf;
+
+ fig0_2serviceAudio->SId = htons((*serviceFIG0_2)->id);
+ fig0_2serviceAudio->Local_flag = 0;
+ fig0_2serviceAudio->CAId = 0;
+ fig0_2serviceAudio->NbServiceComp =
+ (*serviceFIG0_2)->nbComponent(ensemble->components);
+ buf += 3;
+ fig0_2->Length += 3;
+ remaining -= 3;
+ }
+ else {
+ auto fig0_2serviceData = (FIGtype0_2_Service_data*)buf;
+
+ fig0_2serviceData->SId = htonl((*serviceFIG0_2)->id);
+ fig0_2serviceData->Local_flag = 0;
+ fig0_2serviceData->CAId = 0;
+ fig0_2serviceData->NbServiceComp =
+ (*serviceFIG0_2)->nbComponent(ensemble->components);
+ buf += 5;
+ fig0_2->Length += 5;
+ remaining -= 5;
+ }
+
+ int curCpnt = 0;
+ for (auto component = getComponent(
+ ensemble->components, (*serviceFIG0_2)->id );
+ component != ensemble->components.end();
+ component = getComponent(
+ ensemble->components,
+ (*serviceFIG0_2)->id,
+ component )
+ ) {
+ auto subchannel = getSubchannel(
+ ensemble->subchannels, (*component)->subchId);
+
+ if (subchannel == ensemble->subchannels.end()) {
+ etiLog.log(error,
+ "Subchannel %i does not exist for component "
+ "of service %i\n",
+ (*component)->subchId, (*component)->serviceId);
+ throw MuxInitException();
+ }
+
+ switch ((*subchannel)->type) {
+ case Audio:
+ {
+ auto audio_description = (FIGtype0_2_audio_component*)buf;
+ audio_description->TMid = 0;
+ audio_description->ASCTy = (*component)->type;
+ audio_description->SubChId = (*subchannel)->id;
+ audio_description->PS = ((curCpnt == 0) ? 1 : 0);
+ audio_description->CA_flag = 0;
+ }
+ break;
+ case DataDmb:
+ {
+ auto data_description = (FIGtype0_2_data_component*)buf;
+ data_description->TMid = 1;
+ data_description->DSCTy = (*component)->type;
+ data_description->SubChId = (*subchannel)->id;
+ data_description->PS = ((curCpnt == 0) ? 1 : 0);
+ data_description->CA_flag = 0;
+ }
+ break;
+ case Packet:
+ {
+ auto packet_description = (FIGtype0_2_packet_component*)buf;
+ packet_description->TMid = 3;
+ packet_description->setSCId((*component)->packet.id);
+ packet_description->PS = ((curCpnt == 0) ? 1 : 0);
+ packet_description->CA_flag = 0;
+ }
+ break;
+ default:
+ etiLog.log(error,
+ "Component type not supported\n");
+ throw MuxInitException();
+ }
+ buf += 2;
+ fig0_2->Length += 2;
+ remaining -= 2;
+ if (remaining < 0) {
+ etiLog.log(error,
+ "Sorry, no space left in FIG 0/2 to insert "
+ "component %i of program service %i.\n",
+ curCpnt, cur);
+ throw MuxInitException();
+ }
+ ++curCpnt;
+ }
+ }
+ return max_size - remaining;
+}
+
+
+//=========== FIG 0/3 ===========
+
+FIG0_3::FIG0_3(FIGRuntimeInformation *rti) :
+ m_rti(rti)
+{
+}
+
+size_t FIG0_3::fill(uint8_t *buf, size_t max_size)
+{
+ ssize_t remaining = max_size;
+ auto ensemble = m_rti->ensemble;
+
+ FIGtype0_3_header *fig0_3_header = NULL;
+ FIGtype0_3_data *fig0_3_data = NULL;
+
+ for (auto& component : ensemble->components) {
+ auto subchannel = getSubchannel(ensemble->subchannels,
+ component->subchId);
+
+ if (subchannel == ensemble->subchannels.end()) {
+ etiLog.log(error,
+ "Subchannel %i does not exist for component "
+ "of service %i\n",
+ component->subchId, component->serviceId);
+ throw MuxInitException();
+ }
+
+ if ((*subchannel)->type != Packet)
+ continue;
+
+ if (fig0_3_header == NULL) {
+ fig0_3_header = (FIGtype0_3_header*)buf;
+ fig0_3_header->FIGtypeNumber = 0;
+ fig0_3_header->Length = 1;
+ fig0_3_header->CN = 0;
+ fig0_3_header->OE = 0;
+ fig0_3_header->PD = 0;
+ fig0_3_header->Extension = 3;
+
+ buf += 2;
+ remaining -= 2;
+ }
+
+ /* Warning: When bit SCCA_flag is unset(0), the multiplexer
+ * R&S does not send the SCCA field. But, in the Factum ETI
+ * analyzer, if this field is not there, it is an error.
+ */
+ fig0_3_data = (FIGtype0_3_data*)buf;
+ fig0_3_data->setSCId(component->packet.id);
+ fig0_3_data->rfa = 0;
+ fig0_3_data->SCCA_flag = 0;
+ // if 0, datagroups are used
+ fig0_3_data->DG_flag = !component->packet.datagroup;
+ fig0_3_data->rfu = 0;
+ fig0_3_data->DSCTy = component->type;
+ fig0_3_data->SubChId = (*subchannel)->id;
+ fig0_3_data->setPacketAddress(component->packet.address);
+ if (m_rti->factumAnalyzer) {
+ fig0_3_data->SCCA = 0;
+ }
+
+ fig0_3_header->Length += 5;
+ buf += 5;
+ remaining -= 5;
+ if (m_rti->factumAnalyzer) {
+ fig0_3_header->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ }
+
+ if (remaining < 0) {
+ etiLog.level(error) <<
+ "can't add FIG 0/3 to FIB, "
+ "too many packet services";
+ throw MuxInitException();
+ }
+ }
+
+ return max_size - remaining;
+}
+
+//=========== FIG 0/17 ===========
+
+FIG0_17::FIG0_17(FIGRuntimeInformation *rti) :
+ m_rti(rti),
+ m_initialised(false)
+{
+}
+
+size_t FIG0_17::fill(uint8_t *buf, size_t max_size)
+{
+ ssize_t remaining = max_size;
+
+ if (not m_initialised) {
+ serviceFIG0_17 = m_rti->ensemble->services.end();
+ }
+
+ auto ensemble = m_rti->ensemble;
+
+ FIGtype0* fig0 = NULL;
+
+ if (serviceFIG0_17 == ensemble->services.end()) {
+ serviceFIG0_17 = ensemble->services.begin();
+ }
+ for (; serviceFIG0_17 != ensemble->services.end();
+ ++serviceFIG0_17) {
+
+ if ( (*serviceFIG0_17)->pty == 0 &&
+ (*serviceFIG0_17)->language == 0) {
+ continue;
+ }
+
+ if (fig0 == NULL) {
+ fig0 = (FIGtype0*)buf;
+ fig0->FIGtypeNumber = 0;
+ fig0->Length = 1;
+ fig0->CN = 0;
+ fig0->OE = 0;
+ fig0->PD = 0;
+ fig0->Extension = 17;
+ buf += 2;
+ remaining -= 2;
+ }
+
+ if ((*serviceFIG0_17)->language == 0) {
+ if (remaining < 4) {
+ break;
+ }
+ }
+ else {
+ if (remaining < 5) {
+ break;
+ }
+ }
+
+ auto programme = (FIGtype0_17_programme*)buf;
+ programme->SId = htons((*serviceFIG0_17)->id);
+ programme->SD = 1;
+ programme->PS = 0;
+ programme->L = (*serviceFIG0_17)->language != 0;
+ programme->CC = 0;
+ programme->Rfa = 0;
+ programme->NFC = 0;
+ if ((*serviceFIG0_17)->language == 0) {
+ buf[3] = (*serviceFIG0_17)->pty;
+ fig0->Length += 4;
+ buf += 4;
+ remaining -= 4;
+ }
+ else {
+ buf[3] = (*serviceFIG0_17)->language;
+ buf[4] = (*serviceFIG0_17)->pty;
+ fig0->Length += 5;
+ buf += 5;
+ remaining -= 5;
+ }
+ }
+
+ return max_size - remaining;
+}
+
diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h
new file mode 100644
index 0000000..3f02890
--- /dev/null
+++ b/src/fig/FIG0.h
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2015
+ Matthias P. Braendli, matthias.braendli@mpb.li
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FIG0_H_
+#define __FIG0_H_
+
+#include <cstdint>
+
+#include "fig/FIG.h"
+
+// FIG type 0/0, Multiplex Configuration Info (MCI),
+// Ensemble information
+class FIG0_0 : public IFIG
+{
+ public:
+ FIG0_0(FIGRuntimeInformation* rti) :
+ m_rti(rti) {}
+ virtual size_t fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::FIG0_0; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 0; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+};
+
+// FIG type 0/1, MIC, Sub-Channel Organization,
+// one instance of the part for each subchannel
+class FIG0_1 : public IFIG
+{
+ public:
+ FIG0_1(FIGRuntimeInformation* rti);
+ virtual size_t fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::A; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 1; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+ bool m_initialised;
+ std::vector<dabSubchannel*>::iterator subchannelFIG0_1;
+};
+
+// FIG type 0/2, MCI, Service Organization, one instance of
+// FIGtype0_2_Service for each subchannel
+class FIG0_2 : public IFIG
+{
+ public:
+ FIG0_2(FIGRuntimeInformation* rti);
+ virtual size_t fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::A; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 2; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+ bool m_initialised;
+ std::vector<std::shared_ptr<DabService> >::iterator serviceFIG0_2;
+};
+
+// FIG type 0/3
+// The Extension 3 of FIG type 0 (FIG 0/3) gives additional information about
+// the service component description in packet mode.
+class FIG0_3 : public IFIG
+{
+ public:
+ FIG0_3(FIGRuntimeInformation* rti);
+ virtual size_t fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::A; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 3; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+};
+
+// FIG type 0/17
+class FIG0_17 : public IFIG
+{
+ public:
+ FIG0_17(FIGRuntimeInformation* rti);
+ virtual size_t fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::A; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 17; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+ bool m_initialised;
+ std::vector<std::shared_ptr<DabService> >::iterator serviceFIG0_17;
+};
+
+#endif // __FIG0_H_
+
diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp
new file mode 100644
index 0000000..021dd80
--- /dev/null
+++ b/src/fig/FIGCarousel.cpp
@@ -0,0 +1,199 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2015
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ Implementation of the FIG carousel to schedule the FIGs into the
+ FIBs.
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fig/FIGCarousel.h"
+#include <boost/format.hpp>
+#include <iostream>
+#include <deque>
+
+/**************** FIGCarouselElement ****************/
+void FIGCarouselElement::reduce_deadline()
+{
+ deadline -= 24; //ms
+
+ std::cerr << "FIG " << fig->name() <<
+ " deadline decreased to: " << deadline << std::endl;
+
+ if (deadline < 0) {
+ std::cerr << "FIG " << fig->name() <<
+ " has negative scheduling deadline" << std::endl;
+ }
+}
+
+void FIGCarouselElement::increase_deadline()
+{
+ deadline += rate_increment_ms(fig->repetition_rate());
+
+ std::cerr << "FIG " << fig->name() <<
+ " deadline increased to: " << deadline << std::endl;
+}
+
+
+/**************** FIGCarousel *****************/
+
+FIGCarousel::FIGCarousel(boost::shared_ptr<dabEnsemble> ensemble) :
+ m_rti(ensemble),
+ m_fig0_0(&m_rti),
+ m_fig0_1(&m_rti),
+ m_fig0_2(&m_rti),
+ m_fig0_3(&m_rti),
+ m_fig0_17(&m_rti)
+{
+ m_figs_available[std::make_pair(0, 0)] = &m_fig0_0;
+ m_figs_available[std::make_pair(0, 1)] = &m_fig0_1;
+ m_figs_available[std::make_pair(0, 2)] = &m_fig0_2;
+ m_figs_available[std::make_pair(0, 3)] = &m_fig0_3;
+ m_figs_available[std::make_pair(0, 17)] = &m_fig0_17;
+
+ const int fib0 = 0;
+ allocate_fig_to_fib(0, 0, fib0);
+ allocate_fig_to_fib(0, 1, fib0);
+ allocate_fig_to_fib(0, 2, fib0);
+ allocate_fig_to_fib(0, 3, fib0);
+ allocate_fig_to_fib(0, 17, fib0);
+}
+
+void FIGCarousel::set_currentFrame(unsigned long currentFrame)
+{
+ m_rti.currentFrame = currentFrame;
+}
+
+void FIGCarousel::allocate_fig_to_fib(int figtype, int extension, int fib)
+{
+ if (fib < 0 or fib >= 3) {
+ throw std::out_of_range("Invalid FIB");
+ }
+
+ auto fig = m_figs_available.find(std::make_pair(figtype, extension));
+
+ if (fig != m_figs_available.end()) {
+ FIGCarouselElement el;
+ el.fig = fig->second;
+ el.deadline = 0;
+ el.increase_deadline();
+ m_fibs[fib].push_back(el);
+ }
+ else {
+ std::stringstream ss;
+ ss << "No FIG " << figtype << "/" << extension << " available";
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void dumpfib(uint8_t *buf, size_t bufsize) {
+ std::cerr << "FIB ";
+ for (size_t i = 0; i < bufsize; i++) {
+ std::cerr << boost::format("%02x ") % (unsigned int)buf[i];
+ }
+ std::cerr << std::endl;
+}
+
+size_t FIGCarousel::fib0(uint8_t *fib, const size_t bufsize, int framephase) {
+
+ uint8_t *buf = fib;
+
+ std::list<FIGCarouselElement>& figs = m_fibs[0];
+
+ std::cerr << "fib0(framephase=" << framephase << ")" << std::endl;
+
+ std::deque<FIGCarouselElement*> sorted_figs;
+
+ /* Decrement all deadlines */
+ for (auto& fig_el : figs) {
+ fig_el.reduce_deadline();
+
+ sorted_figs.push_back(&fig_el);
+ }
+
+ /* Sort the FIGs in the FIB according to their deadline */
+ std::sort(sorted_figs.begin(), sorted_figs.end(),
+ []( const FIGCarouselElement* left,
+ const FIGCarouselElement* right) {
+ return left->deadline < right->deadline;
+ });
+
+ std::cerr << " Sorted figs:" << std::endl;
+ for (auto& fig_el : sorted_figs) {
+ std::cerr << " " << fig_el->fig->name() <<
+ " d:" << fig_el->deadline << std::endl;
+ }
+
+ /* Data structure to carry FIB */
+ size_t available_size = bufsize;
+
+ /* Take special care for FIG0/0 */
+ auto fig0_0 = find_if(sorted_figs.begin(), sorted_figs.end(),
+ [](const FIGCarouselElement* f) {
+ std::cerr << "Check fig " << f->fig->name() << " " <<
+ rate_increment_ms(f->fig->repetition_rate()) << std::endl;
+ return f->fig->repetition_rate() == FIG_rate::FIG0_0;
+ });
+
+ if (fig0_0 != sorted_figs.end()) {
+ sorted_figs.erase(fig0_0);
+
+ if (framephase == 0) { // TODO check for all TM
+ size_t written = (*fig0_0)->fig->fill(buf, available_size);
+ std::cerr << "Special FIG 0/0 wrote " <<
+ written << " bytes" << std::endl;
+
+ if (written > 0) {
+ available_size -= written;
+ buf += written;
+ (*fig0_0)->increase_deadline();
+ }
+ else {
+ throw std::runtime_error("Failed to write FIG0/0");
+ }
+ }
+ }
+
+
+ /* Fill the FIB with the FIGs, taking the earliest deadline first */
+ while (available_size > 0 and not sorted_figs.empty()) {
+ auto fig_el = sorted_figs[0];
+ size_t written = fig_el->fig->fill(buf, available_size);
+
+ std::cerr << " FIG " << fig_el->fig->name() <<
+ " wrote " << written << " bytes" << std::endl;
+
+ if (written > 0) {
+ available_size -= written;
+ buf += written;
+
+ fig_el->increase_deadline();
+ }
+
+ sorted_figs.pop_front();
+ }
+
+ dumpfib(fib, bufsize);
+
+ return bufsize - available_size;
+}
+
diff --git a/src/fig/FIGCarousel.h b/src/fig/FIGCarousel.h
new file mode 100644
index 0000000..f65bd81
--- /dev/null
+++ b/src/fig/FIGCarousel.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2015
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ Implementation of the FIG carousel to schedule the FIGs into the
+ FIBs.
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FIG_CAROUSEL_H_
+#define __FIG_CAROUSEL_H_
+
+#include "fig/FIG.h"
+#include "fig/FIG0.h"
+#include <list>
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include "MuxElements.h"
+
+struct FIGCarouselElement {
+ IFIG* fig;
+ int deadline; // unit: ms
+
+ void reduce_deadline(void);
+
+ void increase_deadline(void);
+};
+
+class FIGCarousel {
+ public:
+ FIGCarousel(boost::shared_ptr<dabEnsemble> ensemble);
+
+ void set_currentFrame(unsigned long currentFrame);
+
+ void allocate_fig_to_fib(int figtype, int extension, int fib);
+
+ size_t fib0(uint8_t *buf, size_t bufsize, int framephase);
+
+ private:
+ FIGRuntimeInformation m_rti;
+ std::map<std::pair<int, int>, IFIG*> m_figs_available;
+
+ // Each FIB contains a list of carousel elements
+ std::map<int, std::list<FIGCarouselElement> > m_fibs;
+
+ FIG0_0 m_fig0_0;
+ FIG0_1 m_fig0_1;
+ FIG0_2 m_fig0_2;
+ FIG0_3 m_fig0_3;
+ FIG0_17 m_fig0_17;
+};
+
+#endif // __FIG_CAROUSEL_H_
+