diff options
Diffstat (limited to 'src/fig')
-rw-r--r-- | src/fig/FIG.h | 96 | ||||
-rw-r--r-- | src/fig/FIG0.cpp | 483 | ||||
-rw-r--r-- | src/fig/FIG0.h | 121 | ||||
-rw-r--r-- | src/fig/FIGCarousel.cpp | 199 | ||||
-rw-r--r-- | src/fig/FIGCarousel.h | 73 |
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_ + |