diff options
-rw-r--r-- | doc/advanced.mux | 8 | ||||
-rw-r--r-- | doc/example.mux | 11 | ||||
-rw-r--r-- | src/ConfigParser.cpp | 17 | ||||
-rw-r--r-- | src/DabMultiplexer.cpp | 87 | ||||
-rw-r--r-- | src/MuxElements.cpp | 10 | ||||
-rw-r--r-- | src/MuxElements.h | 51 |
6 files changed, 131 insertions, 53 deletions
diff --git a/doc/advanced.mux b/doc/advanced.mux index 1034357..bcfcc9a 100644 --- a/doc/advanced.mux +++ b/doc/advanced.mux @@ -72,11 +72,9 @@ ensemble { ; 1 corresponds to the PTy used in RDS ; 2 corresponds to program types used in north america - ;reconfig-counter 1 ; Uncomment this option to enable FIG0/7, which specifies that - ; the ensemble is compliant to EN 300 401 version 2 - ; This setting sets the Count field of FIG0/7, which is a - ; modulo-1024 binary counter that increments by one for every multiplex reconfiguration. - + ; Enable FIG0/7, which specifies that the ensemble is compliant to EN 300 401 version 2. + ; For more options see doc/advanced.mux + reconfig-counter hash ; all labels are maximum 16 characters in length label "OpenDigitalRadio" diff --git a/doc/example.mux b/doc/example.mux index 3284808..862906f 100644 --- a/doc/example.mux +++ b/doc/example.mux @@ -109,6 +109,17 @@ ensemble { ; or ;local-time-offset 1 ; in hours, supports half-hour offsets + ; The presence of reconfig-counter enables FIG0/7, which specifies that + ; the ensemble is compliant to EN 300 401 version 2. + ; You can either set a number which will be used for the Count field in FIG0/7, + ;reconfig-counter 23 + ; or set + reconfig-counter hash + ; to let ODR-DabMux calculate a hash that depends on your multiplex configuration, + ; ensuring that when you change the configuration, the FIG 0/7 Count also changes + ; + ; Leave the option commented-out if you do not wish to transmit FIG 0/7. + ; If you want to run your machine in UTC time, but still take advantage of the ; automatic calculation of the local time offset, set the environment variable TZ ; to your timezone (e.g. TZ=Europe/Rome) before you launch ODR-DabMux 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<string>("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<string> 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<uint32_t> 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<uint16_t*>(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<std::shared_ptr<DabOutput> >& 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 |