From f6803b2375d1b21ed4cc035e268f8759d5170491 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 20 Apr 2017 05:22:08 +0200 Subject: WIP: Rework FIG0/21 definition and get FIC insertion to compile --- src/ConfigParser.cpp | 205 ++++++++++++++++++++++++++++-------------------- src/Makefile.am | 3 +- src/MuxElements.h | 22 ++++-- src/fig/FIG0.h | 3 +- src/fig/FIG0_21.cpp | 195 ++++++++++++++++++++++++++++++--------------- src/fig/FIG0_21.h | 4 +- src/fig/FIG0structs.h | 11 +++ src/fig/FIGCarousel.cpp | 4 +- src/fig/FIGCarousel.h | 1 + src/utils.cpp | 84 +++++++++++++++++++- 10 files changed, 371 insertions(+), 161 deletions(-) (limited to 'src') 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(); - 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("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("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("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("drm_id")); - - std::stringstream frequencies_ss; - frequencies_ss << pt_entry.get("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("amss_id")); - - std::stringstream frequencies_ss; - frequencies_ss << pt_entry.get("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("continuity"); + + try { + switch (fle.rm) { + case RangeModulation::dab_ensemble: + { + fle.fi_dab.eid = hexparse(pt_entry.get("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("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("pi_code")); + + std::stringstream frequencies_ss; + frequencies_ss << pt_entry.get("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("drm_id")); + + std::stringstream frequencies_ss; + frequencies_ss << pt_entry.get("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("amss_id")); + + std::stringstream frequencies_ss; + frequencies_ss << pt_entry.get("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 > clusters; std::vector > linkagesets; - std::vector > frequency_information; + std::vector > 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 frequencies; }; struct FrequencyInfoDrm { - uint8_t drm_service_id; + uint32_t drm_service_id; std::vector frequencies; }; struct FrequencyInfoFm { + uint16_t pi_code; std::vector frequencies; }; struct FrequencyInfoAmss { - uint8_t amss_service_id; + uint32_t amss_service_id; std::vector 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 frequency_information; +}; + std::vector::iterator getSubchannel( std::vector& 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(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(freq.control_field); + field->setFreq(static_cast( + 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(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(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 >::iterator - freqListEntryFIG0_21; + std::vector >::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 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 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& subchannels) } } -static void printLinking(const shared_ptr ensemble) +static void printLinking(const shared_ptr& 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 ensemble) } } +static void printFrequencyInformation(const shared_ptr& 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& ensemble) { etiLog.log(info, "Ensemble"); @@ -436,6 +513,7 @@ void printEnsemble(const shared_ptr& ensemble) } printLinking(ensemble); + printFrequencyInformation(ensemble); } long hexparse(const std::string& input) -- cgit v1.2.3