aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-11 14:58:05 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-11 14:58:05 +0100
commit5340215304193f18af3bc76c7ae7a6a79f008339 (patch)
tree2f702ce20225c8a345df677b223faf387dac6d1b
parentccbb69188c53eb693853969327bd081c73f02552 (diff)
downloaddabmux-5340215304193f18af3bc76c7ae7a6a79f008339.tar.gz
dabmux-5340215304193f18af3bc76c7ae7a6a79f008339.tar.bz2
dabmux-5340215304193f18af3bc76c7ae7a6a79f008339.zip
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.
-rw-r--r--doc/advanced.mux8
-rw-r--r--doc/example.mux11
-rw-r--r--src/ConfigParser.cpp17
-rw-r--r--src/DabMultiplexer.cpp87
-rw-r--r--src/MuxElements.cpp10
-rw-r--r--src/MuxElements.h51
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