summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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