summaryrefslogtreecommitdiffstats
path: root/src/fig
diff options
context:
space:
mode:
Diffstat (limited to 'src/fig')
-rw-r--r--src/fig/FIG0.h1
-rw-r--r--src/fig/FIG0_6.cpp235
-rw-r--r--src/fig/FIG0_6.h98
-rw-r--r--src/fig/FIG0structs.h19
-rw-r--r--src/fig/FIGCarousel.cpp2
-rw-r--r--src/fig/FIGCarousel.h1
6 files changed, 356 insertions, 0 deletions
diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h
index 927efc1..446e1ac 100644
--- a/src/fig/FIG0.h
+++ b/src/fig/FIG0.h
@@ -31,6 +31,7 @@
#include "fig/FIG0_2.h"
#include "fig/FIG0_3.h"
#include "fig/FIG0_5.h"
+#include "fig/FIG0_6.h"
#include "fig/FIG0_8.h"
#include "fig/FIG0_9.h"
#include "fig/FIG0_10.h"
diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp
new file mode 100644
index 0000000..479d004
--- /dev/null
+++ b/src/fig/FIG0_6.cpp
@@ -0,0 +1,235 @@
+/*
+ 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) 2016
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "fig/FIG0_6.h"
+#include "utils.h"
+
+namespace FIC {
+
+FIG0_6::FIG0_6(FIGRuntimeInformation *rti) :
+ m_rti(rti),
+ m_initialised(false)
+{
+}
+
+FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size)
+{
+ FillStatus fs;
+ ssize_t remaining = max_size;
+ auto ensemble = m_rti->ensemble;
+
+ update();
+
+ if (not m_initialised) {
+ linkageSetFIG0_6 = linkageSubsets.begin();
+ m_initialised = true;
+ }
+
+ FIGtype0* fig0 = NULL;
+
+ for (; linkageSetFIG0_6 != linkageSubsets.end();
+ ++linkageSetFIG0_6) {
+
+ const bool PD = false;
+ const bool ILS = linkageSetFIG0_6->international;
+
+ // need to add key service to num_ids
+ const size_t num_ids = 1 + linkageSetFIG0_6->id_list.size();
+
+ const size_t headersize = sizeof(struct FIGtype0_6_header);
+ const int required_size = sizeof(struct FIGtype0_6) +
+ (num_ids > 0 ?
+ headersize + (PD == 0 ? (ILS == 0 ? 2*num_ids : 3*num_ids) : 4*num_ids) :
+ 0);
+
+ if (fig0 == NULL) {
+ if (remaining < 2 + required_size) {
+ break;
+ }
+ fig0 = (FIGtype0*)buf;
+ fig0->FIGtypeNumber = 0;
+ fig0->Length = 1;
+ fig0->CN = 0;
+ fig0->OE = 0;
+ fig0->PD = PD;
+ fig0->Extension = 6;
+
+ buf += 2;
+ remaining -= 2;
+ }
+ else if (remaining < required_size) {
+ break;
+ }
+
+ FIGtype0_6 *fig0_6 = (FIGtype0_6*)buf;
+
+ fig0_6->IdListFlag = (num_ids > 0);
+ fig0_6->LA = linkageSetFIG0_6->active;
+ fig0_6->SH = linkageSetFIG0_6->hard;
+ fig0_6->ILS = ILS;
+ fig0_6->LSN = linkageSetFIG0_6->lsn;
+
+ fig0->Length += sizeof(struct FIGtype0_6);
+ buf += sizeof(struct FIGtype0_6);
+ remaining -= sizeof(struct FIGtype0_6);
+
+ if (num_ids > 0) {
+ FIGtype0_6_header *header = (FIGtype0_6_header*)buf;
+ header->rfu = 0;
+ if (num_ids > 0x0F) {
+ etiLog.log(error, "Too large number of links for linkage set 0x%04x",
+ linkageSetFIG0_6->lsn);
+ throw MuxInitException();
+ }
+
+ // update() guarantees us that all entries in a linkage set
+ // have the same type
+ for (const auto& l : linkageSetFIG0_6->id_list) {
+ if (l.type != linkageSetFIG0_6->id_list.front().type) {
+ etiLog.log(error, "INTERNAL ERROR: invalid linkage subset 0x%04x",
+ linkageSetFIG0_6->lsn);
+ throw std::runtime_error("INTERNAL ERROR");
+ }
+ }
+
+ switch (linkageSetFIG0_6->id_list.front().type) {
+ case ServiceLinkType::DAB: header->IdLQ = FIG0_6_IDLQ_DAB; break;
+ case ServiceLinkType::FM: header->IdLQ = FIG0_6_IDLQ_RDS; break;
+ case ServiceLinkType::DRM: header->IdLQ = FIG0_6_IDLQ_DRM_AMSS; break;
+ case ServiceLinkType::AMSS: header->IdLQ = FIG0_6_IDLQ_DRM_AMSS; break;
+ }
+ header->rfa = 0;
+ header->num_ids = num_ids;
+
+ fig0->Length += headersize;
+ buf += headersize;
+ remaining -= headersize;
+
+ // TODO insert key service first
+ const std::string keyserviceuid = linkageSetFIG0_6->keyservice;
+ const auto& keyservice = std::find_if(
+ ensemble->services.begin(),
+ ensemble->services.end(),
+ [&](const std::shared_ptr<DabService> srv) {
+ return srv->uid == keyserviceuid;
+ });
+
+ if (keyservice == ensemble->services.end()) {
+ etiLog.log(error, "Invalid key service %s in linkage set 0x%04x",
+ keyserviceuid.c_str(), linkageSetFIG0_6->lsn);
+ throw MuxInitException();
+ }
+
+ if (not PD and not ILS) {
+ buf[0] = (*keyservice)->id >> 8;
+ buf[1] = (*keyservice)->id & 0xFF;
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+
+ for (const auto& l : linkageSetFIG0_6->id_list) {
+ buf[0] = l.id >> 8;
+ buf[1] = l.id & 0xFF;
+ fig0->Length += 2;
+ buf += 2;
+ remaining -= 2;
+ }
+ }
+ if (not PD and ILS) {
+ buf[0] = ensemble->ecc;
+ buf[1] = (*keyservice)->id >> 8;
+ buf[2] = (*keyservice)->id & 0xFF;
+ fig0->Length += 3;
+ buf += 3;
+ remaining -= 3;
+
+ for (const auto& l : linkageSetFIG0_6->id_list) {
+ buf[0] = l.ecc;
+ buf[1] = l.id >> 8;
+ buf[2] = l.id & 0xFF;
+ fig0->Length += 3;
+ buf += 3;
+ remaining -= 3;
+ }
+ }
+ else { // PD == true
+ // TODO if IdLQ is 11, MSB shall be zero
+ buf[0] = (*keyservice)->id >> 24;
+ buf[1] = (*keyservice)->id >> 16;
+ buf[2] = (*keyservice)->id >> 8;
+ buf[3] = (*keyservice)->id & 0xFF;
+ fig0->Length += 4;
+ buf += 4;
+ remaining -= 4;
+
+ for (const auto& l : linkageSetFIG0_6->id_list) {
+ buf[0] = l.id >> 24;
+ buf[1] = l.id >> 16;
+ buf[2] = l.id >> 8;
+ buf[3] = l.id & 0xFF;
+ fig0->Length += 4;
+ buf += 4;
+ remaining -= 4;
+ }
+ }
+ }
+ }
+
+ if (linkageSetFIG0_6 == linkageSubsets.end()) {
+ linkageSetFIG0_6 = linkageSubsets.begin();
+ fs.complete_fig_transmitted = true;
+ }
+
+ fs.num_bytes_written = max_size - remaining;
+ return fs;
+}
+
+void FIG0_6::update()
+{
+ linkageSubsets.clear();
+
+ for (const auto& linkageset : m_rti->ensemble->linkagesets) {
+ const auto lsn = linkageset->data.lsn;
+
+ for (const auto& link : linkageset->data.id_list) {
+ const auto type = link.type;
+
+ const auto subset =
+ std::find_if(linkageSubsets.begin(), linkageSubsets.end(),
+ [&](const LinkageSetData& l) {
+ return not l.id_list.empty() and
+ l.lsn == lsn and l.id_list.front().type == type;
+ });
+
+ if (subset == linkageSubsets.end()) {
+ // A subset with that LSN and type does not exist yet
+ linkageSubsets.push_back( linkageset->data.filter_type(type) );
+ }
+ }
+ }
+}
+
+}
+
diff --git a/src/fig/FIG0_6.h b/src/fig/FIG0_6.h
new file mode 100644
index 0000000..1af396f
--- /dev/null
+++ b/src/fig/FIG0_6.h
@@ -0,0 +1,98 @@
+/*
+ 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) 2016
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include <memory>
+
+#include "fig/FIG0structs.h"
+#include "fig/TransitionHandler.h"
+
+namespace FIC {
+
+// FIG type 0/6
+// Service Linking
+//
+// This feature shall use the SIV signalling (see clause 5.2.2.1). The database
+// shall be divided by use of a database key. Changes to the database shall be
+// signalled using the CEI. The first service in the list of services in each
+// part of the database, as divided by the database key, shall be a service
+// carried in the ensemble. This service is called the key service.
+//
+// The database key comprises the OE and P/D flags and the S/H, ILS, and LSN
+// fields.
+class FIG0_6 : public IFIG
+{
+ public:
+ FIG0_6(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 6; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+ bool m_initialised;
+
+ /* Update the linkageSubsets */
+ void update(void);
+
+ /* A LinkageSet can contain links of different types
+ * (DAB, FM, DRM, AMSS), but the FIG needs to send
+ * different FIGs for each of those, because the IdLQ flag
+ * is common to a list.
+ *
+ * We reorganise all LinkageSets into subsets that have
+ * the same type.
+ */
+ std::list<LinkageSetData> linkageSubsets;
+ std::list<LinkageSetData>::iterator linkageSetFIG0_6;
+};
+
+// FIG0/6 needs a change indicator, which is a short-form FIG (i.e. without the list)
+// and with C/N 1. Since this has another rate, it's implemented in another class.
+//
+// This is signalled once per second for a period of five seconds
+// (TS 103 176 5.2.4.3).
+class FIG0_6_CEI : public IFIG
+{
+ public:
+ FIG0_6_CEI(FIGRuntimeInformation* rti);
+ virtual FillStatus fill(uint8_t *buf, size_t max_size);
+ virtual FIG_rate repetition_rate(void) { return FIG_rate::B; }
+
+ virtual const int figtype(void) const { return 0; }
+ virtual const int figextension(void) const { return 6; }
+
+ private:
+ FIGRuntimeInformation *m_rti;
+ bool m_initialised;
+ std::vector<std::shared_ptr<LinkageSet> >::iterator linkageSetFIG0_6;
+};
+
+}
diff --git a/src/fig/FIG0structs.h b/src/fig/FIG0structs.h
index a1e79d3..4b9b7e0 100644
--- a/src/fig/FIG0structs.h
+++ b/src/fig/FIG0structs.h
@@ -152,6 +152,25 @@ struct FIGtype0_5_short {
uint8_t language;
} PACKED;
+struct FIGtype0_6 {
+ uint16_t IdListFlag:1;
+ uint16_t LA:1; // Linkage actuator
+ uint16_t SH:1; // 0=Soft link / 1=Hard link
+ uint16_t ILS:1; // 0=national / 1=international
+ uint16_t LSN:12; // Linkage Set Number
+} PACKED;
+
+#define FIG0_6_IDLQ_DAB 0x0
+#define FIG0_6_IDLQ_RDS 0x1
+#define FIG0_6_IDLQ_DRM_AMSS 0x3
+
+struct FIGtype0_6_header {
+ uint8_t rfu:1; // must be 0
+ uint8_t IdLQ:2; // Identifier List Qualifier, see above defines
+ uint8_t rfa:1; // must be 0
+ uint8_t num_ids:4; // number of Ids to follow in the list
+} PACKED;
+
struct FIGtype0_8_short {
uint8_t SCIdS:4;
uint8_t rfa_1:3;
diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp
index cbea12b..bd2bf51 100644
--- a/src/fig/FIGCarousel.cpp
+++ b/src/fig/FIGCarousel.cpp
@@ -64,6 +64,7 @@ FIGCarousel::FIGCarousel(std::shared_ptr<dabEnsemble> ensemble) :
m_fig0_2(&m_rti),
m_fig0_3(&m_rti),
m_fig0_5(&m_rti),
+ m_fig0_6(&m_rti),
m_fig0_17(&m_rti),
m_fig0_8(&m_rti),
m_fig1_0(&m_rti),
@@ -94,6 +95,7 @@ FIGCarousel::FIGCarousel(std::shared_ptr<dabEnsemble> ensemble) :
load_and_allocate(m_fig0_2, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_3, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_5, FIBAllocation::FIB_ANY);
+ load_and_allocate(m_fig0_6, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_8, FIBAllocation::FIB_ANY);
load_and_allocate(m_fig0_13, FIBAllocation::FIB_ANY);
diff --git a/src/fig/FIGCarousel.h b/src/fig/FIGCarousel.h
index 67772a6..be0b23f 100644
--- a/src/fig/FIGCarousel.h
+++ b/src/fig/FIGCarousel.h
@@ -92,6 +92,7 @@ class FIGCarousel {
FIG0_2 m_fig0_2;
FIG0_3 m_fig0_3;
FIG0_5 m_fig0_5;
+ FIG0_6 m_fig0_6;
FIG0_17 m_fig0_17;
FIG0_8 m_fig0_8;
FIG1_0 m_fig1_0;