summaryrefslogtreecommitdiffstats
path: root/src/fig/FIG0_21.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fig/FIG0_21.cpp')
-rw-r--r--src/fig/FIG0_21.cpp384
1 files changed, 225 insertions, 159 deletions
diff --git a/src/fig/FIG0_21.cpp b/src/fig/FIG0_21.cpp
index 8f4f95b..5855fb1 100644
--- a/src/fig/FIG0_21.cpp
+++ b/src/fig/FIG0_21.cpp
@@ -83,6 +83,34 @@ FIG0_21::FIG0_21(FIGRuntimeInformation *rti) :
{
}
+static size_t get_num_frequencies(
+ std::vector<FrequencyInformation>::iterator fi)
+{
+ switch (fi->rm) {
+ case RangeModulation::dab_ensemble:
+ if (fi->fi_dab.frequencies.empty()) {
+ throw std::logic_error("Empty DAB FI");
+ }
+ return fi->fi_dab.frequencies.size();
+ case RangeModulation::fm_with_rds:
+ if (fi->fi_fm.frequencies.empty()) {
+ throw std::logic_error("Empty FM FI");
+ }
+ return fi->fi_fm.frequencies.size();
+ case RangeModulation::amss:
+ if (fi->fi_amss.frequencies.empty()) {
+ throw std::logic_error("Empty AMSS FI");
+ }
+ return fi->fi_amss.frequencies.size();
+ case RangeModulation::drm:
+ if (fi->fi_drm.frequencies.empty()) {
+ throw std::logic_error("Empty DRM FI");
+ }
+ return fi->fi_drm.frequencies.size();
+ }
+ throw logic_error("Unhandled get_num_frequencies");
+}
+
FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
{
#define FIG0_21_TRACE discard
@@ -90,75 +118,77 @@ FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
size_t remaining = max_size;
auto ensemble = m_rti->ensemble;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fill init " <<
- (m_initialised ? 1 : 0) << " ********************************";
-
if (not m_initialised) {
freqInfoFIG0_21 = ensemble->frequency_information.begin();
+ fi_frequency_index = 0;
if (freqInfoFIG0_21 != ensemble->frequency_information.end()) {
- m_last_oe = (*freqInfoFIG0_21)->other_ensemble;
+ m_last_oe = freqInfoFIG0_21->other_ensemble;
}
m_initialised = true;
}
FIGtype0* fig0 = nullptr;
- for (; freqInfoFIG0_21 != ensemble->frequency_information.end();
- ++freqInfoFIG0_21) {
+ auto advance_loop = [&](void){
+ if (fi_frequency_index == get_num_frequencies(freqInfoFIG0_21)) {
+ ++freqInfoFIG0_21;
+ fi_frequency_index = 0;
+ }
+ };
+ for (; freqInfoFIG0_21 != ensemble->frequency_information.end();
+ advance_loop()) {
+ /* For better usage of FIC capacity, we want to transmit
+ * frequency lists with
+ * 2 DAB frequencies,
+ * 7 FM frequencies,
+ * 3 AM/DRM frequencies
+ */
+
+ // Check we have space for one frequency
size_t required_fi_size = 2; // RegionId + length of FI list
- for (const auto& fle : (*freqInfoFIG0_21)->frequency_information) {
- size_t list_entry_size = sizeof(struct 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() * 1;
- break;
- case RangeModulation::amss:
- list_entry_size += 1; // Id field 2
- list_entry_size += fle.fi_amss.frequencies.size() * 2;
- break;
- case RangeModulation::drm:
- list_entry_size += 1; // Id field 2
- list_entry_size += fle.fi_drm.frequencies.size() * 2;
- break;
- }
- required_fi_size += list_entry_size;
+ size_t list_entry_size = sizeof(struct FIGtype0_21_fi_list_header);
+ switch (freqInfoFIG0_21->rm) {
+ case RangeModulation::dab_ensemble:
+ list_entry_size += 3;
+ break;
+ case RangeModulation::fm_with_rds:
+ list_entry_size += 1;
+ break;
+ case RangeModulation::amss:
+ list_entry_size += 1; // Id field 2
+ list_entry_size += 2;
+ break;
+ case RangeModulation::drm:
+ list_entry_size += 1; // Id field 2
+ list_entry_size += 2;
+ break;
}
+ required_fi_size += list_entry_size;
- const size_t required_size = sizeof(struct FIGtype0_21_header) + required_fi_size;
+ const size_t required_size =
+ sizeof(struct FIGtype0_21_header) + required_fi_size;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::loop " << (*freqInfoFIG0_21)->uid;
-
- if (m_last_oe != (*freqInfoFIG0_21)->other_ensemble) {
+ if (m_last_oe != freqInfoFIG0_21->other_ensemble) {
// Trigger resend of FIG0 when OE changes
fig0 = nullptr;
- m_last_oe = (*freqInfoFIG0_21)->other_ensemble;
+ m_last_oe = freqInfoFIG0_21->other_ensemble;
etiLog.level(FIG0_21_TRACE) << "FIG0_21::switch OE to " <<
- (*freqInfoFIG0_21)->other_ensemble;
+ freqInfoFIG0_21->other_ensemble;
}
if (fig0 == nullptr) {
if (remaining < 2 + required_size) {
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::no space for fig0: remain " <<
- remaining << " require " << 2 + required_size;
break;
}
- else {
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::inserting fig0: remain " <<
- remaining << " require " << 2 + required_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 =
- (freqInfoFIG0_21 == ensemble->frequency_information.begin() ? 0 : 1);
- fig0->OE = (*freqInfoFIG0_21)->other_ensemble ? 1 : 0;
+ fig0->CN = (fi_frequency_index == 0 ? 0 : 1);
+ fig0->OE = freqInfoFIG0_21->other_ensemble ? 1 : 0;
fig0->PD = false;
fig0->Extension = 21;
@@ -166,149 +196,185 @@ FillStatus FIG0_21::fill(uint8_t *buf, size_t max_size)
remaining -= 2;
}
else if (remaining < required_size) {
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::no space";
break;
}
+ etiLog.level(FIG0_21_TRACE) << "FIG0_21::loop " << freqInfoFIG0_21->uid << " " <<
+ std::distance(ensemble->frequency_information.begin(), freqInfoFIG0_21) <<
+ " freq entry " << fi_frequency_index;
+
auto *fig0_21_header = (FIGtype0_21_header*)buf;
fig0_21_header->rfaHigh = 0;
fig0_21_header->rfaLow = 0;
- fig0_21_header->length_fi = sizeof(struct FIGtype0_21_fi_list_header);
-
- fig0->Length += sizeof(struct FIGtype0_21_header);
- buf += sizeof(struct FIGtype0_21_header);
- remaining -= sizeof(struct FIGtype0_21_header);
-
- for (const auto& fle : (*freqInfoFIG0_21)->frequency_information) {
- switch (fle.rm) {
- case RangeModulation::dab_ensemble:
- fig0_21_header->length_fi += 3 * fle.fi_dab.frequencies.size();
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fle hdr DAB " <<
- fle.fi_dab.frequencies.size();
- break;
- case RangeModulation::fm_with_rds:
- fig0_21_header->length_fi += fle.fi_fm.frequencies.size();
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fle hdr FM " <<
- fle.fi_fm.frequencies.size();
- break;
- case RangeModulation::drm:
- fig0_21_header->length_fi += 1; // ID field 2
- fig0_21_header->length_fi += 2*fle.fi_drm.frequencies.size();
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fle hdr DRM " <<
- fle.fi_drm.frequencies.size();
- break;
- case RangeModulation::amss:
- fig0_21_header->length_fi += 1; // ID field 2
- fig0_21_header->length_fi += 2*fle.fi_amss.frequencies.size();
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fle hdr AMSS " <<
- fle.fi_amss.frequencies.size();
- break;
- }
-
- 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;
- fi_list_header->length_freq_list = 0;
- fi_list_header->range_modulation = static_cast<uint8_t>(fle.rm);
-
- switch (fle.rm) {
- case RangeModulation::dab_ensemble:
- fi_list_header->setId(fle.fi_dab.eid);
- assert(fle.fi_dab.frequencies.size() < 8);
-
- 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));
-
- fi_list_header->addToLength(3);
- fig0->Length += 3;
- buf += 3;
- remaining -= 3;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::freq " <<
- freq.frequency << " rem " << remaining;
+ fig0_21_header->length_fi = sizeof(FIGtype0_21_fi_list_header);
+
+ fig0->Length += sizeof(FIGtype0_21_header);
+ buf += sizeof(FIGtype0_21_header);
+ remaining -= sizeof(FIGtype0_21_header);
+
+ auto *fi_list_header = (FIGtype0_21_fi_list_header*)buf;
+ fig0->Length += sizeof(FIGtype0_21_fi_list_header);
+ buf += sizeof(FIGtype0_21_fi_list_header);
+ remaining -= sizeof(FIGtype0_21_fi_list_header);
+
+ fi_list_header->continuity = freqInfoFIG0_21->continuity;
+ fi_list_header->length_freq_list = 0;
+ fi_list_header->range_modulation = static_cast<uint8_t>(freqInfoFIG0_21->rm);
+
+ bool continue_loop = true;
+
+ switch (freqInfoFIG0_21->rm) {
+ case RangeModulation::dab_ensemble:
+ fi_list_header->setId(freqInfoFIG0_21->fi_dab.eid);
+
+ for (size_t num_inserted = 0, i = fi_frequency_index;
+ num_inserted < 2 and
+ i < freqInfoFIG0_21->fi_dab.frequencies.size();
+ num_inserted++, i++) {
+ if (remaining < 3) {
+ continue_loop = false;
+ break;
}
- break;
- case RangeModulation::fm_with_rds:
- fi_list_header->setId(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;
-
- fi_list_header->addToLength(1);
- fig0->Length += 1;
- buf += 1;
- remaining -= 1;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::freq " <<
- freq;
+
+ const auto& freq = freqInfoFIG0_21->fi_dab.frequencies.at(i);
+
+ 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_21_header->length_fi += 3;
+ fi_list_header->addToLength(3);
+ fig0->Length += 3;
+ buf += 3;
+ remaining -= 3;
+ etiLog.level(FIG0_21_TRACE) << "FIG0_21::freq " <<
+ fi_frequency_index << " " << freq.frequency << " rem " << remaining;
+ fi_frequency_index++;
+ }
+ break;
+ case RangeModulation::fm_with_rds:
+ fi_list_header->setId(freqInfoFIG0_21->fi_fm.pi_code);
+
+ for (size_t num_inserted = 0, i = fi_frequency_index;
+ num_inserted < 7 and
+ i < freqInfoFIG0_21->fi_fm.frequencies.size();
+ num_inserted++, i++) {
+ if (remaining < 1) {
+ continue_loop = false;
+ break;
}
- break;
- case RangeModulation::drm:
- fi_list_header->setId((fle.fi_drm.drm_service_id) & 0xFFFF);
- // Id field 2
- *buf = (fle.fi_drm.drm_service_id >> 16) & 0xFF;
+ const auto& freq = freqInfoFIG0_21->fi_fm.frequencies.at(i);
+ // 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_21_header->length_fi += 1;
fi_list_header->addToLength(1);
fig0->Length += 1;
buf += 1;
remaining -= 1;
-
- for (const auto& freq : fle.fi_drm.frequencies) {
- uint16_t freq_field = static_cast<uint16_t>(freq * 1000.0f);
- buf[0] = freq_field >> 8;
- buf[1] = freq_field & 0xFF;
-
- fi_list_header->addToLength(2);
- fig0->Length += 2;
- buf += 2;
- remaining -= 2;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::freq_field " <<
- freq_field;
+ fi_frequency_index++;
+ }
+ break;
+ case RangeModulation::drm:
+ fi_list_header->setId((freqInfoFIG0_21->fi_drm.drm_service_id) & 0xFFFF);
+
+ if (remaining < 3) {
+ throw logic_error("Incorrect DRM FI size calculation");
+ }
+
+ // Id field 2
+ *buf = (freqInfoFIG0_21->fi_drm.drm_service_id >> 16) & 0xFF;
+ fig0_21_header->length_fi += 1;
+
+ fi_list_header->addToLength(1);
+ fig0->Length += 1;
+ buf += 1;
+ remaining -= 1;
+
+ for (size_t num_inserted = 0, i = fi_frequency_index;
+ num_inserted < 3 and
+ i < freqInfoFIG0_21->fi_drm.frequencies.size();
+ num_inserted++, i++) {
+ if (remaining < 2) {
+ continue_loop = false;
+ break;
}
- break;
- case RangeModulation::amss:
- fi_list_header->setId((fle.fi_amss.amss_service_id) & 0xFFFF);
- // Id field 2
- *buf = (fle.fi_amss.amss_service_id >> 16) & 0xFF;
+ const auto& freq = freqInfoFIG0_21->fi_drm.frequencies.at(i);
+ uint16_t freq_field = static_cast<uint16_t>(freq * 1000.0f);
+ buf[0] = freq_field >> 8;
+ buf[1] = freq_field & 0xFF;
+
+ fi_list_header->addToLength(2);
+ fig0_21_header->length_fi += 2;
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ fi_frequency_index++;
+ }
+ break;
+ case RangeModulation::amss:
+ fi_list_header->setId((freqInfoFIG0_21->fi_amss.amss_service_id) & 0xFFFF);
+
+ if (remaining < 3) {
+ throw logic_error("Incorrect AMSS FI size calculation");
+ }
+
+ // Id field 2
+ *buf = (freqInfoFIG0_21->fi_amss.amss_service_id >> 16) & 0xFF;
+ fig0_21_header->length_fi += 1;
+
+ fi_list_header->addToLength(1);
+ fig0->Length += 1;
+ buf += 1;
+ remaining -= 1;
+
+ for (size_t num_inserted = 0, i = fi_frequency_index;
+ num_inserted < 3 and
+ i < freqInfoFIG0_21->fi_amss.frequencies.size();
+ num_inserted++, i++) {
+ if (remaining < 2) {
+ continue_loop = false;
+ break;
+ }
- fi_list_header->addToLength(1);
- fig0->Length += 1;
- buf += 1;
- remaining -= 1;
+ const auto& freq = freqInfoFIG0_21->fi_amss.frequencies.at(i);
+ uint16_t freq_field = static_cast<uint16_t>(freq * 1000.0f);
+ buf[0] = freq_field >> 8;
+ buf[1] = freq_field & 0xFF;
+
+ fi_list_header->addToLength(2);
+ fig0_21_header->length_fi += 2;
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ fi_frequency_index++;
+ }
+ break;
+ } // switch (RM)
- for (const auto& freq : fle.fi_amss.frequencies) {
- uint16_t freq_field = static_cast<uint16_t>(freq * 1000.0f);
- buf[0] = freq_field >> 8;
- buf[1] = freq_field & 0xFF;
-
- fi_list_header->addToLength(2);
- fig0->Length += 2;
- buf += 2;
- remaining -= 2;
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::freq_field " <<
- freq_field;
- }
- break;
- } // switch (RM)
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::fle end len=" <<
- static_cast<size_t>(fig0->Length) << " rem=" << remaining;
- } // for over fle
- etiLog.level(FIG0_21_TRACE) << "FIG0_21::next FI "
+ etiLog.level(FIG0_21_TRACE) << "FIG0_21::end " <<
+ (continue_loop ? "same " : "next ") << " len=" <<
+ static_cast<size_t>(fig0->Length) << " rem=" << remaining <<
" ********************************";
+
+ if (not continue_loop) {
+ // There is no more space left. The freqInfoFIG0_21 iterator
+ // and fi_frequency_index save the position how to continue
+ // next time we are called.
+ break;
+ }
} // for over FI
if (freqInfoFIG0_21 == ensemble->frequency_information.end()) {
fs.complete_fig_transmitted = true;
+
freqInfoFIG0_21 = ensemble->frequency_information.begin();
+ fi_frequency_index = 0;
}
fs.num_bytes_written = max_size - remaining;