From 38e1b9ca1932c922fc8f64e91596d02961ae3cc1 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 11:00:28 +0200 Subject: Add config file proposal for linking --- doc/servicelinking.mux | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 doc/servicelinking.mux diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux new file mode 100644 index 0000000..da3a86a --- /dev/null +++ b/doc/servicelinking.mux @@ -0,0 +1,136 @@ +; This is an example configuration file that illustrates +; how to define service linking + +; More information about the usage of the tools is available +; in the guide, which can be found on the +; www.opendigitalradio.org website. +; +general { + dabmode 1 + nbframes 0 + + syslog false + tist false + managementport 12720 +} + +remotecontrol { + telnetport 12721 +} + +; Service linking settings +linking { + ; The sets section declares the linkage sets according to + ; TS 103 176 Clause 5.2.3 "Linkage sets". This information will + ; be encoded in FIG 0/6 + sets { + ; Linkage Set Number is a 12-bit number that identifies the linkage set + ; in a country (requires coordination between multiplex operators in a country) + lsn 0xabc + + ; whether this link is active or a "potential future link or de-activated link" + ; This field is also part of the remote control. + active true + + ; Hard link means that all services carry the same programme, soft links means + ; that the programmes are related in some way. + hard true + + ; Whether this linkage set affects only one country or several. Linkage sets that + ; include AMSS or DRM services need to have this set to true. + international false + + ; Every linkage set has to contain a service from the current ensemble + keyservice srv-fu + + ; List of services to be included + list { + ; Every service has a uid that can be used as a human-readable description + + ; The first example is a link to a DAB service on another ensemble. + fu-on-my-friends-mux { + ; Possible options: dab, fm, drm, amss + type dab + + ; if type is dab, the id is a DAB service ID + id 0x8daf + + ; Since this link set has international false, we do not need to specify + ; the ECC. With internation true, the following would be needed + ;ecc 0xec + } + + ; The second example is a link to an FM transmission + fu-on-fm { + ; Possible options: dab, fm, drm, amss + type fm + + ; if type is fm, the id is a PI-code + id 0x1A2B + + ; Also here, ECC declaration is not required + } + } + } +} + +; For information about the ensemble, service, subchannels, components and outputs, +; please see doc/example.mux and doc/advanced.mux +ensemble { + id 0x4fff + ecc 0xec + + local-time-offset auto + label "OpenDigitalRadio" + shortlabel "ODR" +} + +services { + srv-fu { + id 0x8daa + label "Funk" + } + srv-ri { + id 0x8dab + label "Rick" + } +} + +subchannels { + sub-fu { + type dabplus + inputfile "tcp://*:9000" + bitrate 96 + id 1 + protection 3 + zmq-buffer 40 + zmq-prebuffering 20 + } + sub-ri { + type dabplus + inputfile "tcp://*:9000" + bitrate 96 + id 2 + protection 3 + zmq-buffer 40 + zmq-prebuffering 20 + } +} + +components { + comp-fu { + service srv-fu + subchannel sub-fu + } + + comp-ri { + service srv-ri + subchannel sub-ri + } +} + +outputs { + tcp "tcp://0.0.0.0:9200" + throttle "simul://" +} + -- cgit v1.2.3 From 9db03b9e567ca4c716aedd017013069a54f0d66f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 11:31:31 +0200 Subject: Add Linkage data structures to MuxElements --- src/MuxElements.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/MuxElements.h | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index 773ec17..b2f8bca 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -662,4 +662,54 @@ unsigned short DabSubchannel::getSizeDWord(void) const return (bitrate * 3) >> 3; } +static string lsn_to_rc_name(uint16_t lsn) +{ + std::stringstream ss; + ss << "linkset" << + std::uppercase << + std::setfill('0') << + std::setw(4) << + std::hex << + lsn; + return ss.str(); +} + +LinkageSet::LinkageSet(uint16_t lsn, bool hard, bool international) : + RemoteControllable(lsn_to_rc_name(lsn)), + m_lsn(lsn), + m_active(false), + m_hard(hard), + m_international(international) +{ + RC_ADD_PARAMETER(active, "Activate this linkage set [0 or 1]"); +} + +void LinkageSet::set_parameter(const string& parameter, const string& value) +{ + if (parameter == "active") { + stringstream ss; + ss << value; + ss >> m_active; + } + else { + stringstream ss; + ss << "Parameter '" << parameter << + "' is not exported by controllable " << get_rc_name(); + throw ParameterError(ss.str()); + } +} + +const string LinkageSet::get_parameter(const string& parameter) const +{ + stringstream ss; + if (parameter == "active") { + ss << m_active; + } + else { + ss << "Parameter '" << parameter << + "' is not exported by controllable " << get_rc_name(); + throw ParameterError(ss.str()); + } + return ss.str(); +} diff --git a/src/MuxElements.h b/src/MuxElements.h index 7056121..47de4e3 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -191,8 +191,9 @@ class DabLabel class DabService; class DabComponent; - class DabSubchannel; +class LinkageSet; + class dabEnsemble : public RemoteControllable { public: dabEnsemble() @@ -228,6 +229,7 @@ class dabEnsemble : public RemoteControllable { std::vector subchannels; std::vector > clusters; + std::list > linkagesets; }; @@ -421,6 +423,45 @@ class DabService : public RemoteControllable DabService(const DabService& other); }; +enum class ServiceLinkType {dab, fm, drm, amss}; + +/* Represent one link inside a linkage set */ +struct ServiceLink { + ServiceLinkType type; + uint16_t id; + uint8_t ecc; +}; + +/* Represents a linkage set linkage sets according to + * TS 103 176 Clause 5.2.3 "Linkage sets". This information will + * be encoded in FIG 0/6. + */ +class LinkageSet : public RemoteControllable { + public: + LinkageSet(uint16_t lsn, bool hard, bool international); + + private: + /* Linkage Set Number is a 12-bit number that identifies the linkage + * set in a country (requires coordination between multiplex operators + * in a country) + */ + uint16_t m_lsn; + + bool m_active; // Remote-controllable + bool m_hard; + bool m_international; + + DabService *m_keyservice; + std::list id_list; + + /* Remote control */ + virtual void set_parameter(const std::string& parameter, + const std::string& value); + + /* Getting a parameter always returns a string. */ + virtual const std::string get_parameter(const std::string& parameter) const; +}; + std::vector::iterator getSubchannel( std::vector& subchannels, int id); -- cgit v1.2.3 From 35ae5602e9c72077cf9439c2806ad9a625ee6079 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 11:39:53 +0200 Subject: Clarify how to declare several linking sets --- doc/servicelinking.mux | 6 +++--- src/MuxElements.cpp | 17 ++--------------- src/MuxElements.h | 2 +- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index da3a86a..76ac3e5 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -18,12 +18,12 @@ remotecontrol { telnetport 12721 } -; Service linking settings +; Service linking sets linking { - ; The sets section declares the linkage sets according to + ; Every child section declares one linkage sets according to ; TS 103 176 Clause 5.2.3 "Linkage sets". This information will ; be encoded in FIG 0/6 - sets { + set-fu { ; Linkage Set Number is a 12-bit number that identifies the linkage set ; in a country (requires coordination between multiplex operators in a country) lsn 0xabc diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index b2f8bca..ad623b9 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -662,21 +662,8 @@ unsigned short DabSubchannel::getSizeDWord(void) const return (bitrate * 3) >> 3; } -static string lsn_to_rc_name(uint16_t lsn) -{ - std::stringstream ss; - ss << "linkset" << - std::uppercase << - std::setfill('0') << - std::setw(4) << - std::hex << - lsn; - - return ss.str(); -} - -LinkageSet::LinkageSet(uint16_t lsn, bool hard, bool international) : - RemoteControllable(lsn_to_rc_name(lsn)), +LinkageSet::LinkageSet(string name, uint16_t lsn, bool hard, bool international) : + RemoteControllable(name), m_lsn(lsn), m_active(false), m_hard(hard), diff --git a/src/MuxElements.h b/src/MuxElements.h index 47de4e3..ab97fd7 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -438,7 +438,7 @@ struct ServiceLink { */ class LinkageSet : public RemoteControllable { public: - LinkageSet(uint16_t lsn, bool hard, bool international); + LinkageSet(string name, uint16_t lsn, bool hard, bool international); private: /* Linkage Set Number is a 12-bit number that identifies the linkage -- cgit v1.2.3 From 9297ff6af5d41e70d7febc53d7af09055ce3877f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 12:03:32 +0200 Subject: Clarify which parameters are mandatory for linking --- doc/servicelinking.mux | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index 76ac3e5..7012fef 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -26,37 +26,39 @@ linking { set-fu { ; Linkage Set Number is a 12-bit number that identifies the linkage set ; in a country (requires coordination between multiplex operators in a country) + ; (mandatory) lsn 0xabc ; whether this link is active or a "potential future link or de-activated link" - ; This field is also part of the remote control. + ; This field is also part of the remote control. (default false) active true ; Hard link means that all services carry the same programme, soft links means - ; that the programmes are related in some way. + ; that the programmes are related in some way. (default true) hard true ; Whether this linkage set affects only one country or several. Linkage sets that - ; include AMSS or DRM services need to have this set to true. + ; include AMSS or DRM services need to have this set to true. (default false) international false - ; Every linkage set has to contain a service from the current ensemble + ; Every linkage set has to contain a service from the current ensemble (mandatory) keyservice srv-fu - ; List of services to be included + ; List of services to be included (mandatory) list { ; Every service has a uid that can be used as a human-readable description ; The first example is a link to a DAB service on another ensemble. fu-on-my-friends-mux { - ; Possible options: dab, fm, drm, amss + ; Possible options: dab, fm, drm, amss (mandatory) type dab - ; if type is dab, the id is a DAB service ID + ; if type is dab, the id is a DAB service ID (mandatory) id 0x8daf ; Since this link set has international false, we do not need to specify ; the ECC. With internation true, the following would be needed + ; (mandatory if internation true) ;ecc 0xec } -- cgit v1.2.3 From 2e3d29936f70c3c8183a4e2dcb0f967b73de2ec0 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 12:03:50 +0200 Subject: Parse service linking section --- src/ConfigParser.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/MuxElements.cpp | 5 +++ src/MuxElements.h | 8 +++-- 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 6a359b7..af43421 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) 2014, 2015 + Copyright (C) 2016 Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org @@ -142,6 +142,92 @@ uint16_t get_announcement_flag_from_ptree( return flags; } +// Parse the linkage section +void parse_linkage(boost::property_tree::ptree& pt, + std::shared_ptr ensemble, + std::shared_ptr rc + ) +{ + using boost::property_tree::ptree; + using boost::property_tree::ptree_error; + + auto pt_linking = pt.get_child_optional("linking"); + if (pt_linking) + { + for (const auto& it : *pt_linking) { + const string setuid = it.first; + const ptree pt_set = it.second; + + uint16_t lsn = hexparse(pt_set.get("lsn", "0")); + if (lsn == 0) { + etiLog.level(error) << "LSN for linking set " << + setuid << " invalid or missing"; + throw runtime_error("Invalid service linking definition"); + } + + bool active = pt_set.get("active", false); + bool hard = pt_set.get("hard", true); + bool international = pt_set.get("international", false); + + string service_uid = pt_set.get("keyservice", ""); + if (service_uid.empty()) { + etiLog.level(error) << "Key Service for linking set " << + setuid << " invalid or missing"; + throw runtime_error("Invalid service linking definition"); + } + + auto linkageset = make_shared(setuid, lsn, hard, international); + linkageset->set_active(active); + + auto pt_list = pt_set.get_child_optional("list"); + if (not pt_list) { + etiLog.level(error) << "list missing in linking set " << + setuid; + throw runtime_error("Invalid service linking definition"); + } + + for (const auto& it : *pt_list) { + const string linkuid = it.first; + const ptree pt_link = it.second; + + ServiceLink link; + + string link_type = pt_link.get("type", ""); + if (link_type == "dab") link.type = ServiceLinkType::DAB; + else if (link_type == "fm") link.type = ServiceLinkType::FM; + else if (link_type == "drm") link.type = ServiceLinkType::DRM; + else if (link_type == "amss") link.type = ServiceLinkType::AMSS; + else { + etiLog.level(error) << "Invalid type " << link_type << + " for link " << linkuid; + throw runtime_error("Invalid service linking definition"); + } + + link.id = hexparse(pt_link.get("id", "0")); + if (link.id == 0) { + etiLog.level(error) << "id for link " << + linkuid << " invalid or missing"; + throw runtime_error("Invalid service linking definition"); + } + + if (international) { + link.ecc = hexparse(pt_link.get("ecc", "0")); + if (link.ecc == 0) { + etiLog.level(error) << "ecc for link " << + linkuid << " invalid or missing"; + throw runtime_error("Invalid service linking definition"); + } + } + else { + link.ecc = 0; + } + + linkageset->id_list.push_back(link); + } + } + } +} + void parse_ptree(boost::property_tree::ptree& pt, std::shared_ptr ensemble, std::shared_ptr rc @@ -556,6 +642,7 @@ void parse_ptree(boost::property_tree::ptree& pt, } + parse_linkage(pt, ensemble, rc); } void setup_subchannel_from_ptree(DabSubchannel* subchan, diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index ad623b9..60f49be 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -672,6 +672,11 @@ LinkageSet::LinkageSet(string name, uint16_t lsn, bool hard, bool international) RC_ADD_PARAMETER(active, "Activate this linkage set [0 or 1]"); } +void LinkageSet::set_active(bool active) +{ + m_active = active; +} + void LinkageSet::set_parameter(const string& parameter, const string& value) { if (parameter == "active") { diff --git a/src/MuxElements.h b/src/MuxElements.h index ab97fd7..93c291f 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -423,7 +423,7 @@ class DabService : public RemoteControllable DabService(const DabService& other); }; -enum class ServiceLinkType {dab, fm, drm, amss}; +enum class ServiceLinkType {DAB, FM, DRM, AMSS}; /* Represent one link inside a linkage set */ struct ServiceLink { @@ -438,7 +438,10 @@ struct ServiceLink { */ class LinkageSet : public RemoteControllable { public: - LinkageSet(string name, uint16_t lsn, bool hard, bool international); + LinkageSet(std::string name, uint16_t lsn, bool hard, bool international); + void set_active(bool active); + + std::list id_list; private: /* Linkage Set Number is a 12-bit number that identifies the linkage @@ -452,7 +455,6 @@ class LinkageSet : public RemoteControllable { bool m_international; DabService *m_keyservice; - std::list id_list; /* Remote control */ virtual void set_parameter(const std::string& parameter, -- cgit v1.2.3 From 72374f4ba67a8330d197bc3c91dc6a44fa16a69c Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 12:22:22 +0200 Subject: Print linking info on startup --- doc/servicelinking.mux | 2 +- src/ConfigParser.cpp | 4 +++- src/MuxElements.cpp | 17 ++++++----------- src/MuxElements.h | 13 ++++++------- src/utils.cpp | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index 7012fef..7fd90ba 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -110,7 +110,7 @@ subchannels { } sub-ri { type dabplus - inputfile "tcp://*:9000" + inputfile "tcp://*:9001" bitrate 96 id 2 protection 3 diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index af43421..2ca83d3 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -177,7 +177,8 @@ void parse_linkage(boost::property_tree::ptree& pt, } auto linkageset = make_shared(setuid, lsn, hard, international); - linkageset->set_active(active); + linkageset->active = active; + linkageset->keyservice = service_uid; // TODO check if it exists auto pt_list = pt_set.get_child_optional("list"); if (not pt_list) { @@ -224,6 +225,7 @@ void parse_linkage(boost::property_tree::ptree& pt, linkageset->id_list.push_back(link); } + ensemble->linkagesets.push_back(linkageset); } } } diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index 60f49be..656e294 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -664,25 +664,20 @@ unsigned short DabSubchannel::getSizeDWord(void) const LinkageSet::LinkageSet(string name, uint16_t lsn, bool hard, bool international) : RemoteControllable(name), - m_lsn(lsn), - m_active(false), - m_hard(hard), - m_international(international) + lsn(lsn), + active(false), + hard(hard), + international(international) { RC_ADD_PARAMETER(active, "Activate this linkage set [0 or 1]"); } -void LinkageSet::set_active(bool active) -{ - m_active = active; -} - void LinkageSet::set_parameter(const string& parameter, const string& value) { if (parameter == "active") { stringstream ss; ss << value; - ss >> m_active; + ss >> active; } else { stringstream ss; @@ -696,7 +691,7 @@ const string LinkageSet::get_parameter(const string& parameter) const { stringstream ss; if (parameter == "active") { - ss << m_active; + ss << active; } else { ss << "Parameter '" << parameter << diff --git a/src/MuxElements.h b/src/MuxElements.h index 93c291f..8285e61 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -439,23 +439,22 @@ struct ServiceLink { class LinkageSet : public RemoteControllable { public: LinkageSet(std::string name, uint16_t lsn, bool hard, bool international); - void set_active(bool active); std::list id_list; - private: /* Linkage Set Number is a 12-bit number that identifies the linkage * set in a country (requires coordination between multiplex operators * in a country) */ - uint16_t m_lsn; + uint16_t lsn; - bool m_active; // Remote-controllable - bool m_hard; - bool m_international; + bool active; // Remote-controllable + bool hard; + bool international; - DabService *m_keyservice; + std::string keyservice; + private: /* Remote control */ virtual void set_parameter(const std::string& parameter, const std::string& value); diff --git a/src/utils.cpp b/src/utils.cpp index 98ec22d..5b48f21 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -551,6 +551,41 @@ void printSubchannels(vector& subchannels) } } +static void printLinking(const shared_ptr ensemble) +{ + etiLog.log(info, " Linkage Sets"); + for (const auto& linkageset : ensemble->linkagesets) { + etiLog.level(info) << " set " << linkageset->get_rc_name(); + etiLog.log(info, " LSN 0x%04x", linkageset->lsn); + etiLog.level(info) << " active " << (linkageset->active ? "true" : "false"); + etiLog.level(info) << " " << (linkageset->hard ? "hard" : "soft"); + etiLog.level(info) << " international " << (linkageset->international ? "true" : "false"); + etiLog.level(info) << " key service " << linkageset->keyservice; + + etiLog.level(info) << " ID list"; + for (const auto& link : linkageset->id_list) { + switch (link.type) { + case ServiceLinkType::DAB: + etiLog.level(info) << " type DAB"; + break; + case ServiceLinkType::FM: + etiLog.level(info) << " type FM"; + break; + case ServiceLinkType::DRM: + etiLog.level(info) << " type DRM"; + break; + case ServiceLinkType::AMSS: + etiLog.level(info) << " type AMSS"; + break; + } + etiLog.log(info, " id 0x%04x", link.id); + if (linkageset->international) { + etiLog.log(info, " ecc 0x%04x", link.ecc); + } + } + } +} + void printEnsemble(const shared_ptr ensemble) { etiLog.log(info, "Ensemble"); @@ -583,5 +618,7 @@ void printEnsemble(const shared_ptr ensemble) etiLog.level(info) << cluster->tostring(); } } + + printLinking(ensemble); } -- cgit v1.2.3 From 0360110bfb7320f3310737b6b75da5f8cd96edb9 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 16:13:12 +0200 Subject: Move FIG0 structures to separate file --- src/Makefile.am | 2 +- src/fig/FIG0.cpp | 3 +- src/fig/FIG0.h | 319 +--------------------------------------------- src/fig/FIG0structs.h | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.cpp | 1 + 5 files changed, 352 insertions(+), 320 deletions(-) create mode 100644 src/fig/FIG0structs.h diff --git a/src/Makefile.am b/src/Makefile.am index 996ebb8..55510ee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,7 +97,7 @@ odr_dabmux_SOURCES =DabMux.cpp DabMux.h \ bridge.h bridge.c \ crc.h crc.c \ fig/FIG.h fig/FIG.cpp \ - fig/FIG0.cpp fig/FIG0.h \ + fig/FIG0.cpp fig/FIG0.h fig/FIG0structs.h \ fig/FIG1.cpp fig/FIG1.h \ fig/FIGCarousel.cpp fig/FIGCarousel.h \ mpeg.h mpeg.c \ diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp index 4233b5b..bb08fac 100644 --- a/src/fig/FIG0.cpp +++ b/src/fig/FIG0.cpp @@ -3,7 +3,7 @@ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2015, 2016 + Copyright (C) 2016 Matthias P. Braendli, matthias.braendli@mpb.li Implementation of FIG0 @@ -26,6 +26,7 @@ */ #include "fig/FIG0.h" +#include "fig/FIG0structs.h" #include "utils.h" namespace FIC { diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h index 95a8a85..25aea15 100644 --- a/src/fig/FIG0.h +++ b/src/fig/FIG0.h @@ -23,8 +23,7 @@ along with ODR-DabMux. If not, see . */ -#ifndef __FIG0_H_ -#define __FIG0_H_ +#pragma once #include #include @@ -280,321 +279,5 @@ class FIG0_19 : public IFIG std::shared_ptr,int> m_disabled_announcements; }; -#ifdef _WIN32 -# pragma pack(push) -#endif - -struct FIGtype0 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIGtype0_0 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint16_t EId; - uint8_t CIFcnt_hight:5; - uint8_t Al:1; - uint8_t Change:2; - uint8_t CIFcnt_low:8; -} PACKED; - - -struct FIGtype0_2 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIGtype0_2_Service { - uint16_t SId; - uint8_t NbServiceComp:4; - uint8_t CAId:3; - uint8_t Local_flag:1; -} PACKED; - - -struct FIGtype0_2_Service_data { - uint32_t SId; - uint8_t NbServiceComp:4; - uint8_t CAId:3; - uint8_t Local_flag:1; -} PACKED; - - -struct FIGtype0_2_audio_component { - uint8_t ASCTy:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SubChId:6; -} PACKED; - - -struct FIGtype0_2_data_component { - uint8_t DSCTy:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SubChId:6; -} PACKED; - - -struct FIGtype0_2_packet_component { - uint8_t SCId_high:6; - uint8_t TMid:2; - uint8_t CA_flag:1; - uint8_t PS:1; - uint8_t SCId_low:6; - void setSCId(uint16_t SCId) { - SCId_high = SCId >> 6; - SCId_low = SCId & 0x3f; - } -} PACKED; - - -/* Warning: When bit SCCA_flag is unset(0), the multiplexer R&S does not send - * the SCCA field. But, in the Factum ETI analyzer, if this field is not there, - * it is an error. - */ -struct FIGtype0_3 { - uint8_t SCId_high; - uint8_t SCCA_flag:1; - uint8_t rfa:3; - uint8_t SCId_low:4; - uint8_t DSCTy:6; - uint8_t rfu:1; - uint8_t DG_flag:1; - uint8_t Packet_address_high:2; - uint8_t SubChId:6; - uint8_t Packet_address_low; - uint16_t SCCA; - void setSCId(uint16_t SCId) { - SCId_high = SCId >> 4; - SCId_low = SCId & 0xf; - } - void setPacketAddress(uint16_t address) { - Packet_address_high = address >> 8; - Packet_address_low = address & 0xff; - } -} PACKED; - -struct FIGtype0_5_short { - uint8_t SubChId:6; - uint8_t rfu:1; - uint8_t LS:1; - - uint8_t language; -} PACKED; - -struct FIGtype0_8_short { - uint8_t SCIdS:4; - uint8_t rfa_1:3; - uint8_t ext:1; - uint8_t Id:6; - uint8_t MscFic:1; - uint8_t LS:1; - uint8_t rfa_2; -} PACKED; - - -struct FIGtype0_8_long { - uint8_t SCIdS:4; - uint8_t rfa_1:3; - uint8_t ext:1; - uint8_t SCId_high:4; - uint8_t rfa:3; - uint8_t LS:1; - uint8_t SCId_low; - uint8_t rfa_2; - void setSCId(uint16_t id) { - SCId_high = id >> 8; - SCId_low = id & 0xff; - } - uint16_t getSCid() { - return (SCId_high << 8) | SCId_low; - } -} PACKED; - - -struct FIGtype0_9 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint8_t ensembleLto:6; - uint8_t rfa1:1; - uint8_t ext:1; - uint8_t ensembleEcc; - uint8_t tableId; -} PACKED; - - -struct FIGtype0_10_LongForm { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; - - uint8_t MJD_high:7; - uint8_t RFU:1; - - uint8_t MJD_med; - - uint8_t Hours_high:3; - uint8_t UTC:1; - uint8_t ConfInd:1; - uint8_t LSI:1; - uint8_t MJD_low:2; - - uint8_t Minutes:6; - uint8_t Hours_low:2; - - uint8_t Milliseconds_high:2; - uint8_t Seconds:6; - - uint8_t Milliseconds_low; - - void setMJD(uint32_t date) { - MJD_high = (date >> 10) & 0x7f; - MJD_med = (date >> 2) & 0xff; - MJD_low = date & 0x03; - } - void setHours(uint16_t hours) { - Hours_high = (hours >> 2) & 0x07; - Hours_low = hours & 0x03; - } - - void setMilliseconds(uint16_t ms) { - Milliseconds_high = (ms >> 8) & 0x03; - Milliseconds_low = ms & 0xFF; - } -} PACKED; - - -struct FIGtype0_17 { - uint16_t SId; - - uint8_t rfa2_high:4; - uint8_t rfu1:2; - uint8_t rfa1:1; - uint8_t SD:1; // Static/Dynamic - - uint8_t IntCode:5; - uint8_t rfu2:1; - uint8_t rfa2_low:2; -} PACKED; - -struct FIGtype0_18 { - uint16_t SId; - uint16_t ASu; - uint8_t NumClusters:5; - uint8_t Rfa:3; - /* Followed by uint8_t Cluster IDs */ -} PACKED; - -struct FIGtype0_19 { - uint8_t ClusterId; - uint16_t ASw; - uint8_t SubChId:6; - uint8_t RegionFlag:1; // shall be zero - uint8_t NewFlag:1; - // Region and RFa not supported -} PACKED; - -struct FIGtype0_1 { - uint8_t Length:5; - uint8_t FIGtypeNumber:3; - uint8_t Extension:5; - uint8_t PD:1; - uint8_t OE:1; - uint8_t CN:1; -} PACKED; - - -struct FIG_01_SubChannel_ShortF { - uint8_t StartAdress_high:2; - uint8_t SubChId:6; - uint8_t StartAdress_low:8; - uint8_t TableIndex:6; - uint8_t TableSwitch:1; - uint8_t Short_Long_form:1; -} PACKED; - - -struct FIG_01_SubChannel_LongF { - uint8_t StartAdress_high:2; - uint8_t SubChId:6; - uint8_t StartAdress_low:8; - uint8_t Sub_ChannelSize_high:2; - uint8_t ProtectionLevel:2; - uint8_t Option:3; - uint8_t Short_Long_form:1; - uint8_t Sub_ChannelSize_low:8; -} PACKED; - - -// See EN 300 401, Clause 8.1.20 for the FIG0_13 description -struct FIG0_13_shortAppInfo { - uint16_t SId; - uint8_t No:4; - uint8_t SCIdS:4; -} PACKED; - - -struct FIG0_13_longAppInfo { - uint32_t SId; - uint8_t No:4; - uint8_t SCIdS:4; -} PACKED; - - -struct FIG0_13_app { - uint8_t typeHigh; - uint8_t length:5; - uint8_t typeLow:3; - void setType(uint16_t type) { - typeHigh = type >> 3; - typeLow = type & 0x1f; - } - uint16_t xpad; -} PACKED; - -#define FIG0_13_APPTYPE_SLIDESHOW 0x2 -#define FIG0_13_APPTYPE_WEBSITE 0x3 -#define FIG0_13_APPTYPE_TPEG 0x4 -#define FIG0_13_APPTYPE_DGPS 0x5 -#define FIG0_13_APPTYPE_TMC 0x6 -#define FIG0_13_APPTYPE_EPG 0x7 -#define FIG0_13_APPTYPE_DABJAVA 0x8 -#define FIG0_13_APPTYPE_JOURNALINE 0x441 - - -#ifdef _WIN32 -# pragma pack(pop) -#endif - } // namespace FIC -#endif // __FIG0_H_ - diff --git a/src/fig/FIG0structs.h b/src/fig/FIG0structs.h new file mode 100644 index 0000000..a1e79d3 --- /dev/null +++ b/src/fig/FIG0structs.h @@ -0,0 +1,347 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include +#include + +#include "fig/FIG.h" + +#ifdef _WIN32 +# pragma pack(push) +#endif + +struct FIGtype0 { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; +} PACKED; + + +struct FIGtype0_0 { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; + + uint16_t EId; + uint8_t CIFcnt_hight:5; + uint8_t Al:1; + uint8_t Change:2; + uint8_t CIFcnt_low:8; +} PACKED; + + +struct FIGtype0_2 { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; +} PACKED; + + +struct FIGtype0_2_Service { + uint16_t SId; + uint8_t NbServiceComp:4; + uint8_t CAId:3; + uint8_t Local_flag:1; +} PACKED; + + +struct FIGtype0_2_Service_data { + uint32_t SId; + uint8_t NbServiceComp:4; + uint8_t CAId:3; + uint8_t Local_flag:1; +} PACKED; + + +struct FIGtype0_2_audio_component { + uint8_t ASCTy:6; + uint8_t TMid:2; + uint8_t CA_flag:1; + uint8_t PS:1; + uint8_t SubChId:6; +} PACKED; + + +struct FIGtype0_2_data_component { + uint8_t DSCTy:6; + uint8_t TMid:2; + uint8_t CA_flag:1; + uint8_t PS:1; + uint8_t SubChId:6; +} PACKED; + + +struct FIGtype0_2_packet_component { + uint8_t SCId_high:6; + uint8_t TMid:2; + uint8_t CA_flag:1; + uint8_t PS:1; + uint8_t SCId_low:6; + void setSCId(uint16_t SCId) { + SCId_high = SCId >> 6; + SCId_low = SCId & 0x3f; + } +} PACKED; + + +/* Warning: When bit SCCA_flag is unset(0), the multiplexer R&S does not send + * the SCCA field. But, in the Factum ETI analyzer, if this field is not there, + * it is an error. + */ +struct FIGtype0_3 { + uint8_t SCId_high; + uint8_t SCCA_flag:1; + uint8_t rfa:3; + uint8_t SCId_low:4; + uint8_t DSCTy:6; + uint8_t rfu:1; + uint8_t DG_flag:1; + uint8_t Packet_address_high:2; + uint8_t SubChId:6; + uint8_t Packet_address_low; + uint16_t SCCA; + void setSCId(uint16_t SCId) { + SCId_high = SCId >> 4; + SCId_low = SCId & 0xf; + } + void setPacketAddress(uint16_t address) { + Packet_address_high = address >> 8; + Packet_address_low = address & 0xff; + } +} PACKED; + +struct FIGtype0_5_short { + uint8_t SubChId:6; + uint8_t rfu:1; + uint8_t LS:1; + + uint8_t language; +} PACKED; + +struct FIGtype0_8_short { + uint8_t SCIdS:4; + uint8_t rfa_1:3; + uint8_t ext:1; + uint8_t Id:6; + uint8_t MscFic:1; + uint8_t LS:1; + uint8_t rfa_2; +} PACKED; + + +struct FIGtype0_8_long { + uint8_t SCIdS:4; + uint8_t rfa_1:3; + uint8_t ext:1; + uint8_t SCId_high:4; + uint8_t rfa:3; + uint8_t LS:1; + uint8_t SCId_low; + uint8_t rfa_2; + void setSCId(uint16_t id) { + SCId_high = id >> 8; + SCId_low = id & 0xff; + } + uint16_t getSCid() { + return (SCId_high << 8) | SCId_low; + } +} PACKED; + + +struct FIGtype0_9 { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; + + uint8_t ensembleLto:6; + uint8_t rfa1:1; + uint8_t ext:1; + uint8_t ensembleEcc; + uint8_t tableId; +} PACKED; + + +struct FIGtype0_10_LongForm { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; + + uint8_t MJD_high:7; + uint8_t RFU:1; + + uint8_t MJD_med; + + uint8_t Hours_high:3; + uint8_t UTC:1; + uint8_t ConfInd:1; + uint8_t LSI:1; + uint8_t MJD_low:2; + + uint8_t Minutes:6; + uint8_t Hours_low:2; + + uint8_t Milliseconds_high:2; + uint8_t Seconds:6; + + uint8_t Milliseconds_low; + + void setMJD(uint32_t date) { + MJD_high = (date >> 10) & 0x7f; + MJD_med = (date >> 2) & 0xff; + MJD_low = date & 0x03; + } + void setHours(uint16_t hours) { + Hours_high = (hours >> 2) & 0x07; + Hours_low = hours & 0x03; + } + + void setMilliseconds(uint16_t ms) { + Milliseconds_high = (ms >> 8) & 0x03; + Milliseconds_low = ms & 0xFF; + } +} PACKED; + + +struct FIGtype0_17 { + uint16_t SId; + + uint8_t rfa2_high:4; + uint8_t rfu1:2; + uint8_t rfa1:1; + uint8_t SD:1; // Static/Dynamic + + uint8_t IntCode:5; + uint8_t rfu2:1; + uint8_t rfa2_low:2; +} PACKED; + +struct FIGtype0_18 { + uint16_t SId; + uint16_t ASu; + uint8_t NumClusters:5; + uint8_t Rfa:3; + /* Followed by uint8_t Cluster IDs */ +} PACKED; + +struct FIGtype0_19 { + uint8_t ClusterId; + uint16_t ASw; + uint8_t SubChId:6; + uint8_t RegionFlag:1; // shall be zero + uint8_t NewFlag:1; + // Region and RFa not supported +} PACKED; + +struct FIGtype0_1 { + uint8_t Length:5; + uint8_t FIGtypeNumber:3; + uint8_t Extension:5; + uint8_t PD:1; + uint8_t OE:1; + uint8_t CN:1; +} PACKED; + + +struct FIG_01_SubChannel_ShortF { + uint8_t StartAdress_high:2; + uint8_t SubChId:6; + uint8_t StartAdress_low:8; + uint8_t TableIndex:6; + uint8_t TableSwitch:1; + uint8_t Short_Long_form:1; +} PACKED; + + +struct FIG_01_SubChannel_LongF { + uint8_t StartAdress_high:2; + uint8_t SubChId:6; + uint8_t StartAdress_low:8; + uint8_t Sub_ChannelSize_high:2; + uint8_t ProtectionLevel:2; + uint8_t Option:3; + uint8_t Short_Long_form:1; + uint8_t Sub_ChannelSize_low:8; +} PACKED; + + +// See EN 300 401, Clause 8.1.20 for the FIG0_13 description +struct FIG0_13_shortAppInfo { + uint16_t SId; + uint8_t No:4; + uint8_t SCIdS:4; +} PACKED; + + +struct FIG0_13_longAppInfo { + uint32_t SId; + uint8_t No:4; + uint8_t SCIdS:4; +} PACKED; + + +struct FIG0_13_app { + uint8_t typeHigh; + uint8_t length:5; + uint8_t typeLow:3; + void setType(uint16_t type) { + typeHigh = type >> 3; + typeLow = type & 0x1f; + } + uint16_t xpad; +} PACKED; + +#define FIG0_13_APPTYPE_SLIDESHOW 0x2 +#define FIG0_13_APPTYPE_WEBSITE 0x3 +#define FIG0_13_APPTYPE_TPEG 0x4 +#define FIG0_13_APPTYPE_DGPS 0x5 +#define FIG0_13_APPTYPE_TMC 0x6 +#define FIG0_13_APPTYPE_EPG 0x7 +#define FIG0_13_APPTYPE_DABJAVA 0x8 +#define FIG0_13_APPTYPE_JOURNALINE 0x441 + + +#ifdef _WIN32 +# pragma pack(pop) +#endif + diff --git a/src/utils.cpp b/src/utils.cpp index 5b48f21..baf15d5 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -28,6 +28,7 @@ #include #include "DabMux.h" #include "utils.h" +#include "fig/FIG0structs.h" using namespace std; -- cgit v1.2.3 From f198d1a2c799c97fe1e4e92e110cc0782f6f7880 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 30 Sep 2016 17:10:43 +0200 Subject: Add some FIG0/6 structures and skeleton --- src/fig/FIG0.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/fig/FIG0.h | 28 +++++++++++++++++++++ src/fig/FIG0structs.h | 19 ++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp index bb08fac..b560e4c 100644 --- a/src/fig/FIG0.cpp +++ b/src/fig/FIG0.cpp @@ -662,6 +662,75 @@ FillStatus FIG0_5::fill(uint8_t *buf, size_t max_size) return fs; } +//=========== FIG 0/6 =========== + +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; + + if (not m_initialised) { + linkageSetFIG0_6 = m_rti->ensemble->linkagesets.end(); + m_initialised = true; + } + + FIGtype0* fig0 = NULL; + + for (; linkageSetFIG0_6 != ensemble->linkagesets.end(); + ++linkageSetFIG0_6) { + + const int required_size = 2; + + 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 = 0; + fig0->Extension = 5; + + buf += 2; + remaining -= 2; + } + else if (remaining < required_size) { + break; + } + + FIGtype0_6 *fig0_6 = (FIGtype0_6*)buf; + + fig0_6->IdListFlag = 1; + fig0_6->LA = (*linkageSetFIG0_6)->active; + fig0_6->SH = (*linkageSetFIG0_6)->hard; + fig0_6->ILS = (*linkageSetFIG0_6)->international; + fig0_6->LSN = (*linkageSetFIG0_6)->lsn; + +#error "handle FIG insertion and CEI properly" + + fig0->Length += 2; + buf += 2; + remaining -= 2; + } + + if (linkageSetFIG0_6 == ensemble->linkagesets.end()) { + linkageSetFIG0_6 = ensemble->linkagesets.begin(); + fs.complete_fig_transmitted = true; + } + + fs.num_bytes_written = max_size - remaining; + return fs; +} + //=========== FIG 0/8 =========== FIG0_8::FIG0_8(FIGRuntimeInformation *rti) : diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h index 25aea15..5a8a69f 100644 --- a/src/fig/FIG0.h +++ b/src/fig/FIG0.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "fig/FIG.h" @@ -135,6 +136,33 @@ class FIG0_5 : public IFIG std::vector::iterator componentFIG0_5; }; +// 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; + std::list >::iterator linkageSetFIG0_6; +}; + // FIG type 0/8 // The Extension 8 of FIG type 0 (FIG 0/8) provides information to link // together the service component description that is valid within the ensemble 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; -- cgit v1.2.3 From b78139a2fe6ee76bcb85b240733bf803c5430286 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 12:29:20 +0200 Subject: Add some WIP for FIG0/6 --- src/MuxElements.h | 2 +- src/fig/FIG0.cpp | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/fig/FIG0.h | 22 ++++++++++ 3 files changed, 136 insertions(+), 9 deletions(-) diff --git a/src/MuxElements.h b/src/MuxElements.h index 8285e61..2f602ba 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -452,7 +452,7 @@ class LinkageSet : public RemoteControllable { bool hard; bool international; - std::string keyservice; + std::string keyservice; // TODO replace by pointer to service private: /* Remote control */ diff --git a/src/fig/FIG0.cpp b/src/fig/FIG0.cpp index b560e4c..1e179cf 100644 --- a/src/fig/FIG0.cpp +++ b/src/fig/FIG0.cpp @@ -686,7 +686,17 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) for (; linkageSetFIG0_6 != ensemble->linkagesets.end(); ++linkageSetFIG0_6) { - const int required_size = 2; + 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) { @@ -697,7 +707,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) fig0->Length = 1; fig0->CN = 0; fig0->OE = 0; - fig0->PD = 0; + fig0->PD = PD; fig0->Extension = 5; buf += 2; @@ -709,17 +719,112 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) FIGtype0_6 *fig0_6 = (FIGtype0_6*)buf; - fig0_6->IdListFlag = 1; + fig0_6->IdListFlag = (num_ids > 0); fig0_6->LA = (*linkageSetFIG0_6)->active; fig0_6->SH = (*linkageSetFIG0_6)->hard; - fig0_6->ILS = (*linkageSetFIG0_6)->international; + fig0_6->ILS = ILS; fig0_6->LSN = (*linkageSetFIG0_6)->lsn; -#error "handle FIG insertion and CEI properly" + fig0->Length += sizeof(struct FIGtype0_6); + buf += sizeof(struct FIGtype0_6); + remaining -= sizeof(struct FIGtype0_6); - fig0->Length += 2; - buf += 2; - remaining -= 2; + 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(); + } + + header->IdLQ = 0; // TODO not only DAB + 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 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(); + } + for (const auto& l : (*linkageSetFIG0_6)->id_list) { + if (l.type != ServiceLinkType::DAB) { + etiLog.log(error, "TODO only DAB links supported. (linkage set 0x%04x)", + (*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; + } + } + } + + fig0->Length += required_size; + buf += required_size; + remaining -= required_size; } if (linkageSetFIG0_6 == ensemble->linkagesets.end()) { diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h index 5a8a69f..0109219 100644 --- a/src/fig/FIG0.h +++ b/src/fig/FIG0.h @@ -29,6 +29,7 @@ #include #include #include +#include #include "fig/FIG.h" @@ -163,6 +164,27 @@ class FIG0_6 : public IFIG std::list >::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::list >::iterator linkageSetFIG0_6; +}; + // FIG type 0/8 // The Extension 8 of FIG type 0 (FIG 0/8) provides information to link // together the service component description that is valid within the ensemble -- cgit v1.2.3 From c97b43fc819e1e0e963183579d1b50f26f8c6f7f Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 15:36:21 +0200 Subject: Regroup linkagesets into subsets of same type --- src/ConfigParser.cpp | 6 +++--- src/MuxElements.cpp | 33 ++++++++++++++++++++++------ src/MuxElements.h | 37 +++++++++++++++++++------------ src/fig/FIG0_6.cpp | 61 +++++++++++++++++++++++++++++++++++++--------------- src/fig/FIG0_6.h | 19 +++++++++++++--- src/utils.cpp | 16 ++++++++------ 6 files changed, 121 insertions(+), 51 deletions(-) diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 2ca83d3..cb458d7 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -177,8 +177,8 @@ void parse_linkage(boost::property_tree::ptree& pt, } auto linkageset = make_shared(setuid, lsn, hard, international); - linkageset->active = active; - linkageset->keyservice = service_uid; // TODO check if it exists + linkageset->data.active = active; + linkageset->data.keyservice = service_uid; // TODO check if it exists auto pt_list = pt_set.get_child_optional("list"); if (not pt_list) { @@ -223,7 +223,7 @@ void parse_linkage(boost::property_tree::ptree& pt, link.ecc = 0; } - linkageset->id_list.push_back(link); + linkageset->data.id_list.push_back(link); } ensemble->linkagesets.push_back(linkageset); } diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index 656e294..510775e 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -663,12 +663,12 @@ unsigned short DabSubchannel::getSizeDWord(void) const } LinkageSet::LinkageSet(string name, uint16_t lsn, bool hard, bool international) : - RemoteControllable(name), - lsn(lsn), - active(false), - hard(hard), - international(international) + RemoteControllable(name) { + data.lsn = lsn; + data.active = false; + data.hard = hard; + data.international = international; RC_ADD_PARAMETER(active, "Activate this linkage set [0 or 1]"); } @@ -677,7 +677,7 @@ void LinkageSet::set_parameter(const string& parameter, const string& value) if (parameter == "active") { stringstream ss; ss << value; - ss >> active; + ss >> data.active; } else { stringstream ss; @@ -691,7 +691,7 @@ const string LinkageSet::get_parameter(const string& parameter) const { stringstream ss; if (parameter == "active") { - ss << active; + ss << data.active; } else { ss << "Parameter '" << parameter << @@ -700,3 +700,22 @@ const string LinkageSet::get_parameter(const string& parameter) const } return ss.str(); } + +LinkageSetData LinkageSetData::filter_type(ServiceLinkType type) +{ + LinkageSetData lsd; + + lsd.lsn = lsn; + lsd.active = active; + lsd.hard = hard; + lsd.international = international; + lsd.keyservice = keyservice; + + for (const auto& link : id_list) { + if (link.type == type) { + lsd.id_list.push_back(link); + } + } + + return lsd; +} diff --git a/src/MuxElements.h b/src/MuxElements.h index 2f602ba..8efc2cb 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -432,6 +432,28 @@ struct ServiceLink { uint8_t ecc; }; +/* Keep the data out of LinkageSet to make it copyable */ +struct LinkageSetData { + std::list id_list; + + /* Linkage Set Number is a 12-bit number that identifies the linkage + * set in a country (requires coordination between multiplex operators + * in a country) + */ + uint16_t lsn; + + bool active; // Remote-controllable + bool hard; + bool international; + + std::string keyservice; // TODO replace by pointer to service + + /* Return a LinkageSetData with id_list filtered to include + * only those links of a given type + */ + LinkageSetData filter_type(ServiceLinkType type); +}; + /* Represents a linkage set linkage sets according to * TS 103 176 Clause 5.2.3 "Linkage sets". This information will * be encoded in FIG 0/6. @@ -440,20 +462,7 @@ class LinkageSet : public RemoteControllable { public: LinkageSet(std::string name, uint16_t lsn, bool hard, bool international); - std::list id_list; - - /* Linkage Set Number is a 12-bit number that identifies the linkage - * set in a country (requires coordination between multiplex operators - * in a country) - */ - uint16_t lsn; - - bool active; // Remote-controllable - bool hard; - bool international; - - std::string keyservice; // TODO replace by pointer to service - + LinkageSetData data; private: /* Remote control */ virtual void set_parameter(const std::string& parameter, diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index f404a47..8c0e53d 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -40,21 +40,23 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) ssize_t remaining = max_size; auto ensemble = m_rti->ensemble; + update(); + if (not m_initialised) { - linkageSetFIG0_6 = m_rti->ensemble->linkagesets.end(); + linkageSetFIG0_6 = linkageSubsets.begin(); m_initialised = true; } FIGtype0* fig0 = NULL; - for (; linkageSetFIG0_6 != ensemble->linkagesets.end(); + for (; linkageSetFIG0_6 != linkageSubsets.end(); ++linkageSetFIG0_6) { const bool PD = false; - const bool ILS = (*linkageSetFIG0_6)->international; + 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 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) + @@ -84,10 +86,10 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) 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->LA = linkageSetFIG0_6->active; + fig0_6->SH = linkageSetFIG0_6->hard; fig0_6->ILS = ILS; - fig0_6->LSN = (*linkageSetFIG0_6)->lsn; + fig0_6->LSN = linkageSetFIG0_6->lsn; fig0->Length += sizeof(struct FIGtype0_6); buf += sizeof(struct FIGtype0_6); @@ -98,7 +100,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) header->rfu = 0; if (num_ids > 0x0F) { etiLog.log(error, "Too large number of links for linkage set 0x%04x", - (*linkageSetFIG0_6)->lsn); + linkageSetFIG0_6->lsn); throw MuxInitException(); } @@ -111,7 +113,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) remaining -= headersize; // TODO insert key service first - const std::string keyserviceuid =(*linkageSetFIG0_6)->keyservice; + const std::string keyserviceuid = linkageSetFIG0_6->keyservice; const auto& keyservice = std::find_if( ensemble->services.begin(), ensemble->services.end(), @@ -121,13 +123,13 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) if (keyservice == ensemble->services.end()) { etiLog.log(error, "Invalid key service %s in linkage set 0x%04x", - keyserviceuid.c_str(), (*linkageSetFIG0_6)->lsn); + keyserviceuid.c_str(), linkageSetFIG0_6->lsn); throw MuxInitException(); } - for (const auto& l : (*linkageSetFIG0_6)->id_list) { + for (const auto& l : linkageSetFIG0_6->id_list) { if (l.type != ServiceLinkType::DAB) { etiLog.log(error, "TODO only DAB links supported. (linkage set 0x%04x)", - (*linkageSetFIG0_6)->lsn); + linkageSetFIG0_6->lsn); throw MuxInitException(); } } @@ -139,7 +141,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) buf += 2; remaining -= 2; - for (const auto& l : (*linkageSetFIG0_6)->id_list) { + for (const auto& l : linkageSetFIG0_6->id_list) { buf[0] = l.id >> 8; buf[1] = l.id & 0xFF; fig0->Length += 2; @@ -155,7 +157,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) buf += 3; remaining -= 3; - for (const auto& l : (*linkageSetFIG0_6)->id_list) { + for (const auto& l : linkageSetFIG0_6->id_list) { buf[0] = l.ecc; buf[1] = l.id >> 8; buf[2] = l.id & 0xFF; @@ -174,7 +176,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) buf += 4; remaining -= 4; - for (const auto& l : (*linkageSetFIG0_6)->id_list) { + for (const auto& l : linkageSetFIG0_6->id_list) { buf[0] = l.id >> 24; buf[1] = l.id >> 16; buf[2] = l.id >> 8; @@ -191,8 +193,8 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) remaining -= required_size; } - if (linkageSetFIG0_6 == ensemble->linkagesets.end()) { - linkageSetFIG0_6 = ensemble->linkagesets.begin(); + if (linkageSetFIG0_6 == linkageSubsets.end()) { + linkageSetFIG0_6 = linkageSubsets.begin(); fs.complete_fig_transmitted = true; } @@ -200,5 +202,30 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) 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 index db55c06..1af396f 100644 --- a/src/fig/FIG0_6.h +++ b/src/fig/FIG0_6.h @@ -26,7 +26,7 @@ #pragma once #include -#include +#include #include #include "fig/FIG0structs.h" @@ -58,7 +58,20 @@ class FIG0_6 : public IFIG private: FIGRuntimeInformation *m_rti; bool m_initialised; - std::list >::iterator linkageSetFIG0_6; + + /* 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 linkageSubsets; + std::list::iterator linkageSetFIG0_6; }; // FIG0/6 needs a change indicator, which is a short-form FIG (i.e. without the list) @@ -79,7 +92,7 @@ class FIG0_6_CEI : public IFIG private: FIGRuntimeInformation *m_rti; bool m_initialised; - std::list >::iterator linkageSetFIG0_6; + std::vector >::iterator linkageSetFIG0_6; }; } diff --git a/src/utils.cpp b/src/utils.cpp index baf15d5..94268da 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -556,15 +556,17 @@ static void printLinking(const shared_ptr ensemble) { etiLog.log(info, " Linkage Sets"); for (const auto& linkageset : ensemble->linkagesets) { + const auto& lsd = linkageset->data; + etiLog.level(info) << " set " << linkageset->get_rc_name(); - etiLog.log(info, " LSN 0x%04x", linkageset->lsn); - etiLog.level(info) << " active " << (linkageset->active ? "true" : "false"); - etiLog.level(info) << " " << (linkageset->hard ? "hard" : "soft"); - etiLog.level(info) << " international " << (linkageset->international ? "true" : "false"); - etiLog.level(info) << " key service " << linkageset->keyservice; + etiLog.log(info, " LSN 0x%04x", lsd.lsn); + etiLog.level(info) << " active " << (lsd.active ? "true" : "false"); + etiLog.level(info) << " " << (lsd.hard ? "hard" : "soft"); + etiLog.level(info) << " international " << (lsd.international ? "true" : "false"); + etiLog.level(info) << " key service " << lsd.keyservice; etiLog.level(info) << " ID list"; - for (const auto& link : linkageset->id_list) { + for (const auto& link : lsd.id_list) { switch (link.type) { case ServiceLinkType::DAB: etiLog.level(info) << " type DAB"; @@ -580,7 +582,7 @@ static void printLinking(const shared_ptr ensemble) break; } etiLog.log(info, " id 0x%04x", link.id); - if (linkageset->international) { + if (lsd.international) { etiLog.log(info, " ecc 0x%04x", link.ecc); } } -- cgit v1.2.3 From 5736f17d34ffc86aeedb95cf652968eadf256051 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 15:41:04 +0200 Subject: Instantiate and schedule FIG0/6 in the carousel --- src/fig/FIGCarousel.cpp | 2 ++ src/fig/FIGCarousel.h | 1 + 2 files changed, 3 insertions(+) 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 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 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; -- cgit v1.2.3 From 0fa7f1d17cd8554db8e3d3bbe7603495b2ac07c7 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 15:50:58 +0200 Subject: Set IdLQ properly in FIG0/6 --- doc/servicelinking.mux | 5 ++--- src/fig/FIG0_6.cpp | 24 ++++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index 7fd90ba..b9a64d9 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -7,7 +7,7 @@ ; general { dabmode 1 - nbframes 0 + nbframes 10000 syslog false tist false @@ -132,7 +132,6 @@ components { } outputs { - tcp "tcp://0.0.0.0:9200" - throttle "simul://" + file "file://./test.eti?type=raw" } diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 8c0e53d..fa8cbfa 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -104,7 +104,22 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) throw MuxInitException(); } - header->IdLQ = 0; // TODO not only DAB + // 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; @@ -126,13 +141,6 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) keyserviceuid.c_str(), linkageSetFIG0_6->lsn); throw MuxInitException(); } - for (const auto& l : linkageSetFIG0_6->id_list) { - if (l.type != ServiceLinkType::DAB) { - etiLog.log(error, "TODO only DAB links supported. (linkage set 0x%04x)", - linkageSetFIG0_6->lsn); - throw MuxInitException(); - } - } if (not PD and not ILS) { buf[0] = (*keyservice)->id >> 8; -- cgit v1.2.3 From 951c55264c90a8058a271bdcb8d00068dcb80df8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 16:03:24 +0200 Subject: Correct number of bytes inserted for FIG0/6 --- src/fig/FIG0_6.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index fa8cbfa..7732c34 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -195,10 +195,6 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) } } } - - fig0->Length += required_size; - buf += required_size; - remaining -= required_size; } if (linkageSetFIG0_6 == linkageSubsets.end()) { -- cgit v1.2.3 From 14f692c2ae784e86218b1696e9af7e8664ee0f82 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 2 Oct 2016 16:05:48 +0200 Subject: Announce correct FIG Extension for FIG0/6 --- src/fig/FIG0_6.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 7732c34..479d004 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -74,7 +74,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) fig0->CN = 0; fig0->OE = 0; fig0->PD = PD; - fig0->Extension = 5; + fig0->Extension = 6; buf += 2; remaining -= 2; -- cgit v1.2.3 From fbf452591da8f39da1478e636082ef425c994f05 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 3 Oct 2016 21:28:23 +0200 Subject: Add additional test case and example to servicelinking.mux --- doc/servicelinking.mux | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index b9a64d9..38c59ee 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -74,6 +74,35 @@ linking { } } } + + ; And now an international true to test more options + set-ri { + lsn 0xdef + active false + hard soft + international true + keyservice srv-ri + + list { + ri-on-drm { + type drm + id 0x1298 + ecc 0xec + } + + ri-on-amss { + type amss + id 0x1A2B + ecc 0xea + } + + ri-on-fm { + type fm + id 0x4C5D + ecc 0x4f + } + } + } } ; For information about the ensemble, service, subchannels, components and outputs, -- cgit v1.2.3 From daa2a0a54bd4dc6ea8cef43a5c1d0271cbcc71e7 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 3 Oct 2016 21:29:04 +0200 Subject: Fix iterator usage in FIG0/6 --- src/fig/FIG0_6.cpp | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 479d004..20fe78b 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -40,10 +40,8 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) ssize_t remaining = max_size; auto ensemble = m_rti->ensemble; - update(); - if (not m_initialised) { - linkageSetFIG0_6 = linkageSubsets.begin(); + update(); m_initialised = true; } @@ -198,7 +196,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) } if (linkageSetFIG0_6 == linkageSubsets.end()) { - linkageSetFIG0_6 = linkageSubsets.begin(); + update(); fs.complete_fig_transmitted = true; } @@ -229,6 +227,42 @@ void FIG0_6::update() } } } + + linkageSetFIG0_6 = linkageSubsets.begin(); + +#if 0 + etiLog.log(info, " Linkage Sets"); + for (const auto& lsd : linkageSubsets) { + + etiLog.log(info, " LSN 0x%04x", lsd.lsn); + etiLog.level(info) << " active " << (lsd.active ? "true" : "false"); + etiLog.level(info) << " " << (lsd.hard ? "hard" : "soft"); + etiLog.level(info) << " international " << (lsd.international ? "true" : "false"); + etiLog.level(info) << " key service " << lsd.keyservice; + + etiLog.level(info) << " ID list"; + for (const auto& link : lsd.id_list) { + switch (link.type) { + case ServiceLinkType::DAB: + etiLog.level(info) << " type DAB"; + break; + case ServiceLinkType::FM: + etiLog.level(info) << " type FM"; + break; + case ServiceLinkType::DRM: + etiLog.level(info) << " type DRM"; + break; + case ServiceLinkType::AMSS: + etiLog.level(info) << " type AMSS"; + break; + } + etiLog.log(info, " id 0x%04x", link.id); + if (lsd.international) { + etiLog.log(info, " ecc 0x%04x", link.ecc); + } + } + } +#endif } } -- cgit v1.2.3 From 3342f01f9a0e6f1effc7a698208a072d4a120ff8 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 3 Oct 2016 21:29:29 +0200 Subject: Fix byte order in FIG0/6 structures --- src/fig/FIG0_6.cpp | 5 +++-- src/fig/FIG0structs.h | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 20fe78b..7c09078 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -87,7 +87,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) fig0_6->LA = linkageSetFIG0_6->active; fig0_6->SH = linkageSetFIG0_6->hard; fig0_6->ILS = ILS; - fig0_6->LSN = linkageSetFIG0_6->lsn; + fig0_6->setLSN(linkageSetFIG0_6->lsn); fig0->Length += sizeof(struct FIGtype0_6); buf += sizeof(struct FIGtype0_6); @@ -125,7 +125,6 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) 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(), @@ -208,6 +207,8 @@ void FIG0_6::update() { linkageSubsets.clear(); + // TODO check if AMSS and DRM have to be put into a single subset + for (const auto& linkageset : m_rti->ensemble->linkagesets) { const auto lsn = linkageset->data.lsn; diff --git a/src/fig/FIG0structs.h b/src/fig/FIG0structs.h index 4b9b7e0..3b9bfbf 100644 --- a/src/fig/FIG0structs.h +++ b/src/fig/FIG0structs.h @@ -153,11 +153,18 @@ struct FIGtype0_5_short { } 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 + uint8_t LSN_high:4; // Linkage Set Number + uint8_t ILS:1; // 0=national / 1=international + uint8_t SH:1; // 0=Soft link / 1=Hard link + uint8_t LA:1; // Linkage actuator + uint8_t IdListFlag:1; // Marks the presence of the list + + uint8_t LSN_low; // Linkage Set Number + + void setLSN(uint16_t LSN) { + LSN_high = LSN >> 8; + LSN_low = LSN & 0xff; + } } PACKED; #define FIG0_6_IDLQ_DAB 0x0 @@ -165,10 +172,10 @@ struct FIGtype0_6 { #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 + uint8_t rfa:1; // must be 0 + uint8_t IdLQ:2; // Identifier List Qualifier, see above defines + uint8_t rfu:1; // must be 0 } PACKED; struct FIGtype0_8_short { -- cgit v1.2.3 From a951ea2f636360f724ef35e8aabd859e46d42290 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 3 Oct 2016 21:29:51 +0200 Subject: Add missing else if in FIG0/6 --- src/fig/FIG0_6.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 7c09078..401606e 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -154,7 +154,7 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) remaining -= 2; } } - if (not PD and ILS) { + else if (not PD and ILS) { buf[0] = ensemble->ecc; buf[1] = (*keyservice)->id >> 8; buf[2] = (*keyservice)->id & 0xFF; -- cgit v1.2.3 From e6f8d2c621727a7ee7dbafa6f9f06f6905e6cdb7 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 7 Oct 2016 16:54:24 +0200 Subject: Minor comments and copyright changes --- src/DabMux.cpp | 2 +- src/RemoteControl.cpp | 4 +++- src/RemoteControl.h | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/DabMux.cpp b/src/DabMux.cpp index aefa701..6dd30bf 100644 --- a/src/DabMux.cpp +++ b/src/DabMux.cpp @@ -7,7 +7,7 @@ Matthias P. Braendli, matthias.braendli@mpb.li http://www.opendigitalradio.org - */ + */ /* This file is part of ODR-DabMux. diff --git a/src/RemoteControl.cpp b/src/RemoteControl.cpp index 12ab84e..ac9f087 100644 --- a/src/RemoteControl.cpp +++ b/src/RemoteControl.cpp @@ -3,8 +3,10 @@ Her Majesty the Queen in Right of Canada (Communications Research Center Canada) - Copyright (C) 2014 + Copyright (C) 2016 Matthias P. Braendli, matthias.braendli@mpb.li + + http://www.opendigitalradio.org */ /* This file is part of ODR-DabMux. diff --git a/src/RemoteControl.h b/src/RemoteControl.h index c682826..5b735a8 100644 --- a/src/RemoteControl.h +++ b/src/RemoteControl.h @@ -6,8 +6,9 @@ Copyright (C) 2016 Matthias P. Braendli, matthias.braendli@mpb.li + http://www.opendigitalradio.org + This module adds remote-control capability to some of the dabmux modules. - see testremotecontrol/test.cpp for an example of how to use this. */ /* This file is part of ODR-DabMux. -- cgit v1.2.3 From 5c3c6d734ff0c57fd3d45746df23b96e0e7fc99e Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 10 Oct 2016 12:06:45 +0200 Subject: Add FIG0/6 CEI --- src/MuxElements.h | 4 ++- src/fig/FIG0_6.cpp | 87 +++++++++++++++++++++++++++++++++++++++++++++++-- src/fig/FIG0_6.h | 8 ++--- src/fig/FIGCarousel.cpp | 2 ++ src/fig/FIGCarousel.h | 1 + 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/MuxElements.h b/src/MuxElements.h index 8efc2cb..79100a9 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -229,7 +229,7 @@ class dabEnsemble : public RemoteControllable { std::vector subchannels; std::vector > clusters; - std::list > linkagesets; + std::vector > linkagesets; }; @@ -463,6 +463,8 @@ class LinkageSet : public RemoteControllable { LinkageSet(std::string name, uint16_t lsn, bool hard, bool international); LinkageSetData data; + + bool is_active(void) const { return data.active; } private: /* Remote control */ virtual void set_parameter(const std::string& parameter, diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 401606e..411d47c 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -57,9 +57,9 @@ FillStatus FIG0_6::fill(uint8_t *buf, size_t max_size) 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) + + const int required_size = sizeof(struct FIGtype0_6) + headersize + (num_ids > 0 ? - headersize + (PD == 0 ? (ILS == 0 ? 2*num_ids : 3*num_ids) : 4*num_ids) : + (PD == 0 ? (ILS == 0 ? 2*num_ids : 3*num_ids) : 4*num_ids) : 0); if (fig0 == NULL) { @@ -266,5 +266,88 @@ void FIG0_6::update() #endif } + +FIG0_6_CEI::FIG0_6_CEI(FIGRuntimeInformation *rti) : + m_rti(rti) +{ +} + +FillStatus FIG0_6_CEI::fill(uint8_t *buf, size_t max_size) +{ + using namespace std; + + auto ensemble = m_rti->ensemble; + + // We are called every 24ms, and must timeout after 5s + const int timeout = 5000/24; + + m_transition.update_state(timeout, ensemble->linkagesets); + + FillStatus fs; + ssize_t remaining = max_size; + + FIGtype0* fig0 = NULL; + + // Combine all links into one list + set alllinks; + for (const auto& l : m_transition.new_entries) { + alllinks.insert(l.first.get()); + } + for (const auto& l : m_transition.repeated_entries) { + alllinks.insert(l.get()); + } + for (const auto& l : m_transition.disabled_entries) { + alllinks.insert(l.first.get()); + } + + for (auto& link : alllinks) { + const bool PD = false; + const bool ILS = link->data.international; + + // The CEI does not send list contents + const size_t num_ids = 0; + + const size_t headersize = sizeof(struct FIGtype0_6_header); + const int required_size = sizeof(struct FIGtype0_6) + headersize + + (num_ids > 0 ? + (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 = 1; // This is a CEI + 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 = link->data.active; + fig0_6->SH = link->data.hard; + fig0_6->ILS = ILS; + fig0_6->setLSN(link->data.lsn); + + fig0->Length += sizeof(struct FIGtype0_6); + buf += sizeof(struct FIGtype0_6); + remaining -= sizeof(struct FIGtype0_6); + } + + fs.complete_fig_transmitted = true; + return fs; +} + } diff --git a/src/fig/FIG0_6.h b/src/fig/FIG0_6.h index 1af396f..e970102 100644 --- a/src/fig/FIG0_6.h +++ b/src/fig/FIG0_6.h @@ -70,8 +70,8 @@ class FIG0_6 : public IFIG * We reorganise all LinkageSets into subsets that have * the same type. */ - std::list linkageSubsets; - std::list::iterator linkageSetFIG0_6; + std::vector linkageSubsets; + std::vector::iterator linkageSetFIG0_6; }; // FIG0/6 needs a change indicator, which is a short-form FIG (i.e. without the list) @@ -91,8 +91,8 @@ class FIG0_6_CEI : public IFIG private: FIGRuntimeInformation *m_rti; - bool m_initialised; - std::vector >::iterator linkageSetFIG0_6; + + TransitionHandler m_transition; }; } diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp index ac2a80b..2fc6718 100644 --- a/src/fig/FIGCarousel.cpp +++ b/src/fig/FIGCarousel.cpp @@ -65,6 +65,7 @@ FIGCarousel::FIGCarousel(std::shared_ptr ensemble) : m_fig0_3(&m_rti), m_fig0_5(&m_rti), m_fig0_6(&m_rti), + m_fig0_6_cei(&m_rti), m_fig0_17(&m_rti), m_fig0_8(&m_rti), m_fig1_0(&m_rti), @@ -96,6 +97,7 @@ FIGCarousel::FIGCarousel(std::shared_ptr ensemble) : 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_6_cei, 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 f52f266..209fe19 100644 --- a/src/fig/FIGCarousel.h +++ b/src/fig/FIGCarousel.h @@ -90,6 +90,7 @@ class FIGCarousel { FIG0_3 m_fig0_3; FIG0_5 m_fig0_5; FIG0_6 m_fig0_6; + FIG0_6_CEI m_fig0_6_cei; FIG0_17 m_fig0_17; FIG0_8 m_fig0_8; FIG1_0 m_fig1_0; -- cgit v1.2.3 From 6800fb66282525542366bc58df3095b93e3bf8ca Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 28 Nov 2016 20:08:56 +0100 Subject: Remove service linking active from RC This can be added later if the need arises, and when proper testing validates the implementation. --- TODO | 9 ++--- doc/servicelinking.mux | 8 ++--- src/ConfigParser.cpp | 6 ++-- src/MuxElements.cpp | 57 +++++++------------------------ src/MuxElements.h | 58 ++++++++++++++----------------- src/fig/FIG0_6.cpp | 91 +++---------------------------------------------- src/fig/FIG0_6.h | 32 +++++------------ src/fig/FIGCarousel.cpp | 2 -- src/fig/FIGCarousel.h | 1 - src/utils.cpp | 19 +++++------ 10 files changed, 69 insertions(+), 214 deletions(-) diff --git a/TODO b/TODO index 50fc9b8..fb56034 100644 --- a/TODO +++ b/TODO @@ -18,11 +18,12 @@ Initial work started in http://git.mpb.li/git/odr-edilib/ Explicit Service Linking ------------------------ -At the moment there is no support to signal explicit service linking. -Implementing this needs a definition of how it should look like in the -configuration file and in the remote control, and adding new FIGs to signal the -necessary information. +It is impossible to activate/deactive linkage sets. Commit 5c3c6d7 added +some code to transmit a FIG0/6 CEI, but this was subsequently reverted +because it was not tested enough. +Announcement of other frequencies on which to find programmes using FIG 0/21 is +also missing. Inputs for packet data ---------------------- diff --git a/doc/servicelinking.mux b/doc/servicelinking.mux index 38c59ee..f50b3fa 100644 --- a/doc/servicelinking.mux +++ b/doc/servicelinking.mux @@ -7,7 +7,7 @@ ; general { dabmode 1 - nbframes 10000 + nbframes 0 syslog false tist false @@ -29,10 +29,6 @@ linking { ; (mandatory) lsn 0xabc - ; whether this link is active or a "potential future link or de-activated link" - ; This field is also part of the remote control. (default false) - active true - ; Hard link means that all services carry the same programme, soft links means ; that the programmes are related in some way. (default true) hard true @@ -78,7 +74,6 @@ linking { ; And now an international true to test more options set-ri { lsn 0xdef - active false hard soft international true keyservice srv-ri @@ -162,5 +157,6 @@ components { outputs { file "file://./test.eti?type=raw" + throttle "simul://" } diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 1b6093e..7219663 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -137,7 +137,6 @@ static void parse_linkage(boost::property_tree::ptree& pt, throw runtime_error("Invalid service linking definition"); } - bool active = pt_set.get("active", false); bool hard = pt_set.get("hard", true); bool international = pt_set.get("international", false); @@ -149,8 +148,7 @@ static void parse_linkage(boost::property_tree::ptree& pt, } auto linkageset = make_shared(setuid, lsn, hard, international); - linkageset->data.active = active; - linkageset->data.keyservice = service_uid; // TODO check if it exists + linkageset->keyservice = service_uid; // TODO check if it exists auto pt_list = pt_set.get_child_optional("list"); if (not pt_list) { @@ -195,7 +193,7 @@ static void parse_linkage(boost::property_tree::ptree& pt, link.ecc = 0; } - linkageset->data.id_list.push_back(link); + linkageset->id_list.push_back(link); } ensemble->linkagesets.push_back(linkageset); } diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp index 7f92652..9dbe5fc 100644 --- a/src/MuxElements.cpp +++ b/src/MuxElements.cpp @@ -662,53 +662,22 @@ unsigned short DabSubchannel::getSizeDWord() const return (bitrate * 3) >> 3; } -LinkageSet::LinkageSet(string name, uint16_t lsn, bool hard, bool international) : - RemoteControllable(name) +LinkageSet::LinkageSet(const std::string& name, + uint16_t lsn, + bool hard, + bool international) : + lsn(lsn), + active(true), + hard(hard), + international(international) +{} + + +LinkageSet LinkageSet::filter_type(const ServiceLinkType type) { - data.lsn = lsn; - data.active = false; - data.hard = hard; - data.international = international; - RC_ADD_PARAMETER(active, "Activate this linkage set [0 or 1]"); -} - -void LinkageSet::set_parameter(const string& parameter, const string& value) -{ - if (parameter == "active") { - stringstream ss; - ss << value; - ss >> data.active; - } - else { - stringstream ss; - ss << "Parameter '" << parameter << - "' is not exported by controllable " << get_rc_name(); - throw ParameterError(ss.str()); - } -} - -const string LinkageSet::get_parameter(const string& parameter) const -{ - stringstream ss; - if (parameter == "active") { - ss << data.active; - } - else { - ss << "Parameter '" << parameter << - "' is not exported by controllable " << get_rc_name(); - throw ParameterError(ss.str()); - } - return ss.str(); -} - -LinkageSetData LinkageSetData::filter_type(ServiceLinkType type) -{ - LinkageSetData lsd; + LinkageSet lsd(m_name, lsn, hard, international); - lsd.lsn = lsn; lsd.active = active; - lsd.hard = hard; - lsd.international = international; lsd.keyservice = keyservice; for (const auto& link : id_list) { diff --git a/src/MuxElements.h b/src/MuxElements.h index 7ff23a6..968fb14 100644 --- a/src/MuxElements.h +++ b/src/MuxElements.h @@ -432,46 +432,40 @@ struct ServiceLink { uint8_t ecc; }; -/* Keep the data out of LinkageSet to make it copyable */ -struct LinkageSetData { - std::list id_list; - - /* Linkage Set Number is a 12-bit number that identifies the linkage - * set in a country (requires coordination between multiplex operators - * in a country) - */ - uint16_t lsn; - - bool active; // Remote-controllable - bool hard; - bool international; - - std::string keyservice; // TODO replace by pointer to service - - /* Return a LinkageSetData with id_list filtered to include - * only those links of a given type - */ - LinkageSetData filter_type(ServiceLinkType type); -}; - /* Represents a linkage set linkage sets according to * TS 103 176 Clause 5.2.3 "Linkage sets". This information will * be encoded in FIG 0/6. */ -class LinkageSet : public RemoteControllable { +class LinkageSet { public: - LinkageSet(std::string name, uint16_t lsn, bool hard, bool international); + LinkageSet(const std::string& name, + uint16_t lsn, + bool hard, + bool international); - LinkageSetData data; + std::string get_name(void) const { return m_name; } - bool is_active(void) const { return data.active; } - private: - /* Remote control */ - virtual void set_parameter(const std::string& parameter, - const std::string& value); + std::list id_list; - /* Getting a parameter always returns a string. */ - virtual const std::string get_parameter(const std::string& parameter) const; + /* Linkage Set Number is a 12-bit number that identifies the linkage + * set in a country (requires coordination between multiplex operators + * in a country) + */ + uint16_t lsn; + + bool active; // TODO: Remote-controllable + bool hard; + bool international; + + std::string keyservice; // TODO replace by pointer to service + + /* Return a LinkageSet with id_list filtered to include + * only those links of a given type + */ + LinkageSet filter_type(const ServiceLinkType type); + + private: + std::string m_name; }; std::vector::iterator getSubchannel( diff --git a/src/fig/FIG0_6.cpp b/src/fig/FIG0_6.cpp index 411d47c..5174ec2 100644 --- a/src/fig/FIG0_6.cpp +++ b/src/fig/FIG0_6.cpp @@ -210,21 +210,21 @@ void FIG0_6::update() // TODO check if AMSS and DRM have to be put into a single subset for (const auto& linkageset : m_rti->ensemble->linkagesets) { - const auto lsn = linkageset->data.lsn; + const auto lsn = linkageset->lsn; - for (const auto& link : linkageset->data.id_list) { + for (const auto& link : linkageset->id_list) { const auto type = link.type; const auto subset = std::find_if(linkageSubsets.begin(), linkageSubsets.end(), - [&](const LinkageSetData& l) { + [&](const LinkageSet& 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) ); + linkageSubsets.push_back( linkageset->filter_type(type) ); } } } @@ -266,88 +266,5 @@ void FIG0_6::update() #endif } - -FIG0_6_CEI::FIG0_6_CEI(FIGRuntimeInformation *rti) : - m_rti(rti) -{ -} - -FillStatus FIG0_6_CEI::fill(uint8_t *buf, size_t max_size) -{ - using namespace std; - - auto ensemble = m_rti->ensemble; - - // We are called every 24ms, and must timeout after 5s - const int timeout = 5000/24; - - m_transition.update_state(timeout, ensemble->linkagesets); - - FillStatus fs; - ssize_t remaining = max_size; - - FIGtype0* fig0 = NULL; - - // Combine all links into one list - set alllinks; - for (const auto& l : m_transition.new_entries) { - alllinks.insert(l.first.get()); - } - for (const auto& l : m_transition.repeated_entries) { - alllinks.insert(l.get()); - } - for (const auto& l : m_transition.disabled_entries) { - alllinks.insert(l.first.get()); - } - - for (auto& link : alllinks) { - const bool PD = false; - const bool ILS = link->data.international; - - // The CEI does not send list contents - const size_t num_ids = 0; - - const size_t headersize = sizeof(struct FIGtype0_6_header); - const int required_size = sizeof(struct FIGtype0_6) + headersize + - (num_ids > 0 ? - (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 = 1; // This is a CEI - 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 = link->data.active; - fig0_6->SH = link->data.hard; - fig0_6->ILS = ILS; - fig0_6->setLSN(link->data.lsn); - - fig0->Length += sizeof(struct FIGtype0_6); - buf += sizeof(struct FIGtype0_6); - remaining -= sizeof(struct FIGtype0_6); - } - - fs.complete_fig_transmitted = true; - return fs; -} - } diff --git a/src/fig/FIG0_6.h b/src/fig/FIG0_6.h index e970102..e7c81c5 100644 --- a/src/fig/FIG0_6.h +++ b/src/fig/FIG0_6.h @@ -30,10 +30,15 @@ #include #include "fig/FIG0structs.h" -#include "fig/TransitionHandler.h" namespace FIC { +/* TODO + * This FIG code is unable to transmit the CEI to announce + * activation/deactivation of linkage sets. + * The TransitionHandler.h would be useful for that purpose + */ + // FIG type 0/6 // Service Linking // @@ -70,29 +75,8 @@ class FIG0_6 : public IFIG * We reorganise all LinkageSets into subsets that have * the same type. */ - std::vector linkageSubsets; - std::vector::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; - - TransitionHandler m_transition; + std::vector linkageSubsets; + std::vector::iterator linkageSetFIG0_6; }; } diff --git a/src/fig/FIGCarousel.cpp b/src/fig/FIGCarousel.cpp index 2fc6718..ac2a80b 100644 --- a/src/fig/FIGCarousel.cpp +++ b/src/fig/FIGCarousel.cpp @@ -65,7 +65,6 @@ FIGCarousel::FIGCarousel(std::shared_ptr ensemble) : m_fig0_3(&m_rti), m_fig0_5(&m_rti), m_fig0_6(&m_rti), - m_fig0_6_cei(&m_rti), m_fig0_17(&m_rti), m_fig0_8(&m_rti), m_fig1_0(&m_rti), @@ -97,7 +96,6 @@ FIGCarousel::FIGCarousel(std::shared_ptr ensemble) : 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_6_cei, 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 209fe19..f52f266 100644 --- a/src/fig/FIGCarousel.h +++ b/src/fig/FIGCarousel.h @@ -90,7 +90,6 @@ class FIGCarousel { FIG0_3 m_fig0_3; FIG0_5 m_fig0_5; FIG0_6 m_fig0_6; - FIG0_6_CEI m_fig0_6_cei; FIG0_17 m_fig0_17; FIG0_8 m_fig0_8; FIG1_0 m_fig1_0; diff --git a/src/utils.cpp b/src/utils.cpp index 4431407..4c08e8b 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -369,18 +369,17 @@ void printSubchannels(vector& subchannels) static void printLinking(const shared_ptr ensemble) { etiLog.log(info, " Linkage Sets"); - for (const auto& linkageset : ensemble->linkagesets) { - const auto& lsd = linkageset->data; + for (const auto& ls : ensemble->linkagesets) { - etiLog.level(info) << " set " << linkageset->get_rc_name(); - etiLog.log(info, " LSN 0x%04x", lsd.lsn); - etiLog.level(info) << " active " << (lsd.active ? "true" : "false"); - etiLog.level(info) << " " << (lsd.hard ? "hard" : "soft"); - etiLog.level(info) << " international " << (lsd.international ? "true" : "false"); - etiLog.level(info) << " key service " << lsd.keyservice; + etiLog.level(info) << " set " << ls->get_name(); + etiLog.log(info, " LSN 0x%04x", ls->lsn); + etiLog.level(info) << " active " << (ls->active ? "true" : "false"); + etiLog.level(info) << " " << (ls->hard ? "hard" : "soft"); + etiLog.level(info) << " international " << (ls->international ? "true" : "false"); + etiLog.level(info) << " key service " << ls->keyservice; etiLog.level(info) << " ID list"; - for (const auto& link : lsd.id_list) { + for (const auto& link : ls->id_list) { switch (link.type) { case ServiceLinkType::DAB: etiLog.level(info) << " type DAB"; @@ -396,7 +395,7 @@ static void printLinking(const shared_ptr ensemble) break; } etiLog.log(info, " id 0x%04x", link.id); - if (lsd.international) { + if (ls->international) { etiLog.log(info, " ecc 0x%04x", link.ecc); } } -- cgit v1.2.3