1
0
mirror of https://github.com/JvanKatwijk/qt-dab.git synced 2025-10-06 08:12:40 +02:00
Files
SDR-DAB_Qt-DAB/sources/frontend/fib-decoder.cpp

1453 lines
43 KiB
C++
Raw Normal View History

2024-12-27 12:39:00 +01:00
#
2019-03-25 20:17:53 +01:00
/*
2025-03-19 12:32:08 +01:00
* Copyright (C) 2018 .. 2025
2019-03-25 20:17:53 +01:00
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Computing
*
* This file is part of the Qt-DAB program
2020-02-26 13:12:21 +01:00
*
2019-03-25 20:17:53 +01:00
* Qt-DAB 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 2 of the License, or
* (at your option) any later version.
*
* Qt-DAB 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 Qt-DAB; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* fib decoder. Functionality is shared between fic handler, i.e. the
* one preparing the FIC blocks for processing, and the mainthread
* from which calls are coming on selecting a program
*/
#include "fib-decoder.h"
#include <cstring>
#include <vector>
#include "radio.h"
#include "charsets.h"
2023-10-14 11:27:18 +02:00
#include "bit-extractors.h"
2025-03-19 12:32:08 +01:00
#include "fib-config.h"
#include "ensemble.h"
2020-03-02 15:13:34 +01:00
#include "fib-table.h"
2022-02-26 19:54:19 +01:00
#include <QStringList>
#include "dab-tables.h"
2025-03-19 12:32:08 +01:00
#include "fib-printer.h"
2025-02-05 12:52:51 +01:00
#include "time-converter.h"
2019-03-25 20:17:53 +01:00
//
//
2025-05-27 18:50:45 +02:00
// The fibDecoder was rewritten since the "old" one
// contained (a) errors and (b) was incomplete on
// some issues.
// The current one is a straight forward implementation,
// where the FIG's are stored in a (kind of) database
2019-03-25 20:17:53 +01:00
fibDecoder::fibDecoder (RadioInterface *mr) {
myRadioInterface = mr;
2025-07-14 17:25:42 +02:00
connect (this, &fibDecoder::ensembleName,
myRadioInterface, &RadioInterface::ensembleName);
connect (this, &fibDecoder::clockTime,
myRadioInterface, &RadioInterface::clockTime);
connect (this, &fibDecoder::changeinConfiguration,
myRadioInterface, &RadioInterface::changeinConfiguration);
2025-03-19 12:32:08 +01:00
connect (this, &fibDecoder::announcement,
myRadioInterface, &RadioInterface::announcement);
connect (this, &fibDecoder::nrServices,
myRadioInterface, &RadioInterface::nrServices);
2025-03-19 10:08:05 +01:00
connect (this, &fibDecoder::lto_ecc,
myRadioInterface, &RadioInterface::lto_ecc);
2025-03-19 12:32:08 +01:00
connect (this, &fibDecoder::setFreqList,
myRadioInterface, &RadioInterface::setFreqList);
2023-10-24 14:36:30 +02:00
//
// Note that they may change "roles",
2025-03-19 12:32:08 +01:00
currentConfig = new fibConfig();
nextConfig = new fibConfig();
theEnsemble = new ensemble ();
2019-03-25 20:17:53 +01:00
CIFcount = 0;
2022-04-05 20:14:05 +02:00
mjd = 0;
2019-03-25 20:17:53 +01:00
}
2024-03-27 16:24:49 +01:00
fibDecoder::~fibDecoder () {
2020-03-02 15:13:34 +01:00
delete nextConfig;
delete currentConfig;
2025-03-19 12:32:08 +01:00
delete theEnsemble;
2019-03-25 20:17:53 +01:00
}
2021-04-12 12:21:24 +02:00
2019-03-25 20:17:53 +01:00
// FIB's are segments of 256 bits. When here, we already
// passed the crc and we start unpacking into FIGs
// This is merely a dispatcher
2025-07-14 17:25:42 +02:00
void fibDecoder::processFIB (uint8_t *p, uint16_t fib) {
2019-03-25 20:17:53 +01:00
int8_t processedBytes = 0;
uint8_t *d = p;
2019-07-08 23:30:45 +02:00
fibLocker. lock();
2019-03-25 20:17:53 +01:00
(void)fib;
while (processedBytes < 30) {
uint8_t FIGtype = getBits_3 (d, 0);
uint8_t FIGlength = getBits_5 (d, 3);
if ((FIGtype == 0x07) && (FIGlength == 0x3F))
return;
switch (FIGtype) {
case 0:
process_FIG0 (d);
break;
case 1:
process_FIG1 (d);
break;
case 2: // not yet implemented
break;
case 7:
break;
default:
break;
}
//
// Thanks to Ronny Kunze, who discovered that I used
// a p rather than a d
processedBytes += getBits_5 (d, 3) + 1;
// processedBytes += getBits (p, 3, 5) + 1;
d = p + processedBytes * 8;
}
2019-07-08 23:30:45 +02:00
fibLocker. unlock();
2019-03-25 20:17:53 +01:00
}
//
//
void fibDecoder::process_FIG0 (uint8_t *d) {
uint8_t extension = getBits_5 (d, 8 + 3);
switch (extension) {
case 0: // ensemble information (6.4.1)
FIG0Extension0 (d);
break;
case 1: // sub-channel organization (6.2.1)
FIG0Extension1 (d);
break;
case 2: // service organization (6.3.1)
FIG0Extension2 (d);
break;
case 3: // service component in packet mode (6.3.2)
FIG0Extension3 (d);
break;
case 4: // service component with CA (6.3.3)
break;
case 5: // service component language (8.1.2)
FIG0Extension5 (d);
break;
case 6: // service linking information (8.1.15)
break;
case 7: // configuration information (6.4.2)
FIG0Extension7 (d);
break;
case 8: // service component global definition (6.3.5)
FIG0Extension8 (d);
break;
2020-03-02 15:13:34 +01:00
case 9: // country, LTO & international table (8.1.3.2)
2024-03-27 16:24:49 +01:00
FIG0Extension9 (d);
break;
2019-03-25 20:17:53 +01:00
2024-03-27 16:24:49 +01:00
case 10: // date and time (8.1.3.1)
FIG0Extension10 (d);
break;
2019-03-25 20:17:53 +01:00
2025-03-29 10:51:10 +01:00
case 11: // Reserved
2019-03-25 20:17:53 +01:00
break;
2025-03-29 10:51:10 +01:00
case 12: // Reserved
2019-03-25 20:17:53 +01:00
break;
2020-03-02 15:13:34 +01:00
case 13: // user application information (6.3.6)
2019-03-25 20:17:53 +01:00
FIG0Extension13 (d);
break;
2020-03-02 15:13:34 +01:00
case 14: // FEC subchannel organization (6.2.2)
2019-03-25 20:17:53 +01:00
FIG0Extension14 (d);
break;
case 15: // Emergency warning (ETSI TS 104 089
// Not implemented yet
2019-03-25 20:17:53 +01:00
break;
2025-03-29 10:51:10 +01:00
case 16: // Reserved
2019-03-25 20:17:53 +01:00
break;
case 17: // Program type (8.1.5)
FIG0Extension17 (d);
break;
2020-03-02 15:13:34 +01:00
case 18: // announcement support (8.1.6.1)
2024-03-27 16:24:49 +01:00
FIG0Extension18 (d);
break;
2019-03-25 20:17:53 +01:00
2024-03-27 16:24:49 +01:00
case 19: // announcement switching (8.1.6.2)
FIG0Extension19 (d);
break;
2019-03-25 20:17:53 +01:00
case 20: // service component information (8.1.4)
2025-07-22 20:26:02 +02:00
FIG0Extension20 (d);
2020-03-05 22:08:18 +01:00
break; // to be implemented
2019-03-25 20:17:53 +01:00
case 21: // frequency information (8.1.8)
FIG0Extension21 (d);
break;
2025-03-29 10:51:10 +01:00
case 22: // Reserved
2019-03-25 20:17:53 +01:00
break;
2025-03-29 10:51:10 +01:00
case 23: // Reserved
2019-03-25 20:17:53 +01:00
break;
case 24: // OE services (8.1.10)
2020-03-05 22:08:18 +01:00
break; // not implemented
2019-03-25 20:17:53 +01:00
case 25: // OE announcement support (8.1.6.3)
2020-03-05 22:08:18 +01:00
break; // not implemented
2019-03-25 20:17:53 +01:00
case 26: // OE announcement switching (8.1.6.4)
2020-03-05 22:08:18 +01:00
break; // not implemented
2019-03-25 20:17:53 +01:00
2025-03-29 10:51:10 +01:00
case 27: // Reserved
case 28: // Reserved
case 29: // Reserved
case 30: // Reserved
case 31: // Reserved
2019-03-25 20:17:53 +01:00
break;
default:
2025-03-29 10:51:10 +01:00
// fprintf (stderr, "Missed %d\n", extension);
2019-03-25 20:17:53 +01:00
break;
}
}
// Ensemble information, 6.4.1
// FIG0/0 indicated a change in channel organization
// The info is MCI
void fibDecoder::FIG0Extension0 (uint8_t *d) {
uint16_t EId;
uint8_t changeFlag;
uint16_t highpart, lowpart;
int16_t occurrenceChange;
2025-07-20 19:25:14 +02:00
//uint8_t CN_bit = getBits_1 (d, 8 + 0);
2019-03-25 20:17:53 +01:00
uint8_t alarmFlag;
2020-02-26 13:12:21 +01:00
static uint8_t prevChangeFlag = 0;
2019-03-25 20:17:53 +01:00
2025-07-20 19:25:14 +02:00
// (void)CN_bit;
2019-03-25 20:17:53 +01:00
EId = getBits (d, 16, 16);
(void)EId;
changeFlag = getBits_2 (d, 16 + 16);
alarmFlag = getBits_1 (d, 16 + 16 + 2);
2020-02-26 13:12:21 +01:00
highpart = getBits_5 (d, 16 + 19);
lowpart = getBits_8 (d, 16 + 24);
2019-07-07 11:11:46 +02:00
(void)alarmFlag;
2019-03-25 20:17:53 +01:00
occurrenceChange = getBits_8 (d, 16 + 32);
(void)occurrenceChange;
2023-01-21 11:58:25 +01:00
CIFcount_hi = highpart;
CIFcount_lo = lowpart;
2019-03-25 20:17:53 +01:00
CIFcount = highpart * 250 + lowpart;
2020-03-05 22:08:18 +01:00
2025-03-19 12:32:08 +01:00
2020-02-26 13:12:21 +01:00
if ((changeFlag == 0) && (prevChangeFlag == 3)) {
2025-03-19 12:32:08 +01:00
fibConfig *temp = currentConfig;
2020-03-02 15:13:34 +01:00
currentConfig = nextConfig;
nextConfig = temp;
nextConfig -> reset ();
2025-03-19 12:32:08 +01:00
// cleanupServiceList ();
emit changeinConfiguration ();
2020-02-26 13:12:21 +01:00
}
prevChangeFlag = changeFlag;
2019-03-25 20:17:53 +01:00
// if (alarmFlag)
// fprintf (stderr, "serious problem\n");
}
//
// Subchannel organization 6.2.1
// FIG0 extension 1 creates a mapping between the
// sub channel identifications and the positions in the
// relevant CIF.
void fibDecoder::FIG0Extension1 (uint8_t *d) {
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
uint8_t CN_bit = getBits_1 (d, 8 + 0);
uint8_t OE_bit = getBits_1 (d, 8 + 1);
uint8_t PD_bit = getBits_1 (d, 8 + 2);
while (used < Length - 1)
used = HandleFIG0Extension1 (d, used, CN_bit, OE_bit, PD_bit);
}
//
// defining the channels
int16_t fibDecoder::HandleFIG0Extension1 (uint8_t *d, int16_t offset,
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
2019-03-25 20:17:53 +01:00
int16_t bitOffset = offset * 8;
2025-07-20 19:25:14 +02:00
const int16_t subChId = getBits_6 (d, bitOffset);
const int16_t startAdr = getBits (d, bitOffset + 6, 10);
2019-03-25 20:17:53 +01:00
int16_t tabelIndex;
2025-03-19 12:32:08 +01:00
int16_t option, protLevel, chanSize;
fibConfig::subChannel channel;
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2020-03-02 15:13:34 +01:00
static int table_1 [] = {12, 8, 6, 4};
static int table_2 [] = {27, 21, 18, 15};
2019-03-25 20:17:53 +01:00
2020-03-02 15:13:34 +01:00
(void)OE_bit; (void)PD_bit;
2025-03-19 12:32:08 +01:00
channel. subChId = subChId;
channel. startAddr = startAdr;
channel. Length = 0;
channel. FEC_scheme = 0; // corrected later on
2019-03-25 20:17:53 +01:00
if (getBits_1 (d, bitOffset + 16) == 0) { // short form
tabelIndex = getBits_6 (d, bitOffset + 18);
2025-03-19 12:32:08 +01:00
channel. Length = ProtLevel [tabelIndex][0];
channel. shortForm = true; // short form
channel. protLevel = ProtLevel [tabelIndex][1];
channel. bitRate = ProtLevel [tabelIndex][2];
2019-03-25 20:17:53 +01:00
bitOffset += 24;
}
else { // EEP long form
2025-03-19 12:32:08 +01:00
channel. shortForm = false;
2019-03-25 20:17:53 +01:00
option = getBits_3 (d, bitOffset + 17);
if (option == 0) { // A Level protection
protLevel = getBits (d, bitOffset + 20, 2);
2025-03-19 12:32:08 +01:00
channel. protLevel = protLevel;
chanSize = getBits (d, bitOffset + 22, 10);
channel. Length = chanSize;
channel. bitRate = chanSize / table_1 [protLevel] * 8;
2019-03-25 20:17:53 +01:00
}
else // option should be 001
if (option == 001) { // B Level protection
protLevel = getBits_2 (d, bitOffset + 20);
2025-03-19 12:32:08 +01:00
channel. protLevel = protLevel + (1 << 2);
chanSize = getBits (d, bitOffset + 22, 10);
channel. Length = chanSize;
channel. bitRate = chanSize / table_2 [protLevel] * 32;
2019-03-25 20:17:53 +01:00
}
bitOffset += 32;
}
//
// in case the subchannel data was already computed
2020-03-02 15:13:34 +01:00
// we merely compute the offset
2025-03-19 12:32:08 +01:00
if (localBase -> findIndex_subChannel_table (subChId) >= 0)
2019-03-25 20:17:53 +01:00
return bitOffset / 8;
//
2025-03-19 12:32:08 +01:00
localBase -> subChannel_table. push_back (channel);
2019-03-25 20:17:53 +01:00
return bitOffset / 8; // we return bytes
}
//
// Service organization, 6.3.1
2020-03-02 15:13:34 +01:00
// bind channels to SIds
2019-03-25 20:17:53 +01:00
void fibDecoder::FIG0Extension2 (uint8_t *d) {
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length) {
used = HandleFIG0Extension2 (d, used, CN_bit, OE_bit, PD_bit);
}
}
//
//
int16_t fibDecoder::HandleFIG0Extension2 (uint8_t *d,
int16_t offset,
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
2019-03-25 20:17:53 +01:00
int16_t bitOffset = 8 * offset;
2022-01-04 12:00:11 +01:00
uint8_t ecc = 0;
2019-03-25 20:17:53 +01:00
uint8_t cId;
uint32_t SId;
int16_t numberofComponents;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2019-03-25 20:17:53 +01:00
(void)OE_bit;
2020-03-02 15:13:34 +01:00
if (PD_bit == 1) { // long Sid, data
2019-03-25 20:17:53 +01:00
ecc = getBits_8 (d, bitOffset); (void)ecc;
2022-01-04 12:00:11 +01:00
cId = getBits_4 (d, bitOffset + 4);
2019-03-25 20:17:53 +01:00
SId = getLBits (d, bitOffset, 32);
bitOffset += 32;
}
else {
cId = getBits_4 (d, bitOffset); (void)cId;
SId = getBits (d, bitOffset, 16);
bitOffset += 16;
}
2024-03-25 14:35:22 +01:00
2025-03-19 12:32:08 +01:00
numberofComponents = getBits_4 (d, bitOffset + 4);
fibConfig::SId_struct SId_element;
SId_element. announcing = 0;
SId_element. SId = SId;
for (auto &ss: localBase -> SId_table) {
if (ss. SId == SId) {
bitOffset += numberofComponents * 16 + 8;
return bitOffset / 8;
}
}
2019-03-25 20:17:53 +01:00
bitOffset += 8;
2025-07-20 19:25:14 +02:00
for (uint16_t i = 0; i < numberofComponents; i ++) {
2025-03-19 12:32:08 +01:00
fibConfig::serviceComp_C comp;
comp. SId = SId;
comp. compNr = i;
2025-07-20 19:25:14 +02:00
const uint8_t TMid = getBits_2 (d, bitOffset);
2025-03-19 12:32:08 +01:00
comp. TMid = TMid;
2019-03-25 20:17:53 +01:00
if (TMid == 00) { // Audio
2025-03-19 12:32:08 +01:00
comp. ASCTy = getBits_6 (d, bitOffset + 2);
comp. subChId = getBits_6 (d, bitOffset + 8);
comp. PS_flag = getBits_1 (d, bitOffset + 14);
2019-03-25 20:17:53 +01:00
}
else
if (TMid == 3) { // MSC packet data
2025-03-19 12:32:08 +01:00
comp. SCId = getBits (d, bitOffset + 2, 12);
comp. PS_flag = getBits_1 (d, bitOffset + 14);
// uint8_t CA_flag = getBits_1 (d, bitOffset + 15);
2019-03-25 20:17:53 +01:00
}
2020-03-02 15:13:34 +01:00
else
2019-03-25 20:17:53 +01:00
{;}
bitOffset += 16;
2025-03-19 12:32:08 +01:00
if (!localBase -> compIsKnown (comp)) {
SId_element. comps. push_back (localBase -> SC_C_table. size ());
localBase -> SC_C_table. push_back (comp);
}
2019-03-25 20:17:53 +01:00
}
2025-03-19 12:32:08 +01:00
localBase -> SId_table. push_back (SId_element);
2019-03-25 20:17:53 +01:00
return bitOffset / 8; // in Bytes
}
2020-03-02 15:13:34 +01:00
2019-03-25 20:17:53 +01:00
// Service component in packet mode 6.3.2
void fibDecoder::FIG0Extension3 (uint8_t *d) {
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length)
used = HandleFIG0Extension3 (d, used, CN_bit, OE_bit, PD_bit);
}
//
// Note that the SCId (Service Component Identifier) is
// a unique 12 bit number in the ensemble
2020-03-02 15:13:34 +01:00
int16_t fibDecoder::HandleFIG0Extension3 (uint8_t *d,
int16_t used,
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
const int16_t SCId = getBits (d, used * 8, 12);
const int16_t CAOrgflag = getBits_1 (d, used * 8 + 15);
const int16_t DGflag = getBits_1 (d, used * 8 + 16);
const int16_t DSCTy = getBits_6 (d, used * 8 + 18);
const int16_t SubChId = getBits_6 (d, used * 8 + 24);
const int16_t packetAddress = getBits (d, used * 8 + 30, 10);
2019-03-25 20:17:53 +01:00
uint16_t CAOrg = 0;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2019-03-25 20:17:53 +01:00
(void)OE_bit; (void)PD_bit;
if (CAOrgflag == 1) {
CAOrg = getBits (d, used * 8 + 40, 16);
used += 16 / 8;
}
(void)CAOrg;
used += 40 / 8;
2025-03-19 12:32:08 +01:00
for (auto &comp : localBase -> SC_P_table)
if (comp. SCId == SCId)
return used;
fibConfig::serviceComp_P element;
element. SCId = SCId;
element. subChId = SubChId;
element. DSCTy = DSCTy;
element. DG_flag = DGflag;
element. packetAddress = packetAddress;
localBase -> SC_P_table. push_back (element);
2019-03-25 20:17:53 +01:00
return used;
}
// Service component language 8.1.2
void fibDecoder::FIG0Extension5 (uint8_t *d) {
2020-03-02 15:13:34 +01:00
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length) {
2025-07-20 19:25:14 +02:00
used = HandleFIG0Extension5 (d, used, CN_bit, OE_bit, PD_bit);
2019-03-25 20:17:53 +01:00
}
}
2020-03-02 15:13:34 +01:00
int16_t fibDecoder::HandleFIG0Extension5 (uint8_t* d,
2025-07-20 19:25:14 +02:00
uint16_t offset,
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
2019-03-25 20:17:53 +01:00
int16_t bitOffset = offset * 8;
2025-07-20 19:25:14 +02:00
const uint8_t LS_flag = getBits_1 (d, bitOffset);
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
fibConfig::SC_language comp;
(void)OE_bit;
(void)PD_bit;
comp. LS_flag = LS_flag;
if (LS_flag == 0) {
comp. subChId = getBits (d, bitOffset + 2, 6);
for (int i = 0; i < (int) localBase -> language_table. size (); i ++)
if ((localBase -> language_table [i]. LS_flag == 0) &&
(localBase -> language_table [i]. subChId == comp. subChId)) {
bitOffset += 16;
return bitOffset / 8;
}
comp. language = getBits (d, bitOffset + 8, 8);
2019-03-25 20:17:53 +01:00
bitOffset += 16;
}
2025-03-19 12:32:08 +01:00
else {
comp. SCId = getBits (d, bitOffset + 4, 12);
for (int i = 0; i < (int)localBase -> language_table. size (); i ++)
if ((localBase -> language_table [i]. LS_flag == 0) &&
(localBase -> language_table [i]. SCId == comp. SCId)) {
bitOffset += 24;
return bitOffset / 8;
}
comp. language = getBits (d, bitOffset + 16, 8);
2019-03-25 20:17:53 +01:00
bitOffset += 24;
}
2025-03-19 12:32:08 +01:00
localBase -> language_table. push_back (comp);
2019-03-25 20:17:53 +01:00
return bitOffset / 8;
}
//
2020-03-02 15:13:34 +01:00
// FIG0/7: Configuration linking information 6.4.2,
void fibDecoder::FIG0Extension7 (uint8_t *d) {
2021-10-29 15:43:05 +02:00
int16_t used = 2; // offset in bytes
2020-03-02 15:13:34 +01:00
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2020-02-26 13:12:21 +01:00
2025-07-20 19:25:14 +02:00
const int serviceCount = getBits_6 (d, used * 8);
//int counter = getBits (d, used * 8 + 6, 10);
2020-02-26 13:12:21 +01:00
2020-03-02 15:13:34 +01:00
(void)Length;
(void)CN_bit; (void)OE_bit; (void)PD_bit;
2023-04-26 11:27:33 +02:00
// fprintf (stderr, "services : %d\n", serviceCount);
2021-10-28 13:54:58 +02:00
if (CN_bit == 0) // only current configuration for now
nrServices (serviceCount);
2025-07-20 19:25:14 +02:00
// (void)counter;
2019-03-25 20:17:53 +01:00
}
2020-03-02 15:13:34 +01:00
// FIG0/8: Service Component Global Definition (6.3.5)
2019-03-25 20:17:53 +01:00
void fibDecoder::FIG0Extension8 (uint8_t *d) {
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length) {
used = HandleFIG0Extension8 (d, used, CN_bit, OE_bit, PD_bit);
}
}
2020-03-02 15:13:34 +01:00
int16_t fibDecoder::HandleFIG0Extension8 (uint8_t *d,
int16_t used,
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
2019-03-25 20:17:53 +01:00
int16_t bitOffset = used * 8;
2025-07-20 19:25:14 +02:00
const uint32_t SId = getLBits (d, bitOffset, PD_bit == 1 ? 32 : 16);
2025-03-19 12:32:08 +01:00
uint8_t LS_flag;
2019-03-25 20:17:53 +01:00
uint8_t extensionFlag;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
fibConfig::serviceComp_G comp;
2020-03-02 15:13:34 +01:00
(void)OE_bit;
bitOffset += PD_bit == 1 ? 32 : 16;
2019-03-25 20:17:53 +01:00
extensionFlag = getBits_1 (d, bitOffset);
2024-03-27 16:24:49 +01:00
uint8_t SCIds = getBits_4 (d, bitOffset + 4);
2019-03-25 20:17:53 +01:00
2023-11-03 17:47:31 +01:00
// int serviceIndex = find_service (SId);
2020-03-02 15:13:34 +01:00
bitOffset += 8;
2025-03-19 12:32:08 +01:00
LS_flag = getBits_1 (d, bitOffset);
comp. SId = SId;
comp. SCIds = SCIds;
comp. LS_flag = LS_flag;
if (LS_flag == 0) { // short form
comp. subChId = getBits_6 (d, bitOffset + 2);
2020-03-02 15:13:34 +01:00
bitOffset += 8;
2019-03-25 20:17:53 +01:00
}
2020-03-02 15:13:34 +01:00
else { // long form
2025-03-19 12:32:08 +01:00
comp. SCId = getBits (d, bitOffset + 4, 12);
bitOffset += 16;
2019-03-25 20:17:53 +01:00
}
if (extensionFlag)
bitOffset += 8; // skip Rfa
2025-03-19 12:32:08 +01:00
for (auto &el : localBase -> SC_G_table)
if ((el. SId == SId) && (el. SCIds == SCIds))
return bitOffset / 8;
localBase -> SC_G_table. push_back (comp);
2019-03-25 20:17:53 +01:00
return bitOffset / 8;
}
2025-03-19 12:32:08 +01:00
// FIG0/9 Country, LTO and International table, clause 8.1.3.2;
void fibDecoder::FIG0Extension9 (uint8_t *d) {
int16_t used = 2; // offset in bytes
//int16_t Length = getBits_5 (d, 3);
//uint8_t CN_bit = getBits_1 (d, 8 + 0);
//uint8_t OE_bit = getBits_1 (d, 8 + 1);
//uint8_t PD_bit = getBits_1 (d, 8 + 2);
2025-03-29 10:51:10 +01:00
// 6 indicates the number of hours
2025-07-20 19:25:14 +02:00
const int signbit = getBits_1 (d, used * 8 + 2);
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [6] = (signbit == 1)?
-1 * getBits_4 (d, used * 8 + 3):
getBits_4 (d, used * 8 + 3);
2025-03-29 10:51:10 +01:00
// 7 indicates a possible remaining half our
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [7] =
(getBits_1 (d, used * 8 + 7) == 1) ? 30 : 0;
2025-07-20 19:25:14 +02:00
if (signbit != 0)
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [7] = - currentConfig -> dateTime [7];
2025-03-29 10:51:10 +01:00
2025-04-01 19:25:23 +02:00
uint8_t LTO = currentConfig -> dateTime [6];
2025-03-19 12:32:08 +01:00
uint8_t ecc = getBits (d, used * 8 + 8, 8);
theEnsemble -> eccByte = ecc;
theEnsemble -> lto = LTO;
lto_ecc (LTO, ecc);
}
int monthLength [] {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//
// Time in 10 is given in UTC, for other time zones
// we add (or subtract) a number of Hours (half hours)
2025-04-01 19:25:23 +02:00
void fibDecoder::adjustTime (int32_t *dateTime) {
2025-03-19 12:32:08 +01:00
// first adjust the half hour in the amount of minutes
2025-05-27 18:50:45 +02:00
(void)dateTime;
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [4] +=
(currentConfig -> dateTime [7] == 1) ? 30 : 0;
if (currentConfig -> dateTime [4] >= 60) {
currentConfig -> dateTime [4] -= 60;
currentConfig -> dateTime [3] ++;
2025-03-19 12:32:08 +01:00
}
2025-04-01 19:25:23 +02:00
if (currentConfig -> dateTime [4] < 0) {
currentConfig -> dateTime [4] += 60;
currentConfig -> dateTime [3] --;
2025-03-19 12:32:08 +01:00
}
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [3] += currentConfig -> dateTime [6];
if ((0 <= currentConfig -> dateTime [3]) &&
(currentConfig -> dateTime [3] <= 23))
2025-03-19 12:32:08 +01:00
return;
2025-04-01 19:25:23 +02:00
if (currentConfig -> dateTime [3] > 23) {
currentConfig -> dateTime [3] -= 24;
currentConfig -> dateTime [2] ++;
2025-03-19 12:32:08 +01:00
}
2025-04-01 19:25:23 +02:00
if (currentConfig -> dateTime [3] < 0) {
currentConfig -> dateTime [3] += 24;
currentConfig -> dateTime [2] --;
2025-03-19 12:32:08 +01:00
}
2025-04-01 19:25:23 +02:00
if (currentConfig -> dateTime [2] >
monthLength [currentConfig -> dateTime [1] - 1]) {
currentConfig -> dateTime [2] = 1;
currentConfig -> dateTime [1] ++;
if (currentConfig -> dateTime [1] > 12) {
currentConfig -> dateTime [1] = 1;
currentConfig -> dateTime [0] ++;
2025-03-19 12:32:08 +01:00
}
}
2025-04-01 19:25:23 +02:00
if (currentConfig -> dateTime [2] < 0) {
if (currentConfig -> dateTime [1] > 1) {
currentConfig -> dateTime [2] =
monthLength [currentConfig -> dateTime [1] - 1 - 1];
currentConfig -> dateTime [1] --;
2025-03-19 12:32:08 +01:00
}
else {
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [2] = monthLength [11];
currentConfig -> dateTime [1] = 12;
currentConfig -> dateTime [0] --;
2025-03-19 12:32:08 +01:00
}
}
}
2025-03-29 10:51:10 +01:00
2025-03-19 12:32:08 +01:00
// 8.1.3.1 Date and time (d&t)
void fibDecoder::FIG0Extension10 (uint8_t *dd) {
int16_t offset = 16;
this -> mjd = getLBits (dd, offset + 1, 17);
uint16_t theTime [6];
convertTime (mjd, theTime);
// theTime [0] = Y; // Year
// theTime [1] = M; // Month
// theTime [2] = D; // Day
theTime [3] = getBits_5 (dd, offset + 21); // Hours
theTime [4] = getBits_6 (dd, offset + 26); // Minutes
2025-04-01 19:25:23 +02:00
if (getBits_6 (dd, offset + 26) != currentConfig -> dateTime [4])
theTime [5] = 0; // Seconds
2025-03-19 12:32:08 +01:00
if (dd [offset + 20] == 1)
theTime [5] = getBits_6 (dd, offset + 32); // Seconds
//
// take care of different time zones
bool change = false;
for (int i = 0; i < 6; i ++) {
2025-04-01 19:25:23 +02:00
if (theTime [i] != currentConfig -> dateTime [i])
2025-03-19 12:32:08 +01:00
change = true;
2025-04-01 19:25:23 +02:00
currentConfig -> dateTime [i] = theTime [i];
2025-03-19 12:32:08 +01:00
}
#ifdef CLOCK_STREAMER
change = true;
#endif
if (change) {
2025-04-01 19:25:23 +02:00
int utc_day = currentConfig -> dateTime [2];
int utc_hour = currentConfig -> dateTime [3];
int utc_minute = currentConfig -> dateTime [4];
int utc_seconds = currentConfig -> dateTime [5];
adjustTime (currentConfig -> dateTime);
emit clockTime (currentConfig -> dateTime [0],
currentConfig -> dateTime [1],
currentConfig -> dateTime [2],
currentConfig -> dateTime [3],
currentConfig -> dateTime [4],
utc_day, utc_hour, utc_minute, utc_seconds);
2025-03-19 12:32:08 +01:00
}
}
2019-03-25 20:17:53 +01:00
//
// User Application Information 6.3.6
void fibDecoder::FIG0Extension13 (uint8_t *d) {
int16_t used = 2; // offset in bytes
int16_t Length = getBits_5 (d, 3);
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length)
used = HandleFIG0Extension13 (d, used, CN_bit, OE_bit, PD_bit);
}
2022-03-15 19:27:08 +01:00
//
// section 6.3.6 User application Data
2019-03-25 20:17:53 +01:00
int16_t fibDecoder::HandleFIG0Extension13 (uint8_t *d,
int16_t used,
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t pdBit) {
2022-02-26 19:54:19 +01:00
int16_t bitOffset = used * 8;
2019-03-25 20:17:53 +01:00
uint32_t SId = getLBits (d, bitOffset, pdBit == 1 ? 32 : 16);
uint16_t SCIds;
int16_t NoApplications;
int16_t i;
int16_t appType;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
fibConfig::AppType element;
2022-04-05 20:14:05 +02:00
(void)OE_bit;
2020-03-02 15:13:34 +01:00
bitOffset += pdBit == 1 ? 32 : 16;
2019-03-25 20:17:53 +01:00
SCIds = getBits_4 (d, bitOffset);
NoApplications = getBits_4 (d, bitOffset + 4);
2022-12-12 13:52:57 +01:00
bitOffset += 8;
2025-03-19 12:32:08 +01:00
element. SId = SId;
element. SCIds = SCIds;
2020-03-02 15:13:34 +01:00
2019-03-25 20:17:53 +01:00
for (i = 0; i < NoApplications; i ++) {
appType = getBits (d, bitOffset, 11);
int16_t length = getBits_5 (d, bitOffset + 11);
2025-03-19 12:32:08 +01:00
element. Apptype = appType;
2024-01-03 12:26:08 +01:00
bitOffset += (11 + 5 + 8 * length);
2020-03-02 15:13:34 +01:00
}
2025-03-19 12:32:08 +01:00
for (auto &comp : localBase -> AppType_table)
if ((comp. SId == SId) && (comp. SCIds == SCIds))
return bitOffset / 8;
localBase -> AppType_table. push_back (element);
2019-03-25 20:17:53 +01:00
return bitOffset / 8;
}
// FEC sub-channel organization 6.2.2
void fibDecoder::FIG0Extension14 (uint8_t *d) {
int16_t Length = getBits_5 (d, 3); // in Bytes
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
int16_t used = 2; // in Bytes
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2019-03-25 20:17:53 +01:00
2020-03-02 15:13:34 +01:00
(void)OE_bit; (void)PD_bit;
2019-03-25 20:17:53 +01:00
while (used < Length) {
2025-03-19 12:32:08 +01:00
2019-03-25 20:17:53 +01:00
int16_t subChId = getBits_6 (d, used * 8);
uint8_t FEC_scheme = getBits_2 (d, used * 8 + 6);
used = used + 1;
2025-03-19 12:32:08 +01:00
for (auto &subC: localBase -> subChannel_table)
if (subC. subChId == subChId)
subC. FEC_scheme = FEC_scheme;
2019-03-25 20:17:53 +01:00
}
}
2025-03-19 12:32:08 +01:00
//
// program type 8.1.5
2019-03-25 20:17:53 +01:00
void fibDecoder::FIG0Extension17 (uint8_t *d) {
int16_t length = getBits_5 (d, 3);
int16_t offset = 16;
while (offset < length * 8) {
uint16_t SId = getBits (d, offset, 16);
2025-03-19 12:32:08 +01:00
uint8_t typeCode = getBits_5 (d, offset + 27);
for (uint16_t i = 0; i < theEnsemble -> primaries. size (); i ++) {
if (theEnsemble -> primaries [i]. SId == SId) {
theEnsemble -> primaries [i]. programType = typeCode;
break;
}
2020-03-02 15:13:34 +01:00
}
2025-03-19 12:32:08 +01:00
offset += 32;
2019-03-25 20:17:53 +01:00
}
}
//
// Announcement support 8.1.6.1
void fibDecoder::FIG0Extension18 (uint8_t *d) {
int16_t Length = getBits_5 (d, 3); // in Bytes
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
int16_t used = 2; // in Bytes
int16_t bitOffset = used * 8;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2020-03-02 15:13:34 +01:00
(void)OE_bit; (void)PD_bit;
2019-03-25 20:17:53 +01:00
while (bitOffset < Length * 8) {
2019-08-04 20:56:11 +02:00
uint16_t SId = getBits (d, bitOffset, 16);
bitOffset += 16;
2019-03-25 20:17:53 +01:00
uint16_t asuFlags = getBits (d, bitOffset, 16);
2019-08-04 20:56:11 +02:00
bitOffset += 16;
2025-03-19 12:32:08 +01:00
(void) getBits (d, bitOffset, 5); // Rfa
2019-03-25 20:17:53 +01:00
uint8_t nrClusters = getBits (d, bitOffset + 5, 3);
2019-08-04 20:56:11 +02:00
bitOffset += 8;
2020-03-02 15:13:34 +01:00
for (int i = 0; i < nrClusters; i ++) {
2025-03-19 12:32:08 +01:00
fibConfig::FIG18_cluster aC;
uint8_t clusterId = getBits (d, bitOffset + 8 * i, 8);
if (clusterId == 0)
continue;
2025-03-19 12:32:08 +01:00
bool inTable = false;
for (auto &ACe : localBase -> announcement_table) {
if ((ACe. SId == SId) && (clusterId == ACe. clusterId)) {
inTable = true;
break;
}
}
if (!inTable) {
aC. SId = SId;
aC. asuFlags = asuFlags;
aC. clusterId = clusterId;
localBase -> announcement_table. push_back (aC);
}
}
2019-07-06 20:53:41 +02:00
bitOffset += nrClusters * 8;
2019-03-25 20:17:53 +01:00
}
}
2023-12-29 18:36:02 +01:00
2025-03-29 10:51:10 +01:00
// Announcement switching 8.1.6.2
2025-03-19 12:32:08 +01:00
void fibDecoder::FIG0Extension19 (uint8_t *d) {
int16_t Length = getBits_5 (d, 3); // in Bytes
2025-07-20 19:25:14 +02:00
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
int16_t used = 2; // in Bytes
int16_t bitOffset = used * 8;
2025-03-19 12:32:08 +01:00
fibConfig *localBase = CN_bit == 0 ? currentConfig : nextConfig;
2020-03-02 15:13:34 +01:00
(void)OE_bit; (void)PD_bit;
while (bitOffset < Length * 8) {
uint8_t clusterId = getBits (d, bitOffset, 8);
bitOffset += 8;
uint16_t AswFlags = getBits (d, bitOffset, 16);
bitOffset += 16;
2025-03-19 12:32:08 +01:00
uint8_t newFlag = getBits (d, bitOffset, 1);
bitOffset += 1;
uint8_t Rfa = getBits (d, bitOffset, 1);
(void)Rfa;
bitOffset += 1;
uint8_t subChId = getBits (d, bitOffset, 6);
2025-03-19 12:32:08 +01:00
bitOffset += 6;
for (auto &ac : localBase -> announcement_table) {
if ((ac. clusterId == clusterId) && newFlag)
2025-07-14 17:25:42 +02:00
handleAnnouncement (ac. SId,
2025-03-19 12:32:08 +01:00
ac. asuFlags & AswFlags, subChId);
}
}
2025-03-19 12:32:08 +01:00
return;
2019-03-25 20:17:53 +01:00
}
2025-07-22 20:26:02 +02:00
//
// Service Component Information
void fibDecoder::FIG0Extension20 (uint8_t *d) {
int16_t used = 2; // offset in bytes
const int16_t Length = getBits_5 (d, 3);
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2025-03-19 12:32:08 +01:00
2025-07-22 20:26:02 +02:00
return;
while (used < Length)
used = HandleFIG0Extension21 (d, used, CN_bit, OE_bit, PD_bit);
}
int16_t fibDecoder::HandleFIG0Extension20 (uint8_t *d,
uint16_t offset,
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
uint32_t SId = PD_bit? getLBits (d, offset, 32) :
getLBits (d, offset, 16);
offset += PD_bit ? 32 : 16;
uint8_t SCIds = getBits_4 (d, offset); offset += 4;
uint8_t ChangeFlags = getBits_2 (d, offset); offset += 2;
uint8_t PT_flag = getBits_1 (d, offset); offset += 1;
uint8_t SC_flag = getBits_1 (d, offset); offset += 1;
uint8_t AD_flag = getBits_1 (d, offset + 1); offset += 2;
uint8_t SCTy = getBits_6 (d, offset); offset += 6;
uint8_t Date = getBits_5 (d, offset); offset += 5;
uint8_t Hour = getBits_5 (d, offset); offset += 5;
uint8_t Minutes = getBits_6 (d, offset); offset += 6;
uint8_t Seconds = getBits_6 (d, offset); offset += 6;
uint8_t SId_flag = getBits_1 (d, offset); offset += 1;
uint8_t Eid_flag = getBits_1 (d, offset); offset += 1;
uint32_t Transfer_Id = PD_bit ? getLBits (d, offset, 32) :
getLBits (d, offset, 16);
offset += PD_bit ? 32 : 16;
uint16_t Transfer_EId = Eid_flag ? getLBits (d, offset, 16) : 0;
offset += Eid_flag ? 16 : 0;
fprintf (stderr, "%X (%d) is in fig 20\n", SId, SCIds);
return offset;
}
2019-03-25 20:17:53 +01:00
// Frequency information (FI) 8.1.8
void fibDecoder::FIG0Extension21 (uint8_t *d) {
int16_t used = 2; // offset in bytes
2025-07-20 19:25:14 +02:00
const int16_t Length = getBits_5 (d, 3);
const uint8_t CN_bit = getBits_1 (d, 8 + 0);
const uint8_t OE_bit = getBits_1 (d, 8 + 1);
const uint8_t PD_bit = getBits_1 (d, 8 + 2);
2019-03-25 20:17:53 +01:00
while (used < Length)
2025-07-20 19:25:14 +02:00
used = HandleFIG0Extension21 (d, used, CN_bit, OE_bit, PD_bit);
2019-03-25 20:17:53 +01:00
}
2020-03-02 15:13:34 +01:00
int16_t fibDecoder::HandleFIG0Extension21 (uint8_t *d,
2025-07-20 19:25:14 +02:00
uint16_t offset,
const uint8_t CN_bit,
const uint8_t OE_bit,
const uint8_t PD_bit) {
2019-03-25 20:17:53 +01:00
int16_t l_offset = offset * 8;
int16_t l = getBits_5 (d, l_offset + 11);
int16_t upperLimit = l_offset + 16 + l * 8;
int16_t base = l_offset + 16;
2020-03-02 15:13:34 +01:00
(void)CN_bit; (void)OE_bit, (void)PD_bit;
2025-03-19 12:32:08 +01:00
if (OE_bit == 1) // this ios not for use
return upperLimit / 8;
2020-03-02 15:13:34 +01:00
2025-03-19 12:32:08 +01:00
bool newData = false;
2019-03-25 20:17:53 +01:00
while (base < upperLimit) {
uint16_t idField = getBits (d, base, 16);
uint8_t RandM = getBits_4 (d, base + 16);
uint8_t continuity = getBits_1 (d, base + 20);
2019-07-07 11:11:46 +02:00
(void)continuity;
2019-03-25 20:17:53 +01:00
uint8_t length = getBits_3 (d, base + 21);
if (RandM == 0x08) {
uint16_t fmFrequency_key = getBits (d, base + 24, 8);
int32_t fmFrequency = 87500 + fmFrequency_key * 100;
2025-03-19 12:32:08 +01:00
for (auto &serv : theEnsemble -> primaries) {
if ((serv. SId == idField)) {
bool alreadyIn = false;
for (auto freq : serv. fmFrequencies) {
if (fmFrequency == freq) {
alreadyIn = true;
break;
}
}
if (!alreadyIn) {
serv. fmFrequencies. push_back (fmFrequency);
newData = true;
}
2025-03-19 12:32:08 +01:00
}
2019-03-25 20:17:53 +01:00
}
}
base += 24 + length * 8;
}
2025-03-19 12:32:08 +01:00
if (newData)
emit setFreqList ();
2019-03-25 20:17:53 +01:00
return upperLimit / 8;
}
2025-03-19 12:32:08 +01:00
//
2019-03-25 20:17:53 +01:00
// FIG 1 - Cover the different possible labels, section 5.2
void fibDecoder::process_FIG1 (uint8_t *d) {
uint8_t extension = getBits_3 (d, 8 + 5);
switch (extension) {
case 0: // ensemble name
FIG1Extension0 (d);
break;
case 1: // service name
FIG1Extension1 (d);
break;
2025-03-29 10:51:10 +01:00
case 2: // Labels etc
2019-03-25 20:17:53 +01:00
break;
case 3: // obsolete
break;
case 4: // Service Component Label
FIG1Extension4 (d);
break;
case 5: // Data service label
FIG1Extension5 (d);
break;
case 6: // XPAD label - 8.1.14.4
break;
default:
;
}
}
// Name of the ensemble
//
void fibDecoder::FIG1Extension0 (uint8_t *d) {
int16_t offset = 0;
char label [17];
// from byte 1 we deduce:
2025-07-20 19:25:14 +02:00
const uint8_t charSet = getBits_4 (d, 8);
const uint8_t Rfu = getBits_1 (d, 8 + 4);
2019-03-25 20:17:53 +01:00
label [16] = 0x00;
(void)Rfu;
2025-07-20 19:25:14 +02:00
const uint16_t EId = getBits (d, 16, 16);
2019-03-25 20:17:53 +01:00
offset = 32;
if ((charSet <= 16)) { // EBU Latin based repertoire
for (int i = 0; i < 16; i ++) {
label [i] = getBits_8 (d, offset + 8 * i);
}
const QString name = toQStringUsingCharset (
(const char *) label,
(CharacterSet) charSet);
QString realName = name;
for (int i = name. length (); i < 16; i ++)
realName. append (' ');
2025-03-19 12:32:08 +01:00
if (!theEnsemble -> namePresent) {
theEnsemble -> ensembleName = realName;
theEnsemble -> EId = EId;
theEnsemble -> namePresent = true;
2025-07-14 17:25:42 +02:00
ensembleName (EId, name);
2019-03-25 20:17:53 +01:00
}
2025-03-19 12:32:08 +01:00
theEnsemble -> isSynced = true;
2019-03-25 20:17:53 +01:00
}
}
//
// Name of service
void fibDecoder::FIG1Extension1 (uint8_t *d) {
int16_t offset = 32;
char label [17];
// from byte 1 we deduce:
2025-07-20 19:25:14 +02:00
const uint8_t charSet = getBits_4 (d, 8);
const uint8_t Rfu = getBits_1 (d, 8 + 4);
const uint8_t extension = getBits_3 (d, 8 + 5);
const uint32_t SId = getBits (d, 16, 16);
2019-03-25 20:17:53 +01:00
label [16] = 0x00;
2025-03-19 12:32:08 +01:00
(void)Rfu; (void)extension;
2025-02-14 19:33:17 +01:00
if (charSet >= 16) // does not seem right
2020-03-02 15:13:34 +01:00
return;
2025-03-19 12:32:08 +01:00
for (auto &serv : theEnsemble -> primaries) {
if (SId == serv. SId)
return;
}
2020-03-02 15:13:34 +01:00
2025-03-19 12:32:08 +01:00
for (int i = 0; i < 16; i ++)
2020-03-02 15:13:34 +01:00
label [i] = getBits_8 (d, offset + 8 * i);
QString dataName = toQStringUsingCharset (
2019-03-25 20:17:53 +01:00
(const char *) label,
(CharacterSet) charSet);
2023-04-26 20:29:59 +02:00
for (int i = dataName. length (); i < 16; i ++)
dataName. append (' ');
2023-11-03 17:47:31 +01:00
QString shortName;
for (int i = 0; i < 16; i ++)
if (getBits_1 (d, offset + 16 * 8 + i) != 0)
shortName. append (dataName. at (i));
2025-03-19 12:32:08 +01:00
ensemble::service prim;
prim. programType = 0;
2025-06-03 19:44:20 +02:00
prim. name = dataName;
prim. shortName = shortName;
prim. SId = SId;
prim. fmFrequencies. resize (0);
2025-03-19 12:32:08 +01:00
theEnsemble -> primaries. push_back (prim);
2025-03-20 18:23:52 +01:00
int subChId = -1;
2025-05-27 18:50:45 +02:00
for (int i = 0; i < (int)(currentConfig -> SC_C_table. size ()); i ++) {
2025-03-20 18:23:52 +01:00
fibConfig::serviceComp_C comp = currentConfig -> SC_C_table [i];
if ((comp. compNr == 0) && (comp. SId == SId))
subChId = currentConfig -> subChannelOf (i);
}
2025-07-14 17:25:42 +02:00
addToEnsemble (dataName, SId, subChId);
2025-06-03 19:44:20 +02:00
if (theEnsemble -> primaries. size () >= 2)
theEnsemble -> isSynced = true;
2020-03-02 15:13:34 +01:00
}
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
// service component label - 32 bits 8.1.14.3
2019-03-25 20:17:53 +01:00
void fibDecoder::FIG1Extension4 (uint8_t *d) {
2025-03-19 12:32:08 +01:00
char label [17];
int bitOffset = 16;
2019-03-25 20:17:53 +01:00
uint32_t SId;
2025-03-19 12:32:08 +01:00
// from byte 1 we deduce:
2025-07-20 19:25:14 +02:00
const uint8_t charSet = getBits_4 (d, 8);
const uint8_t Rfu = getBits_1 (d, 8 + 4);
const uint8_t extension = getBits_3 (d, 8 + 5);
const uint8_t PD_flag = getBits_1 (d, bitOffset);
const uint8_t SCIds = getBits (d, bitOffset + 4, 4);
2025-03-19 12:32:08 +01:00
if (PD_flag) {
SId = getLBits (d, bitOffset + 8, 32);
bitOffset += 32 + 8;
2019-03-25 20:17:53 +01:00
}
2025-03-19 12:32:08 +01:00
else {
SId = getLBits (d, bitOffset + 8, 16);
bitOffset += 16 + 8;
2019-03-25 20:17:53 +01:00
}
2025-03-19 12:32:08 +01:00
//
// just a check if we already have the servicename
for (auto &serv : theEnsemble -> secondaries)
if (serv. SId == SId)
return;
for (auto &serv :theEnsemble -> primaries)
if (serv. SId == SId)
return;
2020-03-02 15:13:34 +01:00
2025-03-19 12:32:08 +01:00
label [16] = 0x00;
(void)Rfu;
(void)extension;
if (charSet >= 16) // does not seem right
return;
2020-03-02 15:13:34 +01:00
2025-03-19 12:32:08 +01:00
for (int i = 0; i < 16; i ++)
label [i] = getBits_8 (d, bitOffset + 8 * i);
QString dataName = toQStringUsingCharset (
(const char *) label,
(CharacterSet) charSet);
QString shortName;
for (int i = 0; i < 16; i ++)
if (getBits_1 (d, bitOffset + 16 * 8 + i) != 0)
shortName. append (dataName. at (i));
ensemble::service prim;
prim. name = dataName;
prim. shortName = shortName;
prim. SId = SId;
prim. SCIds = SCIds;
theEnsemble -> secondaries. push_back (prim);
2025-07-14 17:25:42 +02:00
addToEnsemble (dataName, SId, -1);
2019-03-25 20:17:53 +01:00
}
// Data service label - 32 bits 8.1.14.2
void fibDecoder::FIG1Extension5 (uint8_t *d) {
char label [17];
uint32_t SId = getLBits (d, 16, 32);
2025-03-19 12:32:08 +01:00
int16_t bitOffset = 48;
2019-03-25 20:17:53 +01:00
// from byte 1 we deduce:
2025-03-19 12:32:08 +01:00
uint8_t charSet = getBits_4 (d, 8);
uint8_t Rfu = getBits_1 (d, 8 + 4);
uint8_t extension = getBits_3 (d, 8 + 5);
2019-03-25 20:17:53 +01:00
label [16] = 0x00;
2025-03-19 12:32:08 +01:00
(void)Rfu; (void)extension;
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
for (auto &serv : theEnsemble -> primaries) {
if (SId == serv. SId)
return;
}
2020-03-02 15:13:34 +01:00
if (charSet > 16)
return; // something wrong
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
for (int i = 0; i < 16; i ++) {
label [i] = getBits_8 (d, bitOffset + 8 * i);
2019-03-25 20:17:53 +01:00
}
2025-03-19 12:32:08 +01:00
QString dataName = toQStringUsingCharset (
(const char *) label,
(CharacterSet) charSet);
QString shortName;
for (int i = 0; i < 16; i ++)
if (getBits_1 (d, bitOffset + 16 * 8 + i) != 0)
shortName. append (dataName. at (i));
2020-03-02 15:13:34 +01:00
2019-03-25 20:17:53 +01:00
2025-03-19 12:32:08 +01:00
ensemble::service prim;
prim. programType = 0;
prim. name = dataName;
prim. shortName = shortName;
prim. SId = SId;
theEnsemble -> primaries. push_back (prim);
2025-07-14 17:25:42 +02:00
addToEnsemble (dataName, SId, -1);
2019-03-25 20:17:53 +01:00
}
2025-07-14 17:25:42 +02:00
void fibDecoder::connectChannel () {
2025-03-19 12:32:08 +01:00
fibLocker. lock();
currentConfig -> reset ();
nextConfig -> reset ();
theEnsemble -> reset ();
2025-07-14 17:25:42 +02:00
connect (this, &fibDecoder::addToEnsemble,
myRadioInterface, &RadioInterface::addToEnsemble);
2025-03-19 12:32:08 +01:00
fibLocker. unlock();
}
2022-08-08 14:01:27 +02:00
2025-07-14 17:25:42 +02:00
void fibDecoder::disconnectChannel () {
2022-08-08 14:01:27 +02:00
fibLocker. lock ();
2025-07-14 17:25:42 +02:00
disconnect (this, &fibDecoder::addToEnsemble,
myRadioInterface, &RadioInterface::addToEnsemble);
2022-08-08 14:01:27 +02:00
currentConfig -> reset ();
nextConfig -> reset ();
2025-03-19 12:32:08 +01:00
theEnsemble -> reset ();
2020-03-02 15:13:34 +01:00
fibLocker. unlock();
2020-02-26 13:12:21 +01:00
}
2020-03-02 15:13:34 +01:00
bool fibDecoder::syncReached() {
2025-03-19 12:32:08 +01:00
return theEnsemble -> isSynced;
2020-02-26 13:12:21 +01:00
}
2025-07-20 19:25:14 +02:00
uint32_t fibDecoder::getSId (const int index) {
2025-03-19 12:32:08 +01:00
return currentConfig -> SC_C_table [index]. SId;
2024-03-25 14:35:22 +01:00
}
2025-07-20 19:25:14 +02:00
uint8_t fibDecoder::serviceType (const int index) {
2025-03-19 12:32:08 +01:00
return currentConfig -> SC_C_table [index]. TMid;
2020-03-02 15:13:34 +01:00
}
2019-03-25 20:17:53 +01:00
2025-07-20 19:25:14 +02:00
void fibDecoder::audioData (const int index, audiodata &ad) {
2025-03-19 12:32:08 +01:00
fibConfig::serviceComp_C &comp = currentConfig -> SC_C_table [index];
for (auto &serv : theEnsemble -> primaries) {
if (serv. SId == comp. SId) {
ad. serviceName = serv. name;
ad. shortName = serv. shortName;
ad. SId = serv. SId;
ad. programType = serv. programType;
ad. fmFrequencies = serv. fmFrequencies;
2025-03-19 12:32:08 +01:00
break;
2020-03-22 14:50:05 +01:00
}
}
2025-03-19 12:32:08 +01:00
int subChId = currentConfig -> subChannelOf (index);
ad. subchId = subChId;
int subChannel_index =
currentConfig -> findIndex_subChannel_table (subChId);
if (subChannel_index < 0)
return;
fibConfig::subChannel &channel =
currentConfig -> subChannel_table [subChannel_index];
ad. startAddr = channel. startAddr;
ad. shortForm = channel. shortForm;
ad. protLevel = channel. protLevel;
ad. length = channel. Length;
ad. bitRate = channel. bitRate;
ad. ASCTy = currentConfig -> dabTypeOf (index);
ad. language = currentConfig -> languageOf (index);
ad. defined = true;
}
2025-07-20 19:25:14 +02:00
void fibDecoder::packetData (const int index, packetdata &pd) {
2025-03-19 12:32:08 +01:00
fibConfig::serviceComp_C &comp = currentConfig -> SC_C_table [index];
for (auto &serv : theEnsemble -> primaries) {
if (serv. SId == comp. SId) {
pd. serviceName = serv. name;
pd. shortName = serv. shortName;
pd. SId = serv. SId;
break;
2020-03-22 14:50:05 +01:00
}
}
2025-03-19 12:32:08 +01:00
int subChId = currentConfig -> subChannelOf (index);
pd. subchId = subChId;
int subChannel_index =
currentConfig -> findIndex_subChannel_table (subChId);
if (subChannel_index < 0)
return;
fibConfig::subChannel &channel =
currentConfig -> subChannel_table [subChannel_index];
pd. startAddr = channel. startAddr;
pd. shortForm = channel. shortForm;
pd. protLevel = channel. protLevel;
pd. length = channel. Length;
pd. bitRate = channel. bitRate;
pd. FEC_scheme = currentConfig -> FEC_schemeOf (index);
pd. appType = currentConfig -> appTypeOf (index);
pd. DGflag = currentConfig -> DG_flag (index);
pd. DSCTy = currentConfig -> DSCTy (index);
pd. packetAddress = currentConfig -> packetAddressOf (index);
pd. defined = true;
}
2025-07-20 19:25:14 +02:00
int fibDecoder::getNrComps (const uint32_t SId) {
2025-03-19 12:32:08 +01:00
for (auto &SId_element : currentConfig -> SId_table)
if (SId_element. SId == SId)
return SId_element. comps. size ();
2019-03-25 20:17:53 +01:00
return 0;
}
2020-03-02 15:13:34 +01:00
//
2025-03-19 12:32:08 +01:00
// for primary services we return the index of the first
// component, the secondary services, the index of the
// component with the matching SCIds
//
2025-07-14 17:25:42 +02:00
int fibDecoder::getServiceComp (const QString &service) {
2025-03-19 12:32:08 +01:00
// first we check to see if the service is a primary one
for (auto &serv : theEnsemble -> primaries) {
if (serv. name != service)
continue;
for (auto & SId_element: currentConfig -> SId_table) {
if (SId_element. SId == serv. SId)
return SId_element. comps [0];
2020-03-02 15:13:34 +01:00
}
}
2025-03-19 12:32:08 +01:00
for (auto &serv : theEnsemble -> secondaries) {
if (serv. name != service)
continue;
2025-07-14 17:25:42 +02:00
return getServiceComp_SCIds (serv. SId, serv. SCIds);
}
2025-03-19 12:32:08 +01:00
return -1;
}
2025-07-20 19:25:14 +02:00
int fibDecoder::getServiceComp (const uint32_t SId,
const int compnr) {
2025-03-19 12:32:08 +01:00
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId == SId) {
return SId_element. comps [compnr];
}
2020-11-02 20:39:30 +01:00
}
2025-03-19 12:32:08 +01:00
return -1;
2020-11-02 20:39:30 +01:00
}
2025-07-20 19:25:14 +02:00
int fibDecoder::getServiceComp_SCIds (const uint32_t SId,
const int SCIds) {
// fprintf (stderr, "Looking for serviceComp %X %d\n", SId, SCIds);
2025-03-19 12:32:08 +01:00
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId != SId)
continue;
for (int i = 0; i < (int) SId_element. comps. size (); i ++) {
int index = SId_element. comps [i];
if (currentConfig -> SCIdsOf (index) == SCIds)
return index;
2022-02-26 19:54:19 +01:00
}
}
2025-03-19 12:32:08 +01:00
return -1;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
bool fibDecoder::isPrimary (const QString &s) {
for (auto &serv : theEnsemble -> primaries) {
if (s == serv. name)
return true;
}
return false;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
uint8_t fibDecoder:: get_ecc () {
return theEnsemble -> eccByte;
2022-02-26 19:54:19 +01:00
}
std::vector<int> fibDecoder::getFrequency (const QString &s) {
std::vector<int> res;
2025-03-19 12:32:08 +01:00
for (auto &serv : theEnsemble -> primaries) {
if (serv. name == s)
return serv. fmFrequencies;
2025-03-19 12:32:08 +01:00
}
return res;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
// required for ETI generation
int fibDecoder::nrChannels () {
return currentConfig -> subChannel_table. size ();
2022-02-26 19:54:19 +01:00
}
2025-03-29 10:51:10 +01:00
//
// needed for generating eti files
2025-07-20 19:25:14 +02:00
void fibDecoder::getChannelInfo (channel_data *d, const int n) {
2025-03-19 12:32:08 +01:00
d -> in_use = true;
d -> id = currentConfig -> subChannel_table [n]. subChId;
d -> start_cu = currentConfig -> subChannel_table [n]. startAddr;
d -> protlev = currentConfig -> subChannel_table [n]. protLevel;
d -> size = currentConfig -> subChannel_table [n]. Length;
d -> bitrate = currentConfig -> subChannel_table [n]. bitRate;
d -> uepFlag = currentConfig -> subChannel_table [n]. shortForm;
2022-02-26 19:54:19 +01:00
}
2025-07-14 17:25:42 +02:00
int32_t fibDecoder::getCIFcount () {
2025-03-19 12:32:08 +01:00
return CIFcount;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
2025-07-14 17:25:42 +02:00
void fibDecoder::getCIFcount (int16_t &high, int16_t &low) {
2025-03-19 12:32:08 +01:00
high = CIFcount_hi;
low = CIFcount_lo;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
uint32_t fibDecoder::julianDate () {
return mjd;
2022-02-26 19:54:19 +01:00
}
2025-03-19 12:32:08 +01:00
QStringList fibDecoder::basicPrint () {
fibPrinter thePrinter (currentConfig, theEnsemble);
return thePrinter. basicPrint ();
2022-02-26 19:54:19 +01:00
}
int fibDecoder::scanWidth () {
2025-03-19 12:32:08 +01:00
fibPrinter thePrinter (currentConfig, theEnsemble);
return thePrinter. scanWidth ();
}
2025-07-14 17:25:42 +02:00
void fibDecoder::handleAnnouncement (uint16_t SId, uint16_t flags,
2025-03-19 12:32:08 +01:00
uint8_t subChId) {
(void)subChId;
for (auto &serv : currentConfig -> SId_table)
if (serv. SId == SId) {
if (serv. announcing != flags)
emit announcement (SId, flags);
serv. announcing = flags;
}
2022-02-26 19:54:19 +01:00
}
2025-07-14 17:25:42 +02:00
uint16_t fibDecoder::getAnnouncing (uint16_t SId) {
2025-03-19 12:32:08 +01:00
for (auto &serv : currentConfig -> SId_table)
if (serv. SId == SId)
return serv. announcing;
return 0;
2023-01-21 11:58:25 +01:00
}
2025-05-06 16:26:16 +02:00
int fibDecoder::freeSpace () {
return currentConfig -> freeSpace ();
}