/*
Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/)
Copyright (C) 2018 Matthias P. Braendli (http://www.opendigitalradio.org)
Copyright (C) 2015 Data Path
This program 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.
This program 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 this program. If not, see .
Authors:
Sergio Sagliocco
Matthias P. Braendli
/ | |- ')|) |-|_ _ (|,_ .| _ ,_ \
Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/
*/
#include "figs.hpp"
#include
#include
#include
#include
static std::unordered_set services_seen;
bool fig0_2_is_complete(int services_id)
{
bool complete = services_seen.count(services_id);
if (complete) {
services_seen.clear();
}
else {
services_seen.insert(services_id);
}
return complete;
}
// FIG 0/2 Basic service and service component definition
// ETSI EN 300 401 6.3.1
fig_result_t fig0_2(fig0_common_t& fig0, const display_settings_t &disp)
{
uint16_t sref, sid;
uint8_t cid, ecc, local, caid, ncomp, timd, ps, ca, subchid, scty;
int k = 1;
uint8_t* f = fig0.f;
fig_result_t r;
while (k < fig0.figlen) {
if (fig0.pd() == 0) {
sid = f[k] * 256 + f[k+1];
ecc = 0;
cid = (f[k] & 0xF0) >> 4;
sref = (f[k] & 0x0F) * 256 + f[k+1];
k += 2;
}
else {
sid = f[k] * 256 * 256 * 256 + \
f[k+1] * 256 * 256 + \
f[k+2] * 256 + \
f[k+3];
ecc = f[k];
cid = (f[k+1] & 0xF0) >> 4;
sref = (f[k+1] & 0x0F) * 256 * 256 + \
f[k+2] * 256 + \
f[k+3];
k += 4;
}
r.complete |= fig0_2_is_complete(sid);
local = (f[k] & 0x80) >> 7;
caid = (f[k] & 0x70) >> 4;
ncomp = f[k] & 0x0F;
r.msgs.emplace_back(0, "-");
r.msgs.emplace_back(1, strprintf("Service ID=0x%X", sid));
if (fig0.pd() != 0) {
r.msgs.emplace_back(1, strprintf("ECC=%d", ecc));
}
r.msgs.emplace_back(1, strprintf("Country id=%d", cid));
r.msgs.emplace_back(1, strprintf("Service reference=%d", sref));
r.msgs.emplace_back(1, strprintf("Number of components=%d", ncomp));
r.msgs.emplace_back(1, strprintf("Local flag=%d", local));
r.msgs.emplace_back(1, strprintf("CAID=%d", caid));
if (fig0.fibcrccorrect) {
auto& service = fig0.ensemble.get_or_create_service(sid);
service.programme_not_data = (fig0.pd() == 0);
}
k++;
r.msgs.emplace_back(1, "Components:");
for (int i = 0; i < ncomp; i++) {
uint8_t scomp[2];
memcpy(scomp, f+k, 2);
r.msgs.emplace_back(2, "-");
r.msgs.emplace_back(3, strprintf("ID=%d", i));
timd = (scomp[0] & 0xC0) >> 6;
ps = (scomp[1] & 0x02) >> 1;
ca = scomp[1] & 0x01;
scty = scomp[0] & 0x3F;
subchid = (scomp[1] & 0xFC) >> 2;
/* useless, kept as reference
if (timd == 3) {
uint16_t scid;
scid = scty*64 + subchid;
}
*/
if (ps == 0) {
r.msgs.emplace_back(3, "primary=true");
}
else {
r.msgs.emplace_back(3, "primary=false");
}
if (fig0.fibcrccorrect) {
// TODO is subchid unique, or do we also need to take timd into the key for identifying
// our components?
auto& service = fig0.ensemble.get_service(sid);
auto& component = service.get_or_create_component(subchid);
component.primary = (ps != 0);
}
if (timd == 0) {
//MSC stream audio
r.msgs.emplace_back(3, "Mode=audio stream");
if (scty == 0)
r.msgs.emplace_back(3, strprintf("ASCTy=MPEG Foreground sound (%d)", scty));
else if (scty == 1)
r.msgs.emplace_back(3, strprintf("ASCTy=MPEG Background sound (%d)", scty));
else if (scty == 2)
r.msgs.emplace_back(3, strprintf("ASCTy=Multi Channel sound (%d)", scty));
else if (scty == 63)
r.msgs.emplace_back(3, strprintf("ASCTy=AAC sound (%d)", scty));
else
r.msgs.emplace_back(3, strprintf("ASCTy=Unknown ASCTy (%d)", scty));
r.msgs.emplace_back(3, strprintf("SubChannel ID=0x%02X", subchid));
r.msgs.emplace_back(3, strprintf("CA=%d", ca));
}
else if (timd == 1) {
// MSC stream data
r.msgs.emplace_back(3, "Mode=data stream");
r.msgs.emplace_back(3, strprintf("DSCTy=%d %s", scty, get_dscty_type(scty)));
r.msgs.emplace_back(3, strprintf("SubChannel ID=0x%02X", subchid));
r.msgs.emplace_back(3, strprintf("CA=%d", ca));
}
else if (timd == 2) {
// FIDC
r.msgs.emplace_back(3, "Mode=FIDC");
r.msgs.emplace_back(3, strprintf("DSCTy=%d %s", scty, get_dscty_type(scty)));
r.msgs.emplace_back(3, strprintf("Fast Information Data Channel ID=0x%02X", subchid));
r.msgs.emplace_back(3, strprintf("CA=%d", ca));
}
else if (timd == 3) {
// MSC Packet mode
r.msgs.emplace_back(3, "Mode=MSC Packet");
r.msgs.emplace_back(3, strprintf("SubChannel ID=0x%02X", subchid));
r.msgs.emplace_back(3, strprintf("CA=%d", ca));
}
k += 2;
}
}
return r;
}