summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/servicelinking.mux70
-rw-r--r--src/ConfigParser.cpp205
-rw-r--r--src/Makefile.am3
-rw-r--r--src/MuxElements.h22
-rw-r--r--src/fig/FIG0.h3
-rw-r--r--src/fig/FIG0_21.cpp195
-rw-r--r--src/fig/FIG0_21.h4
-rw-r--r--src/fig/FIG0structs.h11
-rw-r--r--src/fig/FIGCarousel.cpp4
-rw-r--r--src/fig/FIGCarousel.h1
-rw-r--r--src/utils.cpp84
11 files changed, 410 insertions, 192 deletions
diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux
index 38d4ca1..6c491c8 100644
--- a/doc/servicelinking.mux
+++ b/doc/servicelinking.mux
@@ -100,40 +100,48 @@ linking {
}
}
-; According to ETSI TR 101 496-2 Clause 3.6.10
+; According to ETSI TR 101 496-2 Clause 3.6.10.
+; The configuration structure reflects the FIG 0/21 of
+; ETSI EN 300 401 Clause 8.1.8
frequency_information {
- fi_dab_1 {
- range_modulation dab
- continuity true
- frequencies {
- entry_a {
- signal_mode_1 true
- adjacent true
- frequency 234.208
- }
- entry_b {
- signal_mode_1 true
- adjacent true
- frequency 188.928
+ fi_1 {
+ fi_dab_1 {
+ range_modulation dab
+ continuity true
+ eid 0x4fff
+ frequencies {
+ entry_a {
+ signal_mode_1 true
+ adjacent true
+ frequency 234.208
+ }
+ entry_b {
+ signal_mode_1 true
+ adjacent true
+ frequency 188.928
+ }
}
}
+ fi_fm_1 {
+ range_modulation fm
+ continuity true
+ pi_code 0x1234
+ frequencies "87.6 105.2"
+ }
}
- fi_fm_1 {
- range_modulation fm
- continuity true
- frequencies "87.6 105.2"
- }
- fi_drm_3 {
- range_modulation drm
- continuity true
- drm_id 0x12
- frequencies "15.21 22.4"
- }
- fi_amss_4 {
- range_modulation amss
- continuity true
- amss_id 0x33
- frequencies "14.8"
+ fi_2 {
+ fi_drm_3 {
+ range_modulation drm
+ continuity true
+ drm_id 0x12ab45
+ frequencies "15.21 22.4"
+ }
+ fi_amss_4 {
+ range_modulation amss
+ continuity true
+ amss_id 0x33cc88
+ frequencies "14.8"
+ }
}
}
@@ -194,6 +202,6 @@ components {
outputs {
file "file://./test.eti?type=raw"
- throttle "simul://"
+ ;throttle "simul://"
}
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index d230778..8c7e6b4 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -207,93 +207,132 @@ static void parse_freq_info(boost::property_tree::ptree& pt,
using boost::property_tree::ptree;
using boost::property_tree::ptree_error;
- auto pt_fi = pt.get_child_optional("frequency_information");
- if (pt_fi)
+ auto pt_frequency_information = pt.get_child_optional("frequency_information");
+ if (pt_frequency_information)
{
- for (const auto& it : *pt_fi) {
- const string fi_uid = it.first;
- const ptree pt_entry = it.second;
+ for (const auto& it_fi : *pt_frequency_information) {
+ const string fi_uid = it_fi.first;
+ const ptree pt_fi = it_fi.second;
- FrequencyListEntry fle;
+ auto fi = make_shared<FrequencyInformation>();
- string rm_str = pt_entry.get("range_modulation", "");
- if (rm_str == "dab") {
- fle.rm = RangeModulation::dab_ensemble;
- }
- else if (rm_str == "fm") {
- fle.rm = RangeModulation::fm_with_rds;
- }
- else if (rm_str == "drm") {
- fle.rm = RangeModulation::drm;
- }
- else if (rm_str == "amss") {
- fle.rm = RangeModulation::amss;
- }
- else {
- throw runtime_error("Invalid range_modulation: " + rm_str);
- }
+ fi->uid = fi_uid;
- fle.continuity = pt_entry.get<bool>("continuity");
-
- switch (fle.rm) {
- case RangeModulation::dab_ensemble:
- {
- for (const auto& list_it : pt_entry) {
- const string fi_list_uid = list_it.first;
- const ptree pt_list_entry = list_it.second;
-
- FrequencyInfoDab::ListElement el;
- el.frequency = pt_list_entry.get<float>("frequency");
-
- bool signal_mode_1 = pt_list_entry.get("signal_mode_1", false);
- bool adjacent = pt_list_entry.get("adjacent", false);
-
- if (adjacent and signal_mode_1) {
- el.control_field = FrequencyInfoDab::ControlField_e::adjacent_mode1;
- }
- else if (adjacent and not signal_mode_1) {
- el.control_field = FrequencyInfoDab::ControlField_e::adjacent_no_mode;
- }
- if (not adjacent and signal_mode_1) {
- el.control_field = FrequencyInfoDab::ControlField_e::disjoint_mode1;
- }
- else if (not adjacent and not signal_mode_1) {
- el.control_field = FrequencyInfoDab::ControlField_e::disjoint_no_mode;
- }
- fle.fi_dab.frequencies.push_back(el);
- }
- } break;
- case RangeModulation::fm_with_rds:
- {
- std::stringstream frequencies_ss;
- frequencies_ss << pt_entry.get<string>("frequencies");
- for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
- fle.fi_fm.frequencies.push_back(std::stof(freq));
- }
- } break;
- case RangeModulation::drm:
- {
- fle.fi_drm.drm_service_id = hexparse(pt_entry.get<string>("drm_id"));
-
- std::stringstream frequencies_ss;
- frequencies_ss << pt_entry.get<string>("frequencies");
- for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
- fle.fi_drm.frequencies.push_back(std::stof(freq));
- }
- } break;
- case RangeModulation::amss:
- {
- fle.fi_amss.amss_service_id = hexparse(pt_entry.get<string>("amss_id"));
-
- std::stringstream frequencies_ss;
- frequencies_ss << pt_entry.get<string>("frequencies");
- for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
- fle.fi_amss.frequencies.push_back(std::stof(freq));
- }
- } break;
- }
- }
- }
+ for (const auto& it_fle : pt_fi) {
+ const string fle_uid = it_fle.first;
+ const ptree pt_entry = it_fle.second;
+
+ FrequencyListEntry fle;
+
+ fle.uid = fle_uid;
+
+ string rm_str = pt_entry.get("range_modulation", "");
+ if (rm_str == "dab") {
+ fle.rm = RangeModulation::dab_ensemble;
+ }
+ else if (rm_str == "fm") {
+ fle.rm = RangeModulation::fm_with_rds;
+ }
+ else if (rm_str == "drm") {
+ fle.rm = RangeModulation::drm;
+ }
+ else if (rm_str == "amss") {
+ fle.rm = RangeModulation::amss;
+ }
+ else {
+ throw runtime_error("Invalid range_modulation: " + rm_str);
+ }
+
+ fle.continuity = pt_entry.get<bool>("continuity");
+
+ try {
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ {
+ fle.fi_dab.eid = hexparse(pt_entry.get<string>("eid"));
+
+ for (const auto& list_it : pt_entry.get_child("frequencies")) {
+ const string fi_list_uid = list_it.first;
+ const ptree pt_list_entry = list_it.second;
+
+ FrequencyInfoDab::ListElement el;
+ el.uid = fi_list_uid;
+ el.frequency = pt_list_entry.get<float>("frequency");
+
+ bool signal_mode_1 = pt_list_entry.get("signal_mode_1", false);
+ bool adjacent = pt_list_entry.get("adjacent", false);
+
+ if (adjacent and signal_mode_1) {
+ el.control_field = FrequencyInfoDab::ControlField_e::adjacent_mode1;
+ }
+ else if (adjacent and not signal_mode_1) {
+ el.control_field = FrequencyInfoDab::ControlField_e::adjacent_no_mode;
+ }
+ if (not adjacent and signal_mode_1) {
+ el.control_field = FrequencyInfoDab::ControlField_e::disjoint_mode1;
+ }
+ else if (not adjacent and not signal_mode_1) {
+ el.control_field = FrequencyInfoDab::ControlField_e::disjoint_no_mode;
+ }
+ fle.fi_dab.frequencies.push_back(el);
+ }
+ if (fle.fi_dab.frequencies.size() > 7) {
+ throw runtime_error("Too many frequency entries in FI " + fle.uid);
+ }
+ } break;
+ case RangeModulation::fm_with_rds:
+ {
+ fle.fi_fm.pi_code = hexparse(pt_entry.get<string>("pi_code"));
+
+ std::stringstream frequencies_ss;
+ frequencies_ss << pt_entry.get<string>("frequencies");
+ for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
+ fle.fi_fm.frequencies.push_back(std::stof(freq));
+ }
+ if (fle.fi_fm.frequencies.size() > 7) {
+ throw runtime_error("Too many frequency entries in FI " + fle.uid);
+ }
+ } break;
+ case RangeModulation::drm:
+ {
+ fle.fi_drm.drm_service_id = hexparse(pt_entry.get<string>("drm_id"));
+
+ std::stringstream frequencies_ss;
+ frequencies_ss << pt_entry.get<string>("frequencies");
+ for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
+ fle.fi_drm.frequencies.push_back(std::stof(freq));
+ }
+ if (fle.fi_drm.frequencies.size() > 7) {
+ throw runtime_error("Too many frequency entries in FI " + fle.uid);
+ }
+ } break;
+ case RangeModulation::amss:
+ {
+ fle.fi_amss.amss_service_id = hexparse(pt_entry.get<string>("amss_id"));
+
+ std::stringstream frequencies_ss;
+ frequencies_ss << pt_entry.get<string>("frequencies");
+ for (std::string freq; std::getline(frequencies_ss, freq, ' '); ) {
+ fle.fi_amss.frequencies.push_back(std::stof(freq));
+ }
+ if (fle.fi_amss.frequencies.size() > 7) {
+ throw runtime_error("Too many frequency entries in FI " + fle.uid);
+ }
+ } break;
+ } // switch(rm)
+ }
+ catch (ptree_error &e) {
+ throw runtime_error("invalid configuration for FI " + fle_uid);
+ }
+
+ fi->frequency_information.push_back(fle);
+
+ } // for over fle
+
+ ensemble->frequency_information.push_back(fi);
+
+ } // for over fi
+ } // if FI present
}
void parse_ptree(
diff --git a/src/Makefile.am b/src/Makefile.am
index 065477b..4ee8792 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,7 @@
# (Communications Research Center Canada)
# Pascal Charest
#
-# Copyright (C) 2016, Matthias P. Braendli, http://opendigitalradio.org
+# Copyright (C) 2017, Matthias P. Braendli, http://opendigitalradio.org
#
# This file is part of ODR-DabMux.
@@ -95,6 +95,7 @@ odr_dabmux_SOURCES =DabMux.cpp DabMux.h \
fig/FIG0_17.cpp fig/FIG0_17.h \
fig/FIG0_18.cpp fig/FIG0_18.h \
fig/FIG0_19.cpp fig/FIG0_19.h \
+ fig/FIG0_21.cpp fig/FIG0_21.h \
fig/FIG1.cpp fig/FIG1.h \
fig/FIGCarousel.cpp fig/FIGCarousel.h \
fig/TransitionHandler.h \
diff --git a/src/MuxElements.h b/src/MuxElements.h
index 0eabb69..7f1b828 100644
--- a/src/MuxElements.h
+++ b/src/MuxElements.h
@@ -191,7 +191,7 @@ class DabService;
class DabComponent;
class DabSubchannel;
class LinkageSet;
-struct FrequencyListEntry;
+struct FrequencyInformation;
class dabEnsemble : public RemoteControllable {
public:
@@ -231,7 +231,7 @@ class dabEnsemble : public RemoteControllable {
std::vector<std::shared_ptr<AnnouncementCluster> > clusters;
std::vector<std::shared_ptr<LinkageSet> > linkagesets;
- std::vector<std::shared_ptr<FrequencyListEntry> > frequency_information;
+ std::vector<std::shared_ptr<FrequencyInformation> > frequency_information;
};
@@ -487,29 +487,33 @@ struct FrequencyInfoDab {
disjoint_mode1 = 3};
struct ListElement {
+ std::string uid;
ControlField_e control_field;
float frequency;
};
+ uint16_t eid;
std::vector<ListElement> frequencies;
};
struct FrequencyInfoDrm {
- uint8_t drm_service_id;
+ uint32_t drm_service_id;
std::vector<float> frequencies;
};
struct FrequencyInfoFm {
+ uint16_t pi_code;
std::vector<float> frequencies;
};
struct FrequencyInfoAmss {
- uint8_t amss_service_id;
+ uint32_t amss_service_id;
std::vector<float> frequencies;
};
struct FrequencyListEntry {
- uint16_t id;
+ std::string uid;
+
RangeModulation rm;
bool continuity;
@@ -521,6 +525,14 @@ struct FrequencyListEntry {
FrequencyInfoAmss fi_amss;
};
+struct FrequencyInformation {
+ std::string uid;
+
+ // The latest draft spec does not specify the RegionId anymore, it's
+ // now a reserved field.
+ std::vector<FrequencyListEntry> frequency_information;
+};
+
std::vector<DabSubchannel*>::iterator getSubchannel(
std::vector<DabSubchannel*>& subchannels, int id);
diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h
index 446e1ac..d8de751 100644
--- a/src/fig/FIG0.h
+++ b/src/fig/FIG0.h
@@ -3,7 +3,7 @@
2011, 2012 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2016
+ Copyright (C) 2017
Matthias P. Braendli, matthias.braendli@mpb.li
*/
/*
@@ -39,4 +39,5 @@
#include "fig/FIG0_17.h"
#include "fig/FIG0_18.h"
#include "fig/FIG0_19.h"
+#include "fig/FIG0_21.h"
diff --git a/src/fig/FIG0_21.cpp b/src/fig/FIG0_21.cpp
index a89a8a7..51b4a0d 100644
--- a/src/fig/FIG0_21.cpp
+++ b/src/fig/FIG0_21.cpp
@@ -37,45 +37,21 @@ FIG0_21::FIG0_21(FIGRuntimeInformation *rti) :
FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
{
FillStatus fs;
- ssize_t remaining = max_size;
+ size_t remaining = max_size;
auto ensemble = m_rti->ensemble;
if (not m_initialised) {
- freqListEntryFIG0_21 = ensemble->frequency_information.begin();
+ freqInfoFIG0_21 = ensemble->frequency_information.begin();
m_initialised = true;
}
FIGtype0* fig0 = nullptr;
- for (; freqListEntryFIG0_21 != ensemble->frequency_information.end();
- ++freqListEntryFIG0_21) {
+ for (; freqInfoFIG0_21 != ensemble->frequency_information.end();
+ ++freqInfoFIG0_21) {
- size_t num_list_entries_that_fit = 0;
size_t required_size = sizeof(struct FIGtype0_21_header);
- size_t list_entry_size = sizeof(FIGtype0_21_fi_list_header);
- switch ((*freqListEntryFIG0_21)->rm) {
- case RangeModulation::dab_ensemble:
- list_entry_size += (*freqListEntryFIG0_21)->fi_dab.frequencies.size() * 3;
- break;
- case RangeModulation::fm_with_rds:
- list_entry_size += (*freqListEntryFIG0_21)->fi_fm.frequencies.size() * 3;
- break;
- case RangeModulation::amss:
- list_entry_size += 1; // Id field 2
- list_entry_size += (*freqListEntryFIG0_21)->fi_amss.frequencies.size() * 3;
- break;
- case RangeModulation::drm:
- list_entry_size += 1; // Id field 2
- list_entry_size += (*freqListEntryFIG0_21)->fi_drm.frequencies.size() * 3;
- break;
- }
- required_size += list_entry_size;
-
- etiLog.level(debug) << "FIG0/21 " << num_list_entries_that_fit << " entries"
- "will fit";
-
-
if (fig0 == nullptr) {
if (remaining < 2 + required_size) {
break;
@@ -83,8 +59,10 @@ FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
fig0 = (FIGtype0*)buf;
fig0->FIGtypeNumber = 0;
fig0->Length = 1;
+
+ // Database start or continuation flag, EN 300 401 Clause 5.2.2.1 part b)
fig0->CN =
- (freqListEntryFIG0_21 == ensemble->frequency_information.begin() ? 0 : 1);
+ (freqInfoFIG0_21 == ensemble->frequency_information.begin() ? 0 : 1);
fig0->OE = 0;
fig0->PD = false;
fig0->Extension = 21;
@@ -92,49 +70,136 @@ FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
buf += 2;
remaining -= 2;
}
- else if (remaining < required_size) {
- break;
- }
- auto *fig0_21_header = (FIGtype0_21_header*)buf;
- switch ((*freqListEntryFIG0_21)->rm) {
- case RangeModulation::dab_ensemble:
- fig0_21_header->length_fi = (*freqListEntryFIG0_21)->fi_dab.frequencies.size();
- break;
- case RangeModulation::fm_with_rds:
- fig0_21_header->length_fi = (*freqListEntryFIG0_21)->fi_fm.frequencies.size();
- break;
- case RangeModulation::drm:
- fig0_21_header->length_fi = (*freqListEntryFIG0_21)->fi_drm.frequencies.size();
- break;
- case RangeModulation::amss:
- fig0_21_header->length_fi = (*freqListEntryFIG0_21)->fi_amss.frequencies.size();
- break;
+ if (remaining < required_size) {
+ break;
}
- fig0_21_header->rfa = 0;
-#error "Why do we have lists of FI lists? This is confusing"
-
- switch ((*freqListEntryFIG0_21)->rm) {
- case RangeModulation::dab_ensemble:
- for (const auto& freq : (*freqListEntryFIG0_21)->fi_dab.frequencies) {
+ for (const auto& fle : (*freqInfoFIG0_21)->frequency_information) {
+ size_t list_entry_size = sizeof(FIGtype0_21_fi_list_header);
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ list_entry_size += fle.fi_dab.frequencies.size() * 3;
+ break;
+ case RangeModulation::fm_with_rds:
+ list_entry_size += fle.fi_fm.frequencies.size() * 3;
+ break;
+ case RangeModulation::amss:
+ list_entry_size += 1; // Id field 2
+ list_entry_size += fle.fi_amss.frequencies.size() * 3;
+ break;
+ case RangeModulation::drm:
+ list_entry_size += 1; // Id field 2
+ list_entry_size += fle.fi_drm.frequencies.size() * 3;
+ break;
+ }
- }
- break;
- case RangeModulation::fm_with_rds:
- break;
- case RangeModulation::drm:
- break;
- case RangeModulation::amss:
+ if (remaining < list_entry_size) {
break;
- }
+ }
- fig0->Length += sizeof(struct FIGtype0_21_header);
- buf += sizeof(struct FIGtype0_21_header);
- remaining -= sizeof(struct FIGtype0_21_header);
- }
+ auto *fig0_21_header = (FIGtype0_21_header*)buf;
+ fig0_21_header->rfa = 0; // This was RegionId in EN 300 401 V1.4.1
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ fig0_21_header->length_fi = fle.fi_dab.frequencies.size();
+ break;
+ case RangeModulation::fm_with_rds:
+ fig0_21_header->length_fi = fle.fi_fm.frequencies.size();
+ break;
+ case RangeModulation::drm:
+ fig0_21_header->length_fi = fle.fi_drm.frequencies.size();
+ break;
+ case RangeModulation::amss:
+ fig0_21_header->length_fi = fle.fi_amss.frequencies.size();
+ break;
+ }
+
+ fig0->Length += sizeof(struct FIGtype0_21_header);
+ buf += sizeof(struct FIGtype0_21_header);
+ remaining -= sizeof(struct FIGtype0_21_header);
+
+ auto *fi_list_header = (FIGtype0_21_fi_list_header*)buf;
+ fig0->Length += sizeof(struct FIGtype0_21_fi_list_header);
+ buf += sizeof(struct FIGtype0_21_fi_list_header);
+ remaining -= sizeof(struct FIGtype0_21_fi_list_header);
+
+ fi_list_header->continuity = fle.continuity;
+
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ fi_list_header->id = fle.fi_dab.eid;
+ fi_list_header->range_modulation = static_cast<uint8_t>(fle.rm);
+ assert(fle.fi_dab.frequencies.size() < 8);
+ fi_list_header->length_freq_list = fle.fi_dab.frequencies.size();
+
+ for (const auto& freq : fle.fi_dab.frequencies) {
+ auto *field = (FIGtype0_21_fi_dab_entry*)buf;
+ field->control_field = static_cast<uint8_t>(freq.control_field);
+ field->setFreq(static_cast<uint32_t>(
+ freq.frequency * 1000.0f / 16.0f));
+
+ fig0->Length += 3;
+ buf += 3;
+ remaining -= 3;
+ }
+ break;
+ case RangeModulation::fm_with_rds:
+ fi_list_header->id = fle.fi_fm.pi_code;
+
+ for (const auto& freq : fle.fi_fm.frequencies) {
+ // RealFreq = 87.5 MHz + (F * 100kHz)
+ // => F = (RealFreq - 87.5 MHz) / 100kHz
+ // Do the whole calculation in kHz:
+ *buf = (freq * 1000.0f - 87500.0f) / 100.0f;
+ fig0->Length += 1;
+ buf += 1;
+ remaining -= 1;
+ }
+ break;
+ case RangeModulation::drm:
+ fi_list_header->id = (fle.fi_drm.drm_service_id) & 0xFFFF;
+
+ // Id field 2
+ *buf = (fle.fi_drm.drm_service_id >> 16) & 0xFF;
+ fig0->Length += 1;
+ buf += 1;
+ remaining -= 1;
+
+ for (const auto& freq : fle.fi_drm.frequencies) {
+ uint16_t *freq_field = (uint16_t*)buf;
+
+ *freq_field = static_cast<uint16_t>(freq * 1000.0f);
+
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ }
+ break;
+ case RangeModulation::amss:
+ fi_list_header->id = (fle.fi_amss.amss_service_id) & 0xFFFF;
+
+ // Id field 2
+ *buf = (fle.fi_amss.amss_service_id >> 16) & 0xFF;
+ fig0->Length += 1;
+ buf += 1;
+ remaining -= 1;
+
+ for (const auto& freq : fle.fi_amss.frequencies) {
+ uint16_t *freq_field = (uint16_t*)buf;
+
+ *freq_field = static_cast<uint16_t>(freq * 1000.0f);
+
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ }
+ break;
+ }
+ } // for over fle
+ } // for over FI
- if (freqListEntryFIG0_21 == ensemble->frequency_information.end()) {
+ if (freqInfoFIG0_21 == ensemble->frequency_information.end()) {
fs.complete_fig_transmitted = true;
}
diff --git a/src/fig/FIG0_21.h b/src/fig/FIG0_21.h
index dccb475..2542586 100644
--- a/src/fig/FIG0_21.h
+++ b/src/fig/FIG0_21.h
@@ -50,8 +50,8 @@ class FIG0_21 : public IFIG
bool m_initialised;
- std::vector<std::shared_ptr<FrequencyListEntry> >::iterator
- freqListEntryFIG0_21;
+ std::vector<std::shared_ptr<FrequencyInformation> >::iterator
+ freqInfoFIG0_21;
};
}
diff --git a/src/fig/FIG0structs.h b/src/fig/FIG0structs.h
index f06cc0e..ac2f233 100644
--- a/src/fig/FIG0structs.h
+++ b/src/fig/FIG0structs.h
@@ -380,6 +380,17 @@ struct FIGtype0_21_fi_list_header {
uint8_t length_freq_list:3;
} PACKED;
+struct FIGtype0_21_fi_dab_entry {
+ uint8_t control_field:5;
+ uint8_t freqHigh:3;
+ uint16_t freqLow;
+
+ void setFreq(uint32_t freq) {
+ freqHigh = (freq >> 16) & 0x7;
+ freqLow = freq & 0xffff;
+ }
+} PACKED;
+
#ifdef _WIN32
# pragma pack(pop)
#endif
diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp
index ac2a80b..81f2100 100644
--- a/src/fig/FIGCarousel.cpp
+++ b/src/fig/FIGCarousel.cpp
@@ -75,7 +75,8 @@ FIGCarousel::FIGCarousel(std::shared_ptr<dabEnsemble> ensemble) :
m_fig1_4(&m_rti),
m_fig1_5(&m_rti),
m_fig0_18(&m_rti),
- m_fig0_19(&m_rti)
+ m_fig0_19(&m_rti),
+ m_fig0_21(&m_rti)
{
/* Complete MCI except FIG0/8 should be in FIB0.
* EN 300 401 V1.4.1 Clause 6.1
@@ -109,6 +110,7 @@ FIGCarousel::FIGCarousel(std::shared_ptr<dabEnsemble> ensemble) :
load_and_allocate(m_fig1_5, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_18, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_19, FIBAllocation::FIB_ANY);
+ load_and_allocate(m_fig0_21, FIBAllocation::FIB_ANY);
}
void FIGCarousel::load_and_allocate(IFIG& fig, FIBAllocation fib)
diff --git a/src/fig/FIGCarousel.h b/src/fig/FIGCarousel.h
index f52f266..ec1611d 100644
--- a/src/fig/FIGCarousel.h
+++ b/src/fig/FIGCarousel.h
@@ -101,6 +101,7 @@ class FIGCarousel {
FIG1_5 m_fig1_5;
FIG0_18 m_fig0_18;
FIG0_19 m_fig0_19;
+ FIG0_21 m_fig0_21;
};
} // namespace FIC
diff --git a/src/utils.cpp b/src/utils.cpp
index 38e38ec..a2db735 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -3,7 +3,7 @@
2011, 2012 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2016
+ Copyright (C) 2017
Matthias P. Braendli, matthias.braendli@mpb.li
*/
/*
@@ -97,7 +97,7 @@ void header_message()
fprintf(stderr,
"(Communications Research Centre Canada) All rights reserved.\n\n");
fprintf(stderr,
- "Copyright (C) 2016 Matthias P. Braendli\n");
+ "Copyright (C) 2017 Matthias P. Braendli\n");
fprintf(stderr,
"http://opendigitalradio.org\n\n");
@@ -366,9 +366,12 @@ void printSubchannels(vector<DabSubchannel*>& subchannels)
}
}
-static void printLinking(const shared_ptr<dabEnsemble> ensemble)
+static void printLinking(const shared_ptr<dabEnsemble>& ensemble)
{
etiLog.log(info, " Linkage Sets");
+ if (ensemble->linkagesets.empty()) {
+ etiLog.level(info) << " None ";
+ }
for (const auto& ls : ensemble->linkagesets) {
etiLog.level(info) << " set " << ls->get_name();
@@ -402,6 +405,80 @@ static void printLinking(const shared_ptr<dabEnsemble> ensemble)
}
}
+static void printFrequencyInformation(const shared_ptr<dabEnsemble>& ensemble)
+{
+ etiLog.log(info, " Frequency Information");
+ if (ensemble->frequency_information.empty()) {
+ etiLog.level(info) << " None ";
+ }
+ for (const auto& fi : ensemble->frequency_information) {
+ etiLog.level(info) << " FI " << fi->uid;
+ for (const auto& fle : fi->frequency_information) {
+ etiLog.level(info) << " continuity " << (fle.continuity ? "true" : "false");
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ etiLog.level(info) << " RM: DAB";
+ etiLog.log(info, " EId 0x%04x", fle.fi_dab.eid);
+ break;
+ case RangeModulation::drm:
+ etiLog.level(info) << " RM: DRM";
+ etiLog.log(info, " DRM Id 0x%06x", fle.fi_drm.drm_service_id);
+ break;
+ case RangeModulation::fm_with_rds:
+ etiLog.level(info) << " RM: FM (with RDS)";
+ etiLog.log(info, " PI-Code 0x%04x", fle.fi_fm.pi_code);
+ break;
+ case RangeModulation::amss:
+ etiLog.level(info) << " RM: AMSS";
+ etiLog.log(info, " AMSS Id 0x%06x", fle.fi_amss.amss_service_id);
+ break;
+ }
+
+ switch (fle.rm) {
+ case RangeModulation::dab_ensemble:
+ for (const auto& f : fle.fi_dab.frequencies) {
+ stringstream ss;
+ ss << " " << f.uid << " ";
+ switch (f.control_field) {
+ case FrequencyInfoDab::ControlField_e::adjacent_no_mode:
+ ss << "Adjacent, w/o mode indication, ";
+ break;
+ case FrequencyInfoDab::ControlField_e::adjacent_mode1:
+ ss << "Adjacent, mode I, ";
+ break;
+ case FrequencyInfoDab::ControlField_e::disjoint_no_mode:
+ ss << "Disjoint, w/o mode indication, ";
+ break;
+ case FrequencyInfoDab::ControlField_e::disjoint_mode1:
+ ss << "Disjoint, mode I, ";
+ break;
+ }
+ ss << f.frequency;
+ etiLog.level(info) << ss.str();
+ }
+ break;
+ case RangeModulation::drm:
+ etiLog.log(info, " ID 0x%02x", fle.fi_drm.drm_service_id);
+ for (const auto& f : fle.fi_drm.frequencies) {
+ etiLog.level(info) << " " << f;
+ }
+ break;
+ case RangeModulation::fm_with_rds:
+ for (const auto& f : fle.fi_fm.frequencies) {
+ etiLog.level(info) << " " << f;
+ }
+ break;
+ case RangeModulation::amss:
+ etiLog.log(info, " ID 0x%02x", fle.fi_amss.amss_service_id);
+ for (const auto& f : fle.fi_amss.frequencies) {
+ etiLog.level(info) << " " << f;
+ }
+ break;
+ }
+ }
+ }
+}
+
void printEnsemble(const shared_ptr<dabEnsemble>& ensemble)
{
etiLog.log(info, "Ensemble");
@@ -436,6 +513,7 @@ void printEnsemble(const shared_ptr<dabEnsemble>& ensemble)
}
printLinking(ensemble);
+ printFrequencyInformation(ensemble);
}
long hexparse(const std::string& input)