From dbac3d701cded9545f555dde41d8e29a4d38c020 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 17 Aug 2015 13:11:26 +0200 Subject: FIG Carousel fixes Respect remaining size also for header insertion, solves a bug. Make sure FIGs don't insert only a header and then run out of remaining space. Make warning message more explicit. FIX FIG0/3 for non-program services. --- src/fig/FIG0.cpp | 131 ++++++++++++++++++++++++++---------------------- src/fig/FIGCarousel.cpp | 53 +++++++++++++++++--- 2 files changed, 116 insertions(+), 68 deletions(-) (limited to 'src/fig') diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp index 9d728dd..57321ed 100644 --- a/src/fig/FIG0.cpp +++ b/src/fig/FIG0.cpp @@ -87,17 +87,7 @@ FillStatus FIG0_1::fill(uint8_t *buf, size_t max_size) 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; + FIGtype0_1 *figtype0_1 = NULL; // Rotate through the subchannels until there is no more // space in the FIG0/1 @@ -105,7 +95,24 @@ FillStatus FIG0_1::fill(uint8_t *buf, size_t max_size) ++subchannelFIG0_1) { dabProtection* protection = &(*subchannelFIG0_1)->protection; - if ( (protection->form == UEP && remaining < 3) || + if (figtype0_1 == NULL) { + if ( (protection->form == UEP && remaining < 2 + 3) || + (protection->form == EEP && remaining < 2 + 4) ) { + break; + } + + 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; + } + else if ( (protection->form == UEP && remaining < 3) || (protection->form == EEP && remaining < 4) ) { break; } @@ -205,7 +212,14 @@ FillStatus FIG0_2::fill(uint8_t *buf, size_t max_size) ++cur; + const int required_size = (type == subchannel_type_t::Audio) ? + 3 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components) : + 5 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components); + if (fig0_2 == NULL) { + if (remaining < 2 + required_size) { + break; + } fig0_2 = (FIGtype0_2 *)buf; fig0_2->FIGtypeNumber = 0; @@ -217,16 +231,7 @@ FillStatus FIG0_2::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } - - if (type == subchannel_type_t::Audio and - remaining < 3 + 2 * - (*serviceFIG0_2)->nbComponent(ensemble->components)) { - break; - } - - if (type != subchannel_type_t::Audio and - remaining < 5 + 2 * - (*serviceFIG0_2)->nbComponent(ensemble->components)) { + else if (remaining < required_size) { break; } @@ -350,6 +355,7 @@ FillStatus FIG0_3::fill(uint8_t *buf, size_t max_size) FIGtype0_3_header *fig0_3_header = NULL; FIGtype0_3_data *fig0_3_data = NULL; + // TODO: implement component carousel for (auto& component : ensemble->components) { auto subchannel = getSubchannel(ensemble->subchannels, component->subchId); @@ -454,10 +460,14 @@ FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) throw MuxInitException(); } - if (!(*service)->program) - continue; + const int required_size = (*service)->program ? + ((*subchannel)->type == subchannel_type_t::Packet ? 5 : 4) : + ((*subchannel)->type == subchannel_type_t::Packet ? 7 : 6); if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } fig0 = (FIGtype0*)buf; fig0->FIGtypeNumber = 0; fig0->Length = 1; @@ -468,12 +478,12 @@ FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } + else if (remaining < required_size) { + break; + } if ((*service)->program) { if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet - if (remaining < 5) { - break; - } buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; fig0->Length += 2; @@ -491,9 +501,6 @@ FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) remaining -= 3; } else { // Audio, data stream or FIDC - if (remaining < 4) { - break; - } buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; @@ -515,9 +522,6 @@ FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) } else { // Data if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet - if (remaining < 7) { - break; - } buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; fig0->Length += 4; @@ -535,9 +539,6 @@ FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) remaining -= 3; } else { // Audio, data stream or FIDC - if (remaining < 6 ) { - break; - } buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; fig0->Length += 4; @@ -675,6 +676,7 @@ FillStatus FIG0_10::fill(uint8_t *buf, size_t max_size) fig0_10->PD = 0; fig0_10->Extension = 10; buf += 2; + remaining -= 2; tm* timeData; timeData = gmtime(&m_rti->date); @@ -693,7 +695,7 @@ FillStatus FIG0_10::fill(uint8_t *buf, size_t max_size) fig0_10->setHours(timeData->tm_hour); fig0_10->Minutes = timeData->tm_min; buf += 4; - remaining -= 6; + remaining -= 4; fs.num_bytes_written = max_size - remaining; fs.complete_fig_transmitted = true; @@ -740,7 +742,13 @@ FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) if ( m_transmit_programme && (*subchannel)->type == subchannel_type_t::Audio && (*componentFIG0_13)->audio.uaType != 0xffff) { + + const int required_size = 3+4+11; + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } fig0 = (FIGtype0*)buf; fig0->FIGtypeNumber = 0; fig0->Length = 1; @@ -751,8 +759,7 @@ FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } - - if (remaining < 3+4+11) { + else if (remaining < required_size) { break; } @@ -786,7 +793,12 @@ FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) (*subchannel)->type == subchannel_type_t::Packet && (*componentFIG0_13)->packet.appType != 0xffff) { + const int required_size = 5+2; + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } fig0 = (FIGtype0*)buf; fig0->FIGtypeNumber = 0; fig0->Length = 1; @@ -797,8 +809,7 @@ FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } - - if (remaining < 5+2) { + else if (remaining < required_size) { break; } @@ -865,7 +876,13 @@ FillStatus FIG0_17::fill(uint8_t *buf, size_t max_size) continue; } + const int required_size = (*serviceFIG0_17)->language == 0 ? 4 : 5; + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } fig0 = (FIGtype0*)buf; fig0->FIGtypeNumber = 0; fig0->Length = 1; @@ -876,16 +893,8 @@ FillStatus FIG0_17::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } - - if ((*serviceFIG0_17)->language == 0) { - if (remaining < 4) { - break; - } - } - else { - if (remaining < 5) { - break; - } + else if (remaining < required_size) { + break; } auto programme = (FIGtype0_17_programme*)buf; @@ -951,12 +960,11 @@ FillStatus FIG0_18::fill(uint8_t *buf, size_t max_size) const ssize_t numclusters = (*service)->clusters.size(); - if (remaining < 5 + numclusters) { - break; - } + const int required_size = 5 + numclusters; + if (fig0 == NULL) { - if (remaining < 2 + 5 + numclusters) { + if (remaining < 2 + required_size) { break; } @@ -970,6 +978,9 @@ FillStatus FIG0_18::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } + else if (remaining < required_size) { + break; + } auto programme = (FIGtype0_18*)buf; programme->SId = htons((*service)->id); @@ -1030,11 +1041,6 @@ FillStatus FIG0_19::fill(uint8_t *buf, size_t max_size) fs.complete_fig_transmitted = true; for (const auto& cluster : allclusters) { - if (remaining < length_0_19) { - fs.complete_fig_transmitted = false; - break; - } - if (fig0 == NULL) { if (remaining < 2 + length_0_19) { fs.complete_fig_transmitted = false; @@ -1051,6 +1057,11 @@ FillStatus FIG0_19::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; } + else if (remaining < length_0_19) { + fs.complete_fig_transmitted = false; + break; + } + auto fig0_19 = (FIGtype0_19*)buf; fig0_19->ClusterId = cluster->cluster_id; diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp index d565c23..1d79f2d 100644 --- a/src/fig/FIGCarousel.cpp +++ b/src/fig/FIGCarousel.cpp @@ -32,6 +32,8 @@ #include #include +#define CAROUSELDEBUG 0 + namespace FIC { /**************** FIGCarouselElement ****************/ @@ -40,8 +42,8 @@ void FIGCarouselElement::reduce_deadline() deadline -= 24; //ms if (deadline < 0) { - etiLog.level(warn) << "FIG " << fig->name() << - " has negative scheduling deadline"; + etiLog.level(warn) << "Could not respect repetition rate for FIG " << + fig->name() << " (" << deadline << "ms late)"; } } @@ -160,13 +162,14 @@ size_t FIGCarousel::carousel( return left->deadline < right->deadline; }); - /* Carousel debugging help - std::cerr << " Sorted figs in FIB" << fib << ":" << std::endl; +#if CAROUSELDEBUG + // Carousel debugging help + std::cerr << " ***** Sorted figs in FIB" << fib << ":" << std::endl; for (auto& fig_el : sorted_figs) { std::cerr << " " << fig_el->fig->name() << " d:" << fig_el->deadline << std::endl; } - // */ +#endif /* Data structure to carry FIB */ size_t available_size = bufsize; @@ -178,8 +181,6 @@ size_t FIGCarousel::carousel( }); if (fig0_0 != sorted_figs.end()) { - sorted_figs.erase(fig0_0); - if (framephase == 0) { // TODO check for all TM FillStatus status = (*fig0_0)->fig->fill(pbuf, available_size); size_t written = status.num_bytes_written; @@ -187,6 +188,24 @@ size_t FIGCarousel::carousel( if (written > 0) { available_size -= written; pbuf += written; + +#if CAROUSELDEBUG + std::cerr << " ****** FIG0/0 wrote\t" << written << " bytes" + << std::endl; + + if ( (*fig0_0)->fig->figtype() != 0 or + (*fig0_0)->fig->figextension() != 0 or + written != 6) { + + std::stringstream ss; + ss << "Assertion error: FIG 0/0 is actually " << + (*fig0_0)->fig->figtype() + << "/" << (*fig0_0)->fig->figextension() << + " and wrote " << written << " bytes"; + + throw std::runtime_error(ss.str()); + } +#endif } else { throw std::runtime_error("Failed to write FIG0/0"); @@ -196,6 +215,8 @@ size_t FIGCarousel::carousel( (*fig0_0)->increase_deadline(); } } + + sorted_figs.erase(fig0_0); } @@ -205,9 +226,25 @@ size_t FIGCarousel::carousel( FillStatus status = fig_el->fig->fill(pbuf, available_size); size_t written = status.num_bytes_written; - if (written > 0) { + // If exactly two bytes were written, it's because the FIG did + // only write the header, but no content. + // Writing only one byte is not allowed + if (written == 1 or written == 2) { + std::stringstream ss; + ss << "Assertion error: FIG" << fig_el->fig->figtype() << "/" << + fig_el->fig->figextension() << " wrote not enough data (" << + written << ")"; + throw std::runtime_error(ss.str()); + } + + if (written > 2) { available_size -= written; pbuf += written; +#if CAROUSELDEBUG + std::cerr << " ****** FIG" << fig_el->fig->figtype() << "/" << + fig_el->fig->figextension() << " wrote\t" << written << + " bytes" << std::endl; +#endif } if (status.complete_fig_transmitted) { -- cgit v1.2.3