From 43aebb09438ff589a7be141a5af0aec2c27eaa95 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sat, 18 Jul 2015 22:20:11 +0200 Subject: Add FIG0/2, fib0 scheduler --- src/DabMultiplexer.cpp | 2 +- src/MuxElements.h | 2 +- src/fig/FIG.h | 24 ++++ src/fig/FIG0.cpp | 145 +++++++++++++++++++++- src/fig/FIG0.h | 26 +++- src/fig/FIGCarousel.cpp | 323 ++++++++++++++++-------------------------------- src/fig/FIGCarousel.h | 21 +++- 7 files changed, 319 insertions(+), 224 deletions(-) diff --git a/src/DabMultiplexer.cpp b/src/DabMultiplexer.cpp index 57a4abb..89c32c2 100644 --- a/src/DabMultiplexer.cpp +++ b/src/DabMultiplexer.cpp @@ -26,7 +26,7 @@ #include "DabMultiplexer.h" #include "ConfigParser.h" #include -#include "fic/FIG.h" +#include "fig/FIG.h" using namespace std; using namespace boost; diff --git a/src/MuxElements.h b/src/MuxElements.h index ada7ce3..ebcf708 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -100,7 +100,7 @@ class DabLabel class DabService; class DabComponent; -struct dabSubchannel; +class dabSubchannel; class dabEnsemble : public RemoteControllable { public: dabEnsemble() diff --git a/src/fig/FIG.h b/src/fig/FIG.h index 70b9316..90dd872 100644 --- a/src/fig/FIG.h +++ b/src/fig/FIG.h @@ -52,12 +52,36 @@ enum class FIG_rate { 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 0; // 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; + } +} + 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 index 85a06b5..09dff4d 100644 --- a/src/fig/FIG0.cpp +++ b/src/fig/FIG0.cpp @@ -59,9 +59,9 @@ size_t FIG0_0::fill(uint8_t *buf, size_t max_size) } //=========== FIG 0/1 =========== -// -FIG0_1::FIG0_1(FIGRuntimeInformation *rti) : m_rti(rti) +FIG0_1::FIG0_1(FIGRuntimeInformation *rti) : + m_rti(rti) { subchannelFIG0_1 = m_rti->ensemble->subchannels.end(); } @@ -72,8 +72,8 @@ size_t FIG0_1::fill(uint8_t *buf, size_t max_size) if (max_size < 6) { return 0; } - FIGtype0_1 *fig0_1; - figtype0_1 = (FIGtype0_1 *)buf; + FIGtype0_1 *figtype0_1; + figtype0_1 = (FIGtype0_1*)buf; figtype0_1->FIGtypeNumber = 0; figtype0_1->Length = 1; @@ -100,7 +100,7 @@ size_t FIG0_1::fill(uint8_t *buf, size_t max_size) } if (protection->form == UEP) { - fig0_1subchShort = + FIG_01_SubChannel_ShortF *fig0_1subchShort = (FIG_01_SubChannel_ShortF*)buf; fig0_1subchShort->SubChId = (*subchannelFIG0_1)->id; @@ -119,7 +119,7 @@ size_t FIG0_1::fill(uint8_t *buf, size_t max_size) figtype0_1->Length += 3; } else if (protection->form == EEP) { - fig0_1subchLong1 = + FIG_01_SubChannel_LongF *fig0_1subchLong1 = (FIG_01_SubChannel_LongF*)buf; fig0_1subchLong1->SubChId = (*subchannelFIG0_1)->id; @@ -146,3 +146,136 @@ size_t FIG0_1::fill(uint8_t *buf, size_t max_size) return max_size - remaining; } + +//=========== FIG 0/2 =========== + +FIG0_2::FIG0_2(FIGRuntimeInformation *rti) : + m_rti(rti) +{ + serviceProgFIG0_2 = m_rti->ensemble->services.end(); +} + +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; + + // Rotate through the subchannels until there is no more + // space + if (serviceProgFIG0_2 == m_rti->ensemble->services.end()) { + serviceProgFIG0_2 = m_rti->ensemble->services.begin(); + } + + for (; serviceProgFIG0_2 != m_rti->ensemble->services.end(); + ++serviceProgFIG0_2) { + if ((*serviceProgFIG0_2)->nbComponent(m_rti->ensemble->components) == 0) { + continue; + } + + if ((*serviceProgFIG0_2)->getType(m_rti->ensemble) != Audio) { + 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 = 0; + fig0_2->Extension = 2; + buf += 2; + remaining -= 2; + } + + if (remaining < 3 + 2 * + (*serviceProgFIG0_2)->nbComponent(m_rti->ensemble->components)) { + break; + } + + FIGtype0_2_Service *fig0_2serviceAudio = (FIGtype0_2_Service*)buf; + + fig0_2serviceAudio->SId = htons((*serviceProgFIG0_2)->id); + fig0_2serviceAudio->Local_flag = 0; + fig0_2serviceAudio->CAId = 0; + fig0_2serviceAudio->NbServiceComp = + (*serviceProgFIG0_2)->nbComponent(m_rti->ensemble->components); + buf += 3; + fig0_2->Length += 3; + remaining -= 3; + + int curCpnt = 0; + for (auto component = getComponent( + m_rti->ensemble->components, (*serviceProgFIG0_2)->id ); + component != m_rti->ensemble->components.end(); + component = getComponent( + m_rti->ensemble->components, + (*serviceProgFIG0_2)->id, + component ) + ) { + auto subchannel = getSubchannel( + m_rti->ensemble->subchannels, (*component)->subchId); + + if (subchannel == m_rti->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; +} + diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h index 502ce7e..248b501 100644 --- a/src/fig/FIG0.h +++ b/src/fig/FIG0.h @@ -35,10 +35,14 @@ class FIG0_0 : public IFIG { public: - FIG0_0(FIGRuntimeInformation* rti) : m_rti(rti) {} + 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::A; } + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 0; } + private: FIGRuntimeInformation *m_rti; }; @@ -52,10 +56,30 @@ class FIG0_1 : public IFIG 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; std::vector::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 1; } + + private: + FIGRuntimeInformation *m_rti; + std::vector >::iterator serviceProgFIG0_2; +}; + #endif // __FIG0_H_ diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp index 4e53ef5..eb78269 100644 --- a/src/fig/FIGCarousel.cpp +++ b/src/fig/FIGCarousel.cpp @@ -27,14 +27,32 @@ */ #include "fig/FIGCarousel.h" -#include "fig/FIG0.h" +#include -FIGCarousel::FIGCarousel(boost::shared_ptr ensemble) +void FIGCarouselElement::reduce_deadline() +{ + deadline -= rate_increment_ms(fig->repetition_rate()); + + if (deadline < 0) { + std::cerr << "FIG " << fig->name() << + "has negative scheduling deadline" << std::endl; + } +} + +FIGCarousel::FIGCarousel(boost::shared_ptr ensemble) : + m_fig0_0(&m_rti), + m_fig0_1(&m_rti), + m_fig0_2(&m_rti) { m_rti.ensemble = ensemble; m_rti.currentFrame = 0; - m_figs.emplace_back(&m_rti); - m_figs.emplace_back(&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; + + allocate_fig_to_fib(0, 0, 0); + allocate_fig_to_fib(0, 1, 0); + allocate_fig_to_fib(0, 2, 0); } void FIGCarousel::set_currentFrame(unsigned long currentFrame) @@ -42,232 +60,108 @@ void FIGCarousel::set_currentFrame(unsigned long currentFrame) m_rti.currentFrame = currentFrame; } -#if 0 -void fib0 { - switch (insertFIG) { - - case 0: - case 4: - case 8: - case 12: - // FIG type 0/0, Multiplex Configuration Info (MCI), - // Ensemble information - fig0_0 = (FIGtype0_0 *) & etiFrame[index]; - - 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(ensemble->id); - fig0_0->Change = 0; - fig0_0->Al = 0; - fig0_0->CIFcnt_hight = (currentFrame / 250) % 20; - fig0_0->CIFcnt_low = (currentFrame % 250); - index = index + 6; - figSize += 6; - - break; +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"); + } - case 1: - case 6: - case 10: - case 13: - // FIG type 0/1, MIC, Sub-Channel Organization, - // one instance of the part for each subchannel - figtype0_1 = (FIGtype0_1 *) & etiFrame[index]; - - figtype0_1->FIGtypeNumber = 0; - figtype0_1->Length = 1; - figtype0_1->CN = 0; - figtype0_1->OE = 0; - figtype0_1->PD = 0; - figtype0_1->Extension = 1; - index = index + 2; - figSize += 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(); - } + auto fig = m_figs_available.find(std::make_pair(figtype, extension)); - for (; subchannelFIG0_1 != ensemble->subchannels.end(); - ++subchannelFIG0_1) { - dabProtection* protection = &(*subchannelFIG0_1)->protection; + if (fig != m_figs_available.end()) { + FIGCarouselElement el; + el.fig = fig->second; + el.deadline = 0; + m_fibs[fib].push_back(el); + } + else { + std::stringstream ss; + ss << "No FIG " << figtype << "/" << extension << " available"; + throw std::runtime_error(ss.str()); + } +} - if ( (protection->form == UEP && figSize > 27) || - (protection->form == EEP && figSize > 26) ) { - break; - } +void FIGCarousel::fib0(int framephase) { + std::list figs = m_fibs[0]; - if (protection->form == UEP) { - fig0_1subchShort = - (FIG_01_SubChannel_ShortF*) &etiFrame[index]; - fig0_1subchShort->SubChId = (*subchannelFIG0_1)->id; + std::vector sorted_figs; - fig0_1subchShort->StartAdress_high = - (*subchannelFIG0_1)->startAddress / 256; - fig0_1subchShort->StartAdress_low = - (*subchannelFIG0_1)->startAddress % 256; + /* Decrement all deadlines according to the desired repetition rate */ + for (auto& fig_el : figs) { + fig_el.reduce_deadline(); - fig0_1subchShort->Short_Long_form = 0; - fig0_1subchShort->TableSwitch = 0; - fig0_1subchShort->TableIndex = - protection->uep.tableIndex; + sorted_figs.push_back(fig_el); + } - index = index + 3; - figSize += 3; - figtype0_1->Length += 3; - } - else if (protection->form == EEP) { - fig0_1subchLong1 = - (FIG_01_SubChannel_LongF*) &etiFrame[index]; - 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; - - index = index + 4; - figSize += 4; - figtype0_1->Length += 4; - } + /* 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; + }); + + /* Data structure to carry FIB */ + const size_t fib_size = 30; + uint8_t fib_data[fib_size]; + uint8_t *fib_data_current = fib_data; + size_t available_size = fib_size; + + /* Take special care for FIG0/0 */ + auto fig0_0 = find_if(sorted_figs.begin(), sorted_figs.end(), + [](const FIGCarouselElement& f) { + 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(fib_data_current, available_size); + + if (written > 0) { + available_size -= written; + fib_data_current += written; } - break; - - case 2: - case 9: - case 11: - case 14: - // FIG type 0/2, MCI, Service Organization, one instance of - // FIGtype0_2_Service for each subchannel - fig0_2 = NULL; - cur = 0; - - // Rotate through the subchannels until there is no more - // space in the FIG0/1 - if (serviceProgFIG0_2 == ensemble->services.end()) { - serviceProgFIG0_2 = ensemble->services.begin(); + else { + throw std::runtime_error("Failed to write FIG0/0"); } + } + } - for (; serviceProgFIG0_2 != ensemble->services.end(); - ++serviceProgFIG0_2) { - if (!(*serviceProgFIG0_2)->nbComponent(ensemble->components)) { - continue; - } - - if ((*serviceProgFIG0_2)->getType(ensemble) != 0) { - continue; - } - - ++cur; - - if (fig0_2 == NULL) { - fig0_2 = (FIGtype0_2 *) & etiFrame[index]; - - fig0_2->FIGtypeNumber = 0; - fig0_2->Length = 1; - fig0_2->CN = 0; - fig0_2->OE = 0; - fig0_2->PD = 0; - fig0_2->Extension = 2; - index = index + 2; - figSize += 2; - } + /* 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.begin(); + size_t written = fig_el->fig->fill(fib_data_current, available_size); - if (figSize + 3 - + (*serviceProgFIG0_2)->nbComponent(ensemble->components) - * 2 > 30) { - break; - } + if (written > 0) { + available_size -= written; + fib_data_current += written; + } - fig0_2serviceAudio = (FIGtype0_2_Service*) &etiFrame[index]; + sorted_figs.erase(fig_el); + } +} - fig0_2serviceAudio->SId = htons((*serviceProgFIG0_2)->id); - fig0_2serviceAudio->Local_flag = 0; - fig0_2serviceAudio->CAId = 0; - fig0_2serviceAudio->NbServiceComp = - (*serviceProgFIG0_2)->nbComponent(ensemble->components); - index += 3; - fig0_2->Length += 3; - figSize += 3; +#if 0 +void fib0 { + switch (insertFIG) { - int curCpnt = 0; - for (component = getComponent(ensemble->components, - (*serviceProgFIG0_2)->id); - component != ensemble->components.end(); - component = getComponent(ensemble->components, - (*serviceProgFIG0_2)->id, component)) { - subchannel = getSubchannel(ensemble->subchannels, - (*component)->subchId); + case 0: case 4: case 8: case 12: + // FIG type 0/0, Multiplex Configuration Info (MCI), + // Ensemble information + // ERASED + break; - 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(); - } + case 1: case 6: case 10: case 13: + // FIG type 0/1, MIC, Sub-Channel Organization, + // one instance of the part for each subchannel + // ERASED + break; - switch ((*subchannel)->type) { - case Audio: - audio_description = - (FIGtype0_2_audio_component*)&etiFrame[index]; - 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: - data_description = - (FIGtype0_2_data_component*)&etiFrame[index]; - 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: - packet_description = - (FIGtype0_2_packet_component*)&etiFrame[index]; - 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(); - } - index += 2; - fig0_2->Length += 2; - figSize += 2; - if (figSize > 30) { - 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; - } - } + case 2: case 9: case 11: case 14: + // FIG type 0/2, MCI, Service Organization, one instance of + // FIGtype0_2_Service for each subchannel + // ERASED break; case 3: @@ -518,3 +412,4 @@ void fib0 { } } #endif + diff --git a/src/fig/FIGCarousel.h b/src/fig/FIGCarousel.h index cbb6868..42b8d9c 100644 --- a/src/fig/FIGCarousel.h +++ b/src/fig/FIGCarousel.h @@ -30,20 +30,39 @@ #define __FIG_CAROUSEL_H_ #include "fig/FIG.h" +#include "fig/FIG0.h" #include +#include #include #include "MuxElements.h" +struct FIGCarouselElement { + IFIG* fig; + int deadline; + + void reduce_deadline(void); +}; + class FIGCarousel { public: FIGCarousel(boost::shared_ptr ensemble); void set_currentFrame(unsigned long currentFrame); + void allocate_fig_to_fib(int figtype, int extension, int fib); + + void fib0(int framephase); + private: FIGRuntimeInformation m_rti; - std::list m_figs; + std::map, IFIG*> m_figs_available; + + // Each FIB contains a list of carousel elements + std::map > m_fibs; + FIG0_0 m_fig0_0; + FIG0_1 m_fig0_1; + FIG0_2 m_fig0_2; }; #endif // __FIG_CAROUSEL_H_ -- cgit v1.2.3