From 2a8e60cd761d1f3728c765d646135b2110eea576 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 9 Apr 2017 11:44:27 +0200 Subject: Add FIG0/21 work in progress --- doc/servicelinking.mux | 37 +++++++++++++ src/ConfigParser.cpp | 99 ++++++++++++++++++++++++++++++++- src/MuxElements.h | 59 ++++++++++++++++++-- src/fig/FIG0_21.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ src/fig/FIG0_21.h | 58 ++++++++++++++++++++ src/fig/FIG0structs.h | 15 ++++- 6 files changed, 407 insertions(+), 7 deletions(-) create mode 100644 src/fig/FIG0_21.cpp create mode 100644 src/fig/FIG0_21.h diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index f50b3fa..38d4ca1 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -100,6 +100,43 @@ linking { } } +; According to ETSI TR 101 496-2 Clause 3.6.10 +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_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" + } +} + ; For information about the ensemble, service, subchannels, components and outputs, ; please see doc/example.mux and doc/advanced.mux ensemble { diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 6d67b7b..d230778 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.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 http://www.opendigitalradio.org @@ -200,6 +200,102 @@ static void parse_linkage(boost::property_tree::ptree& pt, } } +// Parse the FI section +static void parse_freq_info(boost::property_tree::ptree& pt, + std::shared_ptr ensemble) +{ + using boost::property_tree::ptree; + using boost::property_tree::ptree_error; + + auto pt_fi = pt.get_child_optional("frequency_information"); + if (pt_fi) + { + for (const auto& it : *pt_fi) { + const string fi_uid = it.first; + const ptree pt_entry = it.second; + + FrequencyListEntry fle; + + 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"); + + 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; + } + } + } +} + void parse_ptree( boost::property_tree::ptree& pt, std::shared_ptr ensemble) @@ -608,6 +704,7 @@ void parse_ptree( } parse_linkage(pt, ensemble); + parse_freq_info(pt, ensemble); } static Inputs::dab_input_zmq_config_t setup_zmq_input( diff --git a/src/MuxElements.h b/src/MuxElements.h index 98e4741..0eabb69 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.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 http://www.opendigitalradio.org @@ -27,8 +27,7 @@ You should have received a copy of the GNU General Public License along with ODR-DabMux. If not, see . */ -#ifndef _MUX_ELEMENTS -#define _MUX_ELEMENTS +#pragma once #include #include @@ -192,6 +191,7 @@ class DabService; class DabComponent; class DabSubchannel; class LinkageSet; +struct FrequencyListEntry; class dabEnsemble : public RemoteControllable { public: @@ -231,6 +231,7 @@ class dabEnsemble : public RemoteControllable { std::vector > clusters; std::vector > linkagesets; + std::vector > frequency_information; }; @@ -470,6 +471,56 @@ class LinkageSet { std::string m_name; }; +// FIG 0/21 +enum class RangeModulation { + dab_ensemble = 0, + drm = 6, + fm_with_rds = 8, + amss = 14 +}; + +struct FrequencyInfoDab { + enum class ControlField_e { + adjacent_no_mode = 0, + adjacent_mode1 = 2, + disjoint_no_mode = 1, + disjoint_mode1 = 3}; + + struct ListElement { + ControlField_e control_field; + float frequency; + }; + + std::vector frequencies; +}; + +struct FrequencyInfoDrm { + uint8_t drm_service_id; + std::vector frequencies; +}; + +struct FrequencyInfoFm { + std::vector frequencies; +}; + +struct FrequencyInfoAmss { + uint8_t amss_service_id; + std::vector frequencies; +}; + +struct FrequencyListEntry { + uint16_t id; + RangeModulation rm; + bool continuity; + + // Only one of those must contain information, which + // must be consistent with RangeModulation + FrequencyInfoDab fi_dab; + FrequencyInfoDrm fi_drm; + FrequencyInfoFm fi_fm; + FrequencyInfoAmss fi_amss; +}; + std::vector::iterator getSubchannel( std::vector& subchannels, int id); @@ -486,5 +537,3 @@ std::vector >::iterator getService( DabComponent* component, std::vector >& services); -#endif - diff --git a/src/fig/FIG0_21.cpp b/src/fig/FIG0_21.cpp new file mode 100644 index 0000000..a89a8a7 --- /dev/null +++ b/src/fig/FIG0_21.cpp @@ -0,0 +1,146 @@ +/* + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Her Majesty the Queen in Right of Canada (Communications + Research Center Canada) + + Copyright (C) 2017 + Matthias P. Braendli, matthias.braendli@mpb.li + */ +/* + This file is part of ODR-DabMux. + + ODR-DabMux is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMux is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMux. If not, see . +*/ + +#include "fig/FIG0_21.h" +#include "utils.h" + +namespace FIC { + +FIG0_21::FIG0_21(FIGRuntimeInformation *rti) : + m_rti(rti), + m_initialised(false) +{ +} + +FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size) +{ + FillStatus fs; + ssize_t remaining = max_size; + auto ensemble = m_rti->ensemble; + + if (not m_initialised) { + freqListEntryFIG0_21 = ensemble->frequency_information.begin(); + m_initialised = true; + } + + FIGtype0* fig0 = nullptr; + + for (; freqListEntryFIG0_21 != ensemble->frequency_information.end(); + ++freqListEntryFIG0_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; + } + fig0 = (FIGtype0*)buf; + fig0->FIGtypeNumber = 0; + fig0->Length = 1; + fig0->CN = + (freqListEntryFIG0_21 == ensemble->frequency_information.begin() ? 0 : 1); + fig0->OE = 0; + fig0->PD = false; + fig0->Extension = 21; + + 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; + } + 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) { + + } + break; + case RangeModulation::fm_with_rds: + break; + case RangeModulation::drm: + break; + case RangeModulation::amss: + break; + } + + fig0->Length += sizeof(struct FIGtype0_21_header); + buf += sizeof(struct FIGtype0_21_header); + remaining -= sizeof(struct FIGtype0_21_header); + } + + if (freqListEntryFIG0_21 == ensemble->frequency_information.end()) { + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + +} + diff --git a/src/fig/FIG0_21.h b/src/fig/FIG0_21.h new file mode 100644 index 0000000..dccb475 --- /dev/null +++ b/src/fig/FIG0_21.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012 Her Majesty the Queen in Right of Canada (Communications + Research Center Canada) + + Copyright (C) 2017 + Matthias P. Braendli, matthias.braendli@mpb.li + */ +/* + This file is part of ODR-DabMux. + + ODR-DabMux is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMux is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMux. If not, see . +*/ + +#pragma once + +#include +#include +#include + +#include "fig/FIG0structs.h" + +namespace FIC { + +// FIG type 0/21 +// Frequency Information +class FIG0_21 : public IFIG +{ + public: + FIG0_21(FIGRuntimeInformation* rti); + virtual FillStatus fill(uint8_t *buf, size_t max_size); + virtual FIG_rate repetition_rate(void) { return FIG_rate::E; } + + virtual const int figtype(void) const { return 0; } + virtual const int figextension(void) const { return 21; } + + private: + FIGRuntimeInformation *m_rti; + + bool m_initialised; + + std::vector >::iterator + freqListEntryFIG0_21; +}; + +} + diff --git a/src/fig/FIG0structs.h b/src/fig/FIG0structs.h index 3b9bfbf..f06cc0e 100644 --- a/src/fig/FIG0structs.h +++ b/src/fig/FIG0structs.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 */ /* @@ -357,6 +357,7 @@ struct FIG0_13_app { uint16_t xpad; } PACKED; + #define FIG0_13_APPTYPE_SLIDESHOW 0x2 #define FIG0_13_APPTYPE_WEBSITE 0x3 #define FIG0_13_APPTYPE_TPEG 0x4 @@ -367,6 +368,18 @@ struct FIG0_13_app { #define FIG0_13_APPTYPE_JOURNALINE 0x441 +struct FIGtype0_21_header { + uint16_t rfa:11; + uint16_t length_fi:5; +} PACKED; + +struct FIGtype0_21_fi_list_header { + uint16_t id; + uint8_t range_modulation:4; + uint8_t continuity:1; + uint8_t length_freq_list:3; +} PACKED; + #ifdef _WIN32 # pragma pack(pop) #endif -- cgit v1.2.3