From 5340215304193f18af3bc76c7ae7a6a79f008339 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 11 Mar 2020 14:58:05 +0100 Subject: Implement a hash function to calculate FIG 0/7 Count field This might not be strictly standards compliant, but it avoids having to save state across mux restarts and doesn't place the burden of incrementing the number on the operator. --- src/ConfigParser.cpp | 17 +++++++++- src/DabMultiplexer.cpp | 87 +++++++++++++++++++++++++------------------------- src/MuxElements.cpp | 10 ++++++ src/MuxElements.h | 51 +++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 8da05ef..4240add 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -420,7 +420,22 @@ static void parse_general(ptree& pt, } ensemble->international_table = pt_ensemble.get("international-table", ensemble->international_table); - ensemble->reconfig_counter = pt_ensemble.get("reconfig-counter", ensemble->reconfig_counter); + + bool reconfig_counter_is_hash = false; + try { + if (pt_ensemble.get("reconfig-counter") == "hash") { + reconfig_counter_is_hash = true; + } + } + catch (const ptree_error &e) { + } + + if (reconfig_counter_is_hash) { + ensemble->reconfig_counter = -2; + } + else { + ensemble->reconfig_counter = pt_ensemble.get("reconfig-counter", ensemble->reconfig_counter); + } string lto_auto = pt_ensemble.get("local-time-offset", ""); if (lto_auto == "auto") { diff --git a/src/DabMultiplexer.cpp b/src/DabMultiplexer.cpp index 2bd8d74..5eca126 100644 --- a/src/DabMultiplexer.cpp +++ b/src/DabMultiplexer.cpp @@ -31,41 +31,6 @@ using namespace std; -// Protection levels and bitrates for UEP. -const unsigned char ProtectionLevelTable[64] = { - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 2, 1, 0, - 4, 3, 1, - 4, 2, 0 -}; - -const unsigned short BitRateTable[64] = { - 32, 32, 32, 32, 32, - 48, 48, 48, 48, 48, - 56, 56, 56, 56, - 64, 64, 64, 64, 64, - 80, 80, 80, 80, 80, - 96, 96, 96, 96, 96, - 112, 112, 112, 112, - 128, 128, 128, 128, 128, - 160, 160, 160, 160, 160, - 192, 192, 192, 192, 192, - 224, 224, 224, 224, 224, - 256, 256, 256, 256, 256, - 320, 320, 320, - 384, 384, 384 -}; - static vector split_pipe_separated_string(const std::string& s) { stringstream ss; @@ -174,6 +139,48 @@ void DabMultiplexer::prepare(bool require_tai_clock) } } + if (ensemble->reconfig_counter == dabEnsemble::RECONFIG_COUNTER_HASH) { + vector data_to_hash; + data_to_hash.push_back(ensemble->id); + data_to_hash.push_back(ensemble->ecc); + + for (const auto& srv : ensemble->services) { + data_to_hash.push_back(srv->id); + data_to_hash.push_back(srv->ecc); + } + + for (const auto& sc : ensemble->components) { + data_to_hash.push_back(sc->serviceId); + data_to_hash.push_back(sc->subchId); + data_to_hash.push_back(sc->type); + data_to_hash.push_back(sc->SCIdS); + } + + + for (const auto& sub : ensemble->subchannels) { + data_to_hash.push_back(sub->id); + data_to_hash.push_back(sub->startAddress); + data_to_hash.push_back(sub->bitrate); + + uint32_t t = 0; + switch (sub->type) { + case subchannel_type_t::DABAudio : t = 1; break; + case subchannel_type_t::DABPlusAudio: t = 2; break; + case subchannel_type_t::DataDmb: t = 3; break; + case subchannel_type_t::Packet: t= 4; break; + } + data_to_hash.push_back(t); + data_to_hash.push_back(sub->protection.to_tpl()); + } + + uint16_t crc_tmp = 0xFFFF; + crc_tmp = crc16(crc_tmp, + reinterpret_cast(data_to_hash.data()), + data_to_hash.size() * sizeof(data_to_hash.data()) / sizeof(uint16_t)); + + ensemble->reconfig_counter = crc_tmp % 1024; + etiLog.level(info) << "Calculated FIG 0/7 Count = " << ensemble->reconfig_counter; + } } @@ -480,20 +487,12 @@ void DabMultiplexer::mux_frame(std::vector >& outputs // number of channels * 4 octets = nb octets total int edi_stream_id = 1; for (auto subchannel : ensemble->subchannels) { - dabProtection* protection = &subchannel->protection; eti_STC *sstc = (eti_STC *) & etiFrame[index]; sstc->SCID = subchannel->id; sstc->startAddress_high = subchannel->startAddress / 256; sstc->startAddress_low = subchannel->startAddress % 256; - // depends on the desired protection form - if (protection->form == UEP) { - sstc->TPL = 0x10 | - ProtectionLevelTable[protection->uep.tableIndex]; - } - else if (protection->form == EEP) { - sstc->TPL = 0x20 | (protection->eep.GetOption() << 2) | protection->level; - } + sstc->TPL = subchannel->protection.to_tpl(); // Sub-channel Stream Length, multiple of 64 bits sstc->STL_high = subchannel->getSizeDWord() / 256; diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index 81466a8..cb2d545 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -400,6 +400,16 @@ vec_sp_component::iterator getComponent( return components.end(); } +uint8_t dabProtection::to_tpl() const +{ + if (form == UEP) { + return 0x10 | ProtectionLevelTable[uep.tableIndex]; + } + else if (form == EEP) { + return 0x20 | (eep.GetOption() << 2) | level; + } + throw logic_error("Invalid protection form"); +} vec_sp_component::iterator getComponent( vec_sp_component& components, diff --git a/src/MuxElements.h b/src/MuxElements.h index ea7fee5..98de70e 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -44,6 +44,43 @@ #include "RemoteControl.h" #include "Eti.h" +// Protection levels and bitrates for UEP. +const unsigned char ProtectionLevelTable[64] = { + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 2, 1, 0, + 4, 3, 1, + 4, 2, 0 +}; + +const unsigned short BitRateTable[64] = { + 32, 32, 32, 32, 32, + 48, 48, 48, 48, 48, + 56, 56, 56, 56, + 64, 64, 64, 64, 64, + 80, 80, 80, 80, 80, + 96, 96, 96, 96, 96, + 112, 112, 112, 112, + 128, 128, 128, 128, 128, + 160, 160, 160, 160, 160, + 192, 192, 192, 192, 192, + 224, 224, 224, 224, 224, + 256, 256, 256, 256, 256, + 320, 320, 320, + 384, 384, 384 +}; + + + class MuxInitException : public std::exception { public: @@ -292,8 +329,13 @@ class dabEnsemble : public RemoteControllable { // 2 corresponds to program types used in north america int international_table = 1; - // Modulo-1024 counter for FIG0/7. Set to -1 to disable FIG0/7 - int reconfig_counter = -1; + // Modulo-1024 counter for FIG0/7. + // Set to RECONFIG_COUNTER_DISABLED to disable FIG0/7. + // Set to RECONFIG_COUNTER_HASH to calculate the counter value using a hash function + // on relevant ensemble configuration parameters. + static constexpr int RECONFIG_COUNTER_DISABLED = -1; + static constexpr int RECONFIG_COUNTER_HASH = -2; + int reconfig_counter = RECONFIG_COUNTER_DISABLED; vec_sp_service services; vec_sp_component components; @@ -333,12 +375,15 @@ enum dab_protection_form_t { }; struct dabProtection { - unsigned char level; + uint8_t level; dab_protection_form_t form; union { dabProtectionUEP uep; dabProtectionEEP eep; }; + + // According to ETSI EN 300 799 5.4.1.2 + uint8_t to_tpl() const; }; class DabSubchannel -- cgit v1.2.3