From bd8fa6855a7fe14ea5e888348ee9ec9bba61dced Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 1 May 2017 08:11:26 +0200 Subject: Rework FIG0/21 parser --- src/fig0_21.cpp | 522 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 288 insertions(+), 234 deletions(-) (limited to 'src/fig0_21.cpp') diff --git a/src/fig0_21.cpp b/src/fig0_21.cpp index 46a196f..c76e292 100644 --- a/src/fig0_21.cpp +++ b/src/fig0_21.cpp @@ -51,269 +51,323 @@ bool fig0_21_is_complete(int region_id) // ETSI EN 300 401 8.1.8 fig_result_t fig0_21(fig0_common_t& fig0, const display_settings_t &disp) { - float freq; - uint32_t ifreq; - uint64_t key; - 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; - fig_result_t r; - bool Continuity_flag; uint8_t* f = fig0.f; + fig_result_t r; - while (i < (fig0.figlen - 1)) { - // iterate over frequency information - // decode RegionId, Length of FI list - RegionId = (f[i] << 3) | (f[i+1] >> 5); + int i = 1; + while (i < fig0.figlen) { + const uint16_t RegionId = (f[i] << 3) | (f[i+1] >> 5); r.complete |= fig0_21_is_complete(RegionId); - Length_FI_list = (f[i+1] & 0x1F); + const uint8_t Length_FI_list = f[i+1] & 0x1F; 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; - while ((j + 2) < (i + Length_FI_list)) { - // iterate over FI list x - // decode Id field, R&M, Continuity flag, Length of Freq list - Id_field = (f[j] << 8) | f[j+1]; - RandM = f[j+2] >> 4; - Continuity_flag = (f[j+2] >> 3) & 0x01; - Length_Freq_list = f[j+2] & 0x07; - std::string idfield; - switch (RandM) { - case 0x0: - case 0x1: - idfield += "EId"; - break; - case 0x6: - idfield += "DRM Service Id"; - break; - case 0x8: - idfield += "RDS PI"; - break; - case 0x9: - case 0xa: - case 0xc: - idfield += "Dummy"; - break; - case 0xe: - idfield += "AMSS Service Id"; - break; - default: - idfield += "invalid"; - r.errors.emplace_back("R&M invalid"); - break; - } - r.msgs.emplace_back(1, strprintf("ID field=0x%X", Id_field) + idfield); - std::string rm_str; - switch (RandM) { - case 0x0: - rm_str += " DAB ensemble, no local windows"; - break; - case 0x6: - rm_str += " DRM"; - break; - case 0x8: - rm_str += " FM with RDS"; - break; - case 0x9: - rm_str += " FM without RDS"; - break; - case 0xa: - rm_str += " AM (MW in 9 kHz steps & LW)"; - break; - case 0xc: - rm_str += " AM (MW in 5 kHz steps & SW)"; - break; - case 0xe: - rm_str += " AMSS"; - break; - default: - rm_str += " Rfu"; - r.errors.emplace_back("R&M is Rfu"); - break; - } - 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: - continuity_str += "=continuous output not expected"; - break; - case 0x6: - continuity_str += "=no compensating time delay on DRM audio signal"; - break; - case 0x8: - case 0x9: - continuity_str += "=no compensating time delay on FM audio signal"; - break; - case 0xa: - case 0xc: - case 0xe: - continuity_str += "=no compensating time delay on AM audio signal"; - break; - default: - continuity_str += "=Rfu"; - break; - } - } - else { // Continuity_flag == 1 - switch (RandM) { - case 0x0: - case 0x1: - continuity_str += "=continuous output possible"; - break; - case 0x6: - continuity_str += "=compensating time delay on DRM audio signal"; - break; - case 0x8: - case 0x9: - continuity_str += "=compensating time delay on FM audio signal"; - break; - case 0xa: - case 0xc: - case 0xe: - continuity_str += "=compensating time delay on AM audio signal"; - break; - default: - continuity_str += "=Rfu"; - r.errors.emplace_back("continuity is Rfu"); - break; - } + for (int FI_ix = 0; FI_ix < Length_FI_list; FI_ix++) { + if (i + 2 >= fig0.figlen) { + r.errors.push_back("FIG0/21 too small!"); + break; + } + + const uint16_t Id_field = (f[i] << 8) | f[i+1]; + const uint8_t RandM = f[i+2] >> 4; + const bool Continuity_flag = (f[i+2] >> 3) & 0x01; + const uint8_t Length_Freq_list = f[i+2] & 0x07; // in bytes + i += 2; + + std::string idfield; + switch (RandM) { + case 0x0: + case 0x1: idfield = "EId"; break; + case 0x6: idfield = "DRM Service Id"; break; + case 0x8: idfield = "RDS PI"; break; + case 0x9: + case 0xa: + case 0xc: idfield = "Dummy"; break; + case 0xe: idfield = "AMSS Service Id"; break; + default: + idfield = "invalid"; + r.errors.emplace_back("R&M invalid"); + break; + } + r.msgs.emplace_back(1, + strprintf("ID field=0x%X ", Id_field) + idfield); + + std::string rm_str; + switch (RandM) { + case 0x0: rm_str = "DAB ensemble, no local windows"; break; + case 0x6: rm_str = "DRM"; break; + case 0x8: rm_str = "FM with RDS"; break; + case 0x9: rm_str = "FM without RDS"; break; + case 0xa: rm_str = "AM (MW in 9 kHz steps & LW)"; break; + case 0xc: rm_str = "AM (MW in 5 kHz steps & SW)"; break; + case 0xe: rm_str = "AMSS"; break; + default: + rm_str = "Rfu"; + r.errors.emplace_back("R&M is Rfu"); + break; + } + 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: + continuity_str = "=continuous output not expected"; + break; + case 0x6: + continuity_str = "=no compensating time delay on DRM audio signal"; + break; + case 0x8: + case 0x9: + continuity_str = "=no compensating time delay on FM audio signal"; + break; + case 0xa: + case 0xc: + case 0xe: + continuity_str = "=no compensating time delay on AM audio signal"; + break; + default: + continuity_str = "=Rfu"; + break; } } - else { // fig0.oe() == 1 - continuity_str = "=reserved for future addition"; - r.errors.emplace_back("Rfu"); + else { // Continuity_flag == 1 + switch (RandM) { + case 0x0: + case 0x1: + continuity_str = "=continuous output possible"; + break; + case 0x6: + continuity_str = "=compensating time delay on DRM audio signal"; + break; + case 0x8: + case 0x9: + continuity_str = "=compensating time delay on FM audio signal"; + break; + case 0xa: + case 0xc: + case 0xe: + continuity_str = "=compensating time delay on AM audio signal"; + break; + default: + continuity_str = "=Rfu"; + r.errors.emplace_back("continuity is Rfu"); + break; + } } + } + else { // fig0.oe() == 1 + continuity_str = "=reserved for future addition"; + r.errors.emplace_back("Rfu"); + } - r.msgs.emplace_back(1, strprintf("Continuity flag=%d ", Continuity_flag) + continuity_str); + 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; - r.msgs.emplace_back(1, strprintf("database key=0x%09" PRId64, key)); - // CEI Change Event Indication - if (Length_Freq_list == 0) { - r.msgs.emplace_back(1, "CEI"); - } - j += 3; // add header + const uint64_t key = + ((uint64_t)fig0.oe() << 32) | ((uint64_t)fig0.pd() << 31) | + ((uint64_t)RegionId << 20) | ((uint64_t)Id_field << 4) | + (uint64_t)RandM; + r.msgs.emplace_back(1, + strprintf("database key=0x%09" PRId64, key)); + + // CEI Change Event Indication + if (Length_Freq_list == 0) { + r.msgs.emplace_back(1, "CEI"); + } + + // Iterate over the frequency infos + switch (RandM) { + case 0x0: + case 0x1: + for (int freq_ix = 0; + freq_ix < Length_Freq_list; + freq_ix++) { + if (i + 3 >= fig0.figlen) { + r.errors.push_back(strprintf( + "FIG 0/21 too small for" + " FI %d, freq %d", + FI_ix, freq_ix)); + break; + } - k = j; - switch (RandM) { - case 0x0: - case 0x1: - while((k + 2) < (j + Length_Freq_list)) { - // iteration over Freq list - ifreq = (((uint32_t)(f[k] & 0x07) << 16) | ((uint32_t)f[k+1] << 8) | (uint32_t)f[k+2]) * 16; - if (ifreq != 0) { - Control_field = (f[k] >> 3); - Control_field_trans_mode = (Control_field >> 1) & 0x07; - if ((Control_field & 0x10) == 0) { - r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); - if ((Control_field & 0x01) == 0) { - r.msgs.emplace_back(2, "geographically adjacent area"); - } - else { // (Control_field & 0x01) == 1 - r.msgs.emplace_back(2, "no geographically adjacent area"); - } - if (Control_field_trans_mode == 0) { - r.msgs.emplace_back(2, "no transmission mode signalled"); - } - else if (Control_field_trans_mode <= 4) { - r.msgs.emplace_back(2, strprintf("transmission mode %d", Control_field_trans_mode)); - } - else { // Control_field_trans_mode > 4 - r.msgs.emplace_back(2, strprintf("invalid transmission mode 0x%x", Control_field_trans_mode)); - } - } - else { // (Control_field & 0x10) == 0x10 - r.msgs.emplace_back(2, strprintf("%d KHz, invalid Control field b23 0x%x", ifreq, Control_field)); - } + // Each entry is 24 bits (5 control + 19 freq) + const uint8_t Control_field = (f[i] >> 3); + const uint32_t freq = 16 * + (((uint32_t)(f[i] & 0x07) << 16) | + ((uint32_t)f[i+1] << 8) | + (uint32_t)f[i+2]); + i += 3; + if (freq == 0) { + r.errors.emplace_back(strprintf( + "Frequency not to be used (0) in" + " FI %d, freq %d", + FI_ix, freq_ix)); + continue; + } + const uint8_t Control_field_trans_mode = (Control_field >> 1) & 0x07; + if ((Control_field & 0x10) == 0) { + r.msgs.emplace_back(2, + strprintf("%d KHz", freq)); + if ((Control_field & 0x01) == 0) { + r.msgs.emplace_back(2, + "geographically adjacent area"); } - else { - r.errors.emplace_back("Frequency not to be used (0)"); + else { // (Control_field & 0x01) == 1 + r.msgs.emplace_back(2, + "no geographically adjacent area"); } - k += 3; - } - break; - case 0x8: - case 0x9: - case 0xa: - while(k < (j + Length_Freq_list)) { - // iteration over Freq list - if (f[k] != 0) { // freq != 0 - if (RandM == 0xa) { - if (f[k] < 16) { - ifreq = (144 + ((uint32_t)f[k] * 9)); - } - else { // f[k] >= 16 - ifreq = (387 + ((uint32_t)f[k] * 9)); - } - r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); - } - else { // RandM == 8 or 9 - freq = (87.5 + ((float)f[k] * 0.1)); - r.msgs.emplace_back(2, strprintf("%.1f MHz", freq)); - } + if (Control_field_trans_mode == 0) { + r.msgs.emplace_back(2, + "no transmission mode signalled"); } - else { - r.errors.emplace_back("Frequency not to be used (0)"); + else if (Control_field_trans_mode <= 4) { + r.msgs.emplace_back(2, + strprintf("transmission mode %d", + Control_field_trans_mode)); + } + else { // Control_field_trans_mode > 4 + r.msgs.emplace_back(2, + strprintf("invalid transmission mode 0x%x", + Control_field_trans_mode)); } - k++; } - break; - case 0xc: - while((k + 1) < (j + Length_Freq_list)) { - // iteration over Freq list - ifreq = (((uint32_t)f[k] << 8) | (uint32_t)f[k+1]) * 5; - if (ifreq != 0) { - r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); + else { // (Control_field & 0x10) == 0x10 + r.msgs.emplace_back(2, + strprintf("%d KHz," + "invalid Control field b23 0x%x", + freq, Control_field)); + } + } + break; + case 0x8: + case 0x9: + case 0xA: + for (int freq_ix = 0; + freq_ix < Length_Freq_list; + freq_ix++) { + if (i + 1 >= fig0.figlen) { + r.errors.push_back(strprintf( + "FIG 0/21 too small for" + " FI %d, freq %d", + FI_ix, freq_ix)); + } + + // entries are 8-bit freq + const uint8_t freq = f[i]; + i++; + if (freq == 0) { + r.errors.emplace_back( + "Frequency not to be used (0)"); + continue; + } + + if (RandM == 0xA) { + if (freq < 16) { + r.msgs.emplace_back(2, + strprintf("%d KHz", + 144 + ((uint32_t)freq * 9))); } - else { - r.errors.emplace_back("Frequency not to be used (0)"); + else { // f[k] >= 16 + r.msgs.emplace_back(2, + strprintf("%d KHz", + 387 + ((uint32_t)freq * 9))); } - k += 2; } - break; - case 0x6: - case 0xe: - while((k + 2) < (j + Length_Freq_list)) { - // iteration over Freq list - Id_field2 = f[k]; - ifreq = ((((uint32_t)f[k+1] & 0x7f) << 8) | (uint32_t)f[k+2]); - if (ifreq != 0) { - r.msgs.emplace_back(2, strprintf("%d KHz", ifreq)); + else { // RandM == 8 or 9 + r.msgs.emplace_back(2, + strprintf("%.1f MHz", + 87.5 + ((float)freq * 0.1))); + } + } + break; + case 0xC: + for (int freq_ix = 0; + freq_ix < Length_Freq_list; + freq_ix++) { + if (i + 2 >= fig0.figlen) { + r.errors.push_back(strprintf( + "FIG 0/21 too small for" + " FI %d, freq %d", + FI_ix, freq_ix)); + } + + // freqs are 16-bit + const uint16_t freq = 5 * + (((uint16_t)f[i] << 8) | + (uint32_t)f[i+1]); + i += 2; + if (freq != 0) { + r.msgs.emplace_back(2, + strprintf("%d KHz", freq)); + } + else { + r.errors.emplace_back( + "Frequency not to be used (0)"); + } + } + break; + case 0x6: + case 0xE: + { + // There is a first 8-bit entry, and the + // list contains 16-bit freqs + if (i + 1 >= fig0.figlen) { + r.errors.push_back(strprintf( + "FIG 0/21 too small for" + " control of" + " FI %d", + FI_ix)); + } + const uint32_t Id_field2 = f[i]; + i++; + + for (int freq_ix = 0; + freq_ix < Length_Freq_list; + freq_ix++) { + if (i + 2 >= fig0.figlen) { + r.errors.push_back(strprintf( + "FIG 0/21 too small for" + " FI %d, freq %d", + FI_ix, freq_ix)); + } + // entries are 16bit freq + const uint16_t freq = + ((((uint16_t)f[i+1] & 0x7f) << 8) | + (uint16_t)f[i+2]); + i += 2; + + if (freq == 0) { + r.msgs.emplace_back(2, + strprintf("%d KHz", freq)); } else { - r.errors.emplace_back("Frequency not to be used (0)"); + r.errors.emplace_back( + "Frequency not to be used (0)"); } + + const uint32_t srv_id = (Id_field2 << 16) | Id_field; if (RandM == 0x6) { - r.msgs.emplace_back(2, strprintf("DRM Service Id 0x%X", Id_field2)); - } - else if (RandM == 0xe) { - r.msgs.emplace_back(2, strprintf("AMSS Service Id 0x%X", Id_field2)); + r.msgs.emplace_back(2, + strprintf("DRM Service Id 0x%X", srv_id)); } - if ((f[k+1] & 0x80) == 0x80) { - r.msgs.emplace_back(2, strprintf("invalid Rfu b15 set to 1 instead of 0")); + else if (RandM == 0xE) { + r.msgs.emplace_back(2, + strprintf("AMSS Service Id 0x%X", srv_id)); } - k += 3; } - break; - default: - break; - } - j += Length_Freq_list; + } + break; + default: + r.errors.push_back(strprintf("Invalid R&M")); + break; } - 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)); } } -- cgit v1.2.3