diff options
Diffstat (limited to 'src/fig')
-rw-r--r-- | src/fig/FIG0.cpp | 1617 | ||||
-rw-r--r-- | src/fig/FIG0.h | 319 | ||||
-rw-r--r-- | src/fig/FIG0_0.cpp | 64 | ||||
-rw-r--r-- | src/fig/FIG0_0.h | 51 | ||||
-rw-r--r-- | src/fig/FIG0_1.cpp | 209 | ||||
-rw-r--r-- | src/fig/FIG0_1.h | 58 | ||||
-rw-r--r-- | src/fig/FIG0_10.cpp | 84 | ||||
-rw-r--r-- | src/fig/FIG0_10.h | 52 | ||||
-rw-r--r-- | src/fig/FIG0_13.cpp | 182 | ||||
-rw-r--r-- | src/fig/FIG0_13.h | 54 | ||||
-rw-r--r-- | src/fig/FIG0_17.cpp | 103 | ||||
-rw-r--r-- | src/fig/FIG0_17.h | 53 | ||||
-rw-r--r-- | src/fig/FIG0_18.cpp | 106 | ||||
-rw-r--r-- | src/fig/FIG0_18.h | 52 | ||||
-rw-r--r-- | src/fig/FIG0_19.cpp | 136 | ||||
-rw-r--r-- | src/fig/FIG0_19.h | 53 | ||||
-rw-r--r-- | src/fig/FIG0_2.cpp | 266 | ||||
-rw-r--r-- | src/fig/FIG0_2.h | 55 | ||||
-rw-r--r-- | src/fig/FIG0_3.cpp | 124 | ||||
-rw-r--r-- | src/fig/FIG0_3.h | 54 | ||||
-rw-r--r-- | src/fig/FIG0_5.cpp | 113 | ||||
-rw-r--r-- | src/fig/FIG0_5.h | 57 | ||||
-rw-r--r-- | src/fig/FIG0_6.cpp | 204 | ||||
-rw-r--r-- | src/fig/FIG0_6.h | 85 | ||||
-rw-r--r-- | src/fig/FIG0_8.cpp | 204 | ||||
-rw-r--r-- | src/fig/FIG0_8.h | 56 | ||||
-rw-r--r-- | src/fig/FIG0_9.cpp | 83 | ||||
-rw-r--r-- | src/fig/FIG0_9.h | 52 | ||||
-rw-r--r-- | src/fig/TransitionHandler.h | 119 |
29 files changed, 2743 insertions, 1922 deletions
diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp deleted file mode 100644 index 1e179cf..0000000 --- a/src/fig/FIG0.cpp +++ /dev/null @@ -1,1617 +0,0 @@ -/* - 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) 2016 - 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 "fig/FIG0structs.h" -#include "utils.h" - -namespace FIC { - -//=========== FIG 0/0 =========== - -FillStatus FIG0_0::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - - if (max_size < 6) { - fs.num_bytes_written = 0; - return fs; - } - - 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); - - fs.complete_fig_transmitted = true; - fs.num_bytes_written = 6; - return fs; -} - - -//=========== FIG 0/1 =========== - -FIG0_1::FIG0_1(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false), - m_watermarkSize(0), - m_watermarkPos(0) -{ - uint8_t buffer[sizeof(m_watermarkData) / 2]; - snprintf((char*)buffer, sizeof(buffer), - "%s %s, %s %s", - PACKAGE_NAME, -#if defined(GITVERSION) - GITVERSION, -#else - PACKAGE_VERSION, -#endif - __DATE__, __TIME__); - - memset(m_watermarkData, 0, sizeof(m_watermarkData)); - m_watermarkData[0] = 0x55; // Sync - m_watermarkData[1] = 0x55; - m_watermarkSize = 16; - for (unsigned i = 0; i < strlen((char*)buffer); ++i) { - for (int j = 0; j < 8; ++j) { - uint8_t bit = (buffer[m_watermarkPos >> 3] >> (7 - (m_watermarkPos & 0x07))) & 1; - m_watermarkData[m_watermarkSize >> 3] |= bit << (7 - (m_watermarkSize & 0x07)); - ++m_watermarkSize; - bit = 1; - m_watermarkData[m_watermarkSize >> 3] |= bit << (7 - (m_watermarkSize & 0x07)); - ++m_watermarkSize; - ++m_watermarkPos; - } - } - m_watermarkPos = 0; -} - -FillStatus FIG0_1::fill(uint8_t *buf, size_t max_size) -{ -#define FIG0_1_TRACE discard - - FillStatus fs; - size_t remaining = max_size; - - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill initialised=" << - (m_initialised ? 1 : 0); - - const int watermark_bit = (m_watermarkData[m_watermarkPos >> 3] >> - (7 - (m_watermarkPos & 0x07))) & 1; - - const bool iterate_forward = (watermark_bit == 1); - - if (not m_initialised) { - m_initialised = true; - - subchannels = m_rti->ensemble->subchannels; - - if (not iterate_forward) { - std::reverse(subchannels.begin(), subchannels.end()); - } - subchannelFIG0_1 = subchannels.begin(); - } - - if (max_size < 6) { - return fs; - } - - FIGtype0_1 *figtype0_1 = NULL; - - // Rotate through the subchannels until there is no more - // space in the FIG0/1 - for (; subchannelFIG0_1 != subchannels.end(); ++subchannelFIG0_1 ) { - size_t subch_iter_ix = std::distance(subchannels.begin(), subchannelFIG0_1); - - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill loop ix=" << subch_iter_ix; - - dabProtection* protection = &(*subchannelFIG0_1)->protection; - - if (figtype0_1 == NULL) { - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill header " << - (protection->form == UEP ? "UEP " : "EEP ") << remaining; - - if ( (protection->form == UEP && remaining < 2 + 3) || - (protection->form == EEP && remaining < 2 + 4) ) { - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill no space for header"; - 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) ) { - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill no space for fig " << - (protection->form == UEP ? "UEP " : "EEP ") << remaining; - 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; - - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill insert UEP id=" << - (int)fig0_1subchShort->SubChId << " rem=" << remaining - << " ix=" << subch_iter_ix; - } - 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 = - (*subchannelFIG0_1)->getSizeCu() / 256; - fig0_1subchLong1->Sub_ChannelSize_low = - (*subchannelFIG0_1)->getSizeCu() % 256; - - buf += 4; - remaining -= 4; - figtype0_1->Length += 4; - - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill insert EEP id=" << - (int)fig0_1subchLong1->SubChId << " rem=" << remaining - << " ix=" << subch_iter_ix; - } - } - - size_t subch_iter_ix = std::distance(subchannels.begin(), subchannelFIG0_1); - - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill loop out, rem=" << remaining - << " ix=" << subch_iter_ix; - - if (subchannelFIG0_1 == subchannels.end()) { - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill completed, rem=" << remaining; - m_initialised = false; - fs.complete_fig_transmitted = true; - - m_watermarkPos++; - if (m_watermarkPos == m_watermarkSize) { - m_watermarkPos = 0; - } - } - - fs.num_bytes_written = max_size - remaining; - etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill wrote " << fs.num_bytes_written; - return fs; -} - - -//=========== FIG 0/2 =========== - -FIG0_2::FIG0_2(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false), - m_inserting_audio_not_data(false) -{ -} - -FillStatus FIG0_2::fill(uint8_t *buf, size_t max_size) -{ -#define FIG0_2_TRACE discard - using namespace std; - - FillStatus fs; - FIGtype0_2 *fig0_2 = NULL; - int cur = 0; - ssize_t remaining = max_size; - - const auto ensemble = m_rti->ensemble; - - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill init " << (m_initialised ? 1 : 0) << - " ********************************"; - - for (const auto& s : ensemble->services) { - // Exclude Fidc type services, TODO unsupported - auto type = s->getType(ensemble); - if (type == subchannel_type_t::Fidc) { - throw invalid_argument("FIG0/2 does not support FIDC"); - } - } - - if (not m_initialised) { - m_audio_services.clear(); - copy_if(ensemble->services.begin(), - ensemble->services.end(), - back_inserter(m_audio_services), - [&](shared_ptr<DabService>& s) { - return s->isProgramme(ensemble); - } ); - - m_data_services.clear(); - copy_if(ensemble->services.begin(), - ensemble->services.end(), - back_inserter(m_data_services), - [&](shared_ptr<DabService>& s) { - return not s->isProgramme(ensemble); - } ); - - m_initialised = true; - m_inserting_audio_not_data = !m_inserting_audio_not_data; - - if (m_inserting_audio_not_data) { - serviceFIG0_2 = m_audio_services.begin(); - } - else { - serviceFIG0_2 = m_data_services.begin(); - } - - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill we have " << - m_audio_services.size() << " audio and " << - m_data_services.size() << " data services. Inserting " << - (m_inserting_audio_not_data ? "AUDIO" : "DATA"); - } - - const auto last_service = m_inserting_audio_not_data ? - m_audio_services.end() : m_data_services.end(); - - // Rotate through the subchannels until there is no more - // space - for (; serviceFIG0_2 != last_service; ++serviceFIG0_2) { - const auto type = (*serviceFIG0_2)->getType(ensemble); - const auto isProgramme = (*serviceFIG0_2)->isProgramme(ensemble); - - etiLog.log(FIG0_2_TRACE, "FIG0_2::fill loop SId=%04x %s/%s", - (*serviceFIG0_2)->id, - m_inserting_audio_not_data ? "AUDIO" : "DATA", - type == subchannel_type_t::Audio ? "Audio" : - type == subchannel_type_t::Packet ? "Packet" : - type == subchannel_type_t::DataDmb ? "DataDmb" : - type == subchannel_type_t::Fidc ? "Fidc" : "?"); - - // filter out services which have no components - if ((*serviceFIG0_2)->nbComponent(ensemble->components) == 0) { - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no components "; - continue; - } - - ++cur; - - const int required_size = isProgramme ? - 3 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components) : - 5 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components); - - if (fig0_2 == NULL) { - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header"; - if (remaining < 2 + required_size) { - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header no place" << - " rem=" << remaining << " req=" << 2 + required_size; - break; - } - fig0_2 = (FIGtype0_2 *)buf; - - fig0_2->FIGtypeNumber = 0; - fig0_2->Length = 1; - fig0_2->CN = 0; - fig0_2->OE = 0; - fig0_2->PD = isProgramme ? 0 : 1; - fig0_2->Extension = 2; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no place" << - " rem=" << remaining << " req=" << required_size; - break; - } - - if (type == subchannel_type_t::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; - - etiLog.log(FIG0_2_TRACE, "FIG0_2::fill audio SId=%04x", - (*serviceFIG0_2)->id); - } - 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; - - etiLog.log(FIG0_2_TRACE, "FIG0_2::fill data SId=%04x", - (*serviceFIG0_2)->id); - } - - 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); - - etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp sub=%04x srv=%04x", - (*component)->subchId, (*component)->serviceId); - - 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 subchannel_type_t::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 subchannel_type_t::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 subchannel_type_t::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; - - etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp length=%d", - fig0_2->Length); - } - } - - if (serviceFIG0_2 == last_service) { - etiLog.log(FIG0_2_TRACE, "FIG0_2::loop reached last"); - m_initialised = false; - fs.complete_fig_transmitted = !m_inserting_audio_not_data; - } - - etiLog.log(FIG0_2_TRACE, "FIG0_2::loop end complete=%d", - fs.complete_fig_transmitted ? 1 : 0); - - fs.num_bytes_written = max_size - remaining; - return fs; -} - - -//=========== FIG 0/3 =========== - -FIG0_3::FIG0_3(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false) -{ -} - -FillStatus FIG0_3::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - ssize_t remaining = max_size; - auto ensemble = m_rti->ensemble; - - if (not m_initialised) { - componentFIG0_3 = m_rti->ensemble->components.end(); - m_initialised = true; - } - - FIGtype0 *fig0 = NULL; - - for (; componentFIG0_3 != ensemble->components.end(); - ++componentFIG0_3) { - auto subchannel = getSubchannel(ensemble->subchannels, - (*componentFIG0_3)->subchId); - - if (subchannel == ensemble->subchannels.end()) { - etiLog.log(error, - "Subchannel %i does not exist for component " - "of service %i\n", - (*componentFIG0_3)->subchId, (*componentFIG0_3)->serviceId); - throw MuxInitException(); - } - - if ((*subchannel)->type != subchannel_type_t::Packet) - continue; - - const int required_size = 5 + (m_rti->factumAnalyzer ? 2 : 0); - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 3; - - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - /* 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. - */ - FIGtype0_3 *fig0_3 = (FIGtype0_3*)buf; - fig0_3->setSCId((*componentFIG0_3)->packet.id); - fig0_3->rfa = 0; - fig0_3->SCCA_flag = 0; - // if 0, datagroups are used - fig0_3->DG_flag = !(*componentFIG0_3)->packet.datagroup; - fig0_3->rfu = 0; - fig0_3->DSCTy = (*componentFIG0_3)->type; - fig0_3->SubChId = (*subchannel)->id; - fig0_3->setPacketAddress((*componentFIG0_3)->packet.address); - if (m_rti->factumAnalyzer) { - fig0_3->SCCA = 0; - } - - fig0->Length += 5; - buf += 5; - remaining -= 5; - if (m_rti->factumAnalyzer) { - fig0->Length += 2; - buf += 2; - remaining -= 2; - } - } - - if (componentFIG0_3 == ensemble->components.end()) { - componentFIG0_3 = ensemble->components.begin(); - fs.complete_fig_transmitted = true; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/5 =========== - -FIG0_5::FIG0_5(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false) -{ -} - -FillStatus FIG0_5::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - ssize_t remaining = max_size; - auto ensemble = m_rti->ensemble; - - if (not m_initialised) { - componentFIG0_5 = m_rti->ensemble->components.end(); - m_initialised = true; - } - - FIGtype0* fig0 = NULL; - - for (; componentFIG0_5 != ensemble->components.end(); - ++componentFIG0_5) { - - auto service = getService(*componentFIG0_5, - ensemble->services); - auto subchannel = getSubchannel(ensemble->subchannels, - (*componentFIG0_5)->subchId); - - if (subchannel == ensemble->subchannels.end()) { - etiLog.log(error, - "Subchannel %i does not exist for component " - "of service %i\n", - (*componentFIG0_5)->subchId, - (*componentFIG0_5)->serviceId); - throw MuxInitException(); - } - - if ( (*service)->language == 0) { - continue; - } - - const int required_size = 2; - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 5; - - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - FIGtype0_5_short *fig0_5 = (FIGtype0_5_short*)buf; - - fig0_5->LS = 0; - fig0_5->rfu = 0; - fig0_5->SubChId = (*subchannel)->id; - fig0_5->language = (*service)->language; - - fig0->Length += 2; - buf += 2; - remaining -= 2; - } - - if (componentFIG0_5 == ensemble->components.end()) { - componentFIG0_5 = ensemble->components.begin(); - fs.complete_fig_transmitted = true; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/6 =========== - -FIG0_6::FIG0_6(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false) -{ -} - -FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - ssize_t remaining = max_size; - auto ensemble = m_rti->ensemble; - - if (not m_initialised) { - linkageSetFIG0_6 = m_rti->ensemble->linkagesets.end(); - m_initialised = true; - } - - FIGtype0* fig0 = NULL; - - for (; linkageSetFIG0_6 != ensemble->linkagesets.end(); - ++linkageSetFIG0_6) { - - const bool PD = false; - const bool ILS = (*linkageSetFIG0_6)->international; - - // need to add key service to num_ids - const size_t num_ids = 1 + (*linkageSetFIG0_6)->id_list.size(); - - const size_t headersize = sizeof(struct FIGtype0_6_header); - const int required_size = sizeof(struct FIGtype0_6) + - (num_ids > 0 ? - headersize + (PD == 0 ? (ILS == 0 ? 2*num_ids : 3*num_ids) : 4*num_ids) : - 0); - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = PD; - fig0->Extension = 5; - - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - FIGtype0_6 *fig0_6 = (FIGtype0_6*)buf; - - fig0_6->IdListFlag = (num_ids > 0); - fig0_6->LA = (*linkageSetFIG0_6)->active; - fig0_6->SH = (*linkageSetFIG0_6)->hard; - fig0_6->ILS = ILS; - fig0_6->LSN = (*linkageSetFIG0_6)->lsn; - - fig0->Length += sizeof(struct FIGtype0_6); - buf += sizeof(struct FIGtype0_6); - remaining -= sizeof(struct FIGtype0_6); - - if (num_ids > 0) { - FIGtype0_6_header *header = (FIGtype0_6_header*)buf; - header->rfu = 0; - if (num_ids > 0x0F) { - etiLog.log(error, "Too large number of links for linkage set 0x%04x", - (*linkageSetFIG0_6)->lsn); - throw MuxInitException(); - } - - header->IdLQ = 0; // TODO not only DAB - header->rfa = 0; - header->num_ids = num_ids; - - fig0->Length += headersize; - buf += headersize; - remaining -= headersize; - - // TODO insert key service first - const std::string keyserviceuid =(*linkageSetFIG0_6)->keyservice; - const auto& keyservice = std::find_if( - ensemble->services.begin(), - ensemble->services.end(), - [&](const std::shared_ptr<DabService> srv) { - return srv->uid == keyserviceuid; - }); - - if (keyservice == ensemble->services.end()) { - etiLog.log(error, "Invalid key service %s in linkage set 0x%04x", - keyserviceuid.c_str(), (*linkageSetFIG0_6)->lsn); - throw MuxInitException(); - } - for (const auto& l : (*linkageSetFIG0_6)->id_list) { - if (l.type != ServiceLinkType::DAB) { - etiLog.log(error, "TODO only DAB links supported. (linkage set 0x%04x)", - (*linkageSetFIG0_6)->lsn); - throw MuxInitException(); - } - } - - if (not PD and not ILS) { - buf[0] = (*keyservice)->id >> 8; - buf[1] = (*keyservice)->id & 0xFF; - fig0->Length += 2; - buf += 2; - remaining -= 2; - - for (const auto& l : (*linkageSetFIG0_6)->id_list) { - buf[0] = l.id >> 8; - buf[1] = l.id & 0xFF; - fig0->Length += 2; - buf += 2; - remaining -= 2; - } - } - if (not PD and ILS) { - buf[0] = ensemble->ecc; - buf[1] = (*keyservice)->id >> 8; - buf[2] = (*keyservice)->id & 0xFF; - fig0->Length += 3; - buf += 3; - remaining -= 3; - - for (const auto& l : (*linkageSetFIG0_6)->id_list) { - buf[0] = l.ecc; - buf[1] = l.id >> 8; - buf[2] = l.id & 0xFF; - fig0->Length += 3; - buf += 3; - remaining -= 3; - } - } - else { // PD == true - // TODO if IdLQ is 11, MSB shall be zero - buf[0] = (*keyservice)->id >> 24; - buf[1] = (*keyservice)->id >> 16; - buf[2] = (*keyservice)->id >> 8; - buf[3] = (*keyservice)->id & 0xFF; - fig0->Length += 4; - buf += 4; - remaining -= 4; - - for (const auto& l : (*linkageSetFIG0_6)->id_list) { - buf[0] = l.id >> 24; - buf[1] = l.id >> 16; - buf[2] = l.id >> 8; - buf[3] = l.id & 0xFF; - fig0->Length += 4; - buf += 4; - remaining -= 4; - } - } - } - - fig0->Length += required_size; - buf += required_size; - remaining -= required_size; - } - - if (linkageSetFIG0_6 == ensemble->linkagesets.end()) { - linkageSetFIG0_6 = ensemble->linkagesets.begin(); - fs.complete_fig_transmitted = true; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/8 =========== - -FIG0_8::FIG0_8(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false), - m_transmit_programme(false) -{ -} - -FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - auto ensemble = m_rti->ensemble; - ssize_t remaining = max_size; - - if (not m_initialised) { - componentFIG0_8 = m_rti->ensemble->components.end(); - m_initialised = true; - } - - FIGtype0* fig0 = NULL; - - for (; componentFIG0_8 != ensemble->components.end(); - ++componentFIG0_8) { - - auto service = getService(*componentFIG0_8, - ensemble->services); - auto subchannel = getSubchannel(ensemble->subchannels, - (*componentFIG0_8)->subchId); - - if (subchannel == ensemble->subchannels.end()) { - etiLog.log(error, - "Subchannel %i does not exist for component " - "of service %i\n", - (*componentFIG0_8)->subchId, - (*componentFIG0_8)->serviceId); - throw MuxInitException(); - } - - if (m_transmit_programme and (*service)->isProgramme(ensemble)) { - const int required_size = - ((*subchannel)->type == subchannel_type_t::Packet ? 5 : 4); - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 8; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet - buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; - buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; - fig0->Length += 2; - buf += 2; - remaining -= 2; - - FIGtype0_8_long* definition = (FIGtype0_8_long*)buf; - memset(definition, 0, 3); - definition->ext = 0; // no rfa - definition->SCIdS = (*componentFIG0_8)->SCIdS; - definition->LS = 1; - definition->setSCId((*componentFIG0_8)->packet.id); - fig0->Length += 3; - buf += 3; // 8 minus rfa - remaining -= 3; - } - else { // Audio, data stream or FIDC - buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; - buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; - - fig0->Length += 2; - buf += 2; - remaining -= 2; - - FIGtype0_8_short* definition = (FIGtype0_8_short*)buf; - memset(definition, 0, 2); - definition->ext = 0; // no rfa - definition->SCIdS = (*componentFIG0_8)->SCIdS; - definition->LS = 0; - definition->MscFic = 0; - definition->Id = (*componentFIG0_8)->subchId; - fig0->Length += 2; - buf += 2; // 4 minus rfa - remaining -= 2; - } - } - else if (!m_transmit_programme and !(*service)->isProgramme(ensemble)) { - // Data - const int required_size = - ((*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; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 1; - fig0->Extension = 8; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet - buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; - buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; - fig0->Length += 4; - buf += 4; - remaining -= 4; - - FIGtype0_8_long* definition = (FIGtype0_8_long*)buf; - memset(definition, 0, 3); - definition->ext = 0; // no rfa - definition->SCIdS = (*componentFIG0_8)->SCIdS; - definition->LS = 1; - definition->setSCId((*componentFIG0_8)->packet.id); - fig0->Length += 3; - buf += 3; // 8 minus rfa - remaining -= 3; - } - else { // Audio, data stream or FIDC - buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; - buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; - fig0->Length += 4; - buf += 4; - remaining -= 4; - - FIGtype0_8_short* definition = (FIGtype0_8_short*)buf; - memset(definition, 0, 2); - definition->ext = 0; // no rfa - definition->SCIdS = (*componentFIG0_8)->SCIdS; - definition->LS = 0; - definition->MscFic = 0; - definition->Id = (*componentFIG0_8)->subchId; - fig0->Length += 2; - buf += 2; // 4 minus rfa - remaining -= 2; - } - } - } - - if (componentFIG0_8 == ensemble->components.end()) { - componentFIG0_8 = ensemble->components.begin(); - - // The full database is sent every second full loop - fs.complete_fig_transmitted = m_transmit_programme; - - m_transmit_programme = not m_transmit_programme; - // Alternate between data and and programme FIG0/13, - // do not mix fig0 with PD=0 with extension 13 stuff - // that actually needs PD=1, and vice versa - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/9 =========== -FIG0_9::FIG0_9(FIGRuntimeInformation *rti) : - m_rti(rti) {} - -FillStatus FIG0_9::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - auto ensemble = m_rti->ensemble; - size_t remaining = max_size; - - if (remaining < 5) { - fs.num_bytes_written = 0; - return fs; - } - - auto fig0_9 = (FIGtype0_9*)buf; - fig0_9->FIGtypeNumber = 0; - fig0_9->Length = 4; - fig0_9->CN = 0; - fig0_9->OE = 0; - fig0_9->PD = 0; - fig0_9->Extension = 9; - - fig0_9->ext = 0; - fig0_9->rfa1 = 0; // Had a different meaning in EN 300 401 V1.4.1 - - if (ensemble->lto_auto) { - time_t now = time(NULL); - struct tm* ltime = localtime(&now); - time_t now2 = timegm(ltime); - ensemble->lto = (now2 - now) / 1800; - } - - if (ensemble->lto >= 0) { - fig0_9->ensembleLto = ensemble->lto; - } - else { - /* Convert to 1-complement representation */ - fig0_9->ensembleLto = (-ensemble->lto) | (1<<5); - } - - fig0_9->ensembleEcc = ensemble->ecc; - fig0_9->tableId = ensemble->international_table; - buf += 5; - remaining -= 5; - - /* No extended field, no support for services with different ECC */ - - fs.num_bytes_written = max_size - remaining; - fs.complete_fig_transmitted = true; - return fs; -} - -//=========== FIG 0/10 =========== - -FIG0_10::FIG0_10(FIGRuntimeInformation *rti) : - m_rti(rti) -{ -} - -FillStatus FIG0_10::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - auto ensemble = m_rti->ensemble; - size_t remaining = max_size; - - if (remaining < 8) { - fs.num_bytes_written = 0; - return fs; - } - - //Time and country identifier - auto fig0_10 = (FIGtype0_10_LongForm*)buf; - - fig0_10->FIGtypeNumber = 0; - fig0_10->Length = 7; - fig0_10->CN = 0; - fig0_10->OE = 0; - fig0_10->PD = 0; - fig0_10->Extension = 10; - buf += 2; - remaining -= 2; - - tm* timeData; - time_t dab_time_seconds = 0; - uint32_t dab_time_millis = 0; - get_dab_time(&dab_time_seconds, &dab_time_millis); - timeData = gmtime(&dab_time_seconds); - - fig0_10->RFU = 0; - fig0_10->setMJD(gregorian2mjd(timeData->tm_year + 1900, - timeData->tm_mon + 1, - timeData->tm_mday)); - fig0_10->LSI = 0; - fig0_10->ConfInd = 1; - fig0_10->UTC = 1; - fig0_10->setHours(timeData->tm_hour); - fig0_10->Minutes = timeData->tm_min; - fig0_10->Seconds = timeData->tm_sec; - fig0_10->setMilliseconds(dab_time_millis); - buf += 6; - remaining -= 6; - - fs.num_bytes_written = max_size - remaining; - fs.complete_fig_transmitted = true; - return fs; -} - -//=========== FIG 0/13 =========== - -FIG0_13::FIG0_13(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false), - m_transmit_programme(false) -{ -} - -FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - auto ensemble = m_rti->ensemble; - ssize_t remaining = max_size; - - if (not m_initialised) { - componentFIG0_13 = m_rti->ensemble->components.end(); - m_initialised = true; - } - - FIGtype0* fig0 = NULL; - - for (; componentFIG0_13 != ensemble->components.end(); - ++componentFIG0_13) { - - auto subchannel = getSubchannel(ensemble->subchannels, - (*componentFIG0_13)->subchId); - - if (subchannel == ensemble->subchannels.end()) { - etiLog.log(error, - "Subchannel %i does not exist for component " - "of service %i\n", - (*componentFIG0_13)->subchId, - (*componentFIG0_13)->serviceId); - throw MuxInitException(); - } - - 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; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 13; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - FIG0_13_shortAppInfo* info = (FIG0_13_shortAppInfo*)buf; - info->SId = htonl((*componentFIG0_13)->serviceId) >> 16; - info->SCIdS = (*componentFIG0_13)->SCIdS; - info->No = 1; - buf += 3; - remaining -= 3; - fig0->Length += 3; - - FIG0_13_app* app = (FIG0_13_app*)buf; - app->setType((*componentFIG0_13)->audio.uaType); - app->length = 2; - app->xpad = htons(0x0c3c); - /* xpad meaning - CA = 0 - CAOrg = 0 - Rfu = 0 - AppTy(5) = 12 (MOT, start of X-PAD data group) - DG = 0 (MSC data groups used) - Rfu = 0 - DSCTy(6) = 60 (MOT) - */ - - buf += 2 + app->length; - remaining -= 2 + app->length; - fig0->Length += 2 + app->length; - } - else if (!m_transmit_programme && - (*subchannel)->type == subchannel_type_t::Packet && - (*componentFIG0_13)->packet.appType != 0xffff) { - - const int required_size = 5+2+2; - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 1; - fig0->Extension = 13; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - FIG0_13_longAppInfo* info = (FIG0_13_longAppInfo*)buf; - info->SId = htonl((*componentFIG0_13)->serviceId); - info->SCIdS = (*componentFIG0_13)->SCIdS; - info->No = 1; - buf += 5; - remaining -= 5; - fig0->Length += 5; - - FIG0_13_app* app = (FIG0_13_app*)buf; - app->setType((*componentFIG0_13)->packet.appType); - if (app->typeLow == FIG0_13_APPTYPE_EPG) { - app->length = 2; - app->xpad = htons(0x0100); - /* xpad used to hold two bytes of EPG profile information - 01 = basic profile - 00 = list terminator */ - } - else { - app->length = 0; - } - buf += 2 + app->length; - remaining -= 2 + app->length; - fig0->Length += 2 + app->length; - } - } - - if (componentFIG0_13 == ensemble->components.end()) { - componentFIG0_13 = ensemble->components.begin(); - - // The full database is sent every second full loop - fs.complete_fig_transmitted = m_transmit_programme; - - m_transmit_programme = not m_transmit_programme; - // Alternate between data and and programme FIG0/13, - // do not mix fig0 with PD=0 with extension 13 stuff - // that actually needs PD=1, and vice versa - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/17 PTy =========== - -FIG0_17::FIG0_17(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false) -{ -} - -FillStatus FIG0_17::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - ssize_t remaining = max_size; - - if (not m_initialised) { - serviceFIG0_17 = m_rti->ensemble->services.end(); - m_initialised = true; - } - - auto ensemble = m_rti->ensemble; - - FIGtype0* fig0 = NULL; - - for (; serviceFIG0_17 != ensemble->services.end(); - ++serviceFIG0_17) { - - if ((*serviceFIG0_17)->pty == 0) { - continue; - } - - const int required_size = 4; - - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - 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; - } - else if (remaining < required_size) { - break; - } - - auto fig0_17 = (FIGtype0_17*)buf; - fig0_17->SId = htons((*serviceFIG0_17)->id); - fig0_17->SD = 1; // We only transmit dynamic PTy - fig0_17->rfa1 = 0; - fig0_17->rfu1 = 0; - fig0_17->rfa2_low = 0; - fig0_17->rfa2_high = 0; - fig0_17->rfu2 = 0; - fig0_17->IntCode = (*serviceFIG0_17)->pty; - - fig0->Length += 4; - buf += 4; - remaining -= 4; - } - - if (serviceFIG0_17 == ensemble->services.end()) { - serviceFIG0_17 = ensemble->services.begin(); - fs.complete_fig_transmitted = true; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/18 =========== - -FIG0_18::FIG0_18(FIGRuntimeInformation *rti) : - m_rti(rti), - m_initialised(false) -{ -} - -FillStatus FIG0_18::fill(uint8_t *buf, size_t max_size) -{ - FillStatus fs; - ssize_t remaining = max_size; - - if (not m_initialised) { - service = m_rti->ensemble->services.end(); - m_initialised = true; - } - - auto ensemble = m_rti->ensemble; - - FIGtype0* fig0 = NULL; - - for (; service != ensemble->services.end(); - ++service) { - - if ( (*service)->ASu == 0 ) { - continue; - } - - const ssize_t numclusters = (*service)->clusters.size(); - - const int required_size = 5 + numclusters; - - - if (fig0 == NULL) { - if (remaining < 2 + required_size) { - break; - } - - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 18; - buf += 2; - remaining -= 2; - } - else if (remaining < required_size) { - break; - } - - auto programme = (FIGtype0_18*)buf; - programme->SId = htons((*service)->id); - programme->ASu = htons((*service)->ASu); - programme->Rfa = 0; - programme->NumClusters = numclusters; - buf += 5; - - for (uint8_t cluster : (*service)->clusters) { - *(buf++) = cluster; - } - - fig0->Length += 5 + numclusters; - remaining -= 5 + numclusters; - } - - if (service == ensemble->services.end()) { - service = ensemble->services.begin(); - fs.complete_fig_transmitted = true; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -//=========== FIG 0/19 =========== - -FIG0_19::FIG0_19(FIGRuntimeInformation *rti) : - m_rti(rti) -{ } - -FillStatus FIG0_19::fill(uint8_t *buf, size_t max_size) -{ - using namespace std; - - update_state(); - - FillStatus fs; - ssize_t remaining = max_size; - - auto ensemble = m_rti->ensemble; - - FIGtype0* fig0 = NULL; - - // Combine all clusters into one list - set<AnnouncementCluster*> allclusters; - for (const auto& cluster : m_new_announcements) { - allclusters.insert(cluster.first.get()); - } - for (const auto& cluster : m_repeated_announcements) { - allclusters.insert(cluster.get()); - } - for (const auto& cluster : m_disabled_announcements) { - allclusters.insert(cluster.first.get()); - } - - const int length_0_19 = 4; - fs.complete_fig_transmitted = true; - for (auto& cluster : allclusters) { - - if (fig0 == NULL) { - if (remaining < 2 + length_0_19) { - fs.complete_fig_transmitted = false; - break; - } - - fig0 = (FIGtype0*)buf; - fig0->FIGtypeNumber = 0; - fig0->Length = 1; - fig0->CN = 0; - fig0->OE = 0; - fig0->PD = 0; - fig0->Extension = 19; - 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; - if (cluster->is_active()) { - fig0_19->ASw = htons(cluster->flags); - } - else { - fig0_19->ASw = 0; - } - fig0_19->NewFlag = 1; - fig0_19->RegionFlag = 0; - fig0_19->SubChId = 0; - bool found = false; - - for (const auto& subchannel : ensemble->subchannels) { - if (subchannel->uid == cluster->subchanneluid) { - fig0_19->SubChId = subchannel->id; - found = true; - break; - } - } - if (not found) { - etiLog.level(warn) << "FIG0/19: could not find subchannel " << - cluster->subchanneluid << " for cluster " << - (int)cluster->cluster_id; - continue; - } - - fig0->Length += length_0_19; - buf += length_0_19; - remaining -= length_0_19; - } - - fs.num_bytes_written = max_size - remaining; - return fs; -} - -void FIG0_19::update_state() -{ - auto ensemble = m_rti->ensemble; - - // We are called every 24ms, and must timeout after 2s - const int timeout = 2000/24; - -//#define DEBUG_FIG0_19 -#ifdef DEBUG_FIG0_19 - etiLog.level(info) << " FIG0/19 new"; - for (const auto& cluster : m_new_announcements) { - etiLog.level(info) << " " << cluster.first->tostring() - << ": " << cluster.second; - } - etiLog.level(info) << " FIG0/19 repeated"; - for (const auto& cluster : m_repeated_announcements) { - etiLog.level(info) << " " << cluster->tostring(); - } - etiLog.level(info) << " FIG0/19 disabled"; - for (const auto& cluster : m_disabled_announcements) { - etiLog.level(info) << " " << cluster.first->tostring() - << ": " << cluster.second; - } - - etiLog.level(info) << " FIG0/19 in ensemble"; -#endif - - for (const auto& cluster : ensemble->clusters) { -#ifdef DEBUG_FIG0_19 - etiLog.level(info) << " " << cluster->tostring(); -#endif - if (cluster->is_active()) { - if (m_repeated_announcements.count(cluster) > 0) { - // We are currently announcing this cluster - continue; - } - - if (m_new_announcements.count(cluster) > 0) { - // We are currently announcing this cluster at a - // fast rate. Handle timeout: - m_new_announcements[cluster] -= 1; - if (m_new_announcements[cluster] <= 0) { - m_repeated_announcements.insert(cluster); - m_new_announcements.erase(cluster); - } - continue; - } - - // unlikely - if (m_disabled_announcements.count(cluster) > 0) { - m_new_announcements[cluster] = timeout; - m_disabled_announcements.erase(cluster); - continue; - } - - // It's a new announcement! - m_new_announcements[cluster] = timeout; - } - else { // Not active - if (m_disabled_announcements.count(cluster) > 0) { - m_disabled_announcements[cluster] -= 1; - if (m_disabled_announcements[cluster] <= 0) { - m_disabled_announcements.erase(cluster); - } - continue; - } - - if (m_repeated_announcements.count(cluster) > 0) { - // We are currently announcing this cluster - m_disabled_announcements[cluster] = timeout; - m_repeated_announcements.erase(cluster); - continue; - } - - // unlikely - if (m_new_announcements.count(cluster) > 0) { - // We are currently announcing this cluster at a - // fast rate. We must stop announcing it - m_disabled_announcements[cluster] = timeout; - m_new_announcements.erase(cluster); - continue; - } - } - } -} - -FIG_rate FIG0_19::repetition_rate(void) -{ - if ( m_new_announcements.size() > 0 or - m_disabled_announcements.size() ) { - return FIG_rate::A_B; - } - else { - return FIG_rate::B; - } -} - -} // namespace FIC - diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h index 0109219..446e1ac 100644 --- a/src/fig/FIG0.h +++ b/src/fig/FIG0.h @@ -25,309 +25,18 @@ #pragma once -#include <cstdint> -#include <map> -#include <set> -#include <vector> -#include <list> - -#include "fig/FIG.h" - -namespace FIC { - -// FIG type 0/0, Multiplex Configuration Info (MCI), -// Ensemble information -class FIG0_0 : public IFIG -{ - public: - FIG0_0(FIGRuntimeInformation* rti) : - m_rti(rti) {} - virtual FillStatus 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 FillStatus 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*> subchannels; - std::vector<DabSubchannel*>::iterator subchannelFIG0_1; - - uint8_t m_watermarkData[128]; - size_t m_watermarkSize; - size_t m_watermarkPos; -}; - -// 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 FillStatus 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; - bool m_inserting_audio_not_data; - std::vector<std::shared_ptr<DabService> > m_audio_services; - std::vector<std::shared_ptr<DabService> > m_data_services; - 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 FillStatus 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; - bool m_initialised; - std::vector<DabComponent*>::iterator componentFIG0_3; -}; - -// FIG type 0/5 -// The service component language feature is used to signal a language -// associated with a service component; the spoken language of an audio -// component or the language of the content of a data component. This -// information can be used for user selection or display. The feature is -// encoded in Extension 5 of FIG type 0 (FIG 0/5). -class FIG0_5 : public IFIG -{ - public: - FIG0_5(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 5; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - std::vector<DabComponent*>::iterator componentFIG0_5; -}; - -// FIG type 0/6 -// Service Linking -// -// This feature shall use the SIV signalling (see clause 5.2.2.1). The database -// shall be divided by use of a database key. Changes to the database shall be -// signalled using the CEI. The first service in the list of services in each -// part of the database, as divided by the database key, shall be a service -// carried in the ensemble. This service is called the key service. -// -// The database key comprises the OE and P/D flags and the S/H, ILS, and LSN -// fields. -class FIG0_6 : public IFIG -{ - public: - FIG0_6(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::E; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 6; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - std::list<std::shared_ptr<LinkageSet> >::iterator linkageSetFIG0_6; -}; - -// FIG0/6 needs a change indicator, which is a short-form FIG (i.e. without the list) -// and with C/N 1. Since this has another rate, it's implemented in another class. -// -// This is signalled once per second for a period of five seconds -// (TS 103 176 5.2.4.3). -class FIG0_6_CEI : public IFIG -{ - public: - FIG0_6_CEI(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 6; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - std::list<std::shared_ptr<LinkageSet> >::iterator linkageSetFIG0_6; -}; - -// FIG type 0/8 -// The Extension 8 of FIG type 0 (FIG 0/8) provides information to link -// together the service component description that is valid within the ensemble -// to a service component description that is valid in other ensembles -class FIG0_8 : public IFIG -{ - public: - FIG0_8(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 8; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - bool m_transmit_programme; - std::vector<DabComponent*>::iterator componentFIG0_8; -}; - -// FIG type 0/9 -// The Country, LTO and International table feature defines the local time -// offset, the International Table and the Extended Country Code (ECC) -class FIG0_9 : public IFIG -{ - public: - FIG0_9(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 9; } - - private: - FIGRuntimeInformation *m_rti; -}; - - -// FIG type 0/10 -// The date and time feature is used to signal a location-independent timing -// reference in UTC format. -class FIG0_10 : public IFIG -{ - public: - FIG0_10(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 10; } - - private: - FIGRuntimeInformation *m_rti; -}; - -// FIG type 0/13 -// User Application Information -class FIG0_13 : public IFIG -{ - public: - FIG0_13(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 13; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - bool m_transmit_programme; - std::vector<DabComponent*>::iterator componentFIG0_13; -}; - -// FIG type 0/17 -// Programme Type (PTy) -class FIG0_17 : public IFIG -{ - public: - FIG0_17(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - 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; -}; - -// FIG type 0/18 -class FIG0_18 : public IFIG -{ - public: - FIG0_18(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 18; } - - private: - FIGRuntimeInformation *m_rti; - bool m_initialised; - std::vector<std::shared_ptr<DabService> >::iterator service; -}; - -// FIG type 0/19 -class FIG0_19 : public IFIG -{ - public: - FIG0_19(FIGRuntimeInformation* rti); - virtual FillStatus fill(uint8_t *buf, size_t max_size); - virtual FIG_rate repetition_rate(void); - - virtual const int figtype(void) const { return 0; } - virtual const int figextension(void) const { return 19; } - - private: - FIGRuntimeInformation *m_rti; - - void update_state(void); - - /* When a new announcement gets active, it is moved into the list - * of new announcements, and gets transmitted at a faster rate for - * two seconds. - * Same for recently disabled announcements. - */ - - /* Map of cluster to frame count */ - std::map< - std::shared_ptr<AnnouncementCluster>,int> m_new_announcements; - - std::set< - std::shared_ptr<AnnouncementCluster> > m_repeated_announcements; - - /* Map of cluster to frame count */ - std::map< - std::shared_ptr<AnnouncementCluster>,int> m_disabled_announcements; -}; - -} // namespace FIC +#include "fig/FIG0structs.h" +#include "fig/FIG0_0.h" +#include "fig/FIG0_1.h" +#include "fig/FIG0_2.h" +#include "fig/FIG0_3.h" +#include "fig/FIG0_5.h" +#include "fig/FIG0_6.h" +#include "fig/FIG0_8.h" +#include "fig/FIG0_9.h" +#include "fig/FIG0_10.h" +#include "fig/FIG0_13.h" +#include "fig/FIG0_17.h" +#include "fig/FIG0_18.h" +#include "fig/FIG0_19.h" diff --git a/src/fig/FIG0_0.cpp b/src/fig/FIG0_0.cpp new file mode 100644 index 0000000..b4b0b3a --- /dev/null +++ b/src/fig/FIG0_0.cpp @@ -0,0 +1,64 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_0.h" +#include "utils.h" + +namespace FIC { + +//=========== FIG 0/0 =========== + +FillStatus FIG0_0::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + + if (max_size < 6) { + fs.num_bytes_written = 0; + return fs; + } + + 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); + + fs.complete_fig_transmitted = true; + fs.num_bytes_written = 6; + return fs; +} + +} + diff --git a/src/fig/FIG0_0.h b/src/fig/FIG0_0.h new file mode 100644 index 0000000..a5310c8 --- /dev/null +++ b/src/fig/FIG0_0.h @@ -0,0 +1,51 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/0, Multiplex Configuration Info (MCI), +// Ensemble information +class FIG0_0 : public IFIG +{ + public: + FIG0_0(FIGRuntimeInformation* rti) : + m_rti(rti) {} + virtual FillStatus 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; +}; + +} diff --git a/src/fig/FIG0_1.cpp b/src/fig/FIG0_1.cpp new file mode 100644 index 0000000..6ed40dd --- /dev/null +++ b/src/fig/FIG0_1.cpp @@ -0,0 +1,209 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_1.h" +#include "utils.h" + +namespace FIC { + +FIG0_1::FIG0_1(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_watermarkSize(0), + m_watermarkPos(0) +{ + uint8_t buffer[sizeof(m_watermarkData) / 2]; + snprintf((char*)buffer, sizeof(buffer), + "%s %s, %s %s", + PACKAGE_NAME, +#if defined(GITVERSION) + GITVERSION, +#else + PACKAGE_VERSION, +#endif + __DATE__, __TIME__); + + memset(m_watermarkData, 0, sizeof(m_watermarkData)); + m_watermarkData[0] = 0x55; // Sync + m_watermarkData[1] = 0x55; + m_watermarkSize = 16; + for (unsigned i = 0; i < strlen((char*)buffer); ++i) { + for (int j = 0; j < 8; ++j) { + uint8_t bit = (buffer[m_watermarkPos >> 3] >> (7 - (m_watermarkPos & 0x07))) & 1; + m_watermarkData[m_watermarkSize >> 3] |= bit << (7 - (m_watermarkSize & 0x07)); + ++m_watermarkSize; + bit = 1; + m_watermarkData[m_watermarkSize >> 3] |= bit << (7 - (m_watermarkSize & 0x07)); + ++m_watermarkSize; + ++m_watermarkPos; + } + } + m_watermarkPos = 0; +} + +FillStatus FIG0_1::fill(uint8_t *buf, size_t max_size) +{ +#define FIG0_1_TRACE discard + + FillStatus fs; + size_t remaining = max_size; + + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill initialised=" << + (m_initialised ? 1 : 0); + + const int watermark_bit = (m_watermarkData[m_watermarkPos >> 3] >> + (7 - (m_watermarkPos & 0x07))) & 1; + + const bool iterate_forward = (watermark_bit == 1); + + if (not m_initialised) { + m_initialised = true; + + subchannels = m_rti->ensemble->subchannels; + + if (not iterate_forward) { + std::reverse(subchannels.begin(), subchannels.end()); + } + subchannelFIG0_1 = subchannels.begin(); + } + + if (max_size < 6) { + return fs; + } + + FIGtype0_1 *figtype0_1 = NULL; + + // Rotate through the subchannels until there is no more + // space in the FIG0/1 + for (; subchannelFIG0_1 != subchannels.end(); ++subchannelFIG0_1 ) { + size_t subch_iter_ix = std::distance(subchannels.begin(), subchannelFIG0_1); + + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill loop ix=" << subch_iter_ix; + + dabProtection* protection = &(*subchannelFIG0_1)->protection; + + if (figtype0_1 == NULL) { + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill header " << + (protection->form == UEP ? "UEP " : "EEP ") << remaining; + + if ( (protection->form == UEP && remaining < 2 + 3) || + (protection->form == EEP && remaining < 2 + 4) ) { + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill no space for header"; + 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) ) { + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill no space for fig " << + (protection->form == UEP ? "UEP " : "EEP ") << remaining; + 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; + + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill insert UEP id=" << + (int)fig0_1subchShort->SubChId << " rem=" << remaining + << " ix=" << subch_iter_ix; + } + 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 = + (*subchannelFIG0_1)->getSizeCu() / 256; + fig0_1subchLong1->Sub_ChannelSize_low = + (*subchannelFIG0_1)->getSizeCu() % 256; + + buf += 4; + remaining -= 4; + figtype0_1->Length += 4; + + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill insert EEP id=" << + (int)fig0_1subchLong1->SubChId << " rem=" << remaining + << " ix=" << subch_iter_ix; + } + } + + size_t subch_iter_ix = std::distance(subchannels.begin(), subchannelFIG0_1); + + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill loop out, rem=" << remaining + << " ix=" << subch_iter_ix; + + if (subchannelFIG0_1 == subchannels.end()) { + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill completed, rem=" << remaining; + m_initialised = false; + fs.complete_fig_transmitted = true; + + m_watermarkPos++; + if (m_watermarkPos == m_watermarkSize) { + m_watermarkPos = 0; + } + } + + fs.num_bytes_written = max_size - remaining; + etiLog.level(FIG0_1_TRACE) << "FIG0_1::fill wrote " << fs.num_bytes_written; + return fs; +} + +} diff --git a/src/fig/FIG0_1.h b/src/fig/FIG0_1.h new file mode 100644 index 0000000..6da4aec --- /dev/null +++ b/src/fig/FIG0_1.h @@ -0,0 +1,58 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// 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 FillStatus 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*> subchannels; + std::vector<DabSubchannel*>::iterator subchannelFIG0_1; + + uint8_t m_watermarkData[128]; + size_t m_watermarkSize; + size_t m_watermarkPos; +}; + +} diff --git a/src/fig/FIG0_10.cpp b/src/fig/FIG0_10.cpp new file mode 100644 index 0000000..e4ff710 --- /dev/null +++ b/src/fig/FIG0_10.cpp @@ -0,0 +1,84 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_10.h" +#include "utils.h" + +namespace FIC { + +FIG0_10::FIG0_10(FIGRuntimeInformation *rti) : + m_rti(rti) +{ +} + +FillStatus FIG0_10::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + auto ensemble = m_rti->ensemble; + size_t remaining = max_size; + + if (remaining < 8) { + fs.num_bytes_written = 0; + return fs; + } + + //Time and country identifier + auto fig0_10 = (FIGtype0_10_LongForm*)buf; + + fig0_10->FIGtypeNumber = 0; + fig0_10->Length = 7; + fig0_10->CN = 0; + fig0_10->OE = 0; + fig0_10->PD = 0; + fig0_10->Extension = 10; + buf += 2; + remaining -= 2; + + tm* timeData; + time_t dab_time_seconds = 0; + uint32_t dab_time_millis = 0; + get_dab_time(&dab_time_seconds, &dab_time_millis); + timeData = gmtime(&dab_time_seconds); + + fig0_10->RFU = 0; + fig0_10->setMJD(gregorian2mjd(timeData->tm_year + 1900, + timeData->tm_mon + 1, + timeData->tm_mday)); + fig0_10->LSI = 0; + fig0_10->ConfInd = 1; + fig0_10->UTC = 1; + fig0_10->setHours(timeData->tm_hour); + fig0_10->Minutes = timeData->tm_min; + fig0_10->Seconds = timeData->tm_sec; + fig0_10->setMilliseconds(dab_time_millis); + buf += 6; + remaining -= 6; + + fs.num_bytes_written = max_size - remaining; + fs.complete_fig_transmitted = true; + return fs; +} + +} diff --git a/src/fig/FIG0_10.h b/src/fig/FIG0_10.h new file mode 100644 index 0000000..2991189 --- /dev/null +++ b/src/fig/FIG0_10.h @@ -0,0 +1,52 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/10 +// The date and time feature is used to signal a location-independent timing +// reference in UTC format. +class FIG0_10 : public IFIG +{ + public: + FIG0_10(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 10; } + + private: + FIGRuntimeInformation *m_rti; +}; + +} diff --git a/src/fig/FIG0_13.cpp b/src/fig/FIG0_13.cpp new file mode 100644 index 0000000..51704f4 --- /dev/null +++ b/src/fig/FIG0_13.cpp @@ -0,0 +1,182 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_13.h" +#include "utils.h" + +namespace FIC { + +FIG0_13::FIG0_13(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_transmit_programme(false) +{ +} + +FillStatus FIG0_13::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + auto ensemble = m_rti->ensemble; + ssize_t remaining = max_size; + + if (not m_initialised) { + componentFIG0_13 = m_rti->ensemble->components.end(); + m_initialised = true; + } + + FIGtype0* fig0 = NULL; + + for (; componentFIG0_13 != ensemble->components.end(); + ++componentFIG0_13) { + + auto subchannel = getSubchannel(ensemble->subchannels, + (*componentFIG0_13)->subchId); + + if (subchannel == ensemble->subchannels.end()) { + etiLog.log(error, + "Subchannel %i does not exist for component " + "of service %i\n", + (*componentFIG0_13)->subchId, + (*componentFIG0_13)->serviceId); + throw MuxInitException(); + } + + 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; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 13; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + FIG0_13_shortAppInfo* info = (FIG0_13_shortAppInfo*)buf; + info->SId = htonl((*componentFIG0_13)->serviceId) >> 16; + info->SCIdS = (*componentFIG0_13)->SCIdS; + info->No = 1; + buf += 3; + remaining -= 3; + fig0->Length += 3; + + FIG0_13_app* app = (FIG0_13_app*)buf; + app->setType((*componentFIG0_13)->audio.uaType); + app->length = 2; + app->xpad = htons(0x0c3c); + /* xpad meaning + CA = 0 + CAOrg = 0 + Rfu = 0 + AppTy(5) = 12 (MOT, start of X-PAD data group) + DG = 0 (MSC data groups used) + Rfu = 0 + DSCTy(6) = 60 (MOT) + */ + + buf += 2 + app->length; + remaining -= 2 + app->length; + fig0->Length += 2 + app->length; + } + else if (!m_transmit_programme && + (*subchannel)->type == subchannel_type_t::Packet && + (*componentFIG0_13)->packet.appType != 0xffff) { + + const int required_size = 5+2+2; + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 1; + fig0->Extension = 13; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + FIG0_13_longAppInfo* info = (FIG0_13_longAppInfo*)buf; + info->SId = htonl((*componentFIG0_13)->serviceId); + info->SCIdS = (*componentFIG0_13)->SCIdS; + info->No = 1; + buf += 5; + remaining -= 5; + fig0->Length += 5; + + FIG0_13_app* app = (FIG0_13_app*)buf; + app->setType((*componentFIG0_13)->packet.appType); + if (app->typeLow == FIG0_13_APPTYPE_EPG) { + app->length = 2; + app->xpad = htons(0x0100); + /* xpad used to hold two bytes of EPG profile information + 01 = basic profile + 00 = list terminator */ + } + else { + app->length = 0; + } + buf += 2 + app->length; + remaining -= 2 + app->length; + fig0->Length += 2 + app->length; + } + } + + if (componentFIG0_13 == ensemble->components.end()) { + componentFIG0_13 = ensemble->components.begin(); + + // The full database is sent every second full loop + fs.complete_fig_transmitted = m_transmit_programme; + + m_transmit_programme = not m_transmit_programme; + // Alternate between data and and programme FIG0/13, + // do not mix fig0 with PD=0 with extension 13 stuff + // that actually needs PD=1, and vice versa + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_13.h b/src/fig/FIG0_13.h new file mode 100644 index 0000000..4c29278 --- /dev/null +++ b/src/fig/FIG0_13.h @@ -0,0 +1,54 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/13 +// User Application Information +class FIG0_13 : public IFIG +{ + public: + FIG0_13(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 13; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + bool m_transmit_programme; + std::vector<DabComponent*>::iterator componentFIG0_13; +}; + +} diff --git a/src/fig/FIG0_17.cpp b/src/fig/FIG0_17.cpp new file mode 100644 index 0000000..2f5f03e --- /dev/null +++ b/src/fig/FIG0_17.cpp @@ -0,0 +1,103 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_17.h" +#include "utils.h" + +namespace FIC { + +FIG0_17::FIG0_17(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_17::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + + if (not m_initialised) { + serviceFIG0_17 = m_rti->ensemble->services.end(); + m_initialised = true; + } + + auto ensemble = m_rti->ensemble; + + FIGtype0* fig0 = NULL; + + for (; serviceFIG0_17 != ensemble->services.end(); + ++serviceFIG0_17) { + + if ((*serviceFIG0_17)->pty == 0) { + continue; + } + + const int required_size = 4; + + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + 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; + } + else if (remaining < required_size) { + break; + } + + auto fig0_17 = (FIGtype0_17*)buf; + fig0_17->SId = htons((*serviceFIG0_17)->id); + fig0_17->SD = 1; // We only transmit dynamic PTy + fig0_17->rfa1 = 0; + fig0_17->rfu1 = 0; + fig0_17->rfa2_low = 0; + fig0_17->rfa2_high = 0; + fig0_17->rfu2 = 0; + fig0_17->IntCode = (*serviceFIG0_17)->pty; + + fig0->Length += 4; + buf += 4; + remaining -= 4; + } + + if (serviceFIG0_17 == ensemble->services.end()) { + serviceFIG0_17 = ensemble->services.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_17.h b/src/fig/FIG0_17.h new file mode 100644 index 0000000..f2861d8 --- /dev/null +++ b/src/fig/FIG0_17.h @@ -0,0 +1,53 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/17 +// Programme Type (PTy) +class FIG0_17 : public IFIG +{ + public: + FIG0_17(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + 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; +}; + +} diff --git a/src/fig/FIG0_18.cpp b/src/fig/FIG0_18.cpp new file mode 100644 index 0000000..9edc3d5 --- /dev/null +++ b/src/fig/FIG0_18.cpp @@ -0,0 +1,106 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_18.h" +#include "utils.h" + +namespace FIC { + +FIG0_18::FIG0_18(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_18::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + + if (not m_initialised) { + service = m_rti->ensemble->services.end(); + m_initialised = true; + } + + auto ensemble = m_rti->ensemble; + + FIGtype0* fig0 = NULL; + + for (; service != ensemble->services.end(); + ++service) { + + if ( (*service)->ASu == 0 ) { + continue; + } + + const ssize_t numclusters = (*service)->clusters.size(); + + const int required_size = 5 + numclusters; + + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 18; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + auto programme = (FIGtype0_18*)buf; + programme->SId = htons((*service)->id); + programme->ASu = htons((*service)->ASu); + programme->Rfa = 0; + programme->NumClusters = numclusters; + buf += 5; + + for (uint8_t cluster : (*service)->clusters) { + *(buf++) = cluster; + } + + fig0->Length += 5 + numclusters; + remaining -= 5 + numclusters; + } + + if (service == ensemble->services.end()) { + service = ensemble->services.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_18.h b/src/fig/FIG0_18.h new file mode 100644 index 0000000..7712efb --- /dev/null +++ b/src/fig/FIG0_18.h @@ -0,0 +1,52 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/18 +class FIG0_18 : public IFIG +{ + public: + FIG0_18(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 18; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + std::vector<std::shared_ptr<DabService> >::iterator service; +}; + +} diff --git a/src/fig/FIG0_19.cpp b/src/fig/FIG0_19.cpp new file mode 100644 index 0000000..8b9aca8 --- /dev/null +++ b/src/fig/FIG0_19.cpp @@ -0,0 +1,136 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_19.h" +#include "utils.h" + +namespace FIC { + +FIG0_19::FIG0_19(FIGRuntimeInformation *rti) : + m_rti(rti) +{ } + +FillStatus FIG0_19::fill(uint8_t *buf, size_t max_size) +{ + using namespace std; + + auto ensemble = m_rti->ensemble; + + // We are called every 24ms, and must timeout after 2s + const int timeout = 2000/24; + + m_transition.update_state(timeout, ensemble->clusters); + + FillStatus fs; + ssize_t remaining = max_size; + + FIGtype0* fig0 = NULL; + + // Combine all clusters into one list + set<AnnouncementCluster*> allclusters; + for (const auto& cluster : m_transition.new_entries) { + allclusters.insert(cluster.first.get()); + } + for (const auto& cluster : m_transition.repeated_entries) { + allclusters.insert(cluster.get()); + } + for (const auto& cluster : m_transition.disabled_entries) { + allclusters.insert(cluster.first.get()); + } + + const int length_0_19 = 4; + fs.complete_fig_transmitted = true; + for (auto& cluster : allclusters) { + + if (fig0 == NULL) { + if (remaining < 2 + length_0_19) { + fs.complete_fig_transmitted = false; + break; + } + + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 19; + 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; + if (cluster->is_active()) { + fig0_19->ASw = htons(cluster->flags); + } + else { + fig0_19->ASw = 0; + } + fig0_19->NewFlag = 1; + fig0_19->RegionFlag = 0; + fig0_19->SubChId = 0; + bool found = false; + + for (const auto& subchannel : ensemble->subchannels) { + if (subchannel->uid == cluster->subchanneluid) { + fig0_19->SubChId = subchannel->id; + found = true; + break; + } + } + if (not found) { + etiLog.level(warn) << "FIG0/19: could not find subchannel " << + cluster->subchanneluid << " for cluster " << + (int)cluster->cluster_id; + continue; + } + + fig0->Length += length_0_19; + buf += length_0_19; + remaining -= length_0_19; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +FIG_rate FIG0_19::repetition_rate(void) +{ + if ( m_transition.new_entries.size() > 0 or + m_transition.disabled_entries.size() ) { + return FIG_rate::A_B; + } + else { + return FIG_rate::B; + } +} + +} diff --git a/src/fig/FIG0_19.h b/src/fig/FIG0_19.h new file mode 100644 index 0000000..ce76f30 --- /dev/null +++ b/src/fig/FIG0_19.h @@ -0,0 +1,53 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" +#include "fig/TransitionHandler.h" + +namespace FIC { + +// FIG type 0/19 +class FIG0_19 : public IFIG +{ + public: + FIG0_19(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void); + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 19; } + + private: + FIGRuntimeInformation *m_rti; + + TransitionHandler<AnnouncementCluster> m_transition; +}; + +} diff --git a/src/fig/FIG0_2.cpp b/src/fig/FIG0_2.cpp new file mode 100644 index 0000000..04bff60 --- /dev/null +++ b/src/fig/FIG0_2.cpp @@ -0,0 +1,266 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_2.h" +#include "utils.h" + +namespace FIC { + +FIG0_2::FIG0_2(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_inserting_audio_not_data(false) +{ +} + +FillStatus FIG0_2::fill(uint8_t *buf, size_t max_size) +{ +#define FIG0_2_TRACE discard + using namespace std; + + FillStatus fs; + FIGtype0_2 *fig0_2 = NULL; + int cur = 0; + ssize_t remaining = max_size; + + const auto ensemble = m_rti->ensemble; + + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill init " << (m_initialised ? 1 : 0) << + " ********************************"; + + for (const auto& s : ensemble->services) { + // Exclude Fidc type services, TODO unsupported + auto type = s->getType(ensemble); + if (type == subchannel_type_t::Fidc) { + throw invalid_argument("FIG0/2 does not support FIDC"); + } + } + + if (not m_initialised) { + m_audio_services.clear(); + copy_if(ensemble->services.begin(), + ensemble->services.end(), + back_inserter(m_audio_services), + [&](shared_ptr<DabService>& s) { + return s->isProgramme(ensemble); + } ); + + m_data_services.clear(); + copy_if(ensemble->services.begin(), + ensemble->services.end(), + back_inserter(m_data_services), + [&](shared_ptr<DabService>& s) { + return not s->isProgramme(ensemble); + } ); + + m_initialised = true; + m_inserting_audio_not_data = !m_inserting_audio_not_data; + + if (m_inserting_audio_not_data) { + serviceFIG0_2 = m_audio_services.begin(); + } + else { + serviceFIG0_2 = m_data_services.begin(); + } + + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill we have " << + m_audio_services.size() << " audio and " << + m_data_services.size() << " data services. Inserting " << + (m_inserting_audio_not_data ? "AUDIO" : "DATA"); + } + + const auto last_service = m_inserting_audio_not_data ? + m_audio_services.end() : m_data_services.end(); + + // Rotate through the subchannels until there is no more + // space + for (; serviceFIG0_2 != last_service; ++serviceFIG0_2) { + const auto type = (*serviceFIG0_2)->getType(ensemble); + const auto isProgramme = (*serviceFIG0_2)->isProgramme(ensemble); + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill loop SId=%04x %s/%s", + (*serviceFIG0_2)->id, + m_inserting_audio_not_data ? "AUDIO" : "DATA", + type == subchannel_type_t::Audio ? "Audio" : + type == subchannel_type_t::Packet ? "Packet" : + type == subchannel_type_t::DataDmb ? "DataDmb" : + type == subchannel_type_t::Fidc ? "Fidc" : "?"); + + // filter out services which have no components + if ((*serviceFIG0_2)->nbComponent(ensemble->components) == 0) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no components "; + continue; + } + + ++cur; + + const int required_size = isProgramme ? + 3 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components) : + 5 + 2 * (*serviceFIG0_2)->nbComponent(ensemble->components); + + if (fig0_2 == NULL) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header"; + if (remaining < 2 + required_size) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill header no place" << + " rem=" << remaining << " req=" << 2 + required_size; + break; + } + fig0_2 = (FIGtype0_2 *)buf; + + fig0_2->FIGtypeNumber = 0; + fig0_2->Length = 1; + fig0_2->CN = 0; + fig0_2->OE = 0; + fig0_2->PD = isProgramme ? 0 : 1; + fig0_2->Extension = 2; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + etiLog.level(FIG0_2_TRACE) << "FIG0_2::fill no place" << + " rem=" << remaining << " req=" << required_size; + break; + } + + if (type == subchannel_type_t::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; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill audio SId=%04x", + (*serviceFIG0_2)->id); + } + 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; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill data SId=%04x", + (*serviceFIG0_2)->id); + } + + 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); + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp sub=%04x srv=%04x", + (*component)->subchId, (*component)->serviceId); + + 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 subchannel_type_t::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 subchannel_type_t::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 subchannel_type_t::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; + + etiLog.log(FIG0_2_TRACE, "FIG0_2::fill comp length=%d", + fig0_2->Length); + } + } + + if (serviceFIG0_2 == last_service) { + etiLog.log(FIG0_2_TRACE, "FIG0_2::loop reached last"); + m_initialised = false; + fs.complete_fig_transmitted = !m_inserting_audio_not_data; + } + + etiLog.log(FIG0_2_TRACE, "FIG0_2::loop end complete=%d", + fs.complete_fig_transmitted ? 1 : 0); + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_2.h b/src/fig/FIG0_2.h new file mode 100644 index 0000000..4190922 --- /dev/null +++ b/src/fig/FIG0_2.h @@ -0,0 +1,55 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { +// 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 FillStatus 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; + bool m_inserting_audio_not_data; + std::vector<std::shared_ptr<DabService> > m_audio_services; + std::vector<std::shared_ptr<DabService> > m_data_services; + std::vector<std::shared_ptr<DabService> >::iterator serviceFIG0_2; +}; + +} diff --git a/src/fig/FIG0_3.cpp b/src/fig/FIG0_3.cpp new file mode 100644 index 0000000..2e84e20 --- /dev/null +++ b/src/fig/FIG0_3.cpp @@ -0,0 +1,124 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_3.h" +#include "utils.h" + +namespace FIC { + +FIG0_3::FIG0_3(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_3::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + auto ensemble = m_rti->ensemble; + + if (not m_initialised) { + componentFIG0_3 = m_rti->ensemble->components.end(); + m_initialised = true; + } + + FIGtype0 *fig0 = NULL; + + for (; componentFIG0_3 != ensemble->components.end(); + ++componentFIG0_3) { + auto subchannel = getSubchannel(ensemble->subchannels, + (*componentFIG0_3)->subchId); + + if (subchannel == ensemble->subchannels.end()) { + etiLog.log(error, + "Subchannel %i does not exist for component " + "of service %i\n", + (*componentFIG0_3)->subchId, (*componentFIG0_3)->serviceId); + throw MuxInitException(); + } + + if ((*subchannel)->type != subchannel_type_t::Packet) + continue; + + const int required_size = 5 + (m_rti->factumAnalyzer ? 2 : 0); + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 3; + + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + /* 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. + */ + FIGtype0_3 *fig0_3 = (FIGtype0_3*)buf; + fig0_3->setSCId((*componentFIG0_3)->packet.id); + fig0_3->rfa = 0; + fig0_3->SCCA_flag = 0; + // if 0, datagroups are used + fig0_3->DG_flag = !(*componentFIG0_3)->packet.datagroup; + fig0_3->rfu = 0; + fig0_3->DSCTy = (*componentFIG0_3)->type; + fig0_3->SubChId = (*subchannel)->id; + fig0_3->setPacketAddress((*componentFIG0_3)->packet.address); + if (m_rti->factumAnalyzer) { + fig0_3->SCCA = 0; + } + + fig0->Length += 5; + buf += 5; + remaining -= 5; + if (m_rti->factumAnalyzer) { + fig0->Length += 2; + buf += 2; + remaining -= 2; + } + } + + if (componentFIG0_3 == ensemble->components.end()) { + componentFIG0_3 = ensemble->components.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_3.h b/src/fig/FIG0_3.h new file mode 100644 index 0000000..7b77086 --- /dev/null +++ b/src/fig/FIG0_3.h @@ -0,0 +1,54 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// 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 FillStatus 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; + bool m_initialised; + std::vector<DabComponent*>::iterator componentFIG0_3; +}; + +} diff --git a/src/fig/FIG0_5.cpp b/src/fig/FIG0_5.cpp new file mode 100644 index 0000000..8650d29 --- /dev/null +++ b/src/fig/FIG0_5.cpp @@ -0,0 +1,113 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_5.h" +#include "utils.h" + +namespace FIC { + +FIG0_5::FIG0_5(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_5::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + auto ensemble = m_rti->ensemble; + + if (not m_initialised) { + componentFIG0_5 = m_rti->ensemble->components.end(); + m_initialised = true; + } + + FIGtype0* fig0 = NULL; + + for (; componentFIG0_5 != ensemble->components.end(); + ++componentFIG0_5) { + + auto service = getService(*componentFIG0_5, + ensemble->services); + auto subchannel = getSubchannel(ensemble->subchannels, + (*componentFIG0_5)->subchId); + + if (subchannel == ensemble->subchannels.end()) { + etiLog.log(error, + "Subchannel %i does not exist for component " + "of service %i\n", + (*componentFIG0_5)->subchId, + (*componentFIG0_5)->serviceId); + throw MuxInitException(); + } + + if ( (*service)->language == 0) { + continue; + } + + const int required_size = 2; + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 5; + + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + FIGtype0_5_short *fig0_5 = (FIGtype0_5_short*)buf; + + fig0_5->LS = 0; + fig0_5->rfu = 0; + fig0_5->SubChId = (*subchannel)->id; + fig0_5->language = (*service)->language; + + fig0->Length += 2; + buf += 2; + remaining -= 2; + } + + if (componentFIG0_5 == ensemble->components.end()) { + componentFIG0_5 = ensemble->components.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_5.h b/src/fig/FIG0_5.h new file mode 100644 index 0000000..2fc92e7 --- /dev/null +++ b/src/fig/FIG0_5.h @@ -0,0 +1,57 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/5 +// The service component language feature is used to signal a language +// associated with a service component; the spoken language of an audio +// component or the language of the content of a data component. This +// information can be used for user selection or display. The feature is +// encoded in Extension 5 of FIG type 0 (FIG 0/5). +class FIG0_5 : public IFIG +{ + public: + FIG0_5(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 5; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + std::vector<DabComponent*>::iterator componentFIG0_5; +}; + +} diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp new file mode 100644 index 0000000..f404a47 --- /dev/null +++ b/src/fig/FIG0_6.cpp @@ -0,0 +1,204 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_6.h" +#include "utils.h" + +namespace FIC { + +FIG0_6::FIG0_6(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + auto ensemble = m_rti->ensemble; + + if (not m_initialised) { + linkageSetFIG0_6 = m_rti->ensemble->linkagesets.end(); + m_initialised = true; + } + + FIGtype0* fig0 = NULL; + + for (; linkageSetFIG0_6 != ensemble->linkagesets.end(); + ++linkageSetFIG0_6) { + + const bool PD = false; + const bool ILS = (*linkageSetFIG0_6)->international; + + // need to add key service to num_ids + const size_t num_ids = 1 + (*linkageSetFIG0_6)->id_list.size(); + + const size_t headersize = sizeof(struct FIGtype0_6_header); + const int required_size = sizeof(struct FIGtype0_6) + + (num_ids > 0 ? + headersize + (PD == 0 ? (ILS == 0 ? 2*num_ids : 3*num_ids) : 4*num_ids) : + 0); + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = PD; + fig0->Extension = 5; + + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + FIGtype0_6 *fig0_6 = (FIGtype0_6*)buf; + + fig0_6->IdListFlag = (num_ids > 0); + fig0_6->LA = (*linkageSetFIG0_6)->active; + fig0_6->SH = (*linkageSetFIG0_6)->hard; + fig0_6->ILS = ILS; + fig0_6->LSN = (*linkageSetFIG0_6)->lsn; + + fig0->Length += sizeof(struct FIGtype0_6); + buf += sizeof(struct FIGtype0_6); + remaining -= sizeof(struct FIGtype0_6); + + if (num_ids > 0) { + FIGtype0_6_header *header = (FIGtype0_6_header*)buf; + header->rfu = 0; + if (num_ids > 0x0F) { + etiLog.log(error, "Too large number of links for linkage set 0x%04x", + (*linkageSetFIG0_6)->lsn); + throw MuxInitException(); + } + + header->IdLQ = 0; // TODO not only DAB + header->rfa = 0; + header->num_ids = num_ids; + + fig0->Length += headersize; + buf += headersize; + remaining -= headersize; + + // TODO insert key service first + const std::string keyserviceuid =(*linkageSetFIG0_6)->keyservice; + const auto& keyservice = std::find_if( + ensemble->services.begin(), + ensemble->services.end(), + [&](const std::shared_ptr<DabService> srv) { + return srv->uid == keyserviceuid; + }); + + if (keyservice == ensemble->services.end()) { + etiLog.log(error, "Invalid key service %s in linkage set 0x%04x", + keyserviceuid.c_str(), (*linkageSetFIG0_6)->lsn); + throw MuxInitException(); + } + for (const auto& l : (*linkageSetFIG0_6)->id_list) { + if (l.type != ServiceLinkType::DAB) { + etiLog.log(error, "TODO only DAB links supported. (linkage set 0x%04x)", + (*linkageSetFIG0_6)->lsn); + throw MuxInitException(); + } + } + + if (not PD and not ILS) { + buf[0] = (*keyservice)->id >> 8; + buf[1] = (*keyservice)->id & 0xFF; + fig0->Length += 2; + buf += 2; + remaining -= 2; + + for (const auto& l : (*linkageSetFIG0_6)->id_list) { + buf[0] = l.id >> 8; + buf[1] = l.id & 0xFF; + fig0->Length += 2; + buf += 2; + remaining -= 2; + } + } + if (not PD and ILS) { + buf[0] = ensemble->ecc; + buf[1] = (*keyservice)->id >> 8; + buf[2] = (*keyservice)->id & 0xFF; + fig0->Length += 3; + buf += 3; + remaining -= 3; + + for (const auto& l : (*linkageSetFIG0_6)->id_list) { + buf[0] = l.ecc; + buf[1] = l.id >> 8; + buf[2] = l.id & 0xFF; + fig0->Length += 3; + buf += 3; + remaining -= 3; + } + } + else { // PD == true + // TODO if IdLQ is 11, MSB shall be zero + buf[0] = (*keyservice)->id >> 24; + buf[1] = (*keyservice)->id >> 16; + buf[2] = (*keyservice)->id >> 8; + buf[3] = (*keyservice)->id & 0xFF; + fig0->Length += 4; + buf += 4; + remaining -= 4; + + for (const auto& l : (*linkageSetFIG0_6)->id_list) { + buf[0] = l.id >> 24; + buf[1] = l.id >> 16; + buf[2] = l.id >> 8; + buf[3] = l.id & 0xFF; + fig0->Length += 4; + buf += 4; + remaining -= 4; + } + } + } + + fig0->Length += required_size; + buf += required_size; + remaining -= required_size; + } + + if (linkageSetFIG0_6 == ensemble->linkagesets.end()) { + linkageSetFIG0_6 = ensemble->linkagesets.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} + diff --git a/src/fig/FIG0_6.h b/src/fig/FIG0_6.h new file mode 100644 index 0000000..db55c06 --- /dev/null +++ b/src/fig/FIG0_6.h @@ -0,0 +1,85 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <list> +#include <memory> + +#include "fig/FIG0structs.h" +#include "fig/TransitionHandler.h" + +namespace FIC { + +// FIG type 0/6 +// Service Linking +// +// This feature shall use the SIV signalling (see clause 5.2.2.1). The database +// shall be divided by use of a database key. Changes to the database shall be +// signalled using the CEI. The first service in the list of services in each +// part of the database, as divided by the database key, shall be a service +// carried in the ensemble. This service is called the key service. +// +// The database key comprises the OE and P/D flags and the S/H, ILS, and LSN +// fields. +class FIG0_6 : public IFIG +{ + public: + FIG0_6(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::E; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 6; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + std::list<std::shared_ptr<LinkageSet> >::iterator linkageSetFIG0_6; +}; + +// FIG0/6 needs a change indicator, which is a short-form FIG (i.e. without the list) +// and with C/N 1. Since this has another rate, it's implemented in another class. +// +// This is signalled once per second for a period of five seconds +// (TS 103 176 5.2.4.3). +class FIG0_6_CEI : public IFIG +{ + public: + FIG0_6_CEI(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 6; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + std::list<std::shared_ptr<LinkageSet> >::iterator linkageSetFIG0_6; +}; + +} diff --git a/src/fig/FIG0_8.cpp b/src/fig/FIG0_8.cpp new file mode 100644 index 0000000..2d25547 --- /dev/null +++ b/src/fig/FIG0_8.cpp @@ -0,0 +1,204 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_8.h" +#include "utils.h" + +namespace FIC { + +FIG0_8::FIG0_8(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false), + m_transmit_programme(false) +{ +} + +FillStatus FIG0_8::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + auto ensemble = m_rti->ensemble; + ssize_t remaining = max_size; + + if (not m_initialised) { + componentFIG0_8 = m_rti->ensemble->components.end(); + m_initialised = true; + } + + FIGtype0* fig0 = NULL; + + for (; componentFIG0_8 != ensemble->components.end(); + ++componentFIG0_8) { + + auto service = getService(*componentFIG0_8, + ensemble->services); + auto subchannel = getSubchannel(ensemble->subchannels, + (*componentFIG0_8)->subchId); + + if (subchannel == ensemble->subchannels.end()) { + etiLog.log(error, + "Subchannel %i does not exist for component " + "of service %i\n", + (*componentFIG0_8)->subchId, + (*componentFIG0_8)->serviceId); + throw MuxInitException(); + } + + if (m_transmit_programme and (*service)->isProgramme(ensemble)) { + const int required_size = + ((*subchannel)->type == subchannel_type_t::Packet ? 5 : 4); + + if (fig0 == NULL) { + if (remaining < 2 + required_size) { + break; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 0; + fig0->Extension = 8; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet + buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; + buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; + fig0->Length += 2; + buf += 2; + remaining -= 2; + + FIGtype0_8_long* definition = (FIGtype0_8_long*)buf; + memset(definition, 0, 3); + definition->ext = 0; // no rfa + definition->SCIdS = (*componentFIG0_8)->SCIdS; + definition->LS = 1; + definition->setSCId((*componentFIG0_8)->packet.id); + fig0->Length += 3; + buf += 3; // 8 minus rfa + remaining -= 3; + } + else { // Audio, data stream or FIDC + buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; + buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; + + fig0->Length += 2; + buf += 2; + remaining -= 2; + + FIGtype0_8_short* definition = (FIGtype0_8_short*)buf; + memset(definition, 0, 2); + definition->ext = 0; // no rfa + definition->SCIdS = (*componentFIG0_8)->SCIdS; + definition->LS = 0; + definition->MscFic = 0; + definition->Id = (*componentFIG0_8)->subchId; + fig0->Length += 2; + buf += 2; // 4 minus rfa + remaining -= 2; + } + } + else if (!m_transmit_programme and !(*service)->isProgramme(ensemble)) { + // Data + const int required_size = + ((*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; + fig0->CN = 0; + fig0->OE = 0; + fig0->PD = 1; + fig0->Extension = 8; + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + if ((*subchannel)->type == subchannel_type_t::Packet) { // Data packet + buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; + buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; + fig0->Length += 4; + buf += 4; + remaining -= 4; + + FIGtype0_8_long* definition = (FIGtype0_8_long*)buf; + memset(definition, 0, 3); + definition->ext = 0; // no rfa + definition->SCIdS = (*componentFIG0_8)->SCIdS; + definition->LS = 1; + definition->setSCId((*componentFIG0_8)->packet.id); + fig0->Length += 3; + buf += 3; // 8 minus rfa + remaining -= 3; + } + else { // Audio, data stream or FIDC + buf[0] = ((*componentFIG0_8)->serviceId >> 8) & 0xFF; + buf[1] = ((*componentFIG0_8)->serviceId) & 0xFF; + fig0->Length += 4; + buf += 4; + remaining -= 4; + + FIGtype0_8_short* definition = (FIGtype0_8_short*)buf; + memset(definition, 0, 2); + definition->ext = 0; // no rfa + definition->SCIdS = (*componentFIG0_8)->SCIdS; + definition->LS = 0; + definition->MscFic = 0; + definition->Id = (*componentFIG0_8)->subchId; + fig0->Length += 2; + buf += 2; // 4 minus rfa + remaining -= 2; + } + } + } + + if (componentFIG0_8 == ensemble->components.end()) { + componentFIG0_8 = ensemble->components.begin(); + + // The full database is sent every second full loop + fs.complete_fig_transmitted = m_transmit_programme; + + m_transmit_programme = not m_transmit_programme; + // Alternate between data and and programme FIG0/13, + // do not mix fig0 with PD=0 with extension 13 stuff + // that actually needs PD=1, and vice versa + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} diff --git a/src/fig/FIG0_8.h b/src/fig/FIG0_8.h new file mode 100644 index 0000000..600f386 --- /dev/null +++ b/src/fig/FIG0_8.h @@ -0,0 +1,56 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/8 +// The Extension 8 of FIG type 0 (FIG 0/8) provides information to link +// together the service component description that is valid within the ensemble +// to a service component description that is valid in other ensembles +class FIG0_8 : public IFIG +{ + public: + FIG0_8(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 8; } + + private: + FIGRuntimeInformation *m_rti; + bool m_initialised; + bool m_transmit_programme; + std::vector<DabComponent*>::iterator componentFIG0_8; +}; + +} diff --git a/src/fig/FIG0_9.cpp b/src/fig/FIG0_9.cpp new file mode 100644 index 0000000..00c2995 --- /dev/null +++ b/src/fig/FIG0_9.cpp @@ -0,0 +1,83 @@ +/* + 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) 2016 + 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/>. +*/ + +#include "fig/FIG0_9.h" +#include "utils.h" + +namespace FIC { + +FIG0_9::FIG0_9(FIGRuntimeInformation *rti) : + m_rti(rti) {} + +FillStatus FIG0_9::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + auto ensemble = m_rti->ensemble; + size_t remaining = max_size; + + if (remaining < 5) { + fs.num_bytes_written = 0; + return fs; + } + + auto fig0_9 = (FIGtype0_9*)buf; + fig0_9->FIGtypeNumber = 0; + fig0_9->Length = 4; + fig0_9->CN = 0; + fig0_9->OE = 0; + fig0_9->PD = 0; + fig0_9->Extension = 9; + + fig0_9->ext = 0; + fig0_9->rfa1 = 0; // Had a different meaning in EN 300 401 V1.4.1 + + if (ensemble->lto_auto) { + time_t now = time(NULL); + struct tm* ltime = localtime(&now); + time_t now2 = timegm(ltime); + ensemble->lto = (now2 - now) / 1800; + } + + if (ensemble->lto >= 0) { + fig0_9->ensembleLto = ensemble->lto; + } + else { + /* Convert to 1-complement representation */ + fig0_9->ensembleLto = (-ensemble->lto) | (1<<5); + } + + fig0_9->ensembleEcc = ensemble->ecc; + fig0_9->tableId = ensemble->international_table; + buf += 5; + remaining -= 5; + + /* No extended field, no support for services with different ECC */ + + fs.num_bytes_written = max_size - remaining; + fs.complete_fig_transmitted = true; + return fs; +} + +} diff --git a/src/fig/FIG0_9.h b/src/fig/FIG0_9.h new file mode 100644 index 0000000..57b2f7b --- /dev/null +++ b/src/fig/FIG0_9.h @@ -0,0 +1,52 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <vector> + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/9 +// The Country, LTO and International table feature defines the local time +// offset, the International Table and the Extended Country Code (ECC) +class FIG0_9 : public IFIG +{ + public: + FIG0_9(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::B; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 9; } + + private: + FIGRuntimeInformation *m_rti; +}; + +} diff --git a/src/fig/TransitionHandler.h b/src/fig/TransitionHandler.h new file mode 100644 index 0000000..59bbe3c --- /dev/null +++ b/src/fig/TransitionHandler.h @@ -0,0 +1,119 @@ +/* + 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) 2016 + 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/>. +*/ + +#pragma once + +#include <cstdint> +#include <map> +#include <set> +#include <vector> +#include <memory> + +namespace FIC { + +// Some FIGs need to adapt their rate or their contents depending +// on if some data entries are stable or currently undergoing a +// change. The TransitionHandler keeps track of which entries +// are in what state. +template<class T> +class TransitionHandler { + public: + // update_state must be called once per ETI frame, and will + // move entries from new to repeated to disabled depending + // on their is_active() return value. + void update_state(int timeout, std::vector<std::shared_ptr<T> > all_entries) + { + for (const auto& entry : all_entries) { + if (entry->is_active()) { + if (repeated_entries.count(entry) > 0) { + // We are currently announcing this entry + continue; + } + + if (new_entries.count(entry) > 0) { + // We are currently announcing this entry at a + // fast rate. Handle timeout: + new_entries[entry] -= 1; + if (new_entries[entry] <= 0) { + repeated_entries.insert(entry); + new_entries.erase(entry); + } + continue; + } + + // unlikely + if (disabled_entries.count(entry) > 0) { + new_entries[entry] = timeout; + disabled_entries.erase(entry); + continue; + } + + // It's a new entry! + new_entries[entry] = timeout; + } + else { // Not active + if (disabled_entries.count(entry) > 0) { + disabled_entries[entry] -= 1; + if (disabled_entries[entry] <= 0) { + disabled_entries.erase(entry); + } + continue; + } + + if (repeated_entries.count(entry) > 0) { + // We are currently announcing this entry + disabled_entries[entry] = timeout; + repeated_entries.erase(entry); + continue; + } + + // unlikely + if (new_entries.count(entry) > 0) { + // We are currently announcing this entry at a + // fast rate. We must stop announcing it + disabled_entries[entry] = timeout; + new_entries.erase(entry); + continue; + } + } + } + } + // The FIG that needs the information about what state an entry is in + // can read from the following data structures. It shall not modify them. + + /* Map to frame count */ + std::map< + std::shared_ptr<T>,int> new_entries; + + std::set< + std::shared_ptr<T> > repeated_entries; + + /* Map to frame count */ + std::map< + std::shared_ptr<T>,int> disabled_entries; +}; + +} // namespace FIC + |