From 0616c12772c4995d0a22b803127af156a37a3a7d Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Thu, 27 Apr 2017 01:39:20 +0200 Subject: Refactor FIG0/X message generation --- src/etisnoop.cpp | 21 +++++++-- src/fig0_0.cpp | 51 +++++++++++--------- src/fig0_1.cpp | 46 ++++++++---------- src/fig0_10.cpp | 26 ++++++---- src/fig0_11.cpp | 99 +++++++++++++++++++------------------- src/fig0_13.cpp | 21 ++++----- src/fig0_14.cpp | 17 ++++--- src/fig0_16.cpp | 48 +++++++------------ src/fig0_17.cpp | 67 +++++++++++++------------- src/fig0_18.cpp | 42 +++++++---------- src/fig0_19.cpp | 34 ++++++-------- src/fig0_2.cpp | 80 +++++++++++++++++-------------- src/fig0_21.cpp | 141 +++++++++++++++++++++++++++---------------------------- src/fig0_22.cpp | 63 ++++++++++--------------- src/fig0_24.cpp | 38 +++++++-------- src/fig0_25.cpp | 49 +++++++++---------- src/fig0_26.cpp | 42 ++++++++--------- src/fig0_27.cpp | 39 ++++++--------- src/fig0_28.cpp | 36 +++++++------- src/fig0_3.cpp | 49 +++++++++---------- src/fig0_31.cpp | 43 +++++++---------- src/fig0_5.cpp | 45 +++++++++--------- src/fig0_6.cpp | 94 +++++++++++++++++-------------------- src/fig0_8.cpp | 42 +++++++---------- src/fig0_9.cpp | 67 +++++++++++++------------- src/figs.cpp | 15 +++--- src/figs.hpp | 70 +++++++++++++++++---------- src/utils.cpp | 43 +++++++++++++---- src/utils.hpp | 7 +-- 29 files changed, 701 insertions(+), 734 deletions(-) diff --git a/src/etisnoop.cpp b/src/etisnoop.cpp index 7137d2e..1ebdf70 100644 --- a/src/etisnoop.cpp +++ b/src/etisnoop.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -701,8 +701,23 @@ void decodeFIG( figs.push_back(figtype, fig0.ext(), figlen); - bool complete = fig0_select(fig0, disp); - rate_announce_fig(figtype, fig0.ext(), complete); + auto fig_result = fig0_select(fig0, disp); + for (const auto& msg : fig_result.msgs) { + std::string s; + for (int i = 0; i < msg.level; i++) { + s += " "; + } + s += msg.msg; + printbuf(s.c_str(), disp.indent+1, nullptr, 0); + } + if (not fig_result.errors.empty()) { + printf("ERRORS:\n"); + for (const auto& err : fig_result.errors) { + printbuf(err.c_str(), disp.indent+1, nullptr, 0); + } + } + + rate_announce_fig(figtype, fig0.ext(), fig_result.complete); } break; diff --git a/src/fig0_0.cpp b/src/fig0_0.cpp index 83f7efa..162110b 100644 --- a/src/fig0_0.cpp +++ b/src/fig0_0.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -29,34 +29,39 @@ // FIG 0/0 Ensemble information // ETSI EN 300 401 6.4 -bool fig0_0(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_0(fig0_common_t& fig0, const display_settings_t &disp) { - uint8_t cid, al, ch, hic, lowc, occ; - uint16_t eid, eref; - char desc[128]; + uint8_t occ; + fig_result_t r; uint8_t* f = fig0.f; - eid = f[1]*256+f[2]; - cid = (f[1] & 0xF0) >> 4; - eref = (f[1] & 0x0F)*256 + \ - f[2]; - ch = (f[3] & 0xC0) >> 6; - al = (f[3] & 0x20) >> 5; - hic = f[3] & 0x1F; - lowc = f[4]; + const uint16_t eid = f[1]*256+f[2]; + r.msgs.push_back(strprintf("Ensemble ID=0x%02x", eid)); + + const uint8_t cid = (f[1] & 0xF0) >> 4; + r.msgs.emplace_back(1, strprintf("Country ID=%d", cid)); + + const uint16_t eref = (f[1] & 0x0F)*256 + \ + f[2]; + r.msgs.emplace_back(1, strprintf("Ensemble reference=%d", eref)); + + const uint8_t ch = (f[3] & 0xC0) >> 6; + r.msgs.push_back(strprintf("Change flag=%d", ch)); + + const uint8_t al = (f[3] & 0x20) >> 5; + r.msgs.push_back(strprintf("Alarm flag=%d", al)); + + const uint8_t hic = f[3] & 0x1F; + const uint8_t lowc = f[4]; + r.msgs.push_back(strprintf("CIF Count=%d/%d", hic, lowc)); + if (ch != 0) { occ = f[5]; - sprintf(desc, - "Ensemble ID=0x%02x (Country id=%d, Ensemble reference=%d), Change flag=%d, Alarm flag=%d, CIF Count=%d/%d, Occurance change=%d", - eid, cid, eref, ch, al, hic, lowc, occ); + r.msgs.push_back(strprintf("Occurrence change=%d", occ)); } - else { - sprintf(desc, - "Ensemble ID=0x%02x (Country id=%d, Ensemble reference=%d), Change flag=%d, Alarm flag=%d, CIF Count=%d/%d", - eid, cid, eref, ch, al, hic, lowc); - } - printbuf(desc, disp+1, NULL, 0); - return true; + r.complete = true; + + return r; } diff --git a/src/fig0_1.cpp b/src/fig0_1.cpp index 80ed906..76cda36 100644 --- a/src/fig0_1.cpp +++ b/src/fig0_1.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -46,17 +46,16 @@ bool fig0_1_is_complete(int subch_id) // FIG 0/1 Basic sub-channel organization // ETSI EN 300 401 6.2.1 -bool fig0_1(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_1(fig0_common_t& fig0, const display_settings_t &disp) { int i = 1; uint8_t* f = fig0.f; - char desc[128]; - bool complete = false; + fig_result_t r; while (i <= fig0.figlen-3) { // iterate over subchannels int subch_id = f[i] >> 2; - complete |= fig0_1_is_complete(subch_id); + r.complete |= fig0_1_is_complete(subch_id); int start_addr = ((f[i] & 0x03) << 8) | (f[i+1]); @@ -70,43 +69,38 @@ bool fig0_1(fig0_common_t& fig0, const display_settings_t &disp) i += 4; + r.msgs.push_back(strprintf("Subch 0x%x", subch_id)); + r.msgs.push_back(strprintf("start_addr %d", start_addr)); + r.msgs.emplace_back("long"); + if (option == 0x00) { - sprintf(desc, - "Subch 0x%x, start_addr %d, long, EEP %d-A, subch size %d", - subch_id, start_addr, protection_level, subchannel_size); + r.msgs.push_back(strprintf("EEP %d-A", protection_level)); } else if (option == 0x01) { - sprintf(desc, - "Subch 0x%x, start_addr %d, long, EEP %d-B, subch size %d", - subch_id, start_addr, protection_level, subchannel_size); + r.msgs.push_back(strprintf("EEP %d-B", protection_level)); } else { - sprintf(desc, - "Subch 0x%x, start_addr %d, long, invalid option %d, protection %d, subch size %d", - subch_id, start_addr, option, protection_level, subchannel_size); + r.errors.push_back(strprintf("Invalid option %d protection %d", option, protection_level)); } + + r.msgs.push_back(strprintf("subch size %d", subchannel_size)); } else { int table_switch = (f[i+2] >> 6) & 0x01; uint32_t table_index = (f[i+2] & 0x3F); - - if (table_switch == 0) { - sprintf(desc, - "Subch 0x%x, start_addr %d, short, table index %d", - subch_id, start_addr, table_index); - } - else { - sprintf(desc, - "Subch 0x%x, start_addr %d, short, invalid table_switch(=1), table index %d", - subch_id, start_addr, table_index); + r.msgs.push_back(strprintf("Subch 0x%x", subch_id)); + r.msgs.push_back(strprintf("start_addr %d", start_addr)); + r.msgs.emplace_back("short"); + if (table_switch != 0) { + r.errors.push_back(strprintf("Invalid table_switch %d", table_switch)); } + r.msgs.push_back(strprintf("table index %d", table_index)); i += 3; } - printbuf(desc, disp+1, NULL, 0); } - return complete; + return r; } diff --git a/src/fig0_10.cpp b/src/fig0_10.cpp index 3c01547..b4af859 100644 --- a/src/fig0_10.cpp +++ b/src/fig0_10.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -31,11 +31,11 @@ // FIG 0/10 Date and time // ETSI EN 300 401 8.1.3.1 -bool fig0_10(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_10(fig0_common_t& fig0, const display_settings_t &disp) { - char desc[256]; char dateStr[256]; dateStr[0] = 0; + fig_result_t r; uint8_t* f = fig0.f; //bool RFU = f[1] >> 7; @@ -59,16 +59,22 @@ bool fig0_10(fig0_common_t& fig0, const display_settings_t &disp) uint8_t seconds = f[5] >> 2; uint16_t milliseconds = ((uint16_t)(f[5] & 0x3) << 8) | f[6]; - sprintf(desc, "FIG 0/%d(long): MJD=0x%X %s, LSI %u, ConfInd %u, UTC Time: %02d:%02d:%02d.%d", - fig0.ext(), MJD, dateStr, LSI, ConfInd, hours, minutes, seconds, milliseconds); - printbuf(desc, disp+1, NULL, 0); + r.msgs.emplace_back("long form"); + r.msgs.push_back(strprintf("MJD=0x%X %s", MJD, dateStr)); + r.msgs.push_back(strprintf("LSI %u", LSI)); + r.msgs.push_back(strprintf("ConfInd %u", ConfInd)); + r.msgs.push_back(strprintf("UTC Time: %02d:%02d:%02d.%d", + hours, minutes, seconds, milliseconds)); } else { - sprintf(desc, "FIG 0/%d(short): MJD=0x%X %s, LSI %u, ConfInd %u, UTC Time: %02d:%02d", - fig0.ext(), MJD, dateStr, LSI, ConfInd, hours, minutes); - printbuf(desc, disp+1, NULL, 0); + r.msgs.emplace_back("short form"); + r.msgs.push_back(strprintf("MJD=0x%X %s", MJD, dateStr)); + r.msgs.push_back(strprintf("LSI %u", LSI)); + r.msgs.push_back(strprintf("ConfInd %u", ConfInd)); + r.msgs.push_back(strprintf("UTC Time: %02d:%02d", hours, minutes)); } - return true; + r.complete = true; + return r; } diff --git a/src/fig0_11.cpp b/src/fig0_11.cpp index d26795f..f019fa3 100644 --- a/src/fig0_11.cpp +++ b/src/fig0_11.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,15 +49,14 @@ bool fig0_11_is_complete(int region_id) // FIG 0/11 Region definition // ETSI EN 300 401 8.1.16.1 -bool fig0_11(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_11(fig0_common_t& fig0, const display_settings_t &disp) { Lat_Lng gps_pos = {0, 0}; int16_t Latitude_coarse, Longitude_coarse; uint16_t Region_Id, Extent_Latitude, Extent_Longitude, key; uint8_t i = 1, j, k, GATy, Rfu, Length_TII_list, Rfa, MainId, Length_SubId_list, SubId; int8_t bit_pos; - char desc[256]; - char tmpbuf[256]; + fig_result_t r; bool GE_flag; uint8_t* f = fig0.f; uint8_t Mode_Identity = get_mode_identity(); @@ -74,58 +73,54 @@ bool fig0_11(fig0_common_t& fig0, const display_settings_t &disp) i += 2; if (GATy == 0) { // TII list - sprintf(desc, "GATy=%d Geographical area defined by a TII list, G/E flag=%d %s coverage area, RegionId=0x%X, database key=0x%X", - GATy, GE_flag, GE_flag?"Global":"Ensemble", Region_Id, key); + r.msgs.push_back(strprintf("GATy=%d", GATy)); + r.msgs.emplace_back("Geographical area defined by a TII list"); + r.msgs.push_back(strprintf("G/E flag=%d %s coverage area", + GE_flag, GE_flag ? "Global" : "Ensemble")); + r.msgs.push_back(strprintf("RegionId=0x%X", Region_Id)); + r.msgs.push_back(strprintf("database key=0x%X", key)); + if (i < fig0.figlen) { Rfu = f[i] >> 5; if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } Length_TII_list = f[i] & 0x1F; - sprintf(tmpbuf, ", Length of TII list=%d", Length_TII_list); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf(", Length of TII list=%d", Length_TII_list)); if (Length_TII_list == 0) { - strcat(desc, ", CEI"); + r.msgs.emplace_back("CEI"); } - printbuf(desc, disp+1, NULL, 0); i++; - for(j = 0;(i < (fig0.figlen - 1)) && (j < Length_TII_list); j++) { + for (j = 0; (i < (fig0.figlen - 1)) && (j < Length_TII_list); j++) { // iterate over Transmitter group Rfa = f[i] >> 7; MainId = f[i] & 0x7F; if (Rfa != 0) { - sprintf(desc, "Rfa=%d invalid value, MainId=0x%X", - Rfa, MainId); + r.errors.push_back(strprintf("Rfa=%d invalid value, MainId=0x%X", Rfa, MainId)); } else { - sprintf(desc, "MainId=0x%X", MainId); + r.msgs.emplace_back(1, strprintf("MainId=0x%X", MainId)); } // check MainId value if ((Mode_Identity == 1) || (Mode_Identity == 2) || (Mode_Identity == 4)) { if (MainId > 69) { // The coding range shall be 0 to 69 for transmission modes I, II and IV - sprintf(tmpbuf, " invalid value for transmission mode %d", Mode_Identity); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("invalid value for transmission mode %d", Mode_Identity)); } } else if (Mode_Identity == 3) { if (MainId > 5) { // The coding range shall be 0 to 5 for transmission modes I, II and IV - sprintf(tmpbuf, " invalid value for transmission mode %d", Mode_Identity); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("invalid value for transmission mode %d", Mode_Identity)); } } Rfa = f[i+1] >> 5; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } Length_SubId_list = f[i+1] & 0x1F; - sprintf(tmpbuf, ", Length of SubId=%d", Length_SubId_list); - strcat(desc, tmpbuf); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("Length of SubId=%d", Length_SubId_list)); i += 2; bit_pos = 3; @@ -134,12 +129,11 @@ bool fig0_11(fig0_common_t& fig0, const display_settings_t &disp) // iterate SubId if (bit_pos >= 0) { SubId |= (f[i] >> bit_pos) & 0x1F; - sprintf(desc, "SubId=0x%X", SubId); + r.msgs.emplace_back(2, strprintf("SubId=0x%X", SubId)); // check SubId value if ((SubId == 0) || (SubId > 23)) { - strcat(desc, " invalid value"); + r.errors.push_back(strprintf("Invalid SubId=0x%X", SubId)); } - printbuf(desc, disp+3, NULL, 0); bit_pos -= 5; SubId = 0; } @@ -154,56 +148,61 @@ bool fig0_11(fig0_common_t& fig0, const display_settings_t &disp) i++; } if (k < Length_SubId_list) { - sprintf(desc, "%d SubId missing, fig length too short !", (Length_SubId_list - k)); - printbuf(desc, disp+3, NULL, 0); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back(strprintf("%d SubId missing, fig length too short !", Length_SubId_list - k)); } } if (j < Length_TII_list) { - sprintf(desc, "%d Transmitter group missing, fig length too short !", (Length_TII_list - j)); - printbuf(desc, disp+2, NULL, 0); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back(strprintf("%d Transmitter group missing, fig length too short !", Length_TII_list - j)); } } } else if (GATy == 1) { // Coordinates - sprintf(desc, "GATy=%d Geographical area defined as a spherical rectangle by the geographical co-ordinates of one corner and its latitude and longitude extents, G/E flag=%d %s coverage area, RegionId=0x%X, database key=0x%X", - GATy, GE_flag, GE_flag?"Global":"Ensemble", Region_Id, key); + r.msgs.push_back(strprintf("GATy=%d", GATy)); + r.msgs.emplace_back("Geographical area defined as a spherical rectangle " + "by the geographical co-ordinates of one corner and its latitude and " + "longitude extents"); + r.msgs.push_back(strprintf("G/E flag=%d %s coverage area", + GE_flag, GE_flag ? "Global" : "Ensemble")); + r.msgs.push_back(strprintf("RegionId=0x%X", Region_Id)); + r.msgs.push_back(strprintf("database key=0x%X", key)); + if (i < (fig0.figlen - 6)) { Latitude_coarse = ((int16_t)f[i] << 8) | ((uint16_t)f[i+1]); Longitude_coarse = ((int16_t)f[i+2] << 8) | ((uint16_t)f[i+3]); gps_pos.latitude = ((double)Latitude_coarse) * 90 / 32768; gps_pos.longitude = ((double)Latitude_coarse) * 180 / 32768; - sprintf(tmpbuf, ", Lat Lng coarse=0x%X 0x%X => %f, %f", - Latitude_coarse, Longitude_coarse, gps_pos.latitude, gps_pos.longitude); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Lat Lng coarse=0x%X 0x%X => %f, %f", + Latitude_coarse, Longitude_coarse, gps_pos.latitude, gps_pos.longitude)); Extent_Latitude = ((uint16_t)f[i+4] << 4) | ((uint16_t)(f[i+5] >> 4)); Extent_Longitude = ((uint16_t)(f[i+5] & 0x0F) << 8) | ((uint16_t)f[i+6]); gps_pos.latitude += ((double)Extent_Latitude) * 90 / 32768; gps_pos.longitude += ((double)Extent_Longitude) * 180 / 32768; - sprintf(tmpbuf, ", Extent Lat Lng=0x%X 0x%X => %f, %f", - Extent_Latitude, Extent_Longitude, gps_pos.latitude, gps_pos.longitude); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Extent Lat Lng=0x%X 0x%X => %f, %f", + Extent_Latitude, Extent_Longitude, gps_pos.latitude, gps_pos.longitude)); } else { - sprintf(tmpbuf, ", Coordinates missing, fig length too short !"); - strcat(desc, tmpbuf); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back("Coordinates missing, fig length too short !"); } - printbuf(desc, disp+1, NULL, 0); i += 7; } else { // Rfu - sprintf(desc, "GATy=%d reserved for future use of the geographical, G/E flag=%d %s coverage area, RegionId=0x%X, database key=0x%X, stop Region definition iteration %d/%d", - GATy, GE_flag, GE_flag?"Global":"Ensemble", Region_Id, key, i, fig0.figlen); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("GATy=%d", GATy)); + r.msgs.emplace_back("reserved for future use of the geographical"); + r.msgs.push_back(strprintf("G/E flag=%d %s coverage area", + GE_flag, GE_flag ? "Global" : "Ensemble")); + r.msgs.push_back(strprintf("RegionId=0x%X", Region_Id)); + r.msgs.push_back(strprintf("database key=0x%X", key)); + r.msgs.push_back(strprintf("stop Region definition iteration %d/%d", + i, fig0.figlen)); // stop Region definition iteration i = fig0.figlen; + r.errors.push_back("Stopping iteration because Rfu encountered"); } } - return complete; + r.complete = complete; + return r; } diff --git a/src/fig0_13.cpp b/src/fig0_13.cpp index 36c36df..ca8880f 100644 --- a/src/fig0_13.cpp +++ b/src/fig0_13.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -73,14 +73,13 @@ std::string get_fig_0_13_userapp(int user_app_type) // FIG 0/13 User application information // ETSI EN 300 401 8.1.20 -bool fig0_13(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_13(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t SId; uint8_t SCIdS; uint8_t No; uint8_t* f = fig0.f; - const int figtype = 0; - char desc[256]; + fig_result_t r; bool complete = false; int k = 1; @@ -109,9 +108,9 @@ bool fig0_13(fig0_common_t& fig0, const display_settings_t &disp) 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, disp+1, NULL, 0); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf("SCIdS=%u", SCIdS)); + r.msgs.push_back(strprintf("No=%u", No)); for (int numapp = 0; numapp < No; numapp++) { uint16_t user_app_type = ((f[k] << 8) | @@ -119,13 +118,13 @@ bool fig0_13(fig0_common_t& fig0, const display_settings_t &disp) uint8_t user_app_len = f[k+1] & 0x1F; k+=2; - sprintf(desc, "User Application %d '%s'; length %u", + r.msgs.emplace_back(1, strprintf("User Application %d '%s'; length %u", user_app_type, get_fig_0_13_userapp(user_app_type).c_str(), - user_app_len); - printbuf(desc, disp+2, NULL, 0); + user_app_len)); } - return complete; + r.complete = complete; + return r; } diff --git a/src/fig0_14.cpp b/src/fig0_14.cpp index 029a21c..65b5797 100644 --- a/src/fig0_14.cpp +++ b/src/fig0_14.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -58,24 +58,23 @@ const char *FEC_schemes_str[4] = { // FIG 0/14 FEC sub-channel organization // ETSI EN 300 401 6.2.2 -bool fig0_14(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_14(fig0_common_t& fig0, const display_settings_t &disp) { uint8_t i = 1, SubChId, FEC_scheme; uint8_t* f = fig0.f; - char desc[256]; - bool complete = false; + fig_result_t r; while (i < fig0.figlen) { // iterate over Sub-channel SubChId = f[i] >> 2; - complete |= fig0_14_is_complete(SubChId); + r.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, disp+1, NULL, 0); + r.msgs.push_back(strprintf("SubChId=0x%X", SubChId)); + r.msgs.emplace_back(1, strprintf("FEC scheme=%d %s", + FEC_scheme, FEC_schemes_str[FEC_scheme])); i++; } - return complete; + return r; } diff --git a/src/fig0_16.cpp b/src/fig0_16.cpp index 4583fc7..bff2a01 100644 --- a/src/fig0_16.cpp +++ b/src/fig0_16.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -54,74 +54,62 @@ bool fig0_16_is_complete(SId_t SId, PNum_t PNum) // FIG 0/16 Programme Number & fig0.oe() Programme Number // ETSI EN 300 401 8.1.4 & 8.1.10.3 -bool fig0_16(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_16(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t SId, PNum, New_SId, New_PNum; uint8_t i = 1, Rfa, Rfu; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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; Update_flag = f[i+4] & 0x01; - sprintf(desc, "SId=0x%X, PNum=0x%X ", SId, PNum); - // Append PNum decoded string - strcatPNum(desc, PNum); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf("PNum=0x%X ", PNum) + pnum_to_str(PNum)); if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=0x%X invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf(", Rfu=0x%X invalid value", Rfu)); } - sprintf(tmpbuf, ", Continuation flag=%d the programme will %s, Update flag=%d %sre-direction", - Continuation_flag, Continuation_flag?"be interrupted but continued later":"not be subject to a planned interruption", - Update_flag, Update_flag?"":"no "); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Continuation flag=%d: the programme will %s", + Continuation_flag, + Continuation_flag ? "be interrupted but continued later" : "not be subject to a planned interruption")); + r.msgs.push_back(strprintf("Update flag=%d %sre-direction", + Update_flag, Update_flag ? "" : "no ")); i += 5; if (Update_flag != 0) { // In the case of a re-direction, the New SId and New PNum shall be appended if (i < (fig0.figlen - 1)) { New_SId = ((uint16_t)f[i] << 8) | ((uint16_t)f[i+1]); - sprintf(tmpbuf, ", New SId=0x%X", New_SId); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("New SId=0x%X", New_SId)); if (i < (fig0.figlen - 3)) { New_PNum = ((uint16_t)f[i+2] << 8) | ((uint16_t)f[i+3]); - sprintf(tmpbuf, ", New PNum=0x%X ", New_PNum); - strcat(desc, tmpbuf); - // Append New_PNum decoded string - strcatPNum(desc, New_PNum); + r.msgs.push_back(strprintf("New PNum=0x%X ", New_PNum) + pnum_to_str(New_PNum)); } else { - sprintf(tmpbuf, ", missing New PNum !"); - strcat(desc, tmpbuf); + r.errors.push_back("missing New PNum !"); } } else { - sprintf(tmpbuf, ", missing New SId and New PNum !"); - strcat(desc, tmpbuf); + r.errors.push_back("missing New SId and New PNum !"); } i += 4; } - - printbuf(desc, disp+1, NULL, 0); } - return complete; + return r; } diff --git a/src/fig0_17.cpp b/src/fig0_17.cpp index 772b804..8eb2ba9 100644 --- a/src/fig0_17.cpp +++ b/src/fig0_17.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,91 +48,90 @@ bool fig0_17_is_complete(int services_id) // FIG 0/17 Programme Type // ETSI EN 300 401 8.1.5 -bool fig0_17(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_17(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t SId; uint8_t i = 1, Rfa, Language, Int_code, Comp_code; - char tmpbuf[512]; - char desc[512]; + fig_result_t r; 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); + r.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); CC_flag = ((f[i+2] >> 4) & 0x01); Rfa = (f[i+2] & 0x0F); - sprintf(desc, "SId=0x%X, S/D=%d Programme Type codes and language (when present), %srepresent the current programme contents, P/S=%d %s service component, L flag=%d language field %s, CC flag=%d complementary code and preceding Rfa and Rfu fields %s", - SId, SD_flag, SD_flag?"":"may not ", PS_flag, PS_flag?"secondary":"primary", - L_flag, L_flag?"present":"absent", CC_flag, CC_flag?"present":"absent"); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf( + "S/D=%d Programme Type codes and language (when present), %srepresent the current programme contents", + SD_flag, SD_flag?"":"may not ")); + r.msgs.push_back(strprintf("P/S=%d %s service component", + PS_flag, PS_flag?"secondary":"primary")); + r.msgs.push_back(strprintf("L flag=%d language field %s", + L_flag, L_flag?"present":"absent")); + r.msgs.push_back(strprintf("CC flag=%d complementary code and preceding Rfa and Rfu fields %s", + CC_flag, CC_flag?"present":"absent")); + if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=0x%X invalid value", Rfa)); } + i += 3; if (L_flag != 0) { if (i < fig0.figlen) { Language = f[i]; - sprintf(tmpbuf, ", Language=0x%X %s", Language, - get_language_name(Language)); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Language=0x%X %s", Language, + get_language_name(Language))); } else { - sprintf(tmpbuf, ", Language= invalid FIG length"); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Language= invalid FIG length")); } i++; } + if (i < fig0.figlen) { Rfa = f[i] >> 6; Rfu = (f[i] >> 5) & 0x01; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=0x%X invalid value", Rfa)); } if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } Int_code = f[i] & 0x1F; - sprintf(tmpbuf, ", Int code=0x%X %s", Int_code, get_programme_type(get_international_table() , Int_code)); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Int code=0x%X %s", Int_code, + get_programme_type(get_international_table(), Int_code))); i++; } else { - sprintf(tmpbuf, ", Int code= invalid FIG length"); - strcat(desc, tmpbuf); + r.errors.push_back("Int code: invalid FIG length"); } + if (CC_flag != 0) { if (i < fig0.figlen) { Rfa = f[i] >> 6; Rfu = (f[i] >> 5) & 0x01; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=0x%X invalid value", Rfa)); } if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } Comp_code = f[i] & 0x1F; - sprintf(tmpbuf, ", Comp code=0x%X %s", Comp_code, get_programme_type(get_international_table() , Comp_code)); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Comp code=0x%X %s", Comp_code, + get_programme_type(get_international_table(), Comp_code))); i++; } else { - sprintf(tmpbuf, ", Comp code= invalid FIG length"); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Comp code= invalid FIG length")); } } - printbuf(desc, disp+1, NULL, 0); } - return complete; + return r; } diff --git a/src/fig0_18.cpp b/src/fig0_18.cpp index abbf9f7..cc82bec 100644 --- a/src/fig0_18.cpp +++ b/src/fig0_18.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,64 +49,54 @@ bool fig0_18_is_complete(int services_id) // FIG 0/18 Announcement support // ETSI EN 300 401 8.1.6.1 -bool fig0_18(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_18(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t key; uint16_t SId, Asu_flags; uint8_t i = 1, j, Rfa, Number_clusters; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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); - sprintf(desc, "SId=0x%X, Asu flags=0x%04x", SId, Asu_flags); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf("Asu flags=0x%04x", Asu_flags)); if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", Number of clusters=%d", Number_clusters); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Number of clusters=%d", Number_clusters)); + key = ((uint32_t)fig0.oe() << 17) | ((uint32_t)fig0.pd() << 16) | (uint32_t)SId; - sprintf(tmpbuf, ", database key=0x%05x", key); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("database key=0x%05x", key)); // CEI Change Event Indication if ((Number_clusters == 0) && (Asu_flags == 0)) { - sprintf(tmpbuf, ", CEI"); - strcat(desc, tmpbuf); + r.msgs.emplace_back("CEI"); } - printbuf(desc, disp+1, NULL, 0); i += 5; for(j = 0; (j < Number_clusters) && (i < fig0.figlen); j++) { // iterate over Cluster Id - sprintf(desc, "Cluster Id=0x%X", f[i]); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("Cluster Id=0x%X", f[i])); i++; } if (j < Number_clusters) { - sprintf(desc, "missing Cluster Id, fig length too short !"); - printbuf(desc, disp+1, NULL, 0); - fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, fig0.ext(), fig0.figlen); + r.errors.push_back("missing Cluster Id, fig length too short !"); } // decode announcement support types - for(j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) { if (Asu_flags & (1 << j)) { - sprintf(desc, "Announcement support=%s", get_announcement_type(j)); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("Announcement support=%s", get_announcement_type(j))); } } } - return complete; + return r; } diff --git a/src/fig0_19.cpp b/src/fig0_19.cpp index 272f230..5fef324 100644 --- a/src/fig0_19.cpp +++ b/src/fig0_19.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,58 +48,52 @@ bool fig0_19_is_complete(int clusters_id) // FIG 0/19 Announcement switching // ETSI EN 300 401 8.1.6.2 -bool fig0_19(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_19(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t Asw_flags; uint8_t i = 1, j, Cluster_Id, SubChId, Rfa, RegionId_LP; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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; SubChId = (f[i+3] & 0x3F); - sprintf(desc, "Cluster Id=0x%02x, Asw flags=0x%04x, New flag=%d %s, Region flag=%d last byte %s, SubChId=%d", - Cluster_Id, Asw_flags, New_flag, (New_flag)?"new":"repeat", Region_flag, (Region_flag)?"present":"absent", SubChId); + r.msgs.push_back(strprintf("Cluster Id=0x%02x", Cluster_Id)); + r.msgs.push_back(strprintf("Asw flags=0x%04x", Asw_flags)); + r.msgs.push_back(strprintf("New flag=%d %s", New_flag, (New_flag)?"new":"repeat")); + r.msgs.push_back(strprintf("Region flag=%d last byte %s", Region_flag, (Region_flag)?"present":"absent")); + r.msgs.push_back(strprintf("SubChId=%d", SubChId)); if (Region_flag) { if (i < (fig0.figlen - 4)) { // read region lower part Rfa = (f[i+4] >> 6); RegionId_LP = (f[i+4] & 0x3F); if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", Region Lower Part=0x%02x", RegionId_LP); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("Region Lower Part=0x%02x", RegionId_LP)); } else { - sprintf(tmpbuf, "missing Region Lower Part, fig length too short !"); - strcat(desc, tmpbuf); - fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, fig0.ext(), fig0.figlen); + r.errors.push_back("missing Region Lower Part, fig length too short !"); } } - printbuf(desc, disp+1, NULL, 0); // decode announcement switching types for(j = 0; j < 16; j++) { if (Asw_flags & (1 << j)) { - sprintf(desc, "Announcement switching=%s", get_announcement_type(j)); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("Announcement switching=%s", get_announcement_type(j))); } } i += (4 + Region_flag); } - return complete; + return r; } diff --git a/src/fig0_2.cpp b/src/fig0_2.cpp index 128396e..85de44c 100644 --- a/src/fig0_2.cpp +++ b/src/fig0_2.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,16 +48,14 @@ bool fig0_2_is_complete(int services_id) // FIG 0/2 Basic service and service component definition // ETSI EN 300 401 6.3.1 -bool fig0_2(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_2(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t sref, sid; uint8_t cid, ecc, local, caid, ncomp, timd, ps, ca, subchid, scty; int k = 1; std::string psdesc; uint8_t* f = fig0.f; - char sctydesc[32]; - char desc[256]; - bool complete = false; + fig_result_t r; while (k < fig0.figlen) { if (fig0.pd() == 0) { @@ -82,29 +80,34 @@ bool fig0_2(fig0_common_t& fig0, const display_settings_t &disp) k += 4; } - complete |= fig0_2_is_complete(sid); + r.complete |= fig0_2_is_complete(sid); local = (f[k] & 0x80) >> 7; caid = (f[k] & 0x70) >> 4; ncomp = f[k] & 0x0F; - if (fig0.pd() == 0) - sprintf(desc, - "Service ID=0x%X (Country id=%d, Service reference=%d), Number of components=%d, Local flag=%d, CAID=%d", - sid, cid, sref, ncomp, local, caid); - else - sprintf(desc, - "Service ID=0x%X (ECC=%d, Country id=%d, Service reference=%d), Number of components=%d, Local flag=%d, CAID=%d", - sid, ecc, cid, sref, ncomp, local, caid); - printbuf(desc, disp+1, NULL, 0); + if (fig0.pd() == 0) { + r.msgs.push_back(strprintf("Service ID=0x%X (Country id=%d, Service reference=%d)", + sid, cid, sref)); + r.msgs.emplace_back(1, strprintf("Number of components=%d", ncomp)); + r.msgs.emplace_back(1, strprintf("Local flag=%d", local)); + r.msgs.emplace_back(1, strprintf("CAID=%d", caid)); + } + else { + r.msgs.push_back(strprintf("Service ID=0x%X (ECC=%d, Country id=%d, Service reference=%d)", + sid, ecc, cid, sref)); + r.msgs.emplace_back(1, strprintf("Number of components=%d", ncomp)); + r.msgs.emplace_back(1, strprintf("Local flag=%d", local)); + r.msgs.emplace_back(1, strprintf("CAID=%d", caid)); + } k++; - for (int i=0; i> 6; ps = (scomp[1] & 0x02) >> 1; ca = scomp[1] & 0x01; @@ -128,41 +131,50 @@ bool fig0_2(fig0_common_t& fig0, const display_settings_t &disp) if (timd == 0) { //MSC stream audio + r.msgs.emplace_back(2, "Stream audio mode"); + r.msgs.emplace_back(2, psdesc); + if (scty == 0) - sprintf(sctydesc, "MPEG Foreground sound (%d)", scty); + r.msgs.emplace_back(2, strprintf("MPEG Foreground sound (%d)", scty)); else if (scty == 1) - sprintf(sctydesc, "MPEG Background sound (%d)", scty); + r.msgs.emplace_back(2, strprintf("MPEG Background sound (%d)", scty)); else if (scty == 2) - sprintf(sctydesc, "Multi Channel sound (%d)", scty); + r.msgs.emplace_back(2, strprintf("Multi Channel sound (%d)", scty)); else if (scty == 63) - sprintf(sctydesc, "AAC sound (%d)", scty); + r.msgs.emplace_back(2, strprintf("AAC sound (%d)", scty)); else - sprintf(sctydesc, "Unknown ASCTy (%d)", scty); + r.msgs.emplace_back(2, strprintf("Unknown ASCTy (%d)", scty)); - sprintf(desc, "Stream audio mode, %s, %s, SubChannel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, strprintf("SubChannel ID=%02X", subchid)); + r.msgs.emplace_back(2, strprintf("CA=%d", ca)); } else if (timd == 1) { // MSC stream data - sprintf(sctydesc, "DSCTy=%d %s", scty, get_dscty_type(scty)); - sprintf(desc, "Stream data mode, %s, %s, SubChannel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, "Stream data mode"); + r.msgs.emplace_back(2, psdesc); + r.msgs.emplace_back(2, strprintf("DSCTy=%d %s", scty, get_dscty_type(scty))); + r.msgs.emplace_back(2, strprintf("SubChannel ID=%02X", subchid)); + r.msgs.emplace_back(2, strprintf("CA=%d", ca)); } else if (timd == 2) { // FIDC - sprintf(sctydesc, "DSCTy=%d %s", scty, get_dscty_type(scty)); - sprintf(desc, "FIDC mode, %s, %s, Fast Information Data Channel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, "FIDC mode"); + r.msgs.emplace_back(2, psdesc); + r.msgs.emplace_back(2, strprintf("DSCTy=%d %s", scty, get_dscty_type(scty))); + r.msgs.emplace_back(2, strprintf("Fast Information Data Channel ID=%02X", subchid)); + r.msgs.emplace_back(2, strprintf("CA=%d", ca)); } else if (timd == 3) { // MSC Packet mode - sprintf(desc, "MSC Packet Mode, %s, Service Component ID=%02X, CA=%d", psdesc.c_str(), subchid, ca); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, "MSC Packet Mode"); + r.msgs.emplace_back(2, psdesc); + r.msgs.emplace_back(2, strprintf("SubChannel ID=%02X", subchid)); + r.msgs.emplace_back(2, strprintf("CA=%d", ca)); } k += 2; } } - return complete; + return r; } diff --git a/src/fig0_21.cpp b/src/fig0_21.cpp index 088bb23..46a196f 100644 --- a/src/fig0_21.cpp +++ b/src/fig0_21.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,7 +49,7 @@ bool fig0_21_is_complete(int region_id) // FIG 0/21 Frequency Information // ETSI EN 300 401 8.1.8 -bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_21(fig0_common_t& fig0, const display_settings_t &disp) { float freq; uint32_t ifreq; @@ -57,20 +57,18 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) uint16_t RegionId, Id_field; uint8_t i = 1, j, k, Length_FI_list, RandM, Length_Freq_list, Control_field; uint8_t Control_field_trans_mode, Id_field2; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.complete |= fig0_21_is_complete(RegionId); Length_FI_list = (f[i+1] & 0x1F); - sprintf(desc, "RegionId=0x%03x", RegionId); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("RegionId=0x%03x", RegionId)); + r.msgs.push_back(strprintf("Len=%d", Length_FI_list)); i += 2; if ((i + Length_FI_list) <= fig0.figlen) { j = i; @@ -81,82 +79,85 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) RandM = f[j+2] >> 4; Continuity_flag = (f[j+2] >> 3) & 0x01; Length_Freq_list = f[j+2] & 0x07; - sprintf(desc, "Id_field="); + std::string idfield; switch (RandM) { case 0x0: case 0x1: - strcat(desc, "EId"); + idfield += "EId"; break; case 0x6: - strcat(desc, "DRM Service Id"); + idfield += "DRM Service Id"; break; case 0x8: - strcat(desc, "RDS PI"); + idfield += "RDS PI"; break; case 0x9: case 0xa: case 0xc: - strcat(desc, "Dummy"); + idfield += "Dummy"; break; case 0xe: - strcat(desc, "AMSS Service Id"); + idfield += "AMSS Service Id"; break; default: - strcat(desc, "invalid"); + idfield += "invalid"; + r.errors.emplace_back("R&M invalid"); break; } - sprintf(tmpbuf, "=0x%X, R&M=0x%1x", Id_field, RandM); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("ID field=0x%X", Id_field) + idfield); + + std::string rm_str; switch (RandM) { case 0x0: - strcat(desc, "=DAB ensemble, no local windows"); + rm_str += " DAB ensemble, no local windows"; break; case 0x6: - strcat(desc, "=DRM"); + rm_str += " DRM"; break; case 0x8: - strcat(desc, "=FM with RDS"); + rm_str += " FM with RDS"; break; case 0x9: - strcat(desc, "=FM without RDS"); + rm_str += " FM without RDS"; break; case 0xa: - strcat(desc, "=AM (MW in 9 kHz steps & LW)"); + rm_str += " AM (MW in 9 kHz steps & LW)"; break; case 0xc: - strcat(desc, "=AM (MW in 5 kHz steps & SW)"); + rm_str += " AM (MW in 5 kHz steps & SW)"; break; case 0xe: - strcat(desc, "=AMSS"); + rm_str += " AMSS"; break; default: - strcat(desc, "=Rfu"); + rm_str += " Rfu"; + r.errors.emplace_back("R&M is Rfu"); break; } - sprintf(tmpbuf, ", Continuity flag=%d", Continuity_flag); - strcat(desc, tmpbuf); - if ((fig0.oe() == 0) || ((fig0.oe() == 1) && (RandM != 0x6) && \ + r.msgs.emplace_back(1, strprintf("R&M=0x%1x", RandM) + rm_str); + std::string continuity_str; + if ((fig0.oe() == 0) || ((fig0.oe() == 1) && (RandM != 0x6) && ((RandM < 0x8) || (RandM > 0xa)) && (RandM != 0xc) && (RandM != 0xe))) { if (Continuity_flag == 0) { switch (RandM) { case 0x0: case 0x1: - strcat(desc, "=continuous output not expected"); + continuity_str += "=continuous output not expected"; break; case 0x6: - strcat(desc, "=no compensating time delay on DRM audio signal"); + continuity_str += "=no compensating time delay on DRM audio signal"; break; case 0x8: case 0x9: - strcat(desc, "=no compensating time delay on FM audio signal"); + continuity_str += "=no compensating time delay on FM audio signal"; break; case 0xa: case 0xc: case 0xe: - strcat(desc, "=no compensating time delay on AM audio signal"); + continuity_str += "=no compensating time delay on AM audio signal"; break; default: - strcat(desc, "=Rfu"); + continuity_str += "=Rfu"; break; } } @@ -164,39 +165,42 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) switch (RandM) { case 0x0: case 0x1: - strcat(desc, "=continuous output possible"); + continuity_str += "=continuous output possible"; break; case 0x6: - strcat(desc, "=compensating time delay on DRM audio signal"); + continuity_str += "=compensating time delay on DRM audio signal"; break; case 0x8: case 0x9: - strcat(desc, "=compensating time delay on FM audio signal"); + continuity_str += "=compensating time delay on FM audio signal"; break; case 0xa: case 0xc: case 0xe: - strcat(desc, "=compensating time delay on AM audio signal"); + continuity_str += "=compensating time delay on AM audio signal"; break; default: - strcat(desc, "=Rfu"); + continuity_str += "=Rfu"; + r.errors.emplace_back("continuity is Rfu"); break; } } } else { // fig0.oe() == 1 - strcat(desc, "=reserved for future addition"); + continuity_str = "=reserved for future addition"; + r.errors.emplace_back("Rfu"); } + + r.msgs.emplace_back(1, strprintf("Continuity flag=%d ", Continuity_flag) + continuity_str); + key = ((uint64_t)fig0.oe() << 32) | ((uint64_t)fig0.pd() << 31) | \ ((uint64_t)RegionId << 20) | ((uint64_t)Id_field << 4) | \ (uint64_t)RandM; - sprintf(tmpbuf, ", database key=0x%09" PRId64, key); + r.msgs.emplace_back(1, strprintf("database key=0x%09" PRId64, key)); // CEI Change Event Indication if (Length_Freq_list == 0) { - strcat(tmpbuf, ", CEI"); + r.msgs.emplace_back(1, "CEI"); } - strcat(desc, tmpbuf); - printbuf(desc, disp+2, NULL, 0); j += 3; // add header k = j; @@ -210,33 +214,30 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) Control_field = (f[k] >> 3); Control_field_trans_mode = (Control_field >> 1) & 0x07; if ((Control_field & 0x10) == 0) { - sprintf(desc, "%d KHz, ", ifreq); + r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); if ((Control_field & 0x01) == 0) { - strcat(desc, "geographically adjacent area, "); + r.msgs.emplace_back(2, "geographically adjacent area"); } else { // (Control_field & 0x01) == 1 - strcat(desc, "no geographically adjacent area, "); + r.msgs.emplace_back(2, "no geographically adjacent area"); } if (Control_field_trans_mode == 0) { - strcat(desc, "no transmission mode signalled"); + r.msgs.emplace_back(2, "no transmission mode signalled"); } else if (Control_field_trans_mode <= 4) { - sprintf(tmpbuf, "transmission mode %d", Control_field_trans_mode); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf("transmission mode %d", Control_field_trans_mode)); } else { // Control_field_trans_mode > 4 - sprintf(tmpbuf, "invalid transmission mode 0x%x", Control_field_trans_mode); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf("invalid transmission mode 0x%x", Control_field_trans_mode)); } } else { // (Control_field & 0x10) == 0x10 - sprintf(desc, "%d KHz, invalid Control field b23 0x%x", ifreq, Control_field); + r.msgs.emplace_back(2, strprintf("%d KHz, invalid Control field b23 0x%x", ifreq, Control_field)); } } else { - sprintf(desc, "Frequency not to be used (0)"); + r.errors.emplace_back("Frequency not to be used (0)"); } - printbuf(desc, disp+3, NULL, 0); k += 3; } break; @@ -253,17 +254,16 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) else { // f[k] >= 16 ifreq = (387 + ((uint32_t)f[k] * 9)); } - sprintf(desc, "%d KHz", ifreq); + r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); } else { // RandM == 8 or 9 freq = (87.5 + ((float)f[k] * 0.1)); - sprintf(desc, "%.1f MHz", freq); + r.msgs.emplace_back(2, strprintf("%.1f MHz", freq)); } } else { - sprintf(desc, "Frequency not to be used (0)"); + r.errors.emplace_back("Frequency not to be used (0)"); } - printbuf(desc, disp+3, NULL, 0); k++; } break; @@ -272,12 +272,11 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) // iteration over Freq list ifreq = (((uint32_t)f[k] << 8) | (uint32_t)f[k+1]) * 5; if (ifreq != 0) { - sprintf(desc, "%d KHz", ifreq); + r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); } else { - sprintf(desc, "Frequency not to be used (0)"); + r.errors.emplace_back("Frequency not to be used (0)"); } - printbuf(desc, disp+3, NULL, 0); k += 2; } break; @@ -288,24 +287,20 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) Id_field2 = f[k]; ifreq = ((((uint32_t)f[k+1] & 0x7f) << 8) | (uint32_t)f[k+2]); if (ifreq != 0) { - sprintf(desc, "%d KHz", ifreq); + r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); } else { - sprintf(desc, "Frequency not to be used (0)"); + r.errors.emplace_back("Frequency not to be used (0)"); } if (RandM == 0x6) { - sprintf(tmpbuf, ", DRM Service Id 0x%X", Id_field2); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf("DRM Service Id 0x%X", Id_field2)); } else if (RandM == 0xe) { - sprintf(tmpbuf, ", AMSS Service Id 0x%X", Id_field2); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf("AMSS Service Id 0x%X", Id_field2)); } if ((f[k+1] & 0x80) == 0x80) { - sprintf(tmpbuf, ", invalid Rfu b15 set to 1 instead of 0"); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf("invalid Rfu b15 set to 1 instead of 0")); } - printbuf(desc, disp+3, NULL, 0); k += 3; } break; @@ -316,8 +311,12 @@ bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp) } i += Length_FI_list; } + else { + r.errors.push_back(strprintf("FIG0/21 FI Len error: expect %d + %d <= %d\n", + i , Length_FI_list, fig0.figlen)); + } } - return complete; + return r; } diff --git a/src/fig0_22.cpp b/src/fig0_22.cpp index c5e8c3f..ca9bb06 100644 --- a/src/fig0_22.cpp +++ b/src/fig0_22.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -59,7 +59,7 @@ void fig0_22_cleardb() // FIG 0/22 Transmitter Identification Information (TII) database // ETSI EN 300 401 8.1.9 -bool fig0_22(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_22(fig0_common_t& fig0, const display_settings_t &disp) { Lat_Lng gps_pos = {0, 0}; double latitude_sub, longitude_sub; @@ -68,39 +68,35 @@ bool fig0_22(fig0_common_t& fig0, const display_settings_t &disp) int16_t Latitude_offset, Longitude_offset; uint8_t i = 1, j, MainId = 0, Rfu, Nb_SubId_fields, SubId; uint8_t Latitude_fine, Longitude_fine; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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); + r.msgs.push_back(strprintf("M/S=%d %sidentifier", + MS, MS?"Sub-":"Main ")); + r.msgs.push_back(strprintf("MainId=0x%X", MainId)); // check MainId value if ((Mode_Identity == 1) || (Mode_Identity == 2) || (Mode_Identity == 4)) { if (MainId > 69) { // The coding range shall be 0 to 69 for transmission modes I, II and IV - sprintf(tmpbuf, " invalid value for transmission mode %d", Mode_Identity); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("invalid value for transmission mode %d", Mode_Identity)); } } else if (Mode_Identity == 3) { if (MainId > 5) { // The coding range shall be 0 to 5 for transmission modes I, II and IV - sprintf(tmpbuf, " invalid value for transmission mode %d", Mode_Identity); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("invalid value for transmission mode %d", Mode_Identity)); } } // print database key - sprintf(tmpbuf, ", database key=0x%X", key); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("database key=0x%X", key)); i++; if (MS == 0) { // Main identifier @@ -113,16 +109,14 @@ bool fig0_22(fig0_common_t& fig0, const display_settings_t &disp) gps_pos.latitude = (double)((int32_t)((((int32_t)Latitude_coarse) << 4) | (uint32_t)Latitude_fine)) * 90 / 524288; gps_pos.longitude = (double)((int32_t)((((int32_t)Longitude_coarse) << 4) | (uint32_t)Longitude_fine)) * 180 / 524288; fig0_22_key_Lat_Lng[key] = gps_pos; - sprintf(tmpbuf, ", Lat Lng coarse=0x%X 0x%X, Lat Lng fine=0x%X 0x%X => Lat Lng=%f, %f", + r.msgs.push_back(strprintf("Lat Lng coarse=0x%X 0x%X, Lat Lng fine=0x%X 0x%X => Lat Lng=%f, %f", Latitude_coarse, Longitude_coarse, Latitude_fine, Longitude_fine, - gps_pos.latitude, gps_pos.longitude); - strcat(desc, tmpbuf); + gps_pos.latitude, gps_pos.longitude)); i += 5; } else { - strcat(desc, ", invalid length of Latitude Longitude coarse fine"); + r.errors.push_back("invalid length of Latitude Longitude coarse fine"); } - printbuf(desc, disp+1, NULL, 0); } else { // MS == 1 // Sub-identifier @@ -131,56 +125,49 @@ bool fig0_22(fig0_common_t& fig0, const display_settings_t &disp) Rfu = f[i] >> 3; Nb_SubId_fields = f[i] & 0x07; if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } - sprintf(tmpbuf, ", Number of SubId fields=%d%s", - Nb_SubId_fields, (Nb_SubId_fields == 0)?", CEI":""); - strcat(desc, tmpbuf); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("Number of SubId fields=%d%s", + Nb_SubId_fields, (Nb_SubId_fields == 0)?", CEI":"")); i++; for(j = i; ((j < (i + (Nb_SubId_fields * 6))) && (j < (fig0.figlen - 5))); j += 6) { // iterate over SubId fields SubId = f[j] >> 3; - sprintf(desc, "SubId=0x%X", SubId); + r.msgs.emplace_back(1, strprintf("SubId=0x%X", SubId)); // check SubId value if ((SubId == 0) || (SubId > 23)) { - strcat(desc, " invalid value"); + r.errors.push_back("invalid value"); } TD = ((f[j] & 0x03) << 8) | f[j+1]; Latitude_offset = (f[j+2] << 8) | f[j+3]; Longitude_offset = (f[j+4] << 8) | f[j+5]; - sprintf(tmpbuf, ", TD=%d us, Lat Lng offset=0x%X 0x%X", - TD, Latitude_offset, Longitude_offset); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("TD=%d us", TD)); + r.msgs.emplace_back(1, strprintf("Lat Lng offset=0x%X 0x%X", Latitude_offset, Longitude_offset)); if (fig0_22_key_Lat_Lng.count(key) > 0) { // latitude longitude available in database for Main Identifier latitude_sub = (90 * (double)Latitude_offset / 524288) + fig0_22_key_Lat_Lng[key].latitude; longitude_sub = (180 * (double)Longitude_offset / 524288) + fig0_22_key_Lat_Lng[key].longitude; - sprintf(tmpbuf, " => Lat Lng=%f, %f", latitude_sub, longitude_sub); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf(" => Lat Lng=%f, %f", latitude_sub, longitude_sub)); } else { // latitude longitude not available in database for Main Identifier latitude_sub = 90 * (double)Latitude_offset / 524288; longitude_sub = 180 * (double)Longitude_offset / 524288; - sprintf(tmpbuf, " => Lat Lng=%f, %f wrong value because Main identifier latitude/longitude not available in database", latitude_sub, longitude_sub); - strcat(desc, tmpbuf); + r.msgs.emplace_back(2, strprintf(" => Lat Lng=%f, %f wrong value because" + " Main identifier latitude/longitude not available in database", latitude_sub, longitude_sub)); } - printbuf(desc, disp+2, NULL, 0); } i += (Nb_SubId_fields * 6); } else { - strcat(desc, ", invalid fig length or Number of SubId fields length"); - printbuf(desc, disp+1, NULL, 0); + r.errors.emplace_back(strprintf("invalid fig length or Number of SubId fields length")); } } } - return complete; + return r; } diff --git a/src/fig0_24.cpp b/src/fig0_24.cpp index d9d0284..24548e5 100644 --- a/src/fig0_24.cpp +++ b/src/fig0_24.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,17 +48,15 @@ bool fig0_24_is_complete(int services_id) // FIG 0/24 fig0.oe() Services // ETSI EN 300 401 8.1.10.2 -bool fig0_24(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_24(fig0_common_t& fig0, const display_settings_t &disp) { uint64_t key; uint32_t SId; uint16_t EId; uint8_t i = 1, j, Number_of_EIds, CAId; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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 @@ -71,39 +69,37 @@ bool fig0_24(fig0_common_t& fig0, const display_settings_t &disp) ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; i += 4; } - complete |= fig0_24_is_complete(SId); + r.complete |= fig0_24_is_complete(SId); Rfa = (f[i] >> 7); CAId = (f[i] >> 4); Number_of_EIds = (f[i] & 0x0f); key = ((uint64_t)fig0.oe() << 33) | ((uint64_t)fig0.pd() << 32) | \ (uint64_t)SId; - if (fig0.pd() == 0) { - sprintf(desc, "SId=0x%X, CAId=%d, Number of EId=%d, database key=%09" PRId64, SId, CAId, Number_of_EIds, key); - } - else { // fig0.pd() == 1 - sprintf(desc, "SId=0x%X, CAId=%d, Number of EId=%d, database key=%09" PRId64, SId, CAId, Number_of_EIds, key); - } + + r.msgs.push_back(strprintf("PD=%d", fig0.pd())); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf("CAId=%d", CAId)); + r.msgs.push_back(strprintf("Number of EId=%d", Number_of_EIds)); + r.msgs.push_back(strprintf("database key=%09" PRId64, key)); + if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } + // CEI Change Event Indication if (Number_of_EIds == 0) { - sprintf(tmpbuf, ", CEI"); - strcat(desc, tmpbuf); + r.msgs.emplace_back("CEI"); } - printbuf(desc, disp+1, NULL, 0); i++; - for(j = i; ((j < (i + (Number_of_EIds * 2))) && (j < fig0.figlen)); j += 2) { + for (j = i; ((j < (i + (Number_of_EIds * 2))) && (j < fig0.figlen)); j += 2) { // iterate over EIds EId = ((uint16_t)f[j] <<8) | (uint16_t)f[j+1]; - sprintf(desc, "EId 0x%04x", EId); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("EId 0x%04x", EId)); } i += (Number_of_EIds * 2); } - return complete; + return r; } diff --git a/src/fig0_25.cpp b/src/fig0_25.cpp index bd98f70..9aa64c0 100644 --- a/src/fig0_25.cpp +++ b/src/fig0_25.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,64 +49,59 @@ bool fig0_25_is_complete(int services_id) // FIG 0/25 fig0.oe() Announcement support // ETSI EN 300 401 8.1.10.5.1 -bool fig0_25(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_25(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t key; uint16_t SId, Asu_flags, EId; uint8_t i = 1, j, Rfu, Number_EIds; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; uint8_t* f = fig0.f; - bool complete = false; - while (i < (fig0.figlen - 4)) { + 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); + r.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); - sprintf(desc, "SId=0x%X, Asu flags=0x%X", SId, Asu_flags); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.emplace_back(1, strprintf("Asu flags=0x%X", Asu_flags)); + r.msgs.emplace_back(1, strprintf("Number of EIds=%d", Number_EIds)); + if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } - sprintf(tmpbuf, ", Number of EIds=%d", Number_EIds); - strcat(desc, tmpbuf); + key = ((uint32_t)fig0.oe() << 17) | ((uint32_t)fig0.pd() << 16) | (uint32_t)SId; - sprintf(tmpbuf, ", database key=0x%05x", key); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("database key=0x%05x", key)); + // CEI Change Event Indication if (Number_EIds == 0) { - sprintf(tmpbuf, ", CEI"); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, "CEI"); } - printbuf(desc, disp+1, NULL, 0); i += 5; - for(j = 0; (j < Number_EIds) && (i < (fig0.figlen - 1)); j++) { + for (j = 0; j < Number_EIds && i < fig0.figlen - 1; j++) { // iterate over EIds EId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1]; - sprintf(desc, "EId=0x%X", EId); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(2, strprintf("EId=0x%X", EId)); i += 2; } + if (j < Number_EIds) { - sprintf(desc, "missing EId, fig length too short !"); - printbuf(desc, disp+1, NULL, 0); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back("missing EId, fig length too short !"); } // decode fig0.oe() announcement support types - for(j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) { if (Asu_flags & (1 << j)) { - sprintf(desc, "fig0.oe() Announcement support=%s", get_announcement_type(j)); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(2, + strprintf("fig0.oe() Announcement support=%s", get_announcement_type(j))); } } } - return complete; + return r; } diff --git a/src/fig0_26.cpp b/src/fig0_26.cpp index 1ad85dc..332a900 100644 --- a/src/fig0_26.cpp +++ b/src/fig0_26.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,31 +49,35 @@ bool fig0_26_is_complete(int cluster_id) // FIG 0/26 fig0.oe() Announcement switching // ETSI EN 300 401 8.1.10.5.2 -bool fig0_26(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_26(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t Asw_flags, EId_Other_Ensemble; uint8_t i = 1, j, Rfa, Cluster_Id_Current_Ensemble, Region_Id_Current_Ensemble; uint8_t Cluster_Id_Other_Ensemble, Region_Id_Other_Ensemble; bool New_flag, Region_flag; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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; Region_Id_Current_Ensemble = f[i+3] & 0x3F; EId_Other_Ensemble = ((uint16_t)f[i+4] << 8) | (uint16_t)f[i+5]; Cluster_Id_Other_Ensemble = f[i+6]; - sprintf(desc, "Cluster Id Current Ensemble=0x%X, Asw flags=0x%X, New flag=%d %s announcement, Region flag=%d last byte %s, Region Id Current Ensemble=0x%X, EId Other Ensemble=0x%X, Cluster Id Other Ensemble=0x%X", - Cluster_Id_Current_Ensemble, Asw_flags, New_flag, New_flag?"newly introduced":"repeated", - Region_flag, Region_flag?"present":"absent. The announcement concerns the whole service area", - Region_Id_Current_Ensemble, EId_Other_Ensemble, Cluster_Id_Other_Ensemble); + + r.msgs.push_back(strprintf("Cluster Id Current Ensemble=0x%X", Cluster_Id_Current_Ensemble)); + r.msgs.emplace_back(1, strprintf("Asw flags=0x%X", Asw_flags)); + r.msgs.emplace_back(1, strprintf("New flag=%d %s announcement", New_flag, New_flag?"newly introduced":"repeated")); + r.msgs.emplace_back(1, strprintf("Region flag=%d last byte %s", + Region_flag, Region_flag?"present":"absent. The announcement concerns the whole service area")); + r.msgs.emplace_back(1, strprintf("Region Id Current Ensemble=0x%X", Region_Id_Current_Ensemble)); + r.msgs.emplace_back(1, strprintf("EId Other Ensemble=0x%X", EId_Other_Ensemble)); + r.msgs.emplace_back(1, strprintf("Cluster Id Other Ensemble=0x%X", Cluster_Id_Other_Ensemble)); + i += 7; if (Region_flag != 0) { if (i < fig0.figlen) { @@ -81,29 +85,23 @@ bool fig0_26(fig0_common_t& fig0, const display_settings_t &disp) Rfa = (f[i] >> 6); Region_Id_Other_Ensemble = f[i] & 0x3F; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", Region Id Other Ensemble=0x%X", Region_Id_Other_Ensemble); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("Region Id Other Ensemble=0x%X", Region_Id_Other_Ensemble)); } else { - sprintf(tmpbuf, "missing Region Id Other Ensemble, fig length too short !"); - strcat(desc, tmpbuf); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back("missing Region Id Other Ensemble, fig length too short !"); } i++; } - printbuf(desc, disp+1, NULL, 0); // decode announcement switching types - for(j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) { if (Asw_flags & (1 << j)) { - sprintf(desc, "Announcement switching=%s", get_announcement_type(j)); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(2, strprintf("Announcement switching=%s", get_announcement_type(j))); } } } - return complete; + return r; } diff --git a/src/fig0_27.cpp b/src/fig0_27.cpp index dfe4468..2b37a85 100644 --- a/src/fig0_27.cpp +++ b/src/fig0_27.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,56 +49,47 @@ bool fig0_27_is_complete(int services_id) // FIG 0/27 FM Announcement support // ETSI EN 300 401 8.1.11.2.1 -bool fig0_27(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_27(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t SId, PI; uint8_t i = 1, j, Rfu, Number_PI_codes, key; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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); + r.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; - sprintf(desc, "SId=0x%X", SId); + r.msgs.push_back(strprintf("SId=0x%X", SId)); if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } - sprintf(tmpbuf, ", Number of PI codes=%d", Number_PI_codes); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("Number of PI codes=%d", Number_PI_codes)); if (Number_PI_codes > 12) { - strcat(desc, " above maximum value of 12"); - fprintf(stderr, "WARNING: FIG 0/%d Number of PI codes=%d > 12 (maximum value)\n", fig0.ext(), Number_PI_codes); + r.errors.push_back(strprintf("Number of PI codes=%d > 12 (maximum value)", Number_PI_codes)); } - sprintf(tmpbuf, ", database key=0x%02X", key); - strcat(desc, tmpbuf); + r.msgs.emplace_back(1, strprintf("database key=0x%02X", key)); // CEI Change Event Indication if (Number_PI_codes == 0) { // The Change Event Indication (CEI) is signalled by the Number of PI codes field = 0 - strcat(desc, ", CEI"); + r.msgs.emplace_back(1, "CEI"); } - printbuf(desc, disp+1, NULL, 0); i += 3; - for(j = 0; (j < Number_PI_codes) && (i < (fig0.figlen - 1)); j++) { + + for (j = 0; j < Number_PI_codes && i < fig0.figlen - 1; j++) { // iterate over PI PI = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1]; - sprintf(desc, "PI=0x%X", PI); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(2, strprintf("PI=0x%X", PI)); i += 2; } if (j != Number_PI_codes) { - sprintf(desc, "fig length too short !"); - printbuf(desc, disp+2, NULL, 0); - fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); + r.errors.push_back("fig length too short !"); } } - return complete; + return r; } diff --git a/src/fig0_28.cpp b/src/fig0_28.cpp index f0cbbdd..c729b03 100644 --- a/src/fig0_28.cpp +++ b/src/fig0_28.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -49,42 +49,40 @@ bool fig0_28_is_complete(int cluster_id) // FIG 0/28 FM Announcement switching // ETSI EN 300 401 8.1.11.2.2 -bool fig0_28(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_28(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t PI; uint8_t i = 1, Cluster_Id_Current_Ensemble, Region_Id_Current_Ensemble; bool New_flag, Rfa; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; uint8_t* f = fig0.f; - bool complete = false; - while (i < (fig0.figlen - 3)) { + 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); + r.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; PI = ((uint16_t)f[i+2] << 8) | (uint16_t)f[i+3]; - sprintf(desc, "Cluster Id Current Ensemble=0x%X", Cluster_Id_Current_Ensemble); + r.msgs.push_back(strprintf("Cluster Id Current Ensemble=0x%X", Cluster_Id_Current_Ensemble)); + if (Cluster_Id_Current_Ensemble == 0) { - strcat(desc, " invalid value"); - fprintf(stderr, "WARNING: FIG 0/%d Cluster Id Current Ensemble invalid value 0\n", fig0.ext()); + r.errors.push_back("Cluster Id Current Ensemble invalid value 0"); } - sprintf(tmpbuf, ", New flag=%d %s announcement", - New_flag, New_flag?"newly introduced":"repeated"); - strcat(desc, tmpbuf); + + r.msgs.emplace_back(1, strprintf("New flag=%d %s announcement", + New_flag, New_flag?"newly introduced":"repeated")); + if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", Region Id Current Ensemble=0x%X, PI=0x%X", Region_Id_Current_Ensemble, PI); - strcat(desc, tmpbuf); - printbuf(desc, disp+1, NULL, 0); + + r.msgs.emplace_back(1, strprintf("Region Id Current Ensemble=0x%X", Region_Id_Current_Ensemble)); + r.msgs.emplace_back(1, strprintf("PI=0x%X", PI)); i += 4; } - return complete; + return r; } diff --git a/src/fig0_3.cpp b/src/fig0_3.cpp index 349b9e9..14e395f 100644 --- a/src/fig0_3.cpp +++ b/src/fig0_3.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,21 +48,19 @@ bool fig0_3_is_complete(int components_id) // FIG 0/3 Service component in packet mode with or without Conditional Access // ETSI EN 300 401 6.3.2 -bool fig0_3(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_3(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t SCId, Packet_address, CAOrg; uint8_t i = 1, Rfa, DSCTy, SubChId, CAMode, SharedFlag; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; bool CAOrg_flag, DG_flag, Rfu; - bool complete = false; uint8_t* f = fig0.f; - while (i < (fig0.figlen - 4)) { + 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); + r.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; @@ -70,41 +68,38 @@ bool fig0_3(fig0_common_t& fig0, const display_settings_t &disp) DSCTy = f[i+2] & 0x3F; SubChId = (f[i+3] >> 2); Packet_address = ((uint16_t)(f[i+3] & 0x03) << 8) | ((uint16_t)f[i+4]); - sprintf(desc, - "SCId=0x%X, CAOrg flag=%d CAOrg field %s, DG flag=%d" - " data groups are %sused to transport the service component," - " DSCTy=%d %s, SubChId=0x%X, Packet address=0x%X", - SCId, CAOrg_flag, CAOrg_flag?"present":"absent", DG_flag, - DG_flag ? "not ": "", - DSCTy, get_dscty_type(DSCTy), SubChId, - Packet_address); + r.msgs.push_back(strprintf("SCId=0x%X", SCId)); + r.msgs.push_back(strprintf("CAOrg flag=%d CAOrg field %s", CAOrg_flag, CAOrg_flag?"present":"absent")); + r.msgs.push_back(strprintf("DG flag=%d", DG_flag)); + r.msgs.push_back(strprintf("data groups are %sused to transport the service component", DG_flag ? "not ": "")); + r.msgs.push_back(strprintf("DSCTy=%d %s", DSCTy, get_dscty_type(DSCTy))); + r.msgs.push_back(strprintf("SubChId=0x%X", SubChId)); + r.msgs.push_back(strprintf("Packet address=0x%X", Packet_address)); + if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } + if (Rfu != 0) { - sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfu=%d invalid value", Rfu)); } + i += 5; if (CAOrg_flag) { - if (i < (fig0.figlen - 1)) { + if (i < fig0.figlen - 1) { CAOrg = ((uint16_t)f[i] << 8) | ((uint16_t)f[i+1]); CAMode = (f[i] >> 5); SharedFlag = f[i+1]; - sprintf(tmpbuf, ", CAOrg=0x%X CAMode=%d \"%s\" SharedFlag=0x%X%s", - CAOrg, CAMode, get_ca_mode(CAMode), SharedFlag, (SharedFlag == 0) ? " invalid" : ""); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("CAOrg=0x%X CAMode=%d \"%s\" SharedFlag=0x%X%s", + CAOrg, CAMode, get_ca_mode(CAMode), SharedFlag, (SharedFlag == 0) ? " invalid" : "")); } else { - sprintf(tmpbuf, ", invalid figlen"); - strcat(desc, tmpbuf); + r.errors.push_back("Invalid figlen"); } i += 2; } - printbuf(desc, disp+1, NULL, 0); } - return complete; + return r; } diff --git a/src/fig0_31.cpp b/src/fig0_31.cpp index 6d0a68c..46e5809 100644 --- a/src/fig0_31.cpp +++ b/src/fig0_31.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,13 +48,12 @@ bool fig0_31_is_complete(uint64_t figtype_flags) // FIG 0/31 FIC re-direction // ETSI EN 300 401 8.1.12 -bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_31(fig0_common_t& fig0, const display_settings_t &disp) { 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]; + fig_result_t r; uint8_t* f = fig0.f; - bool complete = false; if (i < (fig0.figlen - 5)) { // Read FIC re-direction @@ -64,11 +63,11 @@ bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp) 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); + r.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, disp+1, NULL, 0); + r.msgs.push_back(strprintf("FIG type 0 flag field=0x%X", FIG_type0_flag_field)); + r.msgs.push_back(strprintf("FIG type 1 flag field=0x%X", FIG_type1_flag_field)); + r.msgs.push_back(strprintf("FIG type 2 flag field=0x%X", FIG_type2_flag_field)); for(j = 0; j < 32; j++) { // iterate over FIG type 0 re-direction @@ -76,23 +75,19 @@ bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp) if ((flag_field != 0) && ((j <= 5) || (j == 8) || (j == 10) || (j == 13) || (j == 14) || (j == 19) || (j == 26) || (j == 28))) { - sprintf(desc, "fig0.oe()=%d FIG 0/%d carried in AIC, invalid configuration, shall always be carried entirely in the FIC", - fig0.oe(), j); - printbuf(desc, disp+2, NULL, 0); - fprintf(stderr, "WARNING: FIG 0/%d FIG re-direction of fig0.oe()=%d FIG0/%d not allowed\n", fig0.ext(), fig0.oe(), j); + r.errors.push_back(strprintf("fig0.oe()=%d FIG 0/%d carried in AIC, invalid configuration, shall always be carried entirely in the FIC", + fig0.oe(), j)); } else if ((flag_field != 0) && ((j == 21) || (j == 24))) { - sprintf(desc, "fig0.oe()=%d FIG 0/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 0/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j)); } else if (flag_field != 0) { if (fig0.oe() == 0) { - sprintf(desc, "fig0.oe()=%d FIG 0/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 0/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j)); } else { // fig0.oe() == 1 - sprintf(desc, "fig0.oe()=%d FIG 0/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 0/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j)); } - printbuf(desc, disp+2, NULL, 0); } } @@ -101,12 +96,11 @@ bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp) flag_field = FIG_type1_flag_field & ((uint32_t)1 << j); if (flag_field != 0) { if (fig0.oe() == 0) { - sprintf(desc, "fig0.oe()=%d FIG 1/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 1/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j)); } else { // fig0.oe() == 1 - sprintf(desc, "fig0.oe()=%d FIG 1/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 1/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j)); } - printbuf(desc, disp+2, NULL, 0); } } @@ -115,19 +109,18 @@ bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp) flag_field = FIG_type2_flag_field & ((uint32_t)1 << j); if (flag_field != 0) { if (fig0.oe() == 0) { - sprintf(desc, "fig0.oe()=%d FIG 2/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 2/%d carried in AIC, same shall be carried in FIC", fig0.oe(), j)); } else { // fig0.oe() == 1 - sprintf(desc, "fig0.oe()=%d FIG 2/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); + r.msgs.emplace_back(1, strprintf("fig0.oe()=%d FIG 2/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j)); } - printbuf(desc, disp+2, NULL, 0); } } } if (fig0.figlen != 7) { - fprintf(stderr, "WARNING: FIG 0/%d invalid length %d, expecting 7\n", fig0.ext(), fig0.figlen); + r.errors.push_back(strprintf("invalid length %d, expecting 7", fig0.figlen)); } - return complete; + return r; } diff --git a/src/fig0_5.cpp b/src/fig0_5.cpp index d70cca1..485c479 100644 --- a/src/fig0_5.cpp +++ b/src/fig0_5.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -48,67 +48,64 @@ bool fig0_5_is_complete(int components_id) // FIG 0/5 Service component language // ETSI EN 300 401 8.1.2 -bool fig0_5(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_5(fig0_common_t& fig0, const display_settings_t &disp) { uint16_t SCId; uint8_t i = 1, SubChId, FIDCId, Language, Rfa; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; bool LS_flag, MSC_FIC_flag; - bool complete = false; uint8_t* f = fig0.f; - while (i < (fig0.figlen - 1)) { + while (i < fig0.figlen - 1) { // iterate over service component language LS_flag = f[i] >> 7; if (LS_flag == 0) { // Short form (L/S = 0) MSC_FIC_flag = (f[i] >> 6) & 0x01; Language = f[i+1]; + r.msgs.emplace_back("Short form"); + r.msgs.push_back(strprintf("MSC/FIC flag=%d MSC", MSC_FIC_flag)); + if (MSC_FIC_flag == 0) { // 0: MSC in Stream mode and SubChId identifies the sub-channel SubChId = f[i] & 0x3F; - sprintf(desc, "L/S flag=%d short form, MSC/FIC flag=%d MSC, SubChId=0x%X, Language=0x%X %s", - LS_flag, MSC_FIC_flag, SubChId, Language, - get_language_name(Language)); + r.msgs.push_back(strprintf("SubChId=0x%X", SubChId)); } else { // 1: FIC and FIDCId identifies the component FIDCId = f[i] & 0x3F; - sprintf(desc, "L/S flag=%d short form, MSC/FIC flag=%d FIC, FIDCId=0x%X, Language=0x%X %s", - LS_flag, MSC_FIC_flag, FIDCId, Language, - get_language_name(Language)); + r.msgs.push_back(strprintf("FIDCId=0x%X", FIDCId)); } + r.msgs.push_back(strprintf("Language=0x%X %s", + Language, get_language_name(Language))); int key = (MSC_FIC_flag << 7) | (f[i] % 0x3F); - complete |= fig0_5_is_complete(key); - printbuf(desc, disp+1, NULL, 0); + r.complete |= fig0_5_is_complete(key); i += 2; } else { // Long form (L/S = 1) if (i < (fig0.figlen - 2)) { + r.msgs.emplace_back("Long form"); 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); + r.complete |= fig0_5_is_complete(key); Language = f[i+2]; - sprintf(desc, "L/S flag=%d long form", LS_flag); if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", SCId=0x%X, Language=0x%X %s", - SCId, Language, - get_language_name(Language)); - strcat(desc, tmpbuf); - printbuf(desc, disp+1, NULL, 0); + + r.msgs.push_back(strprintf("SCId=0x%X", SCId)); + r.msgs.push_back(strprintf("Language=0x%X %s", + Language, get_language_name(Language))); } i += 3; } } - return complete; + return r; } diff --git a/src/fig0_6.cpp b/src/fig0_6.cpp index 921e36d..a906b17 100644 --- a/src/fig0_6.cpp +++ b/src/fig0_6.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -56,15 +56,13 @@ void fig0_6_cleardb() // FIG 0/6 Service linking information // ETSI EN 300 401 8.1.15 -bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_6(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t j; uint16_t LSN, key; uint8_t i = 1, Number_of_Ids, IdLQ; - char signal_link[256]; - char desc[256]; + fig_result_t r; bool Id_list_flag, LA, SH, ILS, Shd; - bool complete = false; uint8_t* f = fig0.f; @@ -76,30 +74,30 @@ bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp) 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, ""); + r.complete |= fig0_6_is_complete(key); + + r.msgs.push_back(strprintf("Id list flag=%d", Id_list_flag)); + r.msgs.push_back(strprintf("LA=%d %s", LA, LA ? "active" : "inactive")); + r.msgs.push_back(strprintf("S/H=%d %s", SH, SH ? "Hard" : "Soft")); + r.msgs.push_back(strprintf("ILS=%d %s", ILS, ILS ? "international" : "national")); + r.msgs.push_back(strprintf("LSN=%d", LSN)); + r.msgs.push_back(strprintf("database key=0x%04x", key)); + // check activation / deactivation if ((fig0_6_key_la.count(key) > 0) && (fig0_6_key_la[key] != LA)) { if (LA == 0) { - strcat(signal_link, " deactivated"); + r.msgs.emplace_back("deactivated"); } else { - strcat(signal_link, " activated"); + r.msgs.emplace_back("activated"); } } fig0_6_key_la[key] = LA; i += 2; if (Id_list_flag == 0) { if (fig0.cn() == 0) { // Id_list_flag=0 && fig0.cn()=0: CEI Change Event Indication - strcat(signal_link, " CEI"); + r.msgs.emplace_back("CEI"); } - sprintf(desc, "Id list flag=%d, LA=%d %s, S/H=%d %s, ILS=%d %s, LSN=%d, database key=0x%04x%s", - Id_list_flag, - LA, LA ? "active" : "inactive", - SH, SH ? "Hard" : "Soft", - ILS, ILS ? "international" : "national", - LSN, key, signal_link); - printbuf(desc, disp+1, NULL, 0); } else { // Id_list_flag == 1 if (i < fig0.figlen) { @@ -107,43 +105,36 @@ bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp) if (fig0.pd() == 0) { IdLQ = (f[i] >> 5) & 0x03; Shd = (f[i] >> 4) & 0x01; - sprintf(desc, "Id list flag=%d, LA=%d %s, S/H=%d %s, ILS=%d %s, LSN=%d, " - "database key=0x%04x, IdLQ=%d, Shd=%d %s, Number of Ids=%d%s", - Id_list_flag, - LA, (LA)?"active":"inactive", - SH, (SH)?"Hard":"Soft", - ILS, (ILS)?"international":"national", - LSN, key, IdLQ, - Shd, (Shd)?"b11-8 in 4-F are different services":"single service", - Number_of_Ids, signal_link); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("IdLQ=%d", IdLQ)); + r.msgs.push_back(strprintf("Shd=%d %s", Shd, (Shd)?"b11-8 in 4-F are different services":"single service")); + r.msgs.push_back(strprintf("Number of Ids=%d%s", Number_of_Ids)); + if (ILS == 0) { // read Id list for(j = 0; ((j < Number_of_Ids) && ((i+2+(j*2)) < fig0.figlen)); j++) { // ETSI EN 300 401 8.1.15. Some changes were introducted in spec V2 if (((j == 0) && (fig0.oe() == 0) && (fig0.cn() == 0)) || (IdLQ == 0)) { - sprintf(desc, "DAB SId 0x%X", - ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); + r.msgs.emplace_back(1, strprintf("DAB SId 0x%X", + ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)]))); } else if (IdLQ == 1) { - sprintf(desc, "RDS PI 0x%X", - ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); + r.msgs.emplace_back(1, strprintf("RDS PI 0x%X", + ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)]))); } else if (IdLQ == 2) { - sprintf(desc, "(AM-FM legacy) 0x%X", - ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); + r.msgs.emplace_back(1, strprintf("(AM-FM legacy) 0x%X", + ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)]))); } else { // IdLQ == 3 - sprintf(desc, "DRM-AMSS service 0x%X", - ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); + r.msgs.emplace_back(1, strprintf("DRM-AMSS service 0x%X", + ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)]))); } - printbuf(desc, disp+2, NULL, 0); } + // check deadlink if ((Number_of_Ids == 0) && (IdLQ == 1)) { - sprintf(desc, "deadlink"); - printbuf(desc, disp+2, NULL, 0); + r.errors.push_back("deadlink"); } i += (Number_of_Ids * 2) + 1; } @@ -152,37 +143,36 @@ bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp) for(j = 0; ((j < Number_of_Ids) && ((i+3+(j*3)) < fig0.figlen)); j++) { if (((j == 0) && (fig0.oe() == 0) && (fig0.cn() == 0)) || (IdLQ == 0)) { - sprintf(desc, "DAB SId ecc 0x%02X Id 0x%04X", f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)])); + r.msgs.emplace_back(1, strprintf("DAB SId ecc 0x%02X Id 0x%04X", + f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)]))); } else if (IdLQ == 1) { - sprintf(desc, "RDS PI ecc 0x%02X Id 0x%04X", f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)])); + r.msgs.emplace_back(1, strprintf("RDS PI ecc 0x%02X Id 0x%04X", + f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)]))); } else if (IdLQ == 2) { - sprintf(desc, "(AM-FM legacy) ecc 0x%02X Id 0x%04X", f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)])); + r.msgs.emplace_back(1, strprintf("(AM-FM legacy) ecc 0x%02X Id 0x%04X", + f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)]))); } else { // IdLQ == 3 - sprintf(desc, "DRM/AMSS service ecc 0x%02X Id 0x%04X", f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)])); + r.msgs.emplace_back(1, strprintf("DRM/AMSS service ecc 0x%02X Id 0x%04X", + f[i+1+(j*3)], ((f[i+2+(j*3)] << 8) | f[i+3+(j*3)]))); } - printbuf(desc, disp+2, NULL, 0); } // check deadlink if ((Number_of_Ids == 0) && (IdLQ == 1)) { - sprintf(desc, "deadlink"); - printbuf(desc, disp+2, NULL, 0); + r.errors.push_back("deadlink"); } i += (Number_of_Ids * 3) + 1; } } else { // fig0.pd() == 1 - sprintf(desc, "Id list flag=%d, LA=%d %s, S/H=%d %s, ILS=%d %s, LSN=%d, database key=0x%04x, Number of Ids=%d%s", - Id_list_flag, LA, (LA)?"active":"inactive", SH, (SH)?"Hard":"Soft", ILS, (ILS)?"international":"national", LSN, key, Number_of_Ids, signal_link); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("Number of Ids=%d%s", Number_of_Ids)); if (Number_of_Ids > 0) { // read Id list for(j = 0; ((j < Number_of_Ids) && ((i+4+(j*4)) < fig0.figlen)); j++) { - sprintf(desc, "SId 0x%X", - ((f[i+1+(j*4)] << 24) | (f[i+2+(j*4)] << 16) | (f[i+3+(j*4)] << 8) | f[i+4+(j*4)])); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("SId 0x%X", + ((f[i+1+(j*4)] << 24) | (f[i+2+(j*4)] << 16) | (f[i+3+(j*4)] << 8) | f[i+4+(j*4)]))); } } i += (Number_of_Ids * 4) + 1; @@ -191,6 +181,6 @@ bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp) } } - return complete; + return r; } diff --git a/src/fig0_8.cpp b/src/fig0_8.cpp index eb157de..c283a52 100644 --- a/src/fig0_8.cpp +++ b/src/fig0_8.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -57,16 +57,14 @@ bool fig0_8_is_complete(SId_t SId, SCIdS_t SCIdS) // FIG 0/8 Service component global definition // ETSI EN 300 401 6.3.5 -bool fig0_8(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_8(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t SId; uint16_t SCId; uint8_t i = 1, Rfa, SCIdS, SubChId, FIDCId; - char tmpbuf[256]; - char desc[256]; + fig_result_t r; 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 @@ -84,19 +82,19 @@ bool fig0_8(fig0_common_t& fig0, const display_settings_t &disp) 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"); + r.complete |= fig0_8_is_complete(SId, SCIdS); + r.msgs.push_back(strprintf("SId=0x%X", SId)); + r.msgs.push_back(strprintf("Ext flag=%d 8-bit Rfa %s", + Ext_flag, (Ext_flag)?"present":"absent")); + if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", SCIdS=0x%X", SCIdS); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("SCIdS=0x%X", SCIdS)); i++; if (i < fig0.figlen) { LS_flag = f[i] >> 7; - sprintf(tmpbuf, ", L/S flag=%d %s", LS_flag, (LS_flag)?"Long form":"Short form"); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("L/S flag=%d %s", LS_flag, (LS_flag)?"Long form":"Short form")); if (LS_flag == 0) { // Short form if (i < (fig0.figlen - Ext_flag)) { @@ -104,21 +102,18 @@ bool fig0_8(fig0_common_t& fig0, const display_settings_t &disp) if (MSC_FIC_flag == 0) { // MSC in stream mode and SubChId identifies the sub-channel SubChId = f[i] & 0x3F; - sprintf(tmpbuf, ", MSC/FIC flag=%d MSC, SubChId=0x%X", MSC_FIC_flag, SubChId); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("MSC/FIC flag=%d MSC, SubChId=0x%X", MSC_FIC_flag, SubChId)); } else { // FIC and FIDCId identifies the component FIDCId = f[i] & 0x3F; - sprintf(tmpbuf, ", MSC/FIC flag=%d FIC, FIDCId=0x%X", MSC_FIC_flag, FIDCId); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("MSC/FIC flag=%d FIC, FIDCId=0x%X", MSC_FIC_flag, FIDCId)); } if (Ext_flag == 1) { // Rfa field present Rfa = f[i+1]; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=0x%X invalid value", Rfa)); } } } @@ -130,18 +125,15 @@ bool fig0_8(fig0_common_t& fig0, const display_settings_t &disp) Rfa = (f[i] >> 4) & 0x07; SCId = (((uint16_t)f[i] & 0x0F) << 8) | (uint16_t)f[i+1]; if (Rfa != 0) { - sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); - strcat(desc, tmpbuf); + r.errors.push_back(strprintf("Rfa=%d invalid value", Rfa)); } - sprintf(tmpbuf, ", SCId=0x%X", SCId); - strcat(desc, tmpbuf); + r.msgs.push_back(strprintf("SCId=0x%X", SCId)); } i += 2; } } - printbuf(desc, disp+1, NULL, 0); } - return complete; + return r; } diff --git a/src/fig0_9.cpp b/src/fig0_9.cpp index 6e642ee..7c41bdf 100644 --- a/src/fig0_9.cpp +++ b/src/fig0_9.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -29,21 +29,17 @@ #include #include -// fig 0/9 global variables -uint8_t Ensemble_ECC=0; -int8_t Ensemble_LTO=0; -bool LTO_uniq; - // FIG 0/9 Country, LTO and International table // ETSI EN 300 401 8.1.3.2 -bool fig0_9(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_9(fig0_common_t& fig0, const display_settings_t &disp) { uint32_t SId; + uint8_t Ensemble_ECC=0; uint8_t i = 1, j, key, Number_of_services, ECC; int8_t LTO; - char tmpbuf[256]; - char desc[256]; + bool LTO_uniq; + fig_result_t r; bool Ext_flag; uint8_t* f = fig0.f; @@ -52,26 +48,30 @@ bool fig0_9(fig0_common_t& fig0, const display_settings_t &disp) key = ((uint8_t)fig0.oe() << 1) | (uint8_t)fig0.pd(); Ext_flag = f[i] >> 7; LTO_uniq = (f[i]>> 6) & 0x01; - Ensemble_LTO = f[i] & 0x3F; + int8_t Ensemble_LTO = f[i] & 0x3F; if (Ensemble_LTO & 0x20) { // negative Ensemble LTO Ensemble_LTO |= 0xC0; } - sprintf(desc, "Ext flag=%d extended field %s, LTO uniq=%d %s, Ensemble LTO=0x%X %s%d:%02d", - Ext_flag, Ext_flag?"present":"absent", LTO_uniq, - LTO_uniq?"several time zones":"one time zone (time specified by Ensemble LTO)", - (Ensemble_LTO & 0x3F), (Ensemble_LTO >= 0)?"":"-" , abs(Ensemble_LTO) >> 1, (Ensemble_LTO & 0x01) * 30); + r.msgs.push_back(strprintf("Ext flag=%d extended field %s", + Ext_flag, Ext_flag?"present":"absent")); + r.msgs.push_back(strprintf("LTO uniq=%d %s", + LTO_uniq, + LTO_uniq?"several time zones":"one time zone (time specified by Ensemble LTO)")); + r.msgs.push_back(strprintf("Ensemble LTO=0x%X %s%d:%02d", + (Ensemble_LTO & 0x3F), (Ensemble_LTO >= 0)?"":"-" , abs(Ensemble_LTO) >> 1, (Ensemble_LTO & 0x01) * 30)); + if (abs(Ensemble_LTO) > 24) { - sprintf(tmpbuf, " out of range -12 hours to +12 hours"); - strcat(desc, tmpbuf); + r.errors.push_back("LTO out of range -12 hours to +12 hours"); } + Ensemble_ECC = f[i+1]; uint8_t International_Table_Id = f[i+2]; set_international_table(International_Table_Id); - sprintf(tmpbuf, ", Ensemble ECC=0x%X, International Table Id=0x%X, database key=0x%x", - Ensemble_ECC, International_Table_Id, key); - strcat(desc, tmpbuf); - printbuf(desc, disp+1, NULL, 0); + r.msgs.push_back(strprintf("Ensemble ECC=0x%X", Ensemble_ECC)); + r.msgs.push_back(strprintf("International Table Id=0x%X", International_Table_Id)); + r.msgs.push_back(strprintf("database key=0x%x", key)); + i += 3; if (Ext_flag == 1) { // extended field present @@ -83,44 +83,40 @@ bool fig0_9(fig0_common_t& fig0, const display_settings_t &disp) // negative LTO LTO |= 0xC0; } - sprintf(desc, "Number of services=%d, LTO=0x%X %s%d:%02d", - Number_of_services, (LTO & 0x3F), (LTO >= 0)?"":"-" , abs(LTO) >> 1, (LTO & 0x01) * 30); + r.msgs.push_back(strprintf("Number of services=%d", Number_of_services)); + r.msgs.push_back(strprintf("LTO=0x%X %s%d:%02d", + (LTO & 0x3F), (LTO >= 0)?"":"-" , abs(LTO) >> 1, (LTO & 0x01) * 30)); if (abs(LTO) > 24) { - sprintf(tmpbuf, " out of range -12 hours to +12 hours"); - strcat(desc, tmpbuf); + r.errors.push_back("LTO in extended field out of range -12 hours to +12 hours"); } + // CEI Change Event Indication if ((Number_of_services == 0) && (LTO == 0) /* && (Ext_flag == 1) */) { - sprintf(tmpbuf, ", CEI"); - strcat(desc, tmpbuf); + r.msgs.emplace_back("CEI"); } i++; + if (fig0.pd() == 0) { // Programme services, 16 bit SId if (i < fig0.figlen) { ECC = f[i]; - sprintf(tmpbuf, ", ECC=0x%X", ECC); - strcat(desc, tmpbuf); - printbuf(desc, disp+2, NULL, 0); + r.msgs.emplace_back(1, strprintf("ECC=0x%X", ECC)); i++; for(j = i; ((j < (i + (Number_of_services * 2))) && (j < fig0.figlen)); j += 2) { // iterate over SId SId = ((uint32_t)f[j] << 8) | (uint32_t)f[j+1]; - sprintf(desc, "SId 0x%X", SId); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, strprintf("SId 0x%X", SId)); } i += (Number_of_services * 2); } } else { // Data services, 32 bit SId - printbuf(desc, disp+2, NULL, 0); for(j = i; ((j < (i + (Number_of_services * 4))) && (j < fig0.figlen)); j += 4) { // iterate over SId SId = ((uint32_t)f[j] << 24) | ((uint32_t)f[j+1] << 16) | ((uint32_t)f[j+2] << 8) | (uint32_t)f[j+3]; - sprintf(desc, "SId 0x%X", SId); - printbuf(desc, disp+3, NULL, 0); + r.msgs.emplace_back(2, strprintf("SId 0x%X", SId)); } i += (Number_of_services * 4); } @@ -128,6 +124,7 @@ bool fig0_9(fig0_common_t& fig0, const display_settings_t &disp) } } - return true; + r.complete = true; + return r; } diff --git a/src/figs.cpp b/src/figs.cpp index b418cc2..cd557bf 100644 --- a/src/figs.cpp +++ b/src/figs.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -74,7 +74,7 @@ void figs_cleardb() } -bool fig0_select(fig0_common_t& fig0, const display_settings_t &disp) +fig_result_t fig0_select(fig0_common_t& fig0, const display_settings_t &disp) { switch (fig0.ext()) { case 0: return fig0_0(fig0, disp); break; @@ -101,14 +101,11 @@ bool fig0_select(fig0_common_t& fig0, const display_settings_t &disp) case 27: return fig0_27(fig0, disp); break; case 28: return fig0_28(fig0, disp); break; case 31: return fig0_31(fig0, disp); break; - default: { - char desc[256]; - sprintf(desc, "FIG 0/%d: unknown", fig0.ext()); - printbuf(desc, disp, fig0.f+1, fig0.figlen-1); - break; - } + default: break; } - return false; + fig_result_t r; + r.errors.push_back("FIG 0/" + std::to_string(fig0.ext()) + " unknown"); + return r; } diff --git a/src/figs.hpp b/src/figs.hpp index f8f8d97..5986f80 100644 --- a/src/figs.hpp +++ b/src/figs.hpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -27,10 +27,28 @@ #pragma once #include +#include +#include +#include #include "utils.hpp" #include "tables.hpp" #include "watermarkdecoder.hpp" +struct fig_result_t { + struct msg_info_t { + msg_info_t(int level_, const std::string& msg_) : + level(level_), msg(msg_) {} + msg_info_t(const std::string& msg_) : + level(0), msg(msg_) {} + int level = 0; + std::string msg; + }; + + std::vector msgs; + std::vector errors; + bool complete = false; +}; + void figs_cleardb(void); struct fig0_common_t { @@ -80,34 +98,34 @@ void set_international_table(size_t intl_table); void set_mode_identity(uint8_t mid); uint8_t get_mode_identity(); -bool fig0_select(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_select(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_0(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_1(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_2(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_3(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_5(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_0(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_1(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_2(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_3(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_5(fig0_common_t& fig0, const display_settings_t &disp); void fig0_6_cleardb(); -bool fig0_6(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_8(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_9(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_10(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_11(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_13(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_14(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_16(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_17(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_18(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_19(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_21(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_6(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_8(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_9(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_10(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_11(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_13(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_14(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_16(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_17(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_18(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_19(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_21(fig0_common_t& fig0, const display_settings_t &disp); void fig0_22_cleardb(); -bool fig0_22(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_24(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_25(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_26(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_27(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_28(fig0_common_t& fig0, const display_settings_t &disp); -bool fig0_31(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_22(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_24(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_25(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_26(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_27(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_28(fig0_common_t& fig0, const display_settings_t &disp); +fig_result_t fig0_31(fig0_common_t& fig0, const display_settings_t &disp); bool fig1_select(fig1_common_t& fig1, const display_settings_t &disp); diff --git a/src/utils.cpp b/src/utils.cpp index 7ea00bb..75aa880 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -29,6 +29,7 @@ #include "utils.hpp" #include +#include using namespace std; @@ -49,6 +50,29 @@ display_settings_t display_settings_t::operator+(int indent_offset) const return display_settings_t(print, indent+indent_offset); } +std::string strprintf(const char* fmt, ...) +{ + int size = 512; + std::string str; + va_list ap; + while (1) { + str.resize(size); + va_start(ap, fmt); + int n = vsnprintf((char *)str.c_str(), size, fmt, ap); + va_end(ap); + if (n > -1 && n < size) { + str.resize(n); + break; + } + if (n > -1) + size = n + 1; + else + size *= 2; + } + + return str; +} + void printbuf(std::string header, int indent, uint8_t* buffer, @@ -143,34 +167,33 @@ int sprintfMJD(char *dst, int mjd) { return strftime(dst, 256, "%a %b %d %Y", &timeDate); } -char *strcatPNum(char *dest_str, uint16_t Programme_Number) { +std::string pnum_to_str(uint16_t Programme_Number) +{ uint8_t day, hour, minute; - char tempbuf[256]; minute = (uint8_t)(Programme_Number & 0x003F); hour = (uint8_t)((Programme_Number >> 6) & 0x001F); day = (uint8_t)((Programme_Number >> 11) & 0x001F); if (day != 0) { - sprintf(tempbuf, "day of month=%d time=%02d:%02d", day, hour, minute); + return strprintf("day of month=%d time=%02d:%02d", day, hour, minute); } else { // day == 0 // Special codes are allowed when the date part of the PNum field // signals date = "0". In this case, the hours and minutes part of // the field shall contain a special code, as follows if ((hour == 0) && (minute == 0)) { - sprintf(tempbuf, "Status code: no meaningful PNum is currently provided"); + return "Status code: no meaningful PNum is currently provided"; } else if ((hour == 0) && (minute == 1)) { - sprintf(tempbuf, "Blank code: the current programme is not worth recording"); + return "Blank code: the current programme is not worth recording"; } else if ((hour == 0) && (minute == 2)) { - sprintf(tempbuf, "Interrupt code: the interrupt is unplanned (for example a traffic announcement)"); + return "Interrupt code: the interrupt is unplanned " + "(for example a traffic announcement)"; } else { - sprintf(tempbuf, "invalid value"); + return "invalid value"; } } - return strcat(dest_str, tempbuf); } - diff --git a/src/utils.hpp b/src/utils.hpp index 557453d..8c72e8b 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -1,6 +1,6 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://www.csp.it/) - Copyright (C) 2016 Matthias P. Braendli (http://www.opendigitalradio.org) + Copyright (C) 2017 Matthias P. Braendli (http://www.opendigitalradio.org) Copyright (C) 2015 Data Path This program is free software: you can redistribute it and/or modify @@ -46,6 +46,7 @@ struct display_settings_t { int indent; }; +std::string strprintf(const char* fmt, ...); void printbuf(std::string header, const display_settings_t &disp, @@ -69,9 +70,9 @@ void printinfo(const std::string &header, // sprintfMJD: convert MJD (Modified Julian Date) into date string int sprintfMJD(char *dst, int mjd); -// strcatPNum decode Programme_Number into string and append it to dest_str +// Convert Programme Number to string // Programme_Number: this 16-bit field shall define the date and time at which // a programme begins or will be continued. This field is coded in the same way // as the RDS "Programme Item Number (PIN)" feature (EN 62106). -char *strcatPNum(char *dest_str, uint16_t Programme_Number); +std::string pnum_to_str(uint16_t Programme_Number); -- cgit v1.2.3