aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-01-22 14:08:58 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-01-22 14:08:58 +0100
commit74e2beb5b80470a26054c8c51665996b10303f68 (patch)
tree55032f4b62aea432d03c8a49adfab51740b4640b
parente05c1b5903709651aac348fd5144de3ccbbd77a3 (diff)
downloadetisnoop-74e2beb5b80470a26054c8c51665996b10303f68.tar.gz
etisnoop-74e2beb5b80470a26054c8c51665996b10303f68.tar.bz2
etisnoop-74e2beb5b80470a26054c8c51665996b10303f68.zip
Add repetition rate analyser
-rw-r--r--CMakeLists.txt3
-rw-r--r--etisnoop.cpp63
-rw-r--r--fig0_0.cpp4
-rw-r--r--fig0_1.cpp23
-rw-r--r--fig0_10.cpp4
-rw-r--r--fig0_11.cpp26
-rw-r--r--fig0_13.cpp32
-rw-r--r--fig0_14.cpp24
-rw-r--r--fig0_16.cpp29
-rw-r--r--fig0_17.cpp23
-rw-r--r--fig0_18.cpp23
-rw-r--r--fig0_19.cpp22
-rw-r--r--fig0_2.cpp25
-rw-r--r--fig0_21.cpp23
-rw-r--r--fig0_22.cpp25
-rw-r--r--fig0_24.cpp23
-rw-r--r--fig0_25.cpp23
-rw-r--r--fig0_26.cpp23
-rw-r--r--fig0_27.cpp23
-rw-r--r--fig0_28.cpp23
-rw-r--r--fig0_3.cpp24
-rw-r--r--fig0_31.cpp25
-rw-r--r--fig0_5.cpp27
-rw-r--r--fig0_6.cpp24
-rw-r--r--fig0_8.cpp32
-rw-r--r--fig0_9.cpp4
-rw-r--r--fig1.cpp15
-rw-r--r--figs.cpp52
-rw-r--r--figs.hpp54
-rw-r--r--repetitionrate.cpp147
-rw-r--r--repetitionrate.hpp37
-rw-r--r--utils.hpp2
32 files changed, 799 insertions, 108 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8935610..bebb0c6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,7 +25,7 @@ set(VERSION_INFO_MAINT_VERSION git)
# Compiler specific setup
########################################################################
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -std=c++11")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -W -Wall -std=c++11")
########################################################################
@@ -77,6 +77,7 @@ list(APPEND etisnoop_sources
figs.cpp
firecode.c
lib_crc.c
+ repetitionrate.cpp
rsdecoder.cpp
tables.cpp
utils.cpp
diff --git a/etisnoop.cpp b/etisnoop.cpp
index 078a245..251c725 100644
--- a/etisnoop.cpp
+++ b/etisnoop.cpp
@@ -49,6 +49,7 @@
#include "etiinput.h"
#include "figs.hpp"
#include "watermarkdecoder.hpp"
+#include "repetitionrate.hpp"
struct FIG
{
@@ -154,6 +155,7 @@ struct eti_analyse_config_t {
bool ignore_error;
std::map<int, DabPlusSnoop> streams_to_decode;
bool analyse_fic_carousel;
+ bool analyse_fig_rates;
bool decode_watermark;
};
@@ -193,6 +195,7 @@ void usage(void)
" -v increase verbosity (can be given more than once)\n"
" -d N decode subchannel N into .dabp and .wav files\n"
" -f analyse FIC carousel\n"
+ " -r analyse FIG rates\n"
" -w decode CRC-DABMUX and ODR-DabMux watermark.\n");
}
@@ -201,36 +204,36 @@ int main(int argc, char *argv[])
int index;
int ch = 0;
string file_name("-");
- map<int, DabPlusSnoop> streams_to_decode;
- bool ignore_error = false;
- bool analyse_fic_carousel = false;
- bool decode_watermark = false;
+ eti_analyse_config_t config;
while(ch != -1) {
- ch = getopt_long(argc, argv, "d:efhvwi:", longopts, &index);
+ ch = getopt_long(argc, argv, "d:efhrvwi:", longopts, &index);
switch (ch) {
case 'd':
{
int subchix = atoi(optarg);
DabPlusSnoop dps;
- streams_to_decode[subchix] = dps;
+ config.streams_to_decode[subchix] = dps;
}
break;
case 'e':
- ignore_error = true;
+ config.ignore_error = true;
break;
case 'i':
file_name = optarg;
break;
case 'f':
- analyse_fic_carousel = true;
+ config.analyse_fic_carousel = true;
+ break;
+ case 'r':
+ config.analyse_fig_rates = true;
break;
case 'v':
set_verbosity(get_verbosity() + 1);
break;
case 'w':
- decode_watermark = true;
+ config.decode_watermark = true;
break;
case 'h':
usage();
@@ -252,14 +255,8 @@ int main(int argc, char *argv[])
return 1;
}
}
+ config.etifd = etifd;
- eti_analyse_config_t config = {
- .etifd = etifd,
- .ignore_error = ignore_error,
- .streams_to_decode = streams_to_decode,
- .analyse_fic_carousel = analyse_fic_carousel,
- .decode_watermark = decode_watermark
- };
eti_analyse(config);
fclose(etifd);
}
@@ -377,9 +374,10 @@ int eti_analyse(eti_analyse_config_t& config)
// LIDATA - FC
printbuf("FC - Frame Characterization field", 1, p+4, 4);
// LIDATA - FC - FCT
- char fct[25];
- sprintf(fct, "%d", p[4]);
- printbuf("FCT - Frame Count", 2, p+4, 1, fct);
+ char fct_str[25];
+ sprintf(fct_str, "%d", p[4]);
+ int fct = p[4];
+ printbuf("FCT - Frame Count", 2, p+4, 1, fct_str);
// LIDATA - FC - FICF
ficf = (p[5] & 0x80) >> 7;
@@ -556,6 +554,7 @@ int eti_analyse(eti_analyse_config_t& config)
printbuf(sdesc, 1, NULL, 0);
fig=fib;
figs.set_fib(i);
+ rate_new_fib(i);
endmarker=0;
figcount=0;
while (!endmarker) {
@@ -648,6 +647,10 @@ int eti_analyse(eti_analyse_config_t& config)
if (get_verbosity()) {
printf("-------------------------------------------------------------------------------------------------------------\n");
}
+
+ if (config.analyse_fig_rates and (fct % 250) == 0) {
+ rate_disply_analysis();
+ }
}
@@ -663,8 +666,13 @@ int eti_analyse(eti_analyse_config_t& config)
printf("Watermark:\n %s\n", watermark.c_str());
}
+ if (config.analyse_fig_rates) {
+ rate_disply_analysis();
+ }
+
figs_cleardb();
+
return 0;
}
@@ -688,7 +696,8 @@ void decodeFIG(FIGalyser &figs,
figs.push_back(figtype, fig0.ext(), figlen);
- fig0_select(fig0, indent);
+ bool complete = fig0_select(fig0, indent);
+ rate_announce_fig(figtype, fig0.ext(), complete);
}
break;
@@ -698,7 +707,8 @@ void decodeFIG(FIGalyser &figs,
figs.push_back(figtype, fig1.ext(), figlen);
- fig1_select(fig1, indent);
+ bool complete = fig1_select(fig1, indent);
+ rate_announce_fig(figtype, fig1.ext(), complete);
}
break;
case 2:
@@ -716,6 +726,9 @@ void decodeFIG(FIGalyser &figs,
printbuf(desc, indent, f+1, figlen-1);
figs.push_back(figtype, ext, figlen);
+
+ bool complete = true; // TODO verify
+ rate_announce_fig(figtype, ext, complete);
}
break;
case 5:
@@ -733,6 +746,9 @@ void decodeFIG(FIGalyser &figs,
printbuf(desc, indent, f+1, figlen-1);
figs.push_back(figtype, ext, figlen);
+
+ bool complete = true; // TODO verify
+ rate_announce_fig(figtype, ext, complete);
}
break;
case 6:
@@ -740,6 +756,11 @@ void decodeFIG(FIGalyser &figs,
fprintf(stderr, "ERROR: ETI contains unsupported FIG 6\n");
}
break;
+ default:
+ {
+ fprintf(stderr, "ERROR: ETI contains unknown FIG %d\n", figtype);
+ }
+ break;
}
}
diff --git a/fig0_0.cpp b/fig0_0.cpp
index 2b2b6a2..82bfadf 100644
--- a/fig0_0.cpp
+++ b/fig0_0.cpp
@@ -29,7 +29,7 @@
// FIG 0/0 Ensemble information
// ETSI EN 300 401 6.4
-void fig0_0(fig0_common_t& fig0, int indent)
+bool fig0_0(fig0_common_t& fig0, int indent)
{
uint8_t cid, al, ch, hic, lowc, occ;
uint16_t eid, eref;
@@ -56,5 +56,7 @@ void fig0_0(fig0_common_t& fig0, int indent)
eid, cid, eref, ch, al, hic, lowc);
}
printbuf(desc, indent+1, NULL, 0);
+
+ return true;
}
diff --git a/fig0_1.cpp b/fig0_1.cpp
index 791c0ec..f5df4c4 100644
--- a/fig0_1.cpp
+++ b/fig0_1.cpp
@@ -26,18 +26,38 @@
#include "figs.hpp"
#include <cstdio>
+#include <unordered_set>
+
+static std::unordered_set<int> subchannels_seen;
+
+bool fig0_1_is_complete(int subch_id)
+{
+ bool complete = subchannels_seen.count(subch_id);
+
+ if (complete) {
+ subchannels_seen.clear();
+ }
+ else {
+ subchannels_seen.insert(subch_id);
+ }
+
+ return complete;
+}
// FIG 0/1 Basic sub-channel organization
// ETSI EN 300 401 6.2.1
-void fig0_1(fig0_common_t& fig0, int indent)
+bool fig0_1(fig0_common_t& fig0, int indent)
{
int i = 1;
uint8_t* f = fig0.f;
char desc[128];
+ bool complete = false;
while (i < fig0.figlen-3) {
// iterate over subchannels
int subch_id = f[i] >> 2;
+ complete |= fig0_1_is_complete(subch_id);
+
int start_addr = ((f[i] & 0x03) << 8) |
(f[i+1]);
int long_flag = (f[i+2] >> 7);
@@ -87,5 +107,6 @@ void fig0_1(fig0_common_t& fig0, int indent)
printbuf(desc, indent+1, NULL, 0);
}
+ return complete;
}
diff --git a/fig0_10.cpp b/fig0_10.cpp
index c374ef9..5c81c3f 100644
--- a/fig0_10.cpp
+++ b/fig0_10.cpp
@@ -31,7 +31,7 @@
// FIG 0/10 Date and time
// ETSI EN 300 401 8.1.3.1
-void fig0_10(fig0_common_t& fig0, int indent)
+bool fig0_10(fig0_common_t& fig0, int indent)
{
char desc[256];
char dateStr[256];
@@ -68,5 +68,7 @@ void fig0_10(fig0_common_t& fig0, int indent)
fig0.ext(), MJD, dateStr, LSI, ConfInd, hours, minutes);
printbuf(desc, indent+1, NULL, 0);
}
+
+ return true;
}
diff --git a/fig0_11.cpp b/fig0_11.cpp
index cc6bead..40136c3 100644
--- a/fig0_11.cpp
+++ b/fig0_11.cpp
@@ -28,10 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> region_ids_seen;
+
+bool fig0_11_is_complete(int region_id)
+{
+ bool complete = region_ids_seen.count(region_id);
+
+ if (complete) {
+ region_ids_seen.clear();
+ }
+ else {
+ region_ids_seen.insert(region_id);
+ }
+
+ return complete;
+}
+
// FIG 0/11 Region definition
// ETSI EN 300 401 8.1.16.1
-void fig0_11(fig0_common_t& fig0, int indent)
+bool fig0_11(fig0_common_t& fig0, int indent)
{
Lat_Lng gps_pos = {0, 0};
int16_t Latitude_coarse, Longitude_coarse;
@@ -43,12 +61,15 @@ void fig0_11(fig0_common_t& fig0, int indent)
bool GE_flag;
uint8_t* f = fig0.f;
uint8_t Mode_Identity = get_mode_identity();
+ bool complete = false;
while (i < (fig0.figlen - 1)) {
// iterate over Region definition
GATy = f[i] >> 4;
GE_flag = (f[i] >> 3) & 0x01;
Region_Id = ((uint16_t)(f[i] & 0x07) << 8) | ((uint16_t)f[i+1]);
+ complete |= fig0_11_is_complete(Region_Id);
+
key = ((uint16_t)fig0.oe() << 12) | ((uint16_t)fig0.pd() << 11) | Region_Id;
i += 2;
if (GATy == 0) {
@@ -182,4 +203,7 @@ void fig0_11(fig0_common_t& fig0, int indent)
i = fig0.figlen;
}
}
+
+ return complete;
}
+
diff --git a/fig0_13.cpp b/fig0_13.cpp
index 113bb49..ffb5b89 100644
--- a/fig0_13.cpp
+++ b/fig0_13.cpp
@@ -28,6 +28,31 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <set>
+
+/* EN 300 401, 8.1.20, User application information
+ * The combination of the SId and the SCIdS provides a service component
+ * identifier which is valid globally.
+ */
+using SId_t = int;
+using SCIdS_t = int;
+static std::set<std::pair<SId_t, SCIdS_t> > components_ids_seen;
+
+bool fig0_13_is_complete(SId_t SId, SCIdS_t SCIdS)
+{
+ auto key = std::make_pair(SId, SCIdS);
+ bool complete = components_ids_seen.count(key);
+
+ if (complete) {
+ components_ids_seen.clear();
+ }
+ else {
+ components_ids_seen.insert(key);
+ }
+
+ return complete;
+}
+
std::string get_fig_0_13_userapp(int user_app_type)
{
@@ -48,7 +73,7 @@ std::string get_fig_0_13_userapp(int user_app_type)
// FIG 0/13 User application information
// ETSI EN 300 401 8.1.20
-void fig0_13(fig0_common_t& fig0, int indent)
+bool fig0_13(fig0_common_t& fig0, int indent)
{
uint32_t SId;
uint8_t SCIdS;
@@ -56,6 +81,7 @@ void fig0_13(fig0_common_t& fig0, int indent)
uint8_t* f = fig0.f;
const int figtype = 0;
char desc[256];
+ bool complete = false;
int k = 1;
@@ -81,6 +107,8 @@ void fig0_13(fig0_common_t& fig0, int indent)
}
+ complete |= fig0_13_is_complete(SId, SCIdS);
+
sprintf(desc, "FIG %d/%d: SId=0x%X SCIdS=%u No=%u",
figtype, fig0.ext(), SId, SCIdS, No);
printbuf(desc, indent+1, NULL, 0);
@@ -97,5 +125,7 @@ void fig0_13(fig0_common_t& fig0, int indent)
user_app_len);
printbuf(desc, indent+2, NULL, 0);
}
+
+ return complete;
}
diff --git a/fig0_14.cpp b/fig0_14.cpp
index 8d63cae..e72d121 100644
--- a/fig0_14.cpp
+++ b/fig0_14.cpp
@@ -28,6 +28,24 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> subch_ids_seen;
+
+bool fig0_14_is_complete(int subch_id)
+{
+ bool complete = subch_ids_seen.count(subch_id);
+
+ if (complete) {
+ subch_ids_seen.clear();
+ }
+ else {
+ subch_ids_seen.insert(subch_id);
+ }
+
+ return complete;
+}
+
// fig 0/14 FEC Scheme: this 2-bit field shall indicate the Forward Error Correction scheme in use, as follows:
const char *FEC_schemes_str[4] = {
@@ -40,20 +58,24 @@ const char *FEC_schemes_str[4] = {
// FIG 0/14 FEC sub-channel organization
// ETSI EN 300 401 6.2.2
-void fig0_14(fig0_common_t& fig0, int indent)
+bool fig0_14(fig0_common_t& fig0, int indent)
{
uint8_t i = 1, SubChId, FEC_scheme;
uint8_t* f = fig0.f;
char desc[256];
+ bool complete = false;
while (i < fig0.figlen) {
// iterate over Sub-channel
SubChId = f[i] >> 2;
+ complete |= fig0_14_is_complete(SubChId);
FEC_scheme = f[i] & 0x3;
sprintf(desc, "SubChId=0x%X, FEC scheme=%d %s",
SubChId, FEC_scheme, FEC_schemes_str[FEC_scheme]);
printbuf(desc, indent+1, NULL, 0);
i++;
}
+
+ return complete;
}
diff --git a/fig0_16.cpp b/fig0_16.cpp
index aee7d10..24c9040 100644
--- a/fig0_16.cpp
+++ b/fig0_16.cpp
@@ -28,10 +28,33 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <set>
+
+/* SId and PNum look like good candidates to uniquely identify a FIG0_16
+ */
+using SId_t = int;
+using PNum_t = int;
+static std::set<std::pair<SId_t, PNum_t> > components_seen;
+
+bool fig0_16_is_complete(SId_t SId, PNum_t PNum)
+{
+ auto key = std::make_pair(SId, PNum);
+ bool complete = components_seen.count(key);
+
+ if (complete) {
+ components_seen.clear();
+ }
+ else {
+ components_seen.insert(key);
+ }
+
+ return complete;
+}
+
// FIG 0/16 Programme Number & fig0.oe() Programme Number
// ETSI EN 300 401 8.1.4 & 8.1.10.3
-void fig0_16(fig0_common_t& fig0, int indent)
+bool fig0_16(fig0_common_t& fig0, int indent)
{
uint16_t SId, PNum, New_SId, New_PNum;
uint8_t i = 1, Rfa, Rfu;
@@ -39,11 +62,13 @@ void fig0_16(fig0_common_t& fig0, int indent)
char desc[256];
bool Continuation_flag, Update_flag;
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 4)) {
// iterate over Programme Number
SId = ((uint16_t)f[i] << 8) | ((uint16_t)f[i+1]);
PNum = ((uint16_t)f[i+2] << 8) | ((uint16_t)f[i+3]);
+ complete |= fig0_16_is_complete(SId, PNum);
Rfa = f[i+4] >> 6;
Rfu = (f[i+4] >> 2) & 0x0F;
Continuation_flag = (f[i+4] >> 1) & 0x01;
@@ -96,5 +121,7 @@ void fig0_16(fig0_common_t& fig0, int indent)
printbuf(desc, indent+1, NULL, 0);
}
+
+ return complete;
}
diff --git a/fig0_17.cpp b/fig0_17.cpp
index 264d151..120cb4c 100644
--- a/fig0_17.cpp
+++ b/fig0_17.cpp
@@ -28,10 +28,27 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> services_ids_seen;
+
+bool fig0_17_is_complete(int services_id)
+{
+ bool complete = services_ids_seen.count(services_id);
+
+ if (complete) {
+ services_ids_seen.clear();
+ }
+ else {
+ services_ids_seen.insert(services_id);
+ }
+
+ return complete;
+}
// FIG 0/17 Programme Type
// ETSI EN 300 401 8.1.5
-void fig0_17(fig0_common_t& fig0, int indent)
+bool fig0_17(fig0_common_t& fig0, int indent)
{
uint16_t SId;
uint8_t i = 1, Rfa, Language, Int_code, Comp_code;
@@ -39,10 +56,12 @@ void fig0_17(fig0_common_t& fig0, int indent)
char desc[256];
bool SD_flag, PS_flag, L_flag, CC_flag, Rfu;
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 3)) {
// iterate over announcement support
SId = (f[i] << 8) | f[i+1];
+ complete |= fig0_17_is_complete(SId);
SD_flag = (f[i+2] >> 7);
PS_flag = ((f[i+2] >> 6) & 0x01);
L_flag = ((f[i+2] >> 5) & 0x01);
@@ -113,5 +132,7 @@ void fig0_17(fig0_common_t& fig0, int indent)
}
printbuf(desc, indent+1, NULL, 0);
}
+
+ return complete;
}
diff --git a/fig0_18.cpp b/fig0_18.cpp
index c7d7f8a..46a399c 100644
--- a/fig0_18.cpp
+++ b/fig0_18.cpp
@@ -28,11 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> services_seen;
+
+bool fig0_18_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/18 Announcement support
// ETSI EN 300 401 8.1.6.1
-void fig0_18(fig0_common_t& fig0, int indent)
+bool fig0_18(fig0_common_t& fig0, int indent)
{
uint32_t key;
uint16_t SId, Asu_flags;
@@ -41,11 +58,13 @@ void fig0_18(fig0_common_t& fig0, int indent)
char desc[256];
uint8_t* f = fig0.f;
const int figtype = 0;
+ bool complete = false;
while (i < (fig0.figlen - 4)) {
// iterate over announcement support
// SId, Asu flags, Rfa, Number of clusters
SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1];
+ complete |= fig0_18_is_complete(SId);
Asu_flags = ((uint16_t)f[i+2] << 8) | (uint16_t)f[i+3];
Rfa = (f[i+4] >> 5);
Number_clusters = (f[i+4] & 0x1F);
@@ -87,5 +106,7 @@ void fig0_18(fig0_common_t& fig0, int indent)
}
}
}
+
+ return complete;
}
diff --git a/fig0_19.cpp b/fig0_19.cpp
index 1d3593e..31b4ca1 100644
--- a/fig0_19.cpp
+++ b/fig0_19.cpp
@@ -28,11 +28,27 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+static std::unordered_set<int> clusters_seen;
+
+bool fig0_19_is_complete(int clusters_id)
+{
+ bool complete = clusters_seen.count(clusters_id);
+
+ if (complete) {
+ clusters_seen.clear();
+ }
+ else {
+ clusters_seen.insert(clusters_id);
+ }
+
+ return complete;
+}
// FIG 0/19 Announcement switching
// ETSI EN 300 401 8.1.6.2
-void fig0_19(fig0_common_t& fig0, int indent)
+bool fig0_19(fig0_common_t& fig0, int indent)
{
uint16_t Asw_flags;
uint8_t i = 1, j, Cluster_Id, SubChId, Rfa, RegionId_LP;
@@ -41,12 +57,14 @@ void fig0_19(fig0_common_t& fig0, int indent)
bool New_flag, Region_flag;
uint8_t* f = fig0.f;
const int figtype = 0;
+ bool complete = false;
while (i < (fig0.figlen - 3)) {
// iterate over announcement switching
// Cluster Id, Asw flags, New flag, Region flag,
// SubChId, Rfa, Region Id Lower Part
Cluster_Id = f[i];
+ complete |= fig0_19_is_complete(Cluster_Id);
Asw_flags = ((uint16_t)f[i+1] << 8) | (uint16_t)f[i+2];
New_flag = (f[i+3] >> 7);
Region_flag = (f[i+3] >> 6) & 0x1;
@@ -81,5 +99,7 @@ void fig0_19(fig0_common_t& fig0, int indent)
}
i += (4 + Region_flag);
}
+
+ return complete;
}
diff --git a/fig0_2.cpp b/fig0_2.cpp
index 29b52fa..95e6268 100644
--- a/fig0_2.cpp
+++ b/fig0_2.cpp
@@ -28,10 +28,27 @@
#include <cstdio>
#include <string>
#include <cstring>
+#include <unordered_set>
+
+static std::unordered_set<int> 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
-void fig0_2(fig0_common_t& fig0, int indent)
+bool fig0_2(fig0_common_t& fig0, int indent)
{
uint16_t sref, sid;
uint8_t cid, ecc, local, caid, ncomp, timd, ps, ca, subchid, scty;
@@ -40,6 +57,7 @@ void fig0_2(fig0_common_t& fig0, int indent)
uint8_t* f = fig0.f;
char sctydesc[32];
char desc[256];
+ bool complete = false;
while (k < fig0.figlen) {
if (fig0.pd() == 0) {
@@ -63,6 +81,8 @@ void fig0_2(fig0_common_t& fig0, int indent)
k += 4;
}
+ complete |= fig0_2_is_complete(sid);
+
local = (f[k] & 0x80) >> 7;
caid = (f[k] & 0x70) >> 4;
ncomp = f[k] & 0x0F;
@@ -141,6 +161,7 @@ void fig0_2(fig0_common_t& fig0, int indent)
k += 2;
}
}
-}
+ return complete;
+}
diff --git a/fig0_21.cpp b/fig0_21.cpp
index 9e6b113..69f18b9 100644
--- a/fig0_21.cpp
+++ b/fig0_21.cpp
@@ -28,11 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> regions_seen;
+
+bool fig0_21_is_complete(int region_id)
+{
+ bool complete = regions_seen.count(region_id);
+
+ if (complete) {
+ regions_seen.clear();
+ }
+ else {
+ regions_seen.insert(region_id);
+ }
+
+ return complete;
+}
// FIG 0/21 Frequency Information
// ETSI EN 300 401 8.1.8
-void fig0_21(fig0_common_t& fig0, int indent)
+bool fig0_21(fig0_common_t& fig0, int indent)
{
float freq;
uint32_t ifreq;
@@ -44,11 +61,13 @@ void fig0_21(fig0_common_t& fig0, int indent)
char desc[256];
bool Continuity_flag;
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 1)) {
// iterate over frequency information
// decode RegionId, Length of FI list
RegionId = (f[i] << 3) | (f[i+1] >> 5);
+ complete |= fig0_21_is_complete(RegionId);
Length_FI_list = (f[i+1] & 0x1F);
sprintf(desc, "RegionId=0x%03x", RegionId);
printbuf(desc, indent+1, NULL, 0);
@@ -298,5 +317,7 @@ void fig0_21(fig0_common_t& fig0, int indent)
i += Length_FI_list;
}
}
+
+ return complete;
}
diff --git a/fig0_22.cpp b/fig0_22.cpp
index 5c29e8d..dfee52b 100644
--- a/fig0_22.cpp
+++ b/fig0_22.cpp
@@ -28,6 +28,25 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> identifiers_seen;
+
+bool fig0_22_is_complete(int M_S, int MainId)
+{
+ int identifier = (M_S << 7) | MainId;
+
+ bool complete = identifiers_seen.count(identifier);
+
+ if (complete) {
+ identifiers_seen.clear();
+ }
+ else {
+ identifiers_seen.insert(identifier);
+ }
+
+ return complete;
+}
// map for fig 0/22 database
@@ -40,7 +59,7 @@ void fig0_22_cleardb()
// FIG 0/22 Transmitter Identification Information (TII) database
// ETSI EN 300 401 8.1.9
-void fig0_22(fig0_common_t& fig0, int indent)
+bool fig0_22(fig0_common_t& fig0, int indent)
{
Lat_Lng gps_pos = {0, 0};
double latitude_sub, longitude_sub;
@@ -54,11 +73,13 @@ void fig0_22(fig0_common_t& fig0, int indent)
bool MS;
const uint8_t Mode_Identity = get_mode_identity();
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < fig0.figlen) {
// iterate over Transmitter Identification Information (TII) fields
MS = f[i] >> 7;
MainId = f[i] & 0x7F;
+ complete |= fig0_22_is_complete(MS, MainId);
key = (fig0.oe() << 8) | (fig0.pd() << 7) | MainId;
sprintf(desc, "M/S=%d %sidentifier, MainId=0x%X",
MS, MS?"Sub-":"Main ", MainId);
@@ -159,5 +180,7 @@ void fig0_22(fig0_common_t& fig0, int indent)
}
}
}
+
+ return complete;
}
diff --git a/fig0_24.cpp b/fig0_24.cpp
index 03642fb..7867d9e 100644
--- a/fig0_24.cpp
+++ b/fig0_24.cpp
@@ -28,10 +28,27 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> services_seen;
+
+bool fig0_24_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/24 fig0.oe() Services
// ETSI EN 300 401 8.1.10.2
-void fig0_24(fig0_common_t& fig0, int indent)
+bool fig0_24(fig0_common_t& fig0, int indent)
{
uint64_t key;
uint32_t SId;
@@ -41,6 +58,7 @@ void fig0_24(fig0_common_t& fig0, int indent)
char desc[256];
uint8_t* f = fig0.f;
bool Rfa;
+ bool complete = false;
while (i < (fig0.figlen - (((uint8_t)fig0.pd() + 1) * 2))) {
// iterate over other ensembles services
@@ -53,6 +71,7 @@ void fig0_24(fig0_common_t& fig0, int indent)
((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3];
i += 4;
}
+ complete |= fig0_24_is_complete(SId);
Rfa = (f[i] >> 7);
CAId = (f[i] >> 4);
Number_of_EIds = (f[i] & 0x0f);
@@ -84,5 +103,7 @@ void fig0_24(fig0_common_t& fig0, int indent)
}
i += (Number_of_EIds * 2);
}
+
+ return complete;
}
diff --git a/fig0_25.cpp b/fig0_25.cpp
index 7e6b69b..7859868 100644
--- a/fig0_25.cpp
+++ b/fig0_25.cpp
@@ -28,11 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> services_seen;
+
+bool fig0_25_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/25 fig0.oe() Announcement support
// ETSI EN 300 401 8.1.10.5.1
-void fig0_25(fig0_common_t& fig0, int indent)
+bool fig0_25(fig0_common_t& fig0, int indent)
{
uint32_t key;
uint16_t SId, Asu_flags, EId;
@@ -40,11 +57,13 @@ void fig0_25(fig0_common_t& fig0, int indent)
char tmpbuf[256];
char desc[256];
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 4)) {
// iterate over other ensembles announcement support
// SId, Asu flags, Rfu, Number of EIds
SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1];
+ complete |= fig0_25_is_complete(SId);
Asu_flags = ((uint16_t)f[i+2] << 8) | (uint16_t)f[i+3];
Rfu = (f[i+4] >> 4);
Number_EIds = (f[i+4] & 0x0F);
@@ -87,5 +106,7 @@ void fig0_25(fig0_common_t& fig0, int indent)
}
}
}
+
+ return complete;
}
diff --git a/fig0_26.cpp b/fig0_26.cpp
index b519ed8..c2e4316 100644
--- a/fig0_26.cpp
+++ b/fig0_26.cpp
@@ -28,11 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> clusters_seen;
+
+bool fig0_26_is_complete(int cluster_id)
+{
+ bool complete = clusters_seen.count(cluster_id);
+
+ if (complete) {
+ clusters_seen.clear();
+ }
+ else {
+ clusters_seen.insert(cluster_id);
+ }
+
+ return complete;
+}
// FIG 0/26 fig0.oe() Announcement switching
// ETSI EN 300 401 8.1.10.5.2
-void fig0_26(fig0_common_t& fig0, int indent)
+bool fig0_26(fig0_common_t& fig0, int indent)
{
uint16_t Asw_flags, EId_Other_Ensemble;
uint8_t i = 1, j, Rfa, Cluster_Id_Current_Ensemble, Region_Id_Current_Ensemble;
@@ -41,10 +58,12 @@ void fig0_26(fig0_common_t& fig0, int indent)
char tmpbuf[256];
char desc[256];
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 6)) {
// iterate over other ensembles announcement switching
Cluster_Id_Current_Ensemble = f[i];
+ complete = fig0_26_is_complete(Cluster_Id_Current_Ensemble);
Asw_flags = ((uint16_t)f[i+1] << 8) | (uint16_t)f[i+2];
New_flag = f[i+3] >> 7;
Region_flag = (f[i+3] >> 6) & 0x01;
@@ -84,5 +103,7 @@ void fig0_26(fig0_common_t& fig0, int indent)
}
}
}
+
+ return complete;
}
diff --git a/fig0_27.cpp b/fig0_27.cpp
index 6e906b7..1f3f08d 100644
--- a/fig0_27.cpp
+++ b/fig0_27.cpp
@@ -28,21 +28,40 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> services_seen;
+
+bool fig0_27_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/27 FM Announcement support
// ETSI EN 300 401 8.1.11.2.1
-void fig0_27(fig0_common_t& fig0, int indent)
+bool fig0_27(fig0_common_t& fig0, int indent)
{
uint16_t SId, PI;
uint8_t i = 1, j, Rfu, Number_PI_codes, key;
char tmpbuf[256];
char desc[256];
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 2)) {
// iterate over FM announcement support
SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1];
+ complete |= fig0_27_is_complete(SId);
Rfu = f[i+2] >> 4;
Number_PI_codes = f[i+2] & 0x0F;
key = (fig0.oe() << 5) | (fig0.pd() << 4) | Number_PI_codes;
@@ -79,5 +98,7 @@ void fig0_27(fig0_common_t& fig0, int indent)
fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen);
}
}
+
+ return complete;
}
diff --git a/fig0_28.cpp b/fig0_28.cpp
index 8c727b9..68798c4 100644
--- a/fig0_28.cpp
+++ b/fig0_28.cpp
@@ -28,11 +28,28 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> clusters_seen;
+
+bool fig0_28_is_complete(int cluster_id)
+{
+ bool complete = clusters_seen.count(cluster_id);
+
+ if (complete) {
+ clusters_seen.clear();
+ }
+ else {
+ clusters_seen.insert(cluster_id);
+ }
+
+ return complete;
+}
// FIG 0/28 FM Announcement switching
// ETSI EN 300 401 8.1.11.2.2
-void fig0_28(fig0_common_t& fig0, int indent)
+bool fig0_28(fig0_common_t& fig0, int indent)
{
uint16_t PI;
uint8_t i = 1, Cluster_Id_Current_Ensemble, Region_Id_Current_Ensemble;
@@ -40,10 +57,12 @@ void fig0_28(fig0_common_t& fig0, int indent)
char tmpbuf[256];
char desc[256];
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - 3)) {
// iterate over FM announcement switching
Cluster_Id_Current_Ensemble = f[i];
+ complete = fig0_28_is_complete(Cluster_Id_Current_Ensemble);
New_flag = f[i+1] >> 7;
Rfa = (f[i+1] >> 6) & 0x01;
Region_Id_Current_Ensemble = f[i+1] & 0x3F;
@@ -65,5 +84,7 @@ void fig0_28(fig0_common_t& fig0, int indent)
printbuf(desc, indent+1, NULL, 0);
i += 4;
}
+
+ return complete;
}
diff --git a/fig0_3.cpp b/fig0_3.cpp
index 71547b6..adc502f 100644
--- a/fig0_3.cpp
+++ b/fig0_3.cpp
@@ -27,22 +27,42 @@
#include "figs.hpp"
#include <cstdio>
#include <cstring>
+#include <unordered_set>
+
+static std::unordered_set<int> components_ids_seen;
+
+bool fig0_3_is_complete(int components_id)
+{
+ bool complete = components_ids_seen.count(components_id);
+
+ if (complete) {
+ components_ids_seen.clear();
+ }
+ else {
+ components_ids_seen.insert(components_id);
+ }
+
+ return complete;
+}
+
// FIG 0/3 Service component in packet mode with or without Conditional Access
// ETSI EN 300 401 6.3.2
-void fig0_3(fig0_common_t& fig0, int indent)
+bool fig0_3(fig0_common_t& fig0, int indent)
{
uint16_t SCId, Packet_address, CAOrg;
uint8_t i = 1, Rfa, DSCTy, SubChId, CAMode, SharedFlag;
char tmpbuf[256];
char desc[256];
bool CAOrg_flag, DG_flag, Rfu;
+ bool complete = false;
uint8_t* f = fig0.f;
while (i < (fig0.figlen - 4)) {
// iterate over service component in packet mode
SCId = ((uint16_t)f[i] << 4) | ((uint16_t)(f[i+1] >> 4) & 0x0F);
+ complete |= fig0_3_is_complete(SCId);
Rfa = (f[i+1] >> 1) & 0x07;
CAOrg_flag = f[i+1] & 0x01;
DG_flag = (f[i+2] >> 7) & 0x01;
@@ -84,5 +104,7 @@ void fig0_3(fig0_common_t& fig0, int indent)
}
printbuf(desc, indent+1, NULL, 0);
}
+
+ return complete;
}
diff --git a/fig0_31.cpp b/fig0_31.cpp
index e4c3a92..cbaf296 100644
--- a/fig0_31.cpp
+++ b/fig0_31.cpp
@@ -28,15 +28,33 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<uint64_t> figtype_flags_seen;
+
+bool fig0_31_is_complete(uint64_t figtype_flags)
+{
+ bool complete = figtype_flags_seen.count(figtype_flags);
+
+ if (complete) {
+ figtype_flags_seen.clear();
+ }
+ else {
+ figtype_flags_seen.insert(figtype_flags);
+ }
+
+ return complete;
+}
// FIG 0/31 FIC re-direction
// ETSI EN 300 401 8.1.12
-void fig0_31(fig0_common_t& fig0, int indent)
+bool fig0_31(fig0_common_t& fig0, int indent)
{
uint32_t FIG_type0_flag_field = 0, flag_field;
uint8_t i = 1, j, FIG_type1_flag_field = 0, FIG_type2_flag_field = 0;
char desc[256];
uint8_t* f = fig0.f;
+ bool complete = false;
if (i < (fig0.figlen - 5)) {
// Read FIC re-direction
@@ -45,6 +63,9 @@ void fig0_31(fig0_common_t& fig0, int indent)
FIG_type1_flag_field = f[i+4];
FIG_type2_flag_field = f[i+5];
+ uint64_t key = ((uint64_t)FIG_type1_flag_field << 32) | ((uint64_t)FIG_type2_flag_field << 40) | FIG_type0_flag_field;
+ complete |= fig0_31_is_complete(key);
+
sprintf(desc, "FIG type 0 flag field=0x%X, FIG type 1 flag field=0x%X, FIG type 2 flag field=0x%X",
FIG_type0_flag_field, FIG_type1_flag_field, FIG_type2_flag_field);
printbuf(desc, indent+1, NULL, 0);
@@ -106,5 +127,7 @@ void fig0_31(fig0_common_t& fig0, int indent)
if (fig0.figlen != 7) {
fprintf(stderr, "WARNING: FIG 0/%d invalid length %d, expecting 7\n", fig0.ext(), fig0.figlen);
}
+
+ return complete;
}
diff --git a/fig0_5.cpp b/fig0_5.cpp
index f3ef08c..8d966a6 100644
--- a/fig0_5.cpp
+++ b/fig0_5.cpp
@@ -28,16 +28,34 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> components_seen;
+
+bool fig0_5_is_complete(int components_id)
+{
+ bool complete = components_seen.count(components_id);
+
+ if (complete) {
+ components_seen.clear();
+ }
+ else {
+ components_seen.insert(components_id);
+ }
+
+ return complete;
+}
// FIG 0/5 Service component language
// ETSI EN 300 401 8.1.2
-void fig0_5(fig0_common_t& fig0, int indent)
+bool fig0_5(fig0_common_t& fig0, int indent)
{
uint16_t SCId;
uint8_t i = 1, SubChId, FIDCId, Language, Rfa;
char tmpbuf[256];
char desc[256];
bool LS_flag, MSC_FIC_flag;
+ bool complete = false;
uint8_t* f = fig0.f;
@@ -62,6 +80,9 @@ void fig0_5(fig0_common_t& fig0, int indent)
LS_flag, MSC_FIC_flag, FIDCId, Language,
get_language_name(Language));
}
+
+ int key = (MSC_FIC_flag << 7) | (f[i] % 0x3F);
+ complete |= fig0_5_is_complete(key);
printbuf(desc, indent+1, NULL, 0);
i += 2;
}
@@ -70,6 +91,8 @@ void fig0_5(fig0_common_t& fig0, int indent)
if (i < (fig0.figlen - 2)) {
Rfa = (f[i] >> 4) & 0x07;
SCId = (((uint16_t)f[i] & 0x0F) << 8) | (uint16_t)f[i+1];
+ int key = (LS_flag << 15) | SCId;
+ complete |= fig0_5_is_complete(key);
Language = f[i+2];
sprintf(desc, "L/S flag=%d long form", LS_flag);
if (Rfa != 0) {
@@ -85,5 +108,7 @@ void fig0_5(fig0_common_t& fig0, int indent)
i += 3;
}
}
+
+ return complete;
}
diff --git a/fig0_6.cpp b/fig0_6.cpp
index e863951..dc35640 100644
--- a/fig0_6.cpp
+++ b/fig0_6.cpp
@@ -28,6 +28,23 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <unordered_set>
+
+static std::unordered_set<int> links_seen;
+
+bool fig0_6_is_complete(int link_key)
+{
+ bool complete = links_seen.count(link_key);
+
+ if (complete) {
+ links_seen.clear();
+ }
+ else {
+ links_seen.insert(link_key);
+ }
+
+ return complete;
+}
// map between fig 0/6 database key and LA to detect activation and deactivation of links
static std::map<uint16_t, bool> fig0_6_key_la;
@@ -39,7 +56,7 @@ void fig0_6_cleardb()
// FIG 0/6 Service linking information
// ETSI EN 300 401 8.1.15
-void fig0_6(fig0_common_t& fig0, int indent)
+bool fig0_6(fig0_common_t& fig0, int indent)
{
uint32_t j;
uint16_t LSN, key;
@@ -47,6 +64,7 @@ void fig0_6(fig0_common_t& fig0, int indent)
char signal_link[256];
char desc[256];
bool Id_list_flag, LA, SH, ILS, Shd;
+ bool complete = false;
uint8_t* f = fig0.f;
@@ -58,6 +76,7 @@ void fig0_6(fig0_common_t& fig0, int indent)
ILS = (f[i] >> 4) & 0x01;
LSN = ((f[i] & 0x0F) << 8) | f[i+1];
key = (fig0.oe() << 15) | (fig0.pd() << 14) | (SH << 13) | (ILS << 12) | LSN;
+ complete |= fig0_6_is_complete(key);
strcpy(signal_link, "");
// check activation / deactivation
if ((fig0_6_key_la.count(key) > 0) && (fig0_6_key_la[key] != LA)) {
@@ -165,6 +184,7 @@ void fig0_6(fig0_common_t& fig0, int indent)
}
}
}
-}
+ return complete;
+}
diff --git a/fig0_8.cpp b/fig0_8.cpp
index 29fda9a..60f2e0c 100644
--- a/fig0_8.cpp
+++ b/fig0_8.cpp
@@ -28,10 +28,36 @@
#include <cstdio>
#include <cstring>
#include <map>
+#include <set>
+
+/* EN 300 401, 8.1.14.3 Service component label
+ * The combination of the SId and the SCIdS provides a service component
+ * identifier which is valid globally.
+ */
+using SId_t = int;
+using SCIdS_t = int;
+static std::set<std::pair<SId_t, SCIdS_t> > components_seen;
+
+bool fig0_8_is_complete(SId_t SId, SCIdS_t SCIdS)
+{
+ auto key = std::make_pair(SId, SCIdS);
+ bool complete = components_seen.count(key);
+
+ if (complete) {
+ components_seen.clear();
+ }
+ else {
+ components_seen.insert(key);
+ }
+
+ return complete;
+}
+
+
// FIG 0/8 Service component global definition
// ETSI EN 300 401 6.3.5
-void fig0_8(fig0_common_t& fig0, int indent)
+bool fig0_8(fig0_common_t& fig0, int indent)
{
uint32_t SId;
uint16_t SCId;
@@ -40,6 +66,7 @@ void fig0_8(fig0_common_t& fig0, int indent)
char desc[256];
bool Ext_flag, LS_flag, MSC_FIC_flag;
uint8_t* f = fig0.f;
+ bool complete = false;
while (i < (fig0.figlen - (2 + (2 * fig0.pd())))) {
// iterate over service component global definition
@@ -57,6 +84,7 @@ void fig0_8(fig0_common_t& fig0, int indent)
Ext_flag = f[i] >> 7;
Rfa = (f[i] >> 4) & 0x7;
SCIdS = f[i] & 0x0F;
+ complete |= fig0_8_is_complete(SId, SCIdS);
sprintf(desc, "SId=0x%X, Ext flag=%d 8-bit Rfa %s", SId, Ext_flag, (Ext_flag)?"present":"absent");
if (Rfa != 0) {
sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa);
@@ -113,5 +141,7 @@ void fig0_8(fig0_common_t& fig0, int indent)
}
printbuf(desc, indent+1, NULL, 0);
}
+
+ return complete;
}
diff --git a/fig0_9.cpp b/fig0_9.cpp
index 9be0a03..5c8271c 100644
--- a/fig0_9.cpp
+++ b/fig0_9.cpp
@@ -37,7 +37,7 @@ bool LTO_uniq;
// FIG 0/9 Country, LTO and International table
// ETSI EN 300 401 8.1.3.2
-void fig0_9(fig0_common_t& fig0, int indent)
+bool fig0_9(fig0_common_t& fig0, int indent)
{
uint32_t SId;
uint8_t i = 1, j, key, Number_of_services, ECC;
@@ -127,5 +127,7 @@ void fig0_9(fig0_common_t& fig0, int indent)
}
}
}
+
+ return true;
}
diff --git a/fig1.cpp b/fig1.cpp
index 1af64de..6bb095c 100644
--- a/fig1.cpp
+++ b/fig1.cpp
@@ -32,7 +32,7 @@
using namespace std;
// SHORT LABELS
-void fig1_select(fig1_common_t& fig1, int indent)
+bool fig1_select(fig1_common_t& fig1, int indent)
{
uint16_t ext,oe,charset;
uint16_t flag;
@@ -60,7 +60,7 @@ void fig1_select(fig1_common_t& fig1, int indent)
uint16_t eid;
eid = f[1] * 256 + f[2];
sprintf(desc, "Ensemble ID 0x%04X label: \"%s\", Short label mask: 0x%04X", eid, label, flag);
- printinfo(desc, indent+1);
+ printinfo(desc, indent+1, 1);
}
break;
@@ -69,7 +69,7 @@ void fig1_select(fig1_common_t& fig1, int indent)
uint16_t sid;
sid = f[1] * 256 + f[2];
sprintf(desc, "Service ID 0x%X label: \"%s\", Short label mask: 0x%04X", sid, label, flag);
- printinfo(desc, indent+1);
+ printinfo(desc, indent+1, 1);
}
break;
@@ -92,7 +92,7 @@ void fig1_select(fig1_common_t& fig1, int indent)
sprintf(desc,
"Service ID 0x%X , Service Component ID 0x%04X Short, label: \"%s\", label mask: 0x%04X",
sid, SCIdS, label, flag);
- printinfo(desc, indent+1);
+ printinfo(desc, indent+1, 1);
}
break;
@@ -107,7 +107,7 @@ void fig1_select(fig1_common_t& fig1, int indent)
sprintf(desc,
"Service ID 0x%X label: \"%s\", Short label mask: 0x%04X",
sid, label, flag);
- printinfo(desc, indent+1);
+ printinfo(desc, indent+1, 1);
}
break;
@@ -150,7 +150,8 @@ void fig1_select(fig1_common_t& fig1, int indent)
}
break;
}
-}
-
+ // FIG1s always contain a complete set of information
+ return true;
+}
diff --git a/figs.cpp b/figs.cpp
index 4e7e94c..a1557d7 100644
--- a/figs.cpp
+++ b/figs.cpp
@@ -74,33 +74,33 @@ void figs_cleardb()
}
-void fig0_select(fig0_common_t& fig0, int indent)
+bool fig0_select(fig0_common_t& fig0, int indent)
{
switch (fig0.ext()) {
- case 0: fig0_0(fig0, indent); break;
- case 1: fig0_1(fig0, indent); break;
- case 2: fig0_2(fig0, indent); break;
- case 3: fig0_3(fig0, indent); break;
- case 5: fig0_5(fig0, indent); break;
- case 6: fig0_6(fig0, indent); break;
- case 8: fig0_8(fig0, indent); break;
- case 9: fig0_9(fig0, indent); break;
- case 10: fig0_10(fig0, indent); break;
- case 11: fig0_11(fig0, indent); break;
- case 13: fig0_13(fig0, indent); break;
- case 14: fig0_14(fig0, indent); break;
- case 16: fig0_16(fig0, indent); break;
- case 17: fig0_17(fig0, indent); break;
- case 18: fig0_18(fig0, indent); break;
- case 19: fig0_19(fig0, indent); break;
- case 21: fig0_21(fig0, indent); break;
- case 22: fig0_22(fig0, indent); break;
- case 24: fig0_24(fig0, indent); break;
- case 25: fig0_25(fig0, indent); break;
- case 26: fig0_26(fig0, indent); break;
- case 27: fig0_27(fig0, indent); break;
- case 28: fig0_28(fig0, indent); break;
- case 31: fig0_31(fig0, indent); break;
+ case 0: return fig0_0(fig0, indent); break;
+ case 1: return fig0_1(fig0, indent); break;
+ case 2: return fig0_2(fig0, indent); break;
+ case 3: return fig0_3(fig0, indent); break;
+ case 5: return fig0_5(fig0, indent); break;
+ case 6: return fig0_6(fig0, indent); break;
+ case 8: return fig0_8(fig0, indent); break;
+ case 9: return fig0_9(fig0, indent); break;
+ case 10: return fig0_10(fig0, indent); break;
+ case 11: return fig0_11(fig0, indent); break;
+ case 13: return fig0_13(fig0, indent); break;
+ case 14: return fig0_14(fig0, indent); break;
+ case 16: return fig0_16(fig0, indent); break;
+ case 17: return fig0_17(fig0, indent); break;
+ case 18: return fig0_18(fig0, indent); break;
+ case 19: return fig0_19(fig0, indent); break;
+ case 21: return fig0_21(fig0, indent); break;
+ case 22: return fig0_22(fig0, indent); break;
+ case 24: return fig0_24(fig0, indent); break;
+ case 25: return fig0_25(fig0, indent); break;
+ case 26: return fig0_26(fig0, indent); break;
+ case 27: return fig0_27(fig0, indent); break;
+ case 28: return fig0_28(fig0, indent); break;
+ case 31: return fig0_31(fig0, indent); break;
default: {
char desc[256];
sprintf(desc, "FIG 0/%d: unknown", fig0.ext());
@@ -108,5 +108,7 @@ void fig0_select(fig0_common_t& fig0, int indent)
break;
}
}
+
+ return false;
}
diff --git a/figs.hpp b/figs.hpp
index 7dd92eb..7bd5fd0 100644
--- a/figs.hpp
+++ b/figs.hpp
@@ -80,34 +80,34 @@ void set_international_table(size_t intl_table);
void set_mode_identity(uint8_t mid);
uint8_t get_mode_identity();
-void fig0_select(fig0_common_t& fig0, int indent);
+bool fig0_select(fig0_common_t& fig0, int indent);
-void fig0_0(fig0_common_t& fig0, int indent);
-void fig0_1(fig0_common_t& fig0, int indent);
-void fig0_2(fig0_common_t& fig0, int indent);
-void fig0_3(fig0_common_t& fig0, int indent);
-void fig0_5(fig0_common_t& fig0, int indent);
+bool fig0_0(fig0_common_t& fig0, int indent);
+bool fig0_1(fig0_common_t& fig0, int indent);
+bool fig0_2(fig0_common_t& fig0, int indent);
+bool fig0_3(fig0_common_t& fig0, int indent);
+bool fig0_5(fig0_common_t& fig0, int indent);
void fig0_6_cleardb();
-void fig0_6(fig0_common_t& fig0, int indent);
-void fig0_8(fig0_common_t& fig0, int indent);
-void fig0_9(fig0_common_t& fig0, int indent);
-void fig0_10(fig0_common_t& fig0, int indent);
-void fig0_11(fig0_common_t& fig0, int indent);
-void fig0_13(fig0_common_t& fig0, int indent);
-void fig0_14(fig0_common_t& fig0, int indent);
-void fig0_16(fig0_common_t& fig0, int indent);
-void fig0_17(fig0_common_t& fig0, int indent);
-void fig0_18(fig0_common_t& fig0, int indent);
-void fig0_19(fig0_common_t& fig0, int indent);
-void fig0_21(fig0_common_t& fig0, int indent);
+bool fig0_6(fig0_common_t& fig0, int indent);
+bool fig0_8(fig0_common_t& fig0, int indent);
+bool fig0_9(fig0_common_t& fig0, int indent);
+bool fig0_10(fig0_common_t& fig0, int indent);
+bool fig0_11(fig0_common_t& fig0, int indent);
+bool fig0_13(fig0_common_t& fig0, int indent);
+bool fig0_14(fig0_common_t& fig0, int indent);
+bool fig0_16(fig0_common_t& fig0, int indent);
+bool fig0_17(fig0_common_t& fig0, int indent);
+bool fig0_18(fig0_common_t& fig0, int indent);
+bool fig0_19(fig0_common_t& fig0, int indent);
+bool fig0_21(fig0_common_t& fig0, int indent);
void fig0_22_cleardb();
-void fig0_22(fig0_common_t& fig0, int indent);
-void fig0_24(fig0_common_t& fig0, int indent);
-void fig0_25(fig0_common_t& fig0, int indent);
-void fig0_26(fig0_common_t& fig0, int indent);
-void fig0_27(fig0_common_t& fig0, int indent);
-void fig0_28(fig0_common_t& fig0, int indent);
-void fig0_31(fig0_common_t& fig0, int indent);
-
-void fig1_select(fig1_common_t& fig1, int indent);
+bool fig0_22(fig0_common_t& fig0, int indent);
+bool fig0_24(fig0_common_t& fig0, int indent);
+bool fig0_25(fig0_common_t& fig0, int indent);
+bool fig0_26(fig0_common_t& fig0, int indent);
+bool fig0_27(fig0_common_t& fig0, int indent);
+bool fig0_28(fig0_common_t& fig0, int indent);
+bool fig0_31(fig0_common_t& fig0, int indent);
+
+bool fig1_select(fig1_common_t& fig1, int indent);
diff --git a/repetitionrate.cpp b/repetitionrate.cpp
new file mode 100644
index 0000000..45dd495
--- /dev/null
+++ b/repetitionrate.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org)
+
+ 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 <http://www.gnu.org/licenses/>.
+
+ Authors:
+ Matthias P. Braendli <matthias@mpb.li>
+
+*/
+
+#include "repetitionrate.hpp"
+#include <vector>
+#include <map>
+#include <unordered_set>
+
+using namespace std;
+
+const double frame_duration = 24e-3;
+
+struct FIGTypeExt {
+ int figtype;
+ int figextension;
+
+ bool operator<(const FIGTypeExt& other) const {
+ if (this->figtype == other.figtype) {
+ return this->figextension < other.figextension;
+ }
+ else {
+ return this->figtype < other.figtype ;
+ }
+ }
+};
+
+struct FIGRateInfo {
+ // List of frame numbers in which the FIG is present
+ vector<int> frames_present;
+
+ // List of frame numbers in which a complete DB for that FIG has been sent
+ vector<int> frames_complete;
+
+ // Which FIBs this FIG was seen in
+ unordered_set<int> in_fib;
+};
+
+
+static map<FIGTypeExt, FIGRateInfo> fig_rates;
+
+static int current_frame_number = 0;
+static int current_fib = 0;
+
+void rate_announce_fig(int figtype, int figextension, bool complete)
+{
+ FIGTypeExt f = {.figtype = figtype, .figextension = figextension};
+
+ if (fig_rates.count(f) == 0) {
+ FIGRateInfo rate;
+ fig_rates[f] = rate;
+ }
+
+ FIGRateInfo& rate = fig_rates[f];
+
+ rate.frames_present.push_back(current_frame_number);
+ if (complete) {
+ rate.frames_complete.push_back(current_frame_number);
+ }
+ rate.in_fib.insert(current_fib);
+}
+
+void rate_disply_analysis()
+{
+ printf("FIG carousel analysis. Format:\n"
+ " average FIGs per second (total count, delta variance in frames)\n"
+ " average complete FIGs per second (total count, delta variance in frames)\n");
+ for (auto& fig_rate : fig_rates) {
+ auto& frames_present = fig_rate.second.frames_present;
+ auto& frames_complete = fig_rate.second.frames_complete;
+
+ const size_t n_present = frames_present.size();
+ const size_t n_complete = frames_complete.size();
+
+ if (n_present and n_complete) {
+ double average_present_interval =
+ (double)(frames_present.back() - frames_present.front()) /
+ (double)(frames_present.size() - 1);
+
+ double average_complete_interval =
+ (double)(frames_complete.back() - frames_complete.front()) /
+ (double)(frames_complete.size() - 1);
+
+ double variance_of_delta_present = 0;
+ for (size_t i = 1; i < frames_present.size(); i++) {
+ double s =
+ (double)(frames_present[i] - frames_present[i-1]) -
+ average_present_interval;
+
+ variance_of_delta_present += s * s;
+ }
+ variance_of_delta_present /= frames_present.size();
+
+ double variance_of_delta_complete = 0;
+ for (size_t i = 1; i < frames_complete.size(); i++) {
+ double s =
+ (double)(frames_complete[i] - frames_complete[i-1]) -
+ average_complete_interval;
+
+ variance_of_delta_complete += s * s;
+ }
+ variance_of_delta_complete /= frames_complete.size();
+
+ const double n_present_per_second =
+ (double)n_present / (double)current_frame_number / frame_duration;
+
+ const double n_complete_per_second =
+ (double)n_complete / (double)current_frame_number / frame_duration;
+
+ printf("FIG%2d/%2d %2.2f (%6zu %2.2f) %2.2f (%6zu %2.2f)\n",
+ fig_rate.first.figtype, fig_rate.first.figextension,
+ n_present_per_second, n_present, variance_of_delta_present,
+ n_complete_per_second, n_complete, variance_of_delta_complete);
+ }
+ else {
+ printf("FIG%2d/%2d 0\n",
+ fig_rate.first.figtype, fig_rate.first.figextension);
+ }
+ }
+}
+
+void rate_new_fib(int fib)
+{
+ if (fib == 0) {
+ current_frame_number++;
+ }
+
+ current_fib = fib;
+}
+
diff --git a/repetitionrate.hpp b/repetitionrate.hpp
new file mode 100644
index 0000000..72d9db4
--- /dev/null
+++ b/repetitionrate.hpp
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org)
+
+ 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 <http://www.gnu.org/licenses/>.
+
+ Authors:
+ Matthias P. Braendli <matthias@mpb.li>
+
+*/
+
+#pragma once
+#include "utils.hpp"
+
+/* Tell the repetition rate analyser that we have received a given FIG.
+ * The complete flag should be set to true every time a complete
+ * set of information for that FIG has been received
+ */
+void rate_announce_fig(int figtype, int figextension, bool complete);
+
+/* Tell the repetition rate analyser that a new FIB starts.
+ */
+void rate_new_fib(int fib);
+
+/* Print analysis
+ */
+void rate_disply_analysis(void);
diff --git a/utils.hpp b/utils.hpp
index 3913f87..5455957 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -44,7 +44,7 @@ void printbuf(std::string header,
void printinfo(std::string header,
int indent_level,
- int min_verb = 0);
+ int min_verb);
// sprintfMJD: convert MJD (Modified Julian Date) into date string
int sprintfMJD(char *dst, int mjd);