diff options
| author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-01-15 15:03:38 +0100 | 
|---|---|---|
| committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2016-01-15 15:03:38 +0100 | 
| commit | 3576bfcd68ff58e022efc07ef8e1f1b757ccf6fb (patch) | |
| tree | dd8b4ae93ce1b87260794022f56cf8892958692a | |
| parent | 275b55e39a84a3877e7e68b7c800bd0de28c128c (diff) | |
| download | etisnoop-3576bfcd68ff58e022efc07ef8e1f1b757ccf6fb.tar.gz etisnoop-3576bfcd68ff58e022efc07ef8e1f1b757ccf6fb.tar.bz2 etisnoop-3576bfcd68ff58e022efc07ef8e1f1b757ccf6fb.zip | |
Refactor all FIG0/x into separate files
| -rw-r--r-- | CMakeLists.txt | 35 | ||||
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | etisnoop.cpp | 2331 | ||||
| -rw-r--r-- | fig0_0.cpp | 60 | ||||
| -rw-r--r-- | fig0_1.cpp | 91 | ||||
| -rw-r--r-- | fig0_10.cpp | 72 | ||||
| -rw-r--r-- | fig0_11.cpp | 185 | ||||
| -rw-r--r-- | fig0_13.cpp | 101 | ||||
| -rw-r--r-- | fig0_14.cpp | 59 | ||||
| -rw-r--r-- | fig0_16.cpp | 100 | ||||
| -rw-r--r-- | fig0_17.cpp | 117 | ||||
| -rw-r--r-- | fig0_18.cpp | 91 | ||||
| -rw-r--r-- | fig0_19.cpp | 85 | ||||
| -rw-r--r-- | fig0_2.cpp | 146 | ||||
| -rw-r--r-- | fig0_21.cpp | 302 | ||||
| -rw-r--r-- | fig0_22.cpp | 163 | ||||
| -rw-r--r-- | fig0_24.cpp | 88 | ||||
| -rw-r--r-- | fig0_25.cpp | 91 | ||||
| -rw-r--r-- | fig0_26.cpp | 88 | ||||
| -rw-r--r-- | fig0_27.cpp | 83 | ||||
| -rw-r--r-- | fig0_28.cpp | 69 | ||||
| -rw-r--r-- | fig0_3.cpp | 88 | ||||
| -rw-r--r-- | fig0_31.cpp | 110 | ||||
| -rw-r--r-- | fig0_5.cpp | 89 | ||||
| -rw-r--r-- | fig0_6.cpp | 170 | ||||
| -rw-r--r-- | fig0_8.cpp | 117 | ||||
| -rw-r--r-- | fig0_9.cpp | 131 | ||||
| -rw-r--r-- | figs.cpp | 112 | ||||
| -rw-r--r-- | figs.hpp | 96 | ||||
| -rw-r--r-- | tables.cpp | 311 | ||||
| -rw-r--r-- | tables.hpp | 43 | ||||
| -rw-r--r-- | utils.cpp | 154 | ||||
| -rw-r--r-- | utils.hpp | 57 | ||||
| -rw-r--r-- | watermarkdecoder.hpp | 98 | 
35 files changed, 3610 insertions, 2365 deletions
| diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a0c139..1e730dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,13 +46,40 @@ include_directories(${FEC_INCLUDE_DIRS})  list(APPEND etisnoop_sources      dabplussnoop.cpp -    lib_crc.c -    firecode.c -    faad_decoder.cpp -    wavfile.c      etiinput.cpp      etisnoop.cpp +    faad_decoder.cpp +    fig0_0.cpp +    fig0_1.cpp +    fig0_2.cpp +    fig0_3.cpp +    fig0_5.cpp +    fig0_6.cpp +    fig0_8.cpp +    fig0_9.cpp +    fig0_10.cpp +    fig0_11.cpp +    fig0_13.cpp +    fig0_14.cpp +    fig0_16.cpp +    fig0_17.cpp +    fig0_18.cpp +    fig0_19.cpp +    fig0_21.cpp +    fig0_22.cpp +    fig0_24.cpp +    fig0_25.cpp +    fig0_26.cpp +    fig0_27.cpp +    fig0_28.cpp +    fig0_31.cpp +    figs.cpp +    firecode.c +    lib_crc.c      rsdecoder.cpp +    tables.cpp +    utils.cpp +    wavfile.c  )  set_source_files_properties(${etisnoop_sources} PROPERTIES LANGUAGE "CXX") diff --git a/Makefile b/Makefile deleted file mode 100644 index 84f4cf1..0000000 --- a/Makefile +++ /dev/null @@ -1,24 +0,0 @@ - -CXX=g++ - -SOURCES=etisnoop.cpp dabplussnoop.cpp lib_crc.c firecode.c faad_decoder.cpp wavfile.c etiinput.cpp rsdecoder.cpp -HEADERS=dabplussnoop.h lib_crc.h firecode.h faad_decoder.h wavfile.h etiinput.h rsdecoder.h - -all: etisnoop - -etisnoop: $(SOURCES) $(HEADERS) -	$(CXX) -std=c++11 -Wall -ggdb $(SOURCES) -lfaad -lfec -o etisnoop - -etisnoop-static: libfaad $(SOURCES) $(HEADERS) -	$(CXX) -std=c++11 -Wall -ggdb $(SOURCES) -lfec -Ifaad2-2.7/include faad2-2.7/libfaad/.libs/libfaad.a -o etisnoop - -libfaad: -	make -C ./faad2-2.7 - -.PHONY: tags -tags: -	ctags -R . - - -clean: -	rm -f etisnoop *.o @@ -17,24 +17,6 @@ Make sure you have cmake installed and do      cmake ..      make - -Build with old makefile ------------------------ - -Alternatively, use the old Makefile. There are two -variants: - -    make etisnoop - -compiles the tool, dynamically linked against libfaad - -Or you can extract the sources for libfaad2-2.7 into a subfolder of the -same name, configure it, and if required modify it. Then you can do - -    make etisnoop-static - -to compile a version of etisnoop compiled against your own copy of FAAD. -  About  ----- diff --git a/etisnoop.cpp b/etisnoop.cpp index 049790d..09f8280 100644 --- a/etisnoop.cpp +++ b/etisnoop.cpp @@ -44,9 +44,11 @@  #include <sstream>  #include <time.h>  #include "lib_crc.h" - +#include "utils.hpp"  #include "dabplussnoop.h"  #include "etiinput.h" +#include "figs.hpp" +#include "watermarkdecoder.hpp"  struct FIG  { @@ -55,68 +57,6 @@ struct FIG      int len;  }; -class WatermarkDecoder -{ -    public: -        void push_confind_bit(bool confind) -        { -            // The ConfInd of FIG 0/10 contains the CRC-DABMUX and ODR-DabMux watermark -            m_confind_bits.push_back(confind); -        } - -        std::string calculate_watermark() -        { -            // First try to find the 0x55 0x55 sync in the waternark data -            size_t bit_ix; -            int alternance_count = 0; -            bool last_bit = 1; -            for (bit_ix = 0; bit_ix < m_confind_bits.size(); bit_ix++) { -                if (alternance_count == 16) { -                    break; -                } -                else { -                    if (last_bit != m_confind_bits[bit_ix]) { -                        last_bit = m_confind_bits[bit_ix]; -                        alternance_count++; -                    } -                    else { -                        alternance_count = 0; -                        last_bit = 1; -                    } -                } - -            } - -            printf("Found SYNC at offset %zu out of %zu\n", bit_ix - alternance_count, m_confind_bits.size()); - -            std::stringstream watermark_ss; - -            uint8_t b = 0; -            size_t i = 0; -            while (bit_ix < m_confind_bits.size()) { - -                b |= m_confind_bits[bit_ix] << (7 - i); - -                if (i == 7) { -                    watermark_ss << (char)b; - -                    b = 0; -                    i = 0; -                } -                else { -                    i++; -                } - -                bit_ix += 2; -            } - -            return watermark_ss.str(); -        } - -    private: -        std::vector<bool> m_confind_bits; -}; -  class FIGalyser  {      public: @@ -204,167 +144,6 @@ struct FIG0_13_shortAppInfo      uint8_t SCIdS:4;  } PACKED; -class FIG0_5 { -    public: -        // Constructor -        FIG0_5() { -            // Initialization of Language_code_to_char_map: -            // ETSI TS 101 756 V1.6.1 Table 9: European languages -            Language_code_to_char_map[0x00] = "Unknown/not applicable"; -            Language_code_to_char_map[0x01] = "Albanian"; -            Language_code_to_char_map[0x02] = "Breton"; -            Language_code_to_char_map[0x03] = "Catalan"; -            Language_code_to_char_map[0x04] = "Croatian"; -            Language_code_to_char_map[0x05] = "Welsh"; -            Language_code_to_char_map[0x06] = "Czech"; -            Language_code_to_char_map[0x07] = "Danish"; -            Language_code_to_char_map[0x08] = "German"; -            Language_code_to_char_map[0x09] = "English"; -            Language_code_to_char_map[0x0A] = "Spanish"; -            Language_code_to_char_map[0x0B] = "Esperanto"; -            Language_code_to_char_map[0x0C] = "Estonian"; -            Language_code_to_char_map[0x0D] = "Basque"; -            Language_code_to_char_map[0x0E] = "Faroese"; -            Language_code_to_char_map[0x0F] = "French"; -            Language_code_to_char_map[0x10] = "Frisian"; -            Language_code_to_char_map[0x11] = "Irish"; -            Language_code_to_char_map[0x12] = "Gaelic"; -            Language_code_to_char_map[0x13] = "Galician"; -            Language_code_to_char_map[0x14] = "Icelandic"; -            Language_code_to_char_map[0x15] = "Italian"; -            Language_code_to_char_map[0x16] = "Lappish"; -            Language_code_to_char_map[0x17] = "Latin"; -            Language_code_to_char_map[0x18] = "Latvian"; -            Language_code_to_char_map[0x19] = "Luxembourgian"; -            Language_code_to_char_map[0x1A] = "Lithuanian"; -            Language_code_to_char_map[0x1B] = "Hungarian"; -            Language_code_to_char_map[0x1C] = "Maltese"; -            Language_code_to_char_map[0x1D] = "Dutch"; -            Language_code_to_char_map[0x1E] = "Norwegian"; -            Language_code_to_char_map[0x1F] = "Occitan"; -            Language_code_to_char_map[0x20] = "Polish"; -            Language_code_to_char_map[0x21] = "Portuguese"; -            Language_code_to_char_map[0x22] = "Romanian"; -            Language_code_to_char_map[0x23] = "Romansh"; -            Language_code_to_char_map[0x24] = "Serbian"; -            Language_code_to_char_map[0x25] = "Slovak"; -            Language_code_to_char_map[0x26] = "Slovene"; -            Language_code_to_char_map[0x27] = "Finnish"; -            Language_code_to_char_map[0x28] = "Swedish"; -            Language_code_to_char_map[0x29] = "Turkish"; -            Language_code_to_char_map[0x2A] = "Flemish"; -            Language_code_to_char_map[0x2B] = "Walloon"; -            Language_code_to_char_map[0x2C] = "rfu"; -            Language_code_to_char_map[0x2D] = "rfu"; -            Language_code_to_char_map[0x2E] = "rfu"; -            Language_code_to_char_map[0x2F] = "rfu"; -            Language_code_to_char_map[0x30] = "Reserved for national assignment"; -            Language_code_to_char_map[0x31] = "Reserved for national assignment"; -            Language_code_to_char_map[0x32] = "Reserved for national assignment"; -            Language_code_to_char_map[0x33] = "Reserved for national assignment"; -            Language_code_to_char_map[0x34] = "Reserved for national assignment"; -            Language_code_to_char_map[0x35] = "Reserved for national assignment"; -            Language_code_to_char_map[0x36] = "Reserved for national assignment"; -            Language_code_to_char_map[0x37] = "Reserved for national assignment"; -            Language_code_to_char_map[0x38] = "Reserved for national assignment"; -            Language_code_to_char_map[0x39] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3A] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3B] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3C] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3D] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3E] = "Reserved for national assignment"; -            Language_code_to_char_map[0x3F] = "Reserved for national assignment"; - -            // ETSI TS 101 756 V1.6.1 Table 10: Other languages -            Language_code_to_char_map[0x40] = "Background sound/clean feed"; -            Language_code_to_char_map[0x41] = "rfu"; -            Language_code_to_char_map[0x42] = "rfu"; -            Language_code_to_char_map[0x43] = "rfu"; -            Language_code_to_char_map[0x44] = "rfu"; -            Language_code_to_char_map[0x45] = "Zulu"; -            Language_code_to_char_map[0x46] = "Vietnamese"; -            Language_code_to_char_map[0x47] = "Uzbek"; -            Language_code_to_char_map[0x48] = "Urdu"; -            Language_code_to_char_map[0x49] = "Ukranian"; -            Language_code_to_char_map[0x4A] = "Thai"; -            Language_code_to_char_map[0x4B] = "Telugu"; -            Language_code_to_char_map[0x4C] = "Tatar"; -            Language_code_to_char_map[0x4D] = "Tamil"; -            Language_code_to_char_map[0x4E] = "Tadzhik"; -            Language_code_to_char_map[0x4F] = "Swahili"; -            Language_code_to_char_map[0x50] = "Sranan Tongo"; -            Language_code_to_char_map[0x51] = "Somali"; -            Language_code_to_char_map[0x52] = "Sinhalese"; -            Language_code_to_char_map[0x53] = "Shona"; -            Language_code_to_char_map[0x54] = "Serbo-Croat"; -            Language_code_to_char_map[0x55] = "Rusyn"; -            Language_code_to_char_map[0x56] = "Russian"; -            Language_code_to_char_map[0x57] = "Quechua"; -            Language_code_to_char_map[0x58] = "Pushtu"; -            Language_code_to_char_map[0x59] = "Punjabi"; -            Language_code_to_char_map[0x5A] = "Persian"; -            Language_code_to_char_map[0x5B] = "Papiamento"; -            Language_code_to_char_map[0x5C] = "Oriya"; -            Language_code_to_char_map[0x5D] = "Nepali"; -            Language_code_to_char_map[0x5E] = "Ndebele"; -            Language_code_to_char_map[0x5F] = "Marathi"; -            Language_code_to_char_map[0x60] = "Moldavian"; -            Language_code_to_char_map[0x61] = "Malaysian"; -            Language_code_to_char_map[0x62] = "Malagasay"; -            Language_code_to_char_map[0x63] = "Macedonian"; -            Language_code_to_char_map[0x64] = "Laotian"; -            Language_code_to_char_map[0x65] = "Korean"; -            Language_code_to_char_map[0x66] = "Khmer"; -            Language_code_to_char_map[0x67] = "Kazakh"; -            Language_code_to_char_map[0x68] = "Kannada"; -            Language_code_to_char_map[0x69] = "Japanese"; -            Language_code_to_char_map[0x6A] = "Indonesian"; -            Language_code_to_char_map[0x6B] = "Hindi"; -            Language_code_to_char_map[0x6C] = "Hebrew"; -            Language_code_to_char_map[0x6D] = "Hausa"; -            Language_code_to_char_map[0x6E] = "Gurani"; -            Language_code_to_char_map[0x6F] = "Gujurati"; -            Language_code_to_char_map[0x70] = "Greek"; -            Language_code_to_char_map[0x71] = "Georgian"; -            Language_code_to_char_map[0x72] = "Fulani"; -            Language_code_to_char_map[0x73] = "Dari"; -            Language_code_to_char_map[0x74] = "Chuvash"; -            Language_code_to_char_map[0x75] = "Chinese"; -            Language_code_to_char_map[0x76] = "Burmese"; -            Language_code_to_char_map[0x77] = "Bulgarian"; -            Language_code_to_char_map[0x78] = "Bengali"; -            Language_code_to_char_map[0x79] = "Belorussian"; -            Language_code_to_char_map[0x7A] = "Bambora"; -            Language_code_to_char_map[0x7B] = "Azerbaijani"; -            Language_code_to_char_map[0x7C] = "Assamese"; -            Language_code_to_char_map[0x7D] = "Armenian"; -            Language_code_to_char_map[0x7E] = "Arabic"; -            Language_code_to_char_map[0x7F] = "Amharic"; -        } - -        // Destructor -        ~FIG0_5() { -            // Remove elements from Language_code_to_char_map map container -            Language_code_to_char_map.clear(); -        } - -        // Language_to_char decode fig 0/5 language code in string -        // Input : Language code number -        // Return: Language char * -        const char * Language_to_char(uint8_t language) { -            if (Language_code_to_char_map.count(language) > 0) { -                return Language_code_to_char_map[language]; -            } -            else { -                return ""; -            } -        } - -    private: -        // Map between fig 0/5 Language code and Language char -        std::map<uint8_t, const char *> Language_code_to_char_map; -}; -  #define ETINIPACKETSIZE 6144 @@ -379,152 +158,7 @@ struct eti_analyse_config_t {  }; -// Globals -static int verbosity; -static uint8_t Mode_Identity = 0; - -// fig 0/2 fig 0/3 DSCTy types string: -const char *DSCTy_types_str[64] =  { -    // ETSI TS 101 756 V1.6.1 (2014-05) table 2 -    "Unspecified data",                             "Traffic Message Channel (TMC)", -    "Emergency Warning System (EWS)",               "Interactive Text Transmission System (ITTS)", -    "Paging",                                       "Transparent Data Channel (TDC)", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "MPEG-2 Transport Stream, see ETSI TS 102 427", "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Rfu", -    "Rfu",                                          "Embedded IP packets", -    "Multimedia Object Transfer (MOT)",             "Proprietary service: no DSCTy signalled", -    "Not used",                                     "Not used" -}; - -// map between fig 0/6 database key and LA to detect activation and deactivation of links -std::map<uint16_t, bool> fig0_6_key_la; - -// fig 0/9 global variables -uint8_t Ensemble_ECC=0, International_Table_Id=0; -int8_t Ensemble_LTO=0; -bool LTO_uniq; - -// fig 0/14 FEC Scheme: this 2-bit field shall indicate the Forward Error Correction scheme in use, as follows: -const char *FEC_schemes_str[4] =  { -    "no FEC scheme applied", -    "FEC scheme applied according to ETSI EN 300 401 clause 5.3.5", -    "reserved for future definition", -    "reserved for future definition" -}; - -// fig 0/17 Programme type codes -#define INTERNATIONAL_TABLE_SIZE     2 -#define PROGRAMME_TYPE_CODES_SIZE  32 -const char *Programme_type_codes_str[INTERNATIONAL_TABLE_SIZE][PROGRAMME_TYPE_CODES_SIZE] = { -    {   // ETSI TS 101 756 V1.6.1 (2014-05) table 12 -        "No programme type",        "News", -        "Current Affairs",          "Information", -        "Sport",                    "Education", -        "Drama",                    "Culture", -        "Science",                  "Varied", -        "Pop Music",                "Rock Music", -        "Easy Listening Music",     "Light Classical", -        "Serious Classical",        "Other Music", -        "Weather/meteorology",      "Finance/Business", -        "Children's programmes",    "Social Affairs", -        "Religion",                 "Phone In", -        "Travel",                   "Leisure", -        "Jazz Music",               "Country Music", -        "National Music",           "Oldies Music", -        "Folk Music",               "Documentary", -        "Not used",                 "Not used" -    }, -    {   // ETSI TS 101 756 V1.6.1 (2014-05) table 13 -        "No program type",  "News", -        "Information",      "Sports", -        "Talk",             "Rock", -        "Classic Rock",     "Adult Hits", -        "Soft Rock",        "Top 40", -        "Country",          "Oldies", -        "Soft",             "Nostalgia", -        "Jazz",             "Classical", -        "Rhythm and Blues", "Soft Rhythm and Blues", -        "Foreign Language", "Religious Music", -        "Religious Talk",   "Personality", -        "Public",           "College", -        "rfu",              "rfu", -        "rfu",              "rfu", -        "rfu",              "Weather", -        "Not used",         "Not used" -    } -}; - -// fig 0/18 0/19 announcement types (ETSI TS 101 756 V1.6.1 (2014-05) table 14 & 15) -const char *announcement_types_str[16] = { -    "Alarm", -    "Road Traffic flash", -    "Transport flash", -    "Warning/Service", -    "News flash", -    "Area weather flash", -    "Event announcement", -    "Special event", -    "Programme Information", -    "Sport report", -    "Financial report", -    "Reserved for future definition", -    "Reserved for future definition", -    "Reserved for future definition", -    "Reserved for future definition", -    "Reserved for future definition" -}; - -// fig 0/22 struct -typedef struct lat_lng { -    double latitude, longitude; -}Lat_Lng; -// map for fig 0/22 database -std::map<uint16_t, Lat_Lng> fig0_22_key_Lat_Lng; - -// ETSI TS 102 367 V1.2.1 (2006-01) 5.4.1 Conditional Access Mode (CAMode) -const char *CAMode_str[8] = { -    "Sub-channel CA",   "Data Group CA", -    "MOT CA",           "proprietary CA", -    "reserved",         "reserved", -    "reserved",         "reserved" -}; - -  // Function prototypes -void printinfo(string header, -        int indent_level, -        int min_verb=0); - -void printbuf(string header, -        int indent_level, -        uint8_t* buffer, -        size_t size, -        string desc=""); -  void decodeFIG(FIGalyser &figs,                 WatermarkDecoder &wm_decoder,                 uint8_t* figdata, @@ -535,26 +169,8 @@ void decodeFIG(FIGalyser &figs,  int eti_analyse(eti_analyse_config_t& config);  const char *get_programme_type_str(size_t int_table_Id, size_t pty); -char *strcatPNum(char *dest_str, uint16_t Programme_Number);  int sprintfMJD(char *dst, int mjd); -std::string get_fig_0_13_userapp(int user_app_type) -{ -    switch (user_app_type) { -        case 0x000: return "Reserved for future definition"; -        case 0x001: return "Not used"; -        case 0x002: return "MOT Slideshow"; -        case 0x003: return "MOT Broadacst Web Site"; -        case 0x004: return "TPEG"; -        case 0x005: return "DGPS"; -        case 0x006: return "TMC"; -        case 0x007: return "EPG"; -        case 0x008: return "DAB Java"; -        case 0x44a: return "Journaline"; -        default: return "Reserved for future applications"; -    } -} -  #define no_argument 0  #define required_argument 1  #define optional_argument 2 @@ -587,7 +203,6 @@ int main(int argc, char *argv[])      string file_name("-");      map<int, DabPlusSnoop> streams_to_decode; -    verbosity = 0;      bool ignore_error = false;      bool analyse_fic_carousel = false;      bool decode_watermark = false; @@ -612,7 +227,7 @@ int main(int argc, char *argv[])                  analyse_fic_carousel = true;                  break;              case 'v': -                verbosity++; +                set_verbosity(get_verbosity() + 1);                  break;              case 'w':                  decode_watermark = true; @@ -809,7 +424,7 @@ int eti_analyse(eti_analyse_config_t& config)                  ss << "4";              }              printbuf("MID  - Mode Identity", 2, &mid, 1, ss.str()); -            Mode_Identity = mid; +            set_mode_identity(mid);          }          // LIDATA - FC - FL @@ -991,7 +606,7 @@ int eti_analyse(eti_analyse_config_t& config)              else {                  sprintf(sdesc, "id %d, len %d, not selected for decoding", i, stl[i]*8);              } -            if (verbosity > 1) { +            if (get_verbosity() > 1) {                  printbuf("Stream Data", 1, streamdata, stl[i]*8, sdesc);              }              else { @@ -1030,7 +645,7 @@ int eti_analyse(eti_analyse_config_t& config)          printbuf("TIST - Time Stamp", 1, p+12+4*nst+ficf*ficl*4+offset+4, 4, sdesc); -        if (verbosity) { +        if (get_verbosity()) {              printf("-------------------------------------------------------------------------------------------------------------\n");          }      } @@ -1048,9 +663,7 @@ int eti_analyse(eti_analyse_config_t& config)          printf("Watermark:\n  %s\n", watermark.c_str());      } -    // remove elements from fig0_6_key_la and fig0_22_key_Lat_Lng map containers -    fig0_6_key_la.clear(); -    fig0_22_key_Lat_Lng.clear(); +    figs_cleardb();      return 0;  } @@ -1063,1812 +676,19 @@ void decodeFIG(FIGalyser &figs,                 int indent)  {      char desc[512]; -    static FIG0_5 fig0_5;      switch (figtype) {          case 0:              { -                uint16_t ext,cn,oe,pd; +                fig0_common_t fig0(f, figlen, wm_decoder); -                cn = (f[0] & 0x80) >> 7; -                oe = (f[0] & 0x40) >> 6; -                pd = (f[0] & 0x20) >> 5; -                ext = f[0] & 0x1F;                  sprintf(desc, "FIG %d/%d: C/N=%d OE=%d P/D=%d", -                        figtype, ext, cn, oe, pd); +                        figtype, fig0.ext(), fig0.cn(), fig0.oe(), fig0.pd());                  printbuf(desc, indent, f+1, figlen-1); -                figs.push_back(figtype, ext, figlen); - -                switch (ext) { - -                    case 0: // FIG 0/0 Ensemble information -                        {   // ETSI EN 300 401 6.4 -                            uint8_t cid, al, ch, hic, lowc, occ; -                            uint16_t eid, eref; - -                            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]; -                            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); -                            } -                            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, indent+1, NULL, 0); - -                        } -                        break; -                    case 1: // FIG 0/1 Basic sub-channel organization -                        {   // ETSI EN 300 401 6.2.1 -                            int i = 1; - -                            while (i < figlen-3) { -                                // iterate over subchannels -                                int subch_id = f[i] >> 2; -                                int start_addr = ((f[i] & 0x03) << 8) | -                                                 (f[i+1]); -                                int long_flag  = (f[i+2] >> 7); - -                                if (long_flag) { -                                    int option = (f[i+2] >> 4) & 0x07; -                                    int protection_level = (f[i+2] >> 2) & 0x03; -                                    int subchannel_size  = ((f[i+2] & 0x03) << 8 ) | -                                                           f[i+3]; - -                                    i += 4; - -                                    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); -                                    } -                                    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); -                                    } -                                    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); -                                    } -                                } -                                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); -                                    } - -                                    i += 3; -                                } -                                printbuf(desc, indent+1, NULL, 0); -                            } - -                        } -                        break; -                    case 2: // FIG 0/2 Basic service and service component definition -                        {   // ETSI EN 300 401 6.3.1 -                            uint16_t sref, sid; -                            uint8_t cid, ecc, local, caid, ncomp, timd, ps, ca, subchid, scty; -                            int k=1; -                            string psdesc; -                            char sctydesc[32]; - -                            while (k<figlen) { -                                if (pd == 0) { -                                    sid  =  f[k] * 256 + f[k+1]; -                                    cid  = (f[k] & 0xF0) >> 4; -                                    sref = (f[k] & 0x0F) * 256 + f[k+1]; -                                    k += 2; -                                } -                                else { -                                    sid  =  f[k] * 256 * 256 * 256 + \ -                                            f[k+1] * 256 * 256 + \ -                                            f[k+2] * 256 + \ -                                            f[k+3]; - -                                    ecc  =  f[k]; -                                    cid  = (f[k+1] & 0xF0) >> 4; -                                    sref = (f[k+1] & 0x0F) * 256 * 256 + \ -                                           f[k+2] * 256 + \ -                                           f[k+3]; - -                                    k += 4; -                                } - -                                local = (f[k] & 0x80) >> 7; -                                caid  = (f[k] & 0x70) >> 4; -                                ncomp =  f[k] & 0x0F; - -                                if (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, indent+1, NULL, 0); - -                                k++; -                                for (int i=0; i<ncomp; i++) { -                                    uint8_t scomp[2]; - -                                    memcpy(scomp, f+k, 2); -                                    sprintf(desc, "Component[%d]", i); -                                    printbuf(desc, indent+2, scomp, 2, ""); -                                    timd    = (scomp[0] & 0xC0) >> 6; -                                    ps      = (scomp[1] & 0x02) >> 1; -                                    ca      =  scomp[1] & 0x01; -                                    scty    =  scomp[0] & 0x3F; -                                    subchid = (scomp[1] & 0xFC) >> 2; - -                                    /* useless, kept as reference -                                    if (timd == 3) { -                                        uint16_t scid; -                                        scid = scty*64 + subchid; -                                    } -                                    */ - -                                    if (ps == 0) { -                                        psdesc = "Secondary service"; -                                    } -                                    else { -                                        psdesc = "Primary service"; -                                    } - - -                                    if (timd == 0) { -                                        //MSC stream audio -                                        if (scty == 0) -                                            sprintf(sctydesc, "MPEG Foreground sound (%d)", scty); -                                        else if (scty == 1) -                                            sprintf(sctydesc, "MPEG Background sound (%d)", scty); -                                        else if (scty == 2) -                                            sprintf(sctydesc, "Multi Channel sound (%d)", scty); -                                        else if (scty == 63) -                                            sprintf(sctydesc, "AAC sound (%d)", scty); -                                        else -                                            sprintf(sctydesc, "Unknown ASCTy (%d)", scty); - -                                        sprintf(desc, "Stream audio mode, %s, %s, SubChannel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); -                                        printbuf(desc, indent+3, NULL, 0); -                                    } -                                    else if (timd == 1) { -                                        // MSC stream data -                                        sprintf(sctydesc, "DSCTy=%d %s", scty, DSCTy_types_str[scty]); -                                        sprintf(desc, "Stream data mode, %s, %s, SubChannel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); -                                        printbuf(desc, indent+3, NULL, 0); -                                    } -                                    else if (timd == 2) { -                                        // FIDC -                                        sprintf(sctydesc, "DSCTy=%d %s", scty, DSCTy_types_str[scty]); -                                        sprintf(desc, "FIDC mode, %s, %s, Fast Information Data Channel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); -                                        printbuf(desc, indent+3, NULL, 0); -                                    } -                                    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, indent+3, NULL, 0); -                                    } -                                    k += 2; -                                } -                            } -                        } -                        break; -                    case 3: // FIG 0/3 Service component in packet mode with or without Conditional Access -                        {   // ETSI EN 300 401 6.3.2 -                            uint16_t SCId, Packet_address, CAOrg; -                            uint8_t i = 1, Rfa, DSCTy, SubChId, CAMode, SharedFlag; -                            char tmpbuf[256]; -                            bool CAOrg_flag, DG_flag, Rfu; - -                            while (i < (figlen - 4)) { -                                // iterate over service component in packet mode -                                SCId = ((uint16_t)f[i] << 4) | ((uint16_t)(f[i+1] >> 4) & 0x0F); -                                Rfa = (f[i+1] >> 1) & 0x07; -                                CAOrg_flag = f[i+1] & 0x01; -                                DG_flag = (f[i+2] >> 7) & 0x01; -                                Rfu = (f[i+2] >> 6) & 0x01; -                                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, DSCTy_types_str[DSCTy], SubChId, Packet_address); -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                if (Rfu != 0) { -                                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                    strcat(desc, tmpbuf); -                                } -                                i += 5; -                                if (CAOrg_flag) { -                                    if (i < (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, CAMode_str[CAMode], SharedFlag, (SharedFlag == 0)?" invalid":""); -                                        strcat(desc, tmpbuf); -                                    } -                                    else { -                                        sprintf(tmpbuf, ", invalid figlen"); -                                        strcat(desc, tmpbuf); -                                    } -                                    i += 2; -                                } -                                printbuf(desc, indent+1, NULL, 0); -                            } -                        } -                        break; -                    case 5: // FIG 0/5 Service component language -                        {   // ETSI EN 300 401 8.1.2 -                            uint16_t SCId; -                            uint8_t i = 1, SubChId, FIDCId, Language, Rfa; -                            char tmpbuf[256]; -                            bool LS_flag, MSC_FIC_flag; - -                            while (i < (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]; -                                    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, fig0_5.Language_to_char(Language)); -                                    } -                                    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, fig0_5.Language_to_char(Language)); -                                    } -                                    printbuf(desc, indent+1, NULL, 0); -                                    i += 2; -                                } -                                else { -                                    // Long form (L/S = 1) -                                    if (i < (figlen - 2)) { -                                        Rfa = (f[i] >> 4) & 0x07; -                                        SCId = (((uint16_t)f[i] & 0x0F) << 8) | (uint16_t)f[i+1]; -                                        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); -                                        } -                                        sprintf(tmpbuf, ", SCId=0x%X, Language=0x%X %s", -                                                SCId, Language, fig0_5.Language_to_char(Language)); -                                        strcat(desc, tmpbuf); -                                        printbuf(desc, indent+1, NULL, 0); -                                    } -                                    i += 3; -                                    } -                            } -                        } -                        break; -                    case 6: // FIG 0/6 Service linking information -                        {   // ETSI EN 300 401 8.1.15 -                            uint32_t j; -                            uint16_t LSN, key; -                            uint8_t i = 1, Number_of_Ids, IdLQ; -                            char signal_link[256]; -                            bool Id_list_flag, LA, SH, ILS, Shd; - -                            while (i < (figlen - 1)) { -                                // iterate over service linking -                                Id_list_flag  =  (f[i] >> 7) & 0x01; -                                LA  = (f[i] >> 6) & 0x01; -                                SH  = (f[i] >> 5) & 0x01; -                                ILS = (f[i] >> 4) & 0x01; -                                LSN = ((f[i] & 0x0F) << 8) | f[i+1]; -                                key = (oe << 15) | (pd << 14) | (SH << 13) | (ILS << 12) | LSN; -                                strcpy(signal_link, ""); -                                // check activation / deactivation -                                if ((fig0_6_key_la.count(key) > 0) && (fig0_6_key_la[key] != LA)) { -                                    if (LA == 0) { -                                        strcat(signal_link, " deactivated"); -                                    } -                                    else { -                                        strcat(signal_link, " activated"); -                                    } -                                } -                                fig0_6_key_la[key] = LA; -                                i += 2; -                                if (Id_list_flag == 0) { -                                    if (cn == 0) {  // Id_list_flag=0 && cn=0: CEI Change Event Indication -                                        strcat(signal_link, " 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, indent+1, NULL, 0); -                                } -                                else {  // Id_list_flag == 1 -                                    if (i < figlen) { -                                        Number_of_Ids = (f[i] & 0x0F); -                                        if (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, indent+1, NULL, 0); -                                            if (ILS == 0) { -                                                // read Id list -                                                for(j = 0; ((j < Number_of_Ids) && ((i+2+(j*2)) < figlen)); j++) { -                                                    // ETSI EN 300 401 8.1.15: -                                                    // The IdLQ shall not apply to the first entry in the Id list when OE = "0" and  -                                                    // when the version number of the type 0 field is set to "0" (using the C/N flag, see clause 5.2.2.1) -                                                    // ... , the first entry in the Id list of each Service linking field shall be  -                                                    // the SId that applies to the service in the ensemble. -                                                    if (((j == 0) && (oe == 0) && (cn == 0)) || -                                                        (IdLQ == 0)) { -                                                        sprintf(desc, "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)])); -                                                    } -                                                    else if (IdLQ == 2) { -                                                        sprintf(desc, "AM-FM service 0x%X", ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); -                                                    } -                                                    else {  // IdLQ == 3 -                                                        sprintf(desc, "invalid ILS IdLQ configuration"); -                                                    } -                                                    printbuf(desc, indent+2, NULL, 0); -                                                } -                                                // check deadlink -                                                if ((Number_of_Ids == 0) && (IdLQ == 1)) { -                                                    sprintf(desc, "deadlink"); -                                                    printbuf(desc, indent+2, NULL, 0); -                                                } -                                                i += (Number_of_Ids * 2) + 1; -                                            } -                                            else {  // pd == 0 && ILS == 1 -                                                // read Id list -                                                for(j = 0; ((j < Number_of_Ids) && ((i+3+(j*3)) < figlen)); j++) { -                                                    // ETSI EN 300 401 8.1.15: -                                                    // The IdLQ shall not apply to the first entry in the Id list when OE = "0" and  -                                                    // when the version number of the type 0 field is set to "0" (using the C/N flag, see clause 5.2.2.1) -                                                    // ... , the first entry in the Id list of each Service linking field shall be  -                                                    // the SId that applies to the service in the ensemble. -                                                    if (((j == 0) && (oe == 0) && (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)])); -                                                    } -                                                    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)])); -                                                    } -                                                    else if (IdLQ == 2) { -                                                        sprintf(desc, "AM-FM service    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)])); -                                                    } -                                                    printbuf(desc, indent+2, NULL, 0); -                                                } -                                                // check deadlink -                                                if ((Number_of_Ids == 0) && (IdLQ == 1)) { -                                                    sprintf(desc, "deadlink"); -                                                    printbuf(desc, indent+2, NULL, 0); -                                                } -                                                i += (Number_of_Ids * 3) + 1; -                                            } -                                        } -                                        else {  // 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, indent+1, NULL, 0); -                                            if (Number_of_Ids > 0) { -                                                // read Id list -                                                for(j = 0; ((j < Number_of_Ids) && ((i+4+(j*4)) < 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, indent+2, NULL, 0); -                                                } -                                            } -                                            i += (Number_of_Ids * 4) + 1; -                                        } -                                    } -                                } -                            } -                        } -                        break; -                    case 8: // FIG 0/8 Service component global definition -                        {   // ETSI EN 300 401 6.3.5 -                            uint32_t SId; -                            uint16_t SCId; -                            uint8_t i = 1, Rfa, SCIdS, SubChId, FIDCId; -                            char tmpbuf[256]; -                            bool Ext_flag, LS_flag, MSC_FIC_flag; - -                            while (i < (figlen - (2 + (2 * pd)))) { -                                // iterate over service component global definition -                                if (pd == 0) { -                                    // Programme services, 16 bit SId -                                    SId = (f[i] << 8) | f[i+1]; -                                    i += 2; -                                } -                                else { -                                    // Data services, 32 bit SId -                                    SId = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | -                                            ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; -                                    i += 4; -                                } -                                Ext_flag = f[i] >> 7; -                                Rfa = (f[i] >> 4) & 0x7; -                                SCIdS = f[i] & 0x0F; -                                sprintf(desc, "SId=0x%X, Ext flag=%d 8-bit Rfa %s", SId, Ext_flag, (Ext_flag)?"present":"absent"); -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                sprintf(tmpbuf, ", SCIdS=0x%X", SCIdS); -                                strcat(desc, tmpbuf); -                                i++; -                                if (i < figlen) { -                                    LS_flag = f[i] >> 7; -                                    sprintf(tmpbuf, ", L/S flag=%d %s", LS_flag, (LS_flag)?"Long form":"Short form"); -                                    strcat(desc, tmpbuf); -                                    if (LS_flag == 0) { -                                        // Short form -                                        if (i < (figlen - Ext_flag)) { -                                            MSC_FIC_flag = (f[i] >> 6) & 0x01; -                                            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); -                                            } -                                            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); -                                            } -                                            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); -                                                } -                                            } -                                        } -                                        i += (1 + Ext_flag); -                                    } -                                    else { -                                        // Long form -                                        if (i < (figlen - 1)) { -                                            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); -                                            } -                                            sprintf(tmpbuf, ", SCId=0x%X", SCId); -                                            strcat(desc, tmpbuf); -                                        } -                                        i += 2; -                                    } -                                } -                                printbuf(desc, indent+1, NULL, 0); -                            } -                        } -                        break; -                    case 9: // FIG 0/9 Country, LTO and International table -                        {   // ETSI EN 300 401 8.1.3.2 -                            uint32_t SId; -                            uint8_t i = 1, j, key, Number_of_services, ECC; -                            int8_t LTO; -                            char tmpbuf[256]; -                            bool Ext_flag; - -                            if (i < (figlen - 2)) { -                                // get Ensemble LTO, ECC and International Table Id -                                key = ((uint8_t)oe << 1) | (uint8_t)pd; -                                Ext_flag = f[i] >> 7; -                                LTO_uniq = (f[i]>> 6) & 0x01; -                                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); -                                if (abs(Ensemble_LTO) > 24) { -                                    sprintf(tmpbuf, " out of range -12 hours to +12 hours"); -                                    strcat(desc, tmpbuf); -                                } -                                Ensemble_ECC = f[i+1]; -                                International_Table_Id = f[i+2]; -                                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, indent+1, NULL, 0); -                                i += 3; -                                if (Ext_flag == 1) { -                                    // extended field present -                                    while (i < figlen) { -                                        // iterate over extended sub-field -                                        Number_of_services = f[i] >> 6; -                                        LTO = f[i] & 0x3F; -                                        if (LTO & 0x20) { -                                            // 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); -                                        if (abs(LTO) > 24) { -                                            sprintf(tmpbuf, " out of range -12 hours to +12 hours"); -                                            strcat(desc, tmpbuf); -                                        } -                                        // CEI Change Event Indication -                                        if ((Number_of_services == 0) && (LTO == 0) /* && (Ext_flag == 1) */) { -                                            sprintf(tmpbuf, ", CEI"); -                                            strcat(desc, tmpbuf); -                                        } -                                        i++; -                                        if (pd == 0) { -                                            // Programme services, 16 bit SId -                                            if (i < figlen) { -                                                ECC = f[i]; -                                                sprintf(tmpbuf, ", ECC=0x%X", ECC); -                                                strcat(desc, tmpbuf); -                                                printbuf(desc, indent+2, NULL, 0); -                                                i++; -                                                for(j = i; ((j < (i + (Number_of_services * 2))) && (j < 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, indent+3, NULL, 0); -                                                } -                                                i += (Number_of_services * 2); -                                            } -                                        } -                                        else { -                                            // Data services, 32 bit SId -                                            printbuf(desc, indent+2, NULL, 0); -                                            for(j = i; ((j < (i + (Number_of_services * 4))) && (j < 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, indent+3, NULL, 0); -                                            } -                                            i += (Number_of_services * 4); -                                        } -                                    } -                                } -                            } -                        } -                        break; -                    case 10: // FIG 0/10 Date and time -                        {    // ETSI EN 300 401 8.1.3.1 -                            char dateStr[256]; -                            dateStr[0] = 0; - -                            //bool RFU = f[1] >> 7; - -                            uint32_t MJD = (((uint32_t)f[1] & 0x7F) << 10)    | -                                           ((uint32_t)(f[2]) << 2) | -                                           (f[3] >> 6); -                            sprintfMJD(dateStr, MJD); - -                            bool LSI = f[3] & 0x20; -                            bool ConfInd = f[3] & 0x10; -                            wm_decoder.push_confind_bit(ConfInd); -                            bool UTC = f[3] & 0x8; - -                            uint8_t hours = ((f[3] & 0x7) << 2) | -                                            ( f[4] >> 6); +                figs.push_back(figtype, fig0.ext(), figlen); -                            uint8_t minutes = f[4] & 0x3f; - -                            if (UTC) { -                                uint8_t seconds = f[5] >> 2; -                                uint16_t milliseconds = ((uint16_t)(f[5] & 0x2) << 8) | f[6]; - -                                sprintf(desc, "FIG %d/%d(long): MJD=0x%X %s, LSI %u, ConfInd %u, UTC Time: %02d:%02d:%02d.%d", -                                        figtype, ext, MJD, dateStr, LSI, ConfInd, hours, minutes, seconds, milliseconds); -                                printbuf(desc, indent+1, NULL, 0); -                            } -                            else { -                                sprintf(desc, "FIG %d/%d(short): MJD=0x%X %s, LSI %u, ConfInd %u, UTC Time: %02d:%02d", -                                        figtype, ext, MJD, dateStr, LSI, ConfInd, hours, minutes); -                                printbuf(desc, indent+1, NULL, 0); -                            } -                        } -                        break; -                    case 11: // FIG 0/11 Region definition -                        {    // ETSI EN 300 401 8.1.16.1 -                            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 tmpbuf[256]; -                            bool GE_flag; - -                            while (i < (figlen - 1)) { -                                // iterate over Region definition -                                GATy = f[i] >> 4; -                                GE_flag = (f[i] >> 3) & 0x01; -                                Region_Id = ((uint16_t)(f[i] & 0x07) << 8) | ((uint16_t)f[i+1]); -                                key = ((uint16_t)oe << 12) | ((uint16_t)pd << 11) | Region_Id; -                                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); -                                    if (i < figlen) { -                                        Rfu = f[i] >> 5; -                                        if (Rfu != 0) { -                                            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                            strcat(desc, tmpbuf); -                                        } -                                        Length_TII_list = f[i] & 0x1F; -                                        sprintf(tmpbuf, ", Length of TII list=%d", Length_TII_list); -                                        strcat(desc, tmpbuf); -                                        if (Length_TII_list == 0) { -                                            strcat(desc, ", CEI"); -                                        } -                                        printbuf(desc, indent+1, NULL, 0); -                                        i++; - -                                        for(j = 0;(i < (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); -                                            } -                                            else { -                                                sprintf(desc, "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); -                                                } -                                            } -                                            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); -                                                } -                                            } -                                            Rfa = f[i+1] >> 5; -                                            if (Rfa != 0) { -                                                sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                                strcat(desc, tmpbuf); -                                            } -                                            Length_SubId_list = f[i+1] & 0x1F; -                                            sprintf(tmpbuf, ", Length of SubId=%d", Length_SubId_list); -                                            strcat(desc, tmpbuf); -                                            printbuf(desc, indent+2, NULL, 0); -                                            i += 2; - -                                            bit_pos = 3; -                                            SubId = 0; -                                            for(k = 0;(i < figlen) && (k < Length_SubId_list); k++) { -                                                // iterate SubId -                                                if (bit_pos >= 0) { -                                                    SubId |= (f[i] >> bit_pos) & 0x1F; -                                                    sprintf(desc, "SubId=0x%X", SubId); -                                                    // check SubId value -                                                    if ((SubId == 0) || (SubId > 23)) { -                                                        strcat(desc, " invalid value"); -                                                    } -                                                    printbuf(desc, indent+3, NULL, 0); -                                                    bit_pos -= 5; -                                                    SubId = 0; -                                                } -                                                if (bit_pos < 0) { -                                                    SubId = (f[i] << abs(bit_pos)) & 0x1F; -                                                    bit_pos += 8; -                                                    i++; -                                                } -                                            } -                                            if (bit_pos > 3) { -                                                // jump padding -                                                i++; -                                            } -                                            if (k < Length_SubId_list) { -                                                sprintf(desc, "%d SubId missing, fig length too short !", (Length_SubId_list - k)); -                                                printbuf(desc, indent+3, NULL, 0); -                                                fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                            } -                                        } -                                        if (j < Length_TII_list) { -                                            sprintf(desc, "%d Transmitter group missing, fig length too short !", (Length_TII_list - j)); -                                            printbuf(desc, indent+2, NULL, 0); -                                            fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                        } -                                    } -                                } -                                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); -                                    if (i < (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); -                                        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); -                                    } -                                    else { -                                        sprintf(tmpbuf, ", Coordinates missing, fig length too short !"); -                                        strcat(desc, tmpbuf); -                                        fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                    } -                                    printbuf(desc, indent+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, figlen); -                                    printbuf(desc, indent+1, NULL, 0); -                                    // stop Region definition iteration -                                    i = figlen; -                                } -                            } -                        } -                        break; -                    case 13: // FIG 0/13 User application information -                        {    // ETSI EN 300 401 8.1.20 -                            uint32_t SId; -                            uint8_t  SCIdS; -                            uint8_t  No; - -                            int k = 1; - -                            if (pd == 0) { // Programme services, 16 bit SId -                                SId   = (f[k] << 8) | -                                         f[k+1]; -                                k+=2; - -                                SCIdS = f[k] >> 4; -                                No    = f[k] & 0x0F; -                                k++; -                            } -                            else { // Data services, 32 bit SId -                                SId   = (f[k]   << 24) | -                                        (f[k+1] << 16) | -                                        (f[k+2] << 8) | -                                         f[k+3]; -                                k+=4; - -                                SCIdS = f[k] >> 4; -                                No    = f[k] & 0x0F; -                                k++; - -                            } - -                            sprintf(desc, "FIG %d/%d: SId=0x%X SCIdS=%u No=%u", -                                    figtype, ext, SId, SCIdS, No); -                            printbuf(desc, indent+1, NULL, 0); - -                            for (int numapp = 0; numapp < No; numapp++) { -                                uint16_t user_app_type = ((f[k] << 8) | -                                                         (f[k+1] & 0xE0)) >> 5; -                                uint8_t  user_app_len  = f[k+1] & 0x1F; -                                k+=2; - -                                sprintf(desc, "User Application %d '%s'; length %u", -                                        user_app_type, -                                        get_fig_0_13_userapp(user_app_type).c_str(), -                                        user_app_len); -                                printbuf(desc, indent+2, NULL, 0); -                            } -                        } -                        break; -                    case 14: // FIG 0/14 FEC sub-channel organization -                        {    // ETSI EN 300 401 6.2.2 -                            uint8_t i = 1, SubChId, FEC_scheme; - -                            while (i < figlen) { -                                // iterate over Sub-channel -                                SubChId = f[i] >> 2; -                                FEC_scheme = f[i] & 0x3; -                                sprintf(desc, "SubChId=0x%X, FEC scheme=%d %s", -                                        SubChId, FEC_scheme, FEC_schemes_str[FEC_scheme]); -                                printbuf(desc, indent+1, NULL, 0); -                                i++; -                            } -                        } -                        break; -                    case 16: // FIG 0/16 Programme Number & OE Programme Number -                        {    // ETSI EN 300 401 8.1.4 & 8.1.10.3 -                            uint16_t SId, PNum, New_SId, New_PNum; -                            uint8_t i = 1, Rfa, Rfu; -                            char tmpbuf[256]; -                            bool Continuation_flag, Update_flag; - -                            while (i < (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]); -                                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); - -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } - -                                if (Rfu != 0) { -                                    sprintf(tmpbuf, ", Rfu=0x%X invalid value", Rfu); -                                    strcat(desc, tmpbuf); -                                } - -                                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); -                                i += 5; - -                                if (Update_flag != 0) { -                                    // In the case of a re-direction, the New SId and New PNum shall be appended -                                    if (i < (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); -                                        if (i < (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); -                                        } -                                        else { -                                            sprintf(tmpbuf, ", missing New PNum !"); -                                            strcat(desc, tmpbuf); -                                        } -                                    } -                                    else { -                                        sprintf(tmpbuf, ", missing New SId and New PNum !"); -                                        strcat(desc, tmpbuf); -                                    } -                                    i += 4; -                                } - -                                printbuf(desc, indent+1, NULL, 0); -                            } -                        } -                        break; -                    case 17: // FIG 0/17 Programme Type -                        {    // ETSI EN 300 401 8.1.5 -                            uint16_t SId; -                            uint8_t i = 1, Rfa, Language, Int_code, Comp_code; -                            char tmpbuf[256]; -                            bool SD_flag, PS_flag, L_flag, CC_flag, Rfu; -                            while (i < (figlen - 3)) { -                                // iterate over announcement support -                                SId = (f[i] << 8) | f[i+1]; -                                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"); -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                i += 3; -                                if (L_flag != 0) { -                                    if (i < figlen) { -                                        Language = f[i]; -                                        sprintf(tmpbuf, ", Language=0x%X %s", Language, -                                                fig0_5.Language_to_char(Language)); -                                        strcat(desc, tmpbuf); -                                    } -                                    else { -                                        sprintf(tmpbuf, ", Language= invalid FIG length"); -                                        strcat(desc, tmpbuf); -                                    } -                                    i++; -                                } -                                if (i < figlen) { -                                    Rfa = f[i] >> 6; -                                    Rfu = (f[i] >> 5) & 0x01; -                                    if (Rfa != 0) { -                                        sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); -                                        strcat(desc, tmpbuf); -                                    } -                                    if (Rfu != 0) { -                                        sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                        strcat(desc, tmpbuf); -                                    } -                                    Int_code = f[i] & 0x1F; -                                    sprintf(tmpbuf, ", Int code=0x%X %s", Int_code, get_programme_type_str(International_Table_Id , Int_code)); -                                    strcat(desc, tmpbuf); -                                    i++; -                                } -                                else { -                                    sprintf(tmpbuf, ", Int code= invalid FIG length"); -                                    strcat(desc, tmpbuf); -                                } -                                if (CC_flag != 0) { -                                    if (i < figlen) { -                                        Rfa = f[i] >> 6; -                                        Rfu = (f[i] >> 5) & 0x01; -                                        if (Rfa != 0) { -                                            sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); -                                            strcat(desc, tmpbuf); -                                        } -                                        if (Rfu != 0) { -                                            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                            strcat(desc, tmpbuf); -                                        } -                                        Comp_code = f[i] & 0x1F; -                                        sprintf(tmpbuf, ", Comp code=0x%X %s", Comp_code, get_programme_type_str(International_Table_Id , Comp_code)); -                                        strcat(desc, tmpbuf); -                                        i++; -                                    } -                                    else { -                                        sprintf(tmpbuf, ", Comp code= invalid FIG length"); -                                        strcat(desc, tmpbuf); -                                    } -                                } -                                printbuf(desc, indent+1, NULL, 0); -                            } -                        } -                        break; -                    case 18: // FIG 0/18 Announcement support -                        {    // ETSI EN 300 401 8.1.6.1 -                            uint32_t key; -                            uint16_t SId, Asu_flags; -                            uint8_t i = 1, j, Rfa, Number_clusters; -                            char tmpbuf[256]; - -                            while (i < (figlen - 4)) { -                                // iterate over announcement support -                                // SId, Asu flags, Rfa, Number of clusters -                                SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1]; -                                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); -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                sprintf(tmpbuf, ", Number of clusters=%d", Number_clusters); -                                strcat(desc, tmpbuf); -                                key = ((uint32_t)oe << 17) | ((uint32_t)pd << 16) | (uint32_t)SId; -                                sprintf(tmpbuf, ", database key=0x%05x", key); -                                strcat(desc, tmpbuf); -                                // CEI Change Event Indication -                                if ((Number_clusters == 0) && (Asu_flags == 0)) { -                                    sprintf(tmpbuf, ", CEI"); -                                    strcat(desc, tmpbuf); -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                i += 5; - -                                for(j = 0; (j < Number_clusters) && (i < figlen); j++) { -                                    // iterate over Cluster Id -                                    sprintf(desc, "Cluster Id=0x%X", f[i]); -                                    printbuf(desc, indent+2, NULL, 0); -                                    i++; -                                } -                                if (j < Number_clusters) { -                                    sprintf(desc, "missing Cluster Id, fig length too short !"); -                                    printbuf(desc, indent+1, NULL, 0); -                                    fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                } - -                                // decode announcement support types -                                for(j = 0; j < 16; j++) { -                                    if (Asu_flags & (1 << j)) { -                                        sprintf(desc, "Announcement support=%s", announcement_types_str[j]); -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } -                            } -                        } -                        break; -                    case 19: // FIG 0/19 Announcement switching -                        {    // ETSI EN 300 401 8.1.6.2 -                            uint16_t Asw_flags; -                            uint8_t i = 1, j, Cluster_Id, SubChId, Rfa, RegionId_LP; -                            char tmpbuf[256]; -                            bool New_flag, Region_flag; - -                            while (i < (figlen - 3)) { -                                // iterate over announcement switching -                                // Cluster Id, Asw flags, New flag, Region flag, -                                // SubChId, Rfa, Region Id Lower Part -                                Cluster_Id = f[i]; -                                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); -                                if (Region_flag) { -                                    if (i < (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); -                                        } -                                        sprintf(tmpbuf, ", Region Lower Part=0x%02x", RegionId_LP); -                                        strcat(desc, tmpbuf); -                                    } -                                    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, ext, figlen); -                                    } -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                // decode announcement switching types -                                for(j = 0; j < 16; j++) { -                                    if (Asw_flags & (1 << j)) { -                                        sprintf(desc, "Announcement switching=%s", announcement_types_str[j]); -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } -                                i += (4 + Region_flag); -                            } -                        } -                        break; -                    case 21: // FIG 0/21 Frequency Information -                        {    // ETSI EN 300 401 8.1.8 -                            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; -                            char tmpbuf[256]; -                            bool Continuity_flag; - -                            while (i < (figlen - 1)) { -                                // iterate over frequency information -                                // decode RegionId, Length of FI list -                                RegionId  =  (f[i] << 3) | (f[i+1] >> 5); -                                Length_FI_list  = (f[i+1] & 0x1F); -                                sprintf(desc, "RegionId=0x%03x", RegionId); -                                printbuf(desc, indent+1, NULL, 0); -                                i += 2; -                                if ((i + Length_FI_list) <= 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; -                                        sprintf(desc, "Id_field="); -                                        switch (RandM) { -                                            case 0x0: -                                            case 0x1: -                                                strcat(desc, "EId"); -                                                break; -                                            case 0x6: -                                                strcat(desc, "DRM Service Id"); -                                                break; -                                            case 0x8: -                                                strcat(desc, "RDS PI"); -                                                break; -                                            case 0x9: -                                            case 0xa: -                                            case 0xc: -                                                strcat(desc, "Dummy"); -                                                break; -                                            case 0xe: -                                                strcat(desc, "AMSS Service Id"); -                                                break; -                                            default: -                                                strcat(desc, "invalid"); -                                                break; -                                        } -                                        sprintf(tmpbuf, "=0x%X, R&M=0x%1x", Id_field, RandM); -                                        strcat(desc, tmpbuf); -                                        switch (RandM) { -                                            case 0x0: -                                                strcat(desc, "=DAB ensemble, no local windows"); -                                                break; -                                            case 0x6: -                                                strcat(desc, "=DRM"); -                                                break; -                                            case 0x8: -                                                strcat(desc, "=FM with RDS"); -                                                break; -                                            case 0x9: -                                                strcat(desc, "=FM without RDS"); -                                                break; -                                            case 0xa: -                                                strcat(desc, "=AM (MW in 9 kHz steps & LW)"); -                                                break; -                                            case 0xc: -                                                strcat(desc, "=AM (MW in 5 kHz steps & SW)"); -                                                break; -                                            case 0xe: -                                                strcat(desc, "=AMSS"); -                                                break; -                                            default: -                                                strcat(desc, "=Rfu"); -                                                break; -                                        } -                                        sprintf(tmpbuf, ", Continuity flag=%d", Continuity_flag); -                                        strcat(desc, tmpbuf); -                                        if ((oe == 0) || ((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"); -                                                        break; -                                                    case 0x6: -                                                        strcat(desc, "=no compensating time delay on DRM audio signal"); -                                                        break; -                                                    case 0x8: -                                                    case 0x9: -                                                        strcat(desc, "=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"); -                                                        break; -                                                    default: -                                                        strcat(desc, "=Rfu"); -                                                        break; -                                                } -                                            } -                                            else {  // Continuity_flag == 1 -                                                switch (RandM) { -                                                    case 0x0: -                                                    case 0x1: -                                                        strcat(desc, "=continuous output possible"); -                                                        break; -                                                    case 0x6: -                                                        strcat(desc, "=compensating time delay on DRM audio signal"); -                                                        break; -                                                    case 0x8: -                                                    case 0x9: -                                                        strcat(desc, "=compensating time delay on FM audio signal"); -                                                        break; -                                                    case 0xa: -                                                    case 0xc: -                                                    case 0xe: -                                                        strcat(desc, "=compensating time delay on AM audio signal"); -                                                        break; -                                                    default: -                                                        strcat(desc, "=Rfu"); -                                                        break; -                                                } -                                            } -                                        } -                                        else {  // oe == 1 -                                            strcat(desc, "=reserved for future addition"); -                                        } -                                        key = ((uint64_t)oe << 32) | ((uint64_t)pd << 31) | \ -                                                ((uint64_t)RegionId << 20) | ((uint64_t)Id_field << 4) | \ -                                                (uint64_t)RandM; -                                        sprintf(tmpbuf, ", database key=0x%09" PRId64, key); -                                        // CEI Change Event Indication -                                        if (Length_Freq_list == 0) { -                                            strcat(tmpbuf, ", CEI"); -                                        } -                                        strcat(desc, tmpbuf); -                                        printbuf(desc, indent+2, NULL, 0); -                                        j += 3; // add header - -                                        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) { -                                                            sprintf(desc, "%d KHz, ", ifreq); -                                                            if ((Control_field & 0x01) == 0) { -                                                                strcat(desc, "geographically adjacent area, "); -                                                            } -                                                            else {  // (Control_field & 0x01) == 1 -                                                                strcat(desc, "no geographically adjacent area, "); -                                                            } -                                                            if (Control_field_trans_mode == 0) { -                                                                strcat(desc, "no transmission mode signalled"); -                                                            } -                                                            else if (Control_field_trans_mode <= 4) { -                                                                sprintf(tmpbuf, "transmission mode %d", Control_field_trans_mode); -                                                                strcat(desc, tmpbuf); -                                                            } -                                                            else {  // Control_field_trans_mode > 4 -                                                                sprintf(tmpbuf, "invalid transmission mode 0x%x", Control_field_trans_mode); -                                                                strcat(desc, tmpbuf); -                                                            } -                                                        } -                                                        else {  // (Control_field & 0x10) == 0x10 -                                                            sprintf(desc, "%d KHz, invalid Control field b23 0x%x", ifreq, Control_field); -                                                        } -                                                    } -                                                    else { -                                                        sprintf(desc, "Frequency not to be used (0)"); -                                                    } -                                                    printbuf(desc, indent+3, NULL, 0); -                                                    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)); -                                                            } -                                                            sprintf(desc, "%d KHz", ifreq); -                                                        } -                                                        else {  // RandM == 8 or 9 -                                                            freq = (87.5 + ((float)f[k] * 0.1)); -                                                            sprintf(desc, "%.1f MHz", freq); -                                                        } -                                                    } -                                                    else { -                                                        sprintf(desc, "Frequency not to be used (0)"); -                                                    } -                                                    printbuf(desc, indent+3, NULL, 0); -                                                    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) { -                                                        sprintf(desc, "%d KHz", ifreq); -                                                    } -                                                    else { -                                                        sprintf(desc, "Frequency not to be used (0)"); -                                                    } -                                                    printbuf(desc, indent+3, NULL, 0); -                                                    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) { -                                                        sprintf(desc, "%d KHz", ifreq); -                                                    } -                                                    else { -                                                        sprintf(desc, "Frequency not to be used (0)"); -                                                    } -                                                    if (RandM == 0x6) { -                                                        sprintf(tmpbuf, ", DRM Service Id 0x%X", Id_field2); -                                                        strcat(desc, tmpbuf); -                                                    } -                                                    else if (RandM == 0xe) { -                                                        sprintf(tmpbuf, ", AMSS Service Id 0x%X", Id_field2); -                                                        strcat(desc, tmpbuf); -                                                    } -                                                    if ((f[k+1] & 0x80) == 0x80) { -                                                        sprintf(tmpbuf, ", invalid Rfu b15 set to 1 instead of 0"); -                                                        strcat(desc, tmpbuf); -                                                    } -                                                    printbuf(desc, indent+3, NULL, 0); -                                                    k += 3; -                                                } -                                                break; -                                            default: -                                                break; -                                        } -                                        j += Length_Freq_list; -                                    } -                                    i += Length_FI_list; -                                } -                            } -                        } -                        break; -                    case 22: // FIG 0/22 Transmitter Identification Information (TII) database -                        {    // ETSI EN 300 401 8.1.9 -                            Lat_Lng gps_pos = {0, 0}; -                            double latitude_sub, longitude_sub; -                            int16_t Latitude_coarse, Longitude_coarse; -                            uint16_t key, TD; -                            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]; -                            bool MS; - -                            while (i < figlen) { -                                // iterate over Transmitter Identification Information (TII) fields -                                MS = f[i] >> 7; -                                MainId = f[i] & 0x7F; -                                key = (oe << 8) | (pd << 7) | MainId; -                                sprintf(desc, "M/S=%d %sidentifier, MainId=0x%X", -                                        MS, MS?"Sub-":"Main ", 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); -                                    } -                                } -                                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); -                                    } -                                } -                                // print database key -                                sprintf(tmpbuf, ", database key=0x%X", key); -                                strcat(desc, tmpbuf); -                                i++; -                                if (MS == 0) { -                                    // Main identifier - -                                    if (i < (figlen - 4)) { -                                        Latitude_coarse = (f[i] << 8) | f[i+1]; -                                        Longitude_coarse = (f[i+2] << 8) | f[i+3]; -                                        Latitude_fine = f[i+4] >> 4; -                                        Longitude_fine = f[i+4] & 0x0F; -                                        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", -                                                Latitude_coarse, Longitude_coarse, Latitude_fine, Longitude_fine, -                                                gps_pos.latitude, gps_pos.longitude); -                                        strcat(desc, tmpbuf); -                                        i += 5; -                                    } -                                    else { -                                        strcat(desc, ", invalid length of Latitude Longitude coarse fine"); -                                    } -                                    printbuf(desc, indent+1, NULL, 0); -                                } -                                else {  // MS == 1 -                                    // Sub-identifier - -                                    if (i < figlen) { -                                        Rfu = f[i] >> 3; -                                        Nb_SubId_fields = f[i] & 0x07; -                                        if (Rfu != 0) { -                                            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                            strcat(desc, tmpbuf); -                                        } -                                        sprintf(tmpbuf, ", Number of SubId fields=%d%s", -                                                Nb_SubId_fields, (Nb_SubId_fields == 0)?", CEI":""); -                                        strcat(desc, tmpbuf); -                                        printbuf(desc, indent+1, NULL, 0); -                                        i++; - -                                        for(j = i; ((j < (i + (Nb_SubId_fields * 6))) && (j < (figlen - 5))); j += 6) { -                                            // iterate over SubId fields -                                            SubId = f[j] >> 3; -                                            sprintf(desc, "SubId=0x%X", SubId); -                                            // check SubId value -                                            if ((SubId == 0) || (SubId > 23)) { -                                                strcat(desc, " 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); - -                                            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); -                                            } -                                            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); -                                            } -                                            printbuf(desc, indent+2, NULL, 0); -                                        } -                                        i += (Nb_SubId_fields * 6); -                                    } -                                    else { -                                        strcat(desc, ", invalid fig length or Number of SubId fields length"); -                                        printbuf(desc, indent+1, NULL, 0); -                                    } -                                } -                            } -                        } -                        break; -                    case 24: // FIG 0/24 OE Services -                        {    // ETSI EN 300 401 8.1.10.2 -                            uint64_t key; -                            uint32_t SId; -                            uint16_t EId; -                            uint8_t i = 1, j, Number_of_EIds, CAId; -                            char tmpbuf[256]; -                            bool Rfa; - -                            while (i < (figlen - (((uint8_t)pd + 1) * 2))) { -                                // iterate over other ensembles services -                                if (pd == 0) { -                                    SId = ((uint32_t)f[i] << 8) | (uint32_t)f[i+1]; -                                    i += 2; -                                } -                                else {  // pd == 1 -                                    SId = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | -                                            ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; -                                    i += 4; -                                } -                                Rfa  =  (f[i] >> 7); -                                CAId  = (f[i] >> 4); -                                Number_of_EIds  = (f[i] & 0x0f); -                                key = ((uint64_t)oe << 33) | ((uint64_t)pd << 32) | \ -                                        (uint64_t)SId; -                                if (pd == 0) { -                                    sprintf(desc, "SId=0x%X, CAId=%d, Number of EId=%d, database key=%09" PRId64, SId, CAId, Number_of_EIds, key); -                                } -                                else {  // pd == 1 -                                    sprintf(desc, "SId=0x%X, CAId=%d, Number of EId=%d, database key=%09" PRId64, SId, CAId, Number_of_EIds, key); -                                } -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                // CEI Change Event Indication -                                if (Number_of_EIds == 0) { -                                    sprintf(tmpbuf, ", CEI"); -                                    strcat(desc, tmpbuf); -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                i++; - -                                for(j = i; ((j < (i + (Number_of_EIds * 2))) && (j < 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, indent+2, NULL, 0); -                                } -                                i += (Number_of_EIds * 2); -                            } -                        } -                        break; -                    case 25: // FIG 0/25 OE Announcement support -                        {    // ETSI EN 300 401 8.1.10.5.1 -                            uint32_t key; -                            uint16_t SId, Asu_flags, EId; -                            uint8_t i = 1, j, Rfu, Number_EIds; -                            char tmpbuf[256]; - -                            while (i < (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]; -                                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); -                                if (Rfu != 0) { -                                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                    strcat(desc, tmpbuf); -                                } -                                sprintf(tmpbuf, ", Number of EIds=%d", Number_EIds); -                                strcat(desc, tmpbuf); -                                key = ((uint32_t)oe << 17) | ((uint32_t)pd << 16) | (uint32_t)SId; -                                sprintf(tmpbuf, ", database key=0x%05x", key); -                                strcat(desc, tmpbuf); -                                // CEI Change Event Indication -                                if (Number_EIds == 0) { -                                    sprintf(tmpbuf, ", CEI"); -                                    strcat(desc, tmpbuf); -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                i += 5; - -                                for(j = 0; (j < Number_EIds) && (i < (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, indent+2, NULL, 0); -                                    i += 2; -                                } -                                if (j < Number_EIds) { -                                    sprintf(desc, "missing EId, fig length too short !"); -                                    printbuf(desc, indent+1, NULL, 0); -                                    fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                } - -                                // decode OE announcement support types -                                for(j = 0; j < 16; j++) { -                                    if (Asu_flags & (1 << j)) { -                                        sprintf(desc, "OE Announcement support=%s", announcement_types_str[j]); -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } -                            } -                        } -                        break; -                    case 26: // FIG 0/26 OE Announcement switching -                        {    // ETSI EN 300 401 8.1.10.5.2 -                            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]; - -                            while (i < (figlen - 6)) { -                                // iterate over other ensembles announcement switching -                                Cluster_Id_Current_Ensemble = f[i]; -                                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); -                                i += 7; -                                if (Region_flag != 0) { -                                    if (i < figlen) { -                                        // get Region Id Other Ensemble -                                        Rfa = (f[i] >> 6); -                                        Region_Id_Other_Ensemble = f[i] & 0x3F; -                                        if (Rfa != 0) { -                                            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                            strcat(desc, tmpbuf); -                                        } -                                        sprintf(tmpbuf, ", Region Id Other Ensemble=0x%X", Region_Id_Other_Ensemble); -                                        strcat(desc, tmpbuf); -                                    } -                                    else { -                                        sprintf(tmpbuf, "missing Region Id Other Ensemble, fig length too short !"); -                                        strcat(desc, tmpbuf); -                                        fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                    } -                                    i++; -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                // decode announcement switching types -                                for(j = 0; j < 16; j++) { -                                    if (Asw_flags & (1 << j)) { -                                        sprintf(desc, "Announcement switching=%s", announcement_types_str[j]); -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } -                            } -                        } -                        break; -                    case 27: // FIG 0/27 FM Announcement support -                        {    // ETSI EN 300 401 8.1.11.2.1 -                            uint16_t SId, PI; -                            uint8_t i = 1, j, Rfu, Number_PI_codes, key; -                            char tmpbuf[256]; - -                            while (i < (figlen - 2)) { -                                // iterate over FM announcement support -                                SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1]; -                                Rfu = f[i+2] >> 4; -                                Number_PI_codes = f[i+2] & 0x0F; -                                key = (oe << 5) | (pd << 4) | Number_PI_codes; -                                sprintf(desc, "SId=0x%X", SId); -                                if (Rfu != 0) { -                                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); -                                    strcat(desc, tmpbuf); -                                } -                                sprintf(tmpbuf, ", Number of PI codes=%d", Number_PI_codes); -                                strcat(desc, tmpbuf); -                                if (Number_PI_codes > 12) { -                                    strcat(desc, " above maximum value of 12"); -                                    fprintf(stderr, "WARNING: FIG %d/%d Number of PI codes=%d > 12 (maximum value)\n", figtype, ext, Number_PI_codes); -                                } -                                sprintf(tmpbuf, ", database key=0x%02X", key); -                                strcat(desc, tmpbuf); -                                // 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"); -                                } -                                printbuf(desc, indent+1, NULL, 0); -                                i += 3; -                                for(j = 0; (j < Number_PI_codes) && (i < (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, indent+2, NULL, 0); -                                    i += 2; -                                } -                                if (j != Number_PI_codes) { -                                    sprintf(desc, "fig length too short !"); -                                    printbuf(desc, indent+2, NULL, 0); -                                    fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, ext, figlen); -                                } -                            } -                        } -                        break; -                    case 28: // FIG 0/28 FM Announcement switching -                        {    // ETSI EN 300 401 8.1.11.2.2 -                            uint16_t PI; -                            uint8_t i = 1, Cluster_Id_Current_Ensemble, Region_Id_Current_Ensemble; -                            bool New_flag, Rfa; -                            char tmpbuf[256]; - -                            while (i < (figlen - 3)) { -                                // iterate over FM announcement switching -                                Cluster_Id_Current_Ensemble = f[i]; -                                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); -                                if (Cluster_Id_Current_Ensemble == 0) { -                                    strcat(desc, " invalid value"); -                                    fprintf(stderr, "WARNING: FIG %d/%d Cluster Id Current Ensemble invalid value 0\n", figtype, ext); -                                } -                                sprintf(tmpbuf, ", New flag=%d %s announcement", -                                        New_flag, New_flag?"newly introduced":"repeated"); -                                strcat(desc, tmpbuf); -                                if (Rfa != 0) { -                                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); -                                    strcat(desc, tmpbuf); -                                } -                                sprintf(tmpbuf, ", Region Id Current Ensemble=0x%X, PI=0x%X", Region_Id_Current_Ensemble, PI); -                                strcat(desc, tmpbuf); -                                printbuf(desc, indent+1, NULL, 0); -                                i += 4; -                            } -                        } -                        break; -                    case 31: // FIG 0/31 FIC re-direction -                        {    // ETSI EN 300 401 8.1.12 -                            uint32_t FIG_type0_flag_field = 0, flag_field; -                            uint8_t i = 1, j, FIG_type1_flag_field = 0, FIG_type2_flag_field = 0; - -                            if (i < (figlen - 5)) { -                                // Read FIC re-direction -                                FIG_type0_flag_field = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | -                                                       ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; -                                FIG_type1_flag_field = f[i+4]; -                                FIG_type2_flag_field = f[i+5]; - -                                sprintf(desc, "FIG type 0 flag field=0x%X, FIG type 1 flag field=0x%X, FIG type 2 flag field=0x%X", -                                        FIG_type0_flag_field, FIG_type1_flag_field, FIG_type2_flag_field); -                                printbuf(desc, indent+1, NULL, 0); - -                                for(j = 0; j < 32; j++) { -                                    // iterate over FIG type 0 re-direction -                                    flag_field = FIG_type0_flag_field & ((uint32_t)1 << j); -                                    if ((flag_field != 0) && ((j <= 5) || (j == 8) || -                                        (j == 10) || (j == 13) || (j == 14) || -                                        (j == 19) || (j == 26) || (j == 28))) { -                                        sprintf(desc, "oe=%d FIG 0/%d carried in AIC, invalid configuration, shall always be carried entirely in the FIC", -                                                oe, j); -                                        printbuf(desc, indent+2, NULL, 0); -                                        fprintf(stderr, "WARNING: FIG %d/%d FIG re-direction of oe=%d FIG0/%d not allowed\n", figtype, ext, oe, j); -                                    } -                                    else if ((flag_field != 0) && ((j == 21) || (j == 24))) { -                                        sprintf(desc, "oe=%d FIG 0/%d carried in AIC, same shall be carried in FIC", oe, j); -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                    else if (flag_field != 0) { -                                        if (oe == 0) { -                                            sprintf(desc, "oe=%d FIG 0/%d carried in AIC, same shall be carried in FIC", oe, j); -                                        } -                                        else {  // oe == 1 -                                            sprintf(desc, "oe=%d FIG 0/%d carried in AIC, may be carried entirely in AIC", oe, j); -                                        } -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } - -                                for(j = 0; j < 8; j++) { -                                    // iterate over FIG type 1 re-direction -                                    flag_field = FIG_type1_flag_field & ((uint32_t)1 << j); -                                    if (flag_field != 0) { -                                        if (oe == 0) { -                                            sprintf(desc, "oe=%d FIG 1/%d carried in AIC, same shall be carried in FIC", oe, j); -                                        } -                                        else {  // oe == 1 -                                            sprintf(desc, "oe=%d FIG 1/%d carried in AIC, may be carried entirely in AIC", oe, j); -                                        } -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } - -                                for(j = 0; j < 8; j++) { -                                    // iterate over FIG type 2 re-direction -                                    flag_field = FIG_type2_flag_field & ((uint32_t)1 << j); -                                    if (flag_field != 0) { -                                        if (oe == 0) { -                                            sprintf(desc, "oe=%d FIG 2/%d carried in AIC, same shall be carried in FIC", oe, j); -                                        } -                                        else {  // oe == 1 -                                            sprintf(desc, "oe=%d FIG 2/%d carried in AIC, may be carried entirely in AIC", oe, j); -                                        } -                                        printbuf(desc, indent+2, NULL, 0); -                                    } -                                } -                            } -                            if (figlen != 7) { -                                fprintf(stderr, "WARNING: FIG %d/%d invalid length %d, expecting 7\n", figtype, ext, figlen); -                            } -                        } -                        break; -                } +                fig0_select(fig0, indent);              }              break; @@ -3033,131 +853,4 @@ void decodeFIG(FIGalyser &figs,      }  } -// get_programme_type_str return the programme type string from international table Id and programme type -const char *get_programme_type_str(size_t int_table_Id, size_t pty) { -    if ((int_table_Id - 1) < INTERNATIONAL_TABLE_SIZE) { -       if (pty < PROGRAMME_TYPE_CODES_SIZE) { -           return Programme_type_codes_str[int_table_Id - 1][pty]; -       } -       else { -           return "invalid programme type"; -       } -    } -    else { -        return "unknown international table Id"; -    } -} - -// strcatPNum decode Programme_Number into string and append it to dest_str -// 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) { -    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); -    } -    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"); -        } -        else if ((hour == 0) && (minute == 1)) { -            sprintf(tempbuf, "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)"); -        } -        else { -            sprintf(tempbuf, "invalid value"); -        } -    } -    return strcat(dest_str, tempbuf); -} - -// sprintfMJD: convert MJD (Modified Julian Date) into date string -int sprintfMJD(char *dst, int mjd) { -    // EN 62106 Annex G -    // These formulas are applicable between the inclusive dates: 1st March 1900 to 28th February 2100 -    int y, m, k; -    struct tm timeDate; - -    memset(&timeDate, 0, sizeof(struct tm)); - -    // find Y, M, D from MJD -    y = (int)(((double)mjd - 15078.2) / 365.25); -    m = (int)(((double)mjd - 14956.1 - (int)((double)y * 365.25)) / 30.6001); -    timeDate.tm_mday = mjd - 14956 - (int)((double)y * 365.25) - (int)((double)m * 30.6001); -    if ((m == 14) || (m == 15)) { -        k = 1; -    } -    else { -        k = 0; -    } -    timeDate.tm_year = y + k; -    timeDate.tm_mon = (m - 1 - (k * 12)) - 1; - -    // find WD from MJD -    timeDate.tm_wday = (((mjd + 2) % 7) + 1) % 7; - -    //timeDate.tm_yday = 0; // Number of days since the first day of January not calculated -    timeDate.tm_isdst = -1; // No time print then information not available - -    // print date string -    if ((timeDate.tm_mday < 0) || (timeDate.tm_mon < 0) || (timeDate.tm_year < 0)) { -        return sprintf(dst, "invalid MJD mday=%d mon=%d year=%d", timeDate.tm_mday, timeDate.tm_mon, timeDate.tm_year); -    } -    return strftime(dst, 256, "%a %b %d %Y", &timeDate); -} - -void printinfo(string header, -        int indent_level, -        int min_verb) -{ -    if (verbosity >= min_verb) { -        for (int i = 0; i < indent_level; i++) { -            printf("\t"); -        } -        printf("%s\n", header.c_str()); -    } -} - -void printbuf(string header, -        int indent_level, -        uint8_t* buffer, -        size_t size, -        string desc) -{ -    if (verbosity > 0) { -        for (int i = 0; i < indent_level; i++) { -            printf("\t"); -        } - -        printf("%s", header.c_str()); - -        if (verbosity > 1) { -            if (size != 0) { -                printf(": "); -            } - -            for (size_t i = 0; i < size; i++) { -                printf("%02x ", buffer[i]); -            } -        } - -        if (desc != "") { -            printf(" [%s] ", desc.c_str()); -        } - -        printf("\n"); -    } -} - diff --git a/fig0_0.cpp b/fig0_0.cpp new file mode 100644 index 0000000..2b2b6a2 --- /dev/null +++ b/fig0_0.cpp @@ -0,0 +1,60 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> + +// FIG 0/0 Ensemble information +// ETSI EN 300 401 6.4 +void fig0_0(fig0_common_t& fig0, int indent) +{ +    uint8_t cid, al, ch, hic, lowc, occ; +    uint16_t eid, eref; +    char desc[128]; +    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]; +    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); +    } +    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, indent+1, NULL, 0); +} + diff --git a/fig0_1.cpp b/fig0_1.cpp new file mode 100644 index 0000000..791c0ec --- /dev/null +++ b/fig0_1.cpp @@ -0,0 +1,91 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> + +// FIG 0/1 Basic sub-channel organization +// ETSI EN 300 401 6.2.1 +void fig0_1(fig0_common_t& fig0, int indent) +{ +    int i = 1; +    uint8_t* f = fig0.f; +    char desc[128]; + +    while (i < fig0.figlen-3) { +        // iterate over subchannels +        int subch_id = f[i] >> 2; +        int start_addr = ((f[i] & 0x03) << 8) | +            (f[i+1]); +        int long_flag  = (f[i+2] >> 7); + +        if (long_flag) { +            int option = (f[i+2] >> 4) & 0x07; +            int protection_level = (f[i+2] >> 2) & 0x03; +            int subchannel_size  = ((f[i+2] & 0x03) << 8 ) | +                f[i+3]; + +            i += 4; + +            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); +            } +            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); +            } +            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); +            } +        } +        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); +            } + +            i += 3; +        } +        printbuf(desc, indent+1, NULL, 0); +    } + +} + diff --git a/fig0_10.cpp b/fig0_10.cpp new file mode 100644 index 0000000..c374ef9 --- /dev/null +++ b/fig0_10.cpp @@ -0,0 +1,72 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/10 Date and time +// ETSI EN 300 401 8.1.3.1 +void fig0_10(fig0_common_t& fig0, int indent) +{ +    char desc[256]; +    char dateStr[256]; +    dateStr[0] = 0; +    uint8_t* f = fig0.f; + +    //bool RFU = f[1] >> 7; + +    uint32_t MJD = (((uint32_t)f[1] & 0x7F) << 10)    | +                   ((uint32_t)(f[2]) << 2) | +                   (f[3] >> 6); +    sprintfMJD(dateStr, MJD); + +    bool LSI = f[3] & 0x20; +    bool ConfInd = f[3] & 0x10; +    fig0.wm_decoder.push_confind_bit(ConfInd); +    bool UTC = f[3] & 0x8; + +    uint8_t hours = ((f[3] & 0x7) << 2) | +                    ( f[4] >> 6); + +    uint8_t minutes = f[4] & 0x3f; + +    if (UTC) { +        uint8_t seconds = f[5] >> 2; +        uint16_t milliseconds = ((uint16_t)(f[5] & 0x2) << 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, indent+1, NULL, 0); +    } +    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, indent+1, NULL, 0); +    } +} + diff --git a/fig0_11.cpp b/fig0_11.cpp new file mode 100644 index 0000000..cc6bead --- /dev/null +++ b/fig0_11.cpp @@ -0,0 +1,185 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/11 Region definition +// ETSI EN 300 401 8.1.16.1 +void fig0_11(fig0_common_t& fig0, int indent) +{ +    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]; +    bool GE_flag; +    uint8_t* f = fig0.f; +    uint8_t Mode_Identity = get_mode_identity(); + +    while (i < (fig0.figlen - 1)) { +        // iterate over Region definition +        GATy = f[i] >> 4; +        GE_flag = (f[i] >> 3) & 0x01; +        Region_Id = ((uint16_t)(f[i] & 0x07) << 8) | ((uint16_t)f[i+1]); +        key = ((uint16_t)fig0.oe() << 12) | ((uint16_t)fig0.pd() << 11) | Region_Id; +        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); +            if (i < fig0.figlen) { +                Rfu = f[i] >> 5; +                if (Rfu != 0) { +                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +                    strcat(desc, tmpbuf); +                } +                Length_TII_list = f[i] & 0x1F; +                sprintf(tmpbuf, ", Length of TII list=%d", Length_TII_list); +                strcat(desc, tmpbuf); +                if (Length_TII_list == 0) { +                    strcat(desc, ", CEI"); +                } +                printbuf(desc, indent+1, NULL, 0); +                i++; + +                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); +                    } +                    else { +                        sprintf(desc, "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); +                        } +                    } +                    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); +                        } +                    } +                    Rfa = f[i+1] >> 5; +                    if (Rfa != 0) { +                        sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +                        strcat(desc, tmpbuf); +                    } +                    Length_SubId_list = f[i+1] & 0x1F; +                    sprintf(tmpbuf, ", Length of SubId=%d", Length_SubId_list); +                    strcat(desc, tmpbuf); +                    printbuf(desc, indent+2, NULL, 0); +                    i += 2; + +                    bit_pos = 3; +                    SubId = 0; +                    for(k = 0;(i < fig0.figlen) && (k < Length_SubId_list); k++) { +                        // iterate SubId +                        if (bit_pos >= 0) { +                            SubId |= (f[i] >> bit_pos) & 0x1F; +                            sprintf(desc, "SubId=0x%X", SubId); +                            // check SubId value +                            if ((SubId == 0) || (SubId > 23)) { +                                strcat(desc, " invalid value"); +                            } +                            printbuf(desc, indent+3, NULL, 0); +                            bit_pos -= 5; +                            SubId = 0; +                        } +                        if (bit_pos < 0) { +                            SubId = (f[i] << abs(bit_pos)) & 0x1F; +                            bit_pos += 8; +                            i++; +                        } +                    } +                    if (bit_pos > 3) { +                        // jump padding +                        i++; +                    } +                    if (k < Length_SubId_list) { +                        sprintf(desc, "%d SubId missing, fig length too short !", (Length_SubId_list - k)); +                        printbuf(desc, indent+3, NULL, 0); +                        fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); +                    } +                } +                if (j < Length_TII_list) { +                    sprintf(desc, "%d Transmitter group missing, fig length too short !", (Length_TII_list - j)); +                    printbuf(desc, indent+2, NULL, 0); +                    fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); +                } +            } +        } +        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); +            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); +                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); +            } +            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); +            } +            printbuf(desc, indent+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, indent+1, NULL, 0); +            // stop Region definition iteration +            i = fig0.figlen; +        } +    } +} diff --git a/fig0_13.cpp b/fig0_13.cpp new file mode 100644 index 0000000..113bb49 --- /dev/null +++ b/fig0_13.cpp @@ -0,0 +1,101 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +std::string get_fig_0_13_userapp(int user_app_type) +{ +    switch (user_app_type) { +        case 0x000: return "Reserved for future definition"; +        case 0x001: return "Not used"; +        case 0x002: return "MOT Slideshow"; +        case 0x003: return "MOT Broadacst Web Site"; +        case 0x004: return "TPEG"; +        case 0x005: return "DGPS"; +        case 0x006: return "TMC"; +        case 0x007: return "EPG"; +        case 0x008: return "DAB Java"; +        case 0x44a: return "Journaline"; +        default: return "Reserved for future applications"; +    } +} + +// FIG 0/13 User application information +// ETSI EN 300 401 8.1.20 +void fig0_13(fig0_common_t& fig0, int indent) +{ +    uint32_t SId; +    uint8_t  SCIdS; +    uint8_t  No; +    uint8_t* f = fig0.f; +    const int figtype = 0; +    char desc[256]; + +    int k = 1; + +    if (fig0.pd() == 0) { // Programme services, 16 bit SId +        SId  = (f[k] << 8) | +                f[k+1]; +        k+=2; + +        SCIdS = f[k] >> 4; +        No    = f[k] & 0x0F; +        k++; +    } +    else { // Data services, 32 bit SId +        SId   = (f[k]   << 24) | +            (f[k+1] << 16) | +            (f[k+2] << 8) | +            f[k+3]; +        k+=4; + +        SCIdS = f[k] >> 4; +        No    = f[k] & 0x0F; +        k++; + +    } + +    sprintf(desc, "FIG %d/%d: SId=0x%X SCIdS=%u No=%u", +            figtype, fig0.ext(), SId, SCIdS, No); +    printbuf(desc, indent+1, NULL, 0); + +    for (int numapp = 0; numapp < No; numapp++) { +        uint16_t user_app_type = ((f[k] << 8) | +                (f[k+1] & 0xE0)) >> 5; +        uint8_t  user_app_len  = f[k+1] & 0x1F; +        k+=2; + +        sprintf(desc, "User Application %d '%s'; length %u", +                user_app_type, +                get_fig_0_13_userapp(user_app_type).c_str(), +                user_app_len); +        printbuf(desc, indent+2, NULL, 0); +    } +} + diff --git a/fig0_14.cpp b/fig0_14.cpp new file mode 100644 index 0000000..8d63cae --- /dev/null +++ b/fig0_14.cpp @@ -0,0 +1,59 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// fig 0/14 FEC Scheme: this 2-bit field shall indicate the Forward Error Correction scheme in use, as follows: +const char *FEC_schemes_str[4] =  { +    "no FEC scheme applied", +    "FEC scheme applied according to ETSI EN 300 401 clause 5.3.5", +    "reserved for future definition", +    "reserved for future definition" +}; + + +// FIG 0/14 FEC sub-channel organization +// ETSI EN 300 401 6.2.2 +void fig0_14(fig0_common_t& fig0, int indent) +{ +    uint8_t i = 1, SubChId, FEC_scheme; +    uint8_t* f = fig0.f; +    char desc[256]; + +    while (i < fig0.figlen) { +        // iterate over Sub-channel +        SubChId = f[i] >> 2; +        FEC_scheme = f[i] & 0x3; +        sprintf(desc, "SubChId=0x%X, FEC scheme=%d %s", +                SubChId, FEC_scheme, FEC_schemes_str[FEC_scheme]); +        printbuf(desc, indent+1, NULL, 0); +        i++; +    } +} + diff --git a/fig0_16.cpp b/fig0_16.cpp new file mode 100644 index 0000000..aee7d10 --- /dev/null +++ b/fig0_16.cpp @@ -0,0 +1,100 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/16 Programme Number & fig0.oe() Programme Number +// ETSI EN 300 401 8.1.4 & 8.1.10.3 +void fig0_16(fig0_common_t& fig0, int indent) +{ +    uint16_t SId, PNum, New_SId, New_PNum; +    uint8_t i = 1, Rfa, Rfu; +    char tmpbuf[256]; +    char desc[256]; +    bool Continuation_flag, Update_flag; +    uint8_t* f = fig0.f; + +    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]); +        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); + +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } + +        if (Rfu != 0) { +            sprintf(tmpbuf, ", Rfu=0x%X invalid value", Rfu); +            strcat(desc, tmpbuf); +        } + +        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); +        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); +                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); +                } +                else { +                    sprintf(tmpbuf, ", missing New PNum !"); +                    strcat(desc, tmpbuf); +                } +            } +            else { +                sprintf(tmpbuf, ", missing New SId and New PNum !"); +                strcat(desc, tmpbuf); +            } +            i += 4; +        } + +        printbuf(desc, indent+1, NULL, 0); +    } +} + diff --git a/fig0_17.cpp b/fig0_17.cpp new file mode 100644 index 0000000..264d151 --- /dev/null +++ b/fig0_17.cpp @@ -0,0 +1,117 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/17 Programme Type +// ETSI EN 300 401 8.1.5 +void fig0_17(fig0_common_t& fig0, int indent) +{ +    uint16_t SId; +    uint8_t i = 1, Rfa, Language, Int_code, Comp_code; +    char tmpbuf[256]; +    char desc[256]; +    bool SD_flag, PS_flag, L_flag, CC_flag, Rfu; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 3)) { +        // iterate over announcement support +        SId = (f[i] << 8) | f[i+1]; +        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"); +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=0x%X invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        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); +            } +            else { +                sprintf(tmpbuf, ", Language= invalid FIG length"); +                strcat(desc, tmpbuf); +            } +            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); +            } +            if (Rfu != 0) { +                sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +                strcat(desc, tmpbuf); +            } +            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); +            i++; +        } +        else { +            sprintf(tmpbuf, ", Int code= invalid FIG length"); +            strcat(desc, tmpbuf); +        } +        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); +                } +                if (Rfu != 0) { +                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +                    strcat(desc, tmpbuf); +                } +                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); +                i++; +            } +            else { +                sprintf(tmpbuf, ", Comp code= invalid FIG length"); +                strcat(desc, tmpbuf); +            } +        } +        printbuf(desc, indent+1, NULL, 0); +    } +} + diff --git a/fig0_18.cpp b/fig0_18.cpp new file mode 100644 index 0000000..c7d7f8a --- /dev/null +++ b/fig0_18.cpp @@ -0,0 +1,91 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/18 Announcement support +// ETSI EN 300 401 8.1.6.1 +void fig0_18(fig0_common_t& fig0, int indent) +{ +    uint32_t key; +    uint16_t SId, Asu_flags; +    uint8_t i = 1, j, Rfa, Number_clusters; +    char tmpbuf[256]; +    char desc[256]; +    uint8_t* f = fig0.f; +    const int figtype = 0; + +    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]; +        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); +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        sprintf(tmpbuf, ", Number of clusters=%d", Number_clusters); +        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); +        // CEI Change Event Indication +        if ((Number_clusters == 0) && (Asu_flags == 0)) { +            sprintf(tmpbuf, ", CEI"); +            strcat(desc, tmpbuf); +        } +        printbuf(desc, indent+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, indent+2, NULL, 0); +            i++; +        } +        if (j < Number_clusters) { +            sprintf(desc, "missing Cluster Id, fig length too short !"); +            printbuf(desc, indent+1, NULL, 0); +            fprintf(stderr, "WARNING: FIG %d/%d length %d too short !\n", figtype, fig0.ext(), fig0.figlen); +        } + +        // decode announcement support types +        for(j = 0; j < 16; j++) { +            if (Asu_flags & (1 << j)) { +                sprintf(desc, "Announcement support=%s", get_announcement_type(j)); +                printbuf(desc, indent+2, NULL, 0); +            } +        } +    } +} + diff --git a/fig0_19.cpp b/fig0_19.cpp new file mode 100644 index 0000000..1d3593e --- /dev/null +++ b/fig0_19.cpp @@ -0,0 +1,85 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/19 Announcement switching +// ETSI EN 300 401 8.1.6.2 +void fig0_19(fig0_common_t& fig0, int indent) +{ +    uint16_t Asw_flags; +    uint8_t i = 1, j, Cluster_Id, SubChId, Rfa, RegionId_LP; +    char tmpbuf[256]; +    char desc[256]; +    bool New_flag, Region_flag; +    uint8_t* f = fig0.f; +    const int figtype = 0; + +    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]; +        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); +        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); +                } +                sprintf(tmpbuf, ", Region Lower Part=0x%02x", RegionId_LP); +                strcat(desc, tmpbuf); +            } +            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); +            } +        } +        printbuf(desc, indent+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, indent+2, NULL, 0); +            } +        } +        i += (4 + Region_flag); +    } +} + diff --git a/fig0_2.cpp b/fig0_2.cpp new file mode 100644 index 0000000..29b52fa --- /dev/null +++ b/fig0_2.cpp @@ -0,0 +1,146 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <string> +#include <cstring> + +// FIG 0/2 Basic service and service component definition +// ETSI EN 300 401 6.3.1 +void fig0_2(fig0_common_t& fig0, int indent) +{ +    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]; + +    while (k < fig0.figlen) { +        if (fig0.pd() == 0) { +            sid  =  f[k] * 256 + f[k+1]; +            cid  = (f[k] & 0xF0) >> 4; +            sref = (f[k] & 0x0F) * 256 + f[k+1]; +            k += 2; +        } +        else { +            sid  =  f[k] * 256 * 256 * 256 + \ +                    f[k+1] * 256 * 256 + \ +                    f[k+2] * 256 + \ +                    f[k+3]; + +            ecc  =  f[k]; +            cid  = (f[k+1] & 0xF0) >> 4; +            sref = (f[k+1] & 0x0F) * 256 * 256 + \ +                   f[k+2] * 256 + \ +                   f[k+3]; + +            k += 4; +        } + +        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, indent+1, NULL, 0); + +        k++; +        for (int i=0; i<ncomp; i++) { +            uint8_t scomp[2]; + +            memcpy(scomp, f+k, 2); +            sprintf(desc, "Component[%d]", i); +            printbuf(desc, indent+2, scomp, 2, ""); +            timd    = (scomp[0] & 0xC0) >> 6; +            ps      = (scomp[1] & 0x02) >> 1; +            ca      =  scomp[1] & 0x01; +            scty    =  scomp[0] & 0x3F; +            subchid = (scomp[1] & 0xFC) >> 2; + +            /* useless, kept as reference +               if (timd == 3) { +               uint16_t scid; +               scid = scty*64 + subchid; +               } +               */ + +            if (ps == 0) { +                psdesc = "Secondary service"; +            } +            else { +                psdesc = "Primary service"; +            } + + +            if (timd == 0) { +                //MSC stream audio +                if (scty == 0) +                    sprintf(sctydesc, "MPEG Foreground sound (%d)", scty); +                else if (scty == 1) +                    sprintf(sctydesc, "MPEG Background sound (%d)", scty); +                else if (scty == 2) +                    sprintf(sctydesc, "Multi Channel sound (%d)", scty); +                else if (scty == 63) +                    sprintf(sctydesc, "AAC sound (%d)", scty); +                else +                    sprintf(sctydesc, "Unknown ASCTy (%d)", scty); + +                sprintf(desc, "Stream audio mode, %s, %s, SubChannel ID=%02X, CA=%d", psdesc.c_str(), sctydesc, subchid, ca); +                printbuf(desc, indent+3, NULL, 0); +            } +            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, indent+3, NULL, 0); +            } +            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, indent+3, NULL, 0); +            } +            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, indent+3, NULL, 0); +            } +            k += 2; +        } +    } +} + + diff --git a/fig0_21.cpp b/fig0_21.cpp new file mode 100644 index 0000000..9e6b113 --- /dev/null +++ b/fig0_21.cpp @@ -0,0 +1,302 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/21 Frequency Information +// ETSI EN 300 401 8.1.8 +void fig0_21(fig0_common_t& fig0, int indent) +{ +    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; +    char tmpbuf[256]; +    char desc[256]; +    bool Continuity_flag; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 1)) { +        // iterate over frequency information +        // decode RegionId, Length of FI list +        RegionId  =  (f[i] << 3) | (f[i+1] >> 5); +        Length_FI_list  = (f[i+1] & 0x1F); +        sprintf(desc, "RegionId=0x%03x", RegionId); +        printbuf(desc, indent+1, NULL, 0); +        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; +                sprintf(desc, "Id_field="); +                switch (RandM) { +                    case 0x0: +                    case 0x1: +                        strcat(desc, "EId"); +                        break; +                    case 0x6: +                        strcat(desc, "DRM Service Id"); +                        break; +                    case 0x8: +                        strcat(desc, "RDS PI"); +                        break; +                    case 0x9: +                    case 0xa: +                    case 0xc: +                        strcat(desc, "Dummy"); +                        break; +                    case 0xe: +                        strcat(desc, "AMSS Service Id"); +                        break; +                    default: +                        strcat(desc, "invalid"); +                        break; +                } +                sprintf(tmpbuf, "=0x%X, R&M=0x%1x", Id_field, RandM); +                strcat(desc, tmpbuf); +                switch (RandM) { +                    case 0x0: +                        strcat(desc, "=DAB ensemble, no local windows"); +                        break; +                    case 0x6: +                        strcat(desc, "=DRM"); +                        break; +                    case 0x8: +                        strcat(desc, "=FM with RDS"); +                        break; +                    case 0x9: +                        strcat(desc, "=FM without RDS"); +                        break; +                    case 0xa: +                        strcat(desc, "=AM (MW in 9 kHz steps & LW)"); +                        break; +                    case 0xc: +                        strcat(desc, "=AM (MW in 5 kHz steps & SW)"); +                        break; +                    case 0xe: +                        strcat(desc, "=AMSS"); +                        break; +                    default: +                        strcat(desc, "=Rfu"); +                        break; +                } +                sprintf(tmpbuf, ", Continuity flag=%d", Continuity_flag); +                strcat(desc, tmpbuf); +                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"); +                                break; +                            case 0x6: +                                strcat(desc, "=no compensating time delay on DRM audio signal"); +                                break; +                            case 0x8: +                            case 0x9: +                                strcat(desc, "=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"); +                                break; +                            default: +                                strcat(desc, "=Rfu"); +                                break; +                        } +                    } +                    else {  // Continuity_flag == 1 +                        switch (RandM) { +                            case 0x0: +                            case 0x1: +                                strcat(desc, "=continuous output possible"); +                                break; +                            case 0x6: +                                strcat(desc, "=compensating time delay on DRM audio signal"); +                                break; +                            case 0x8: +                            case 0x9: +                                strcat(desc, "=compensating time delay on FM audio signal"); +                                break; +                            case 0xa: +                            case 0xc: +                            case 0xe: +                                strcat(desc, "=compensating time delay on AM audio signal"); +                                break; +                            default: +                                strcat(desc, "=Rfu"); +                                break; +                        } +                    } +                } +                else {  // fig0.oe() == 1 +                    strcat(desc, "=reserved for future addition"); +                } +                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); +                // CEI Change Event Indication +                if (Length_Freq_list == 0) { +                    strcat(tmpbuf, ", CEI"); +                } +                strcat(desc, tmpbuf); +                printbuf(desc, indent+2, NULL, 0); +                j += 3; // add header + +                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) { +                                    sprintf(desc, "%d KHz, ", ifreq); +                                    if ((Control_field & 0x01) == 0) { +                                        strcat(desc, "geographically adjacent area, "); +                                    } +                                    else {  // (Control_field & 0x01) == 1 +                                        strcat(desc, "no geographically adjacent area, "); +                                    } +                                    if (Control_field_trans_mode == 0) { +                                        strcat(desc, "no transmission mode signalled"); +                                    } +                                    else if (Control_field_trans_mode <= 4) { +                                        sprintf(tmpbuf, "transmission mode %d", Control_field_trans_mode); +                                        strcat(desc, tmpbuf); +                                    } +                                    else {  // Control_field_trans_mode > 4 +                                        sprintf(tmpbuf, "invalid transmission mode 0x%x", Control_field_trans_mode); +                                        strcat(desc, tmpbuf); +                                    } +                                } +                                else {  // (Control_field & 0x10) == 0x10 +                                    sprintf(desc, "%d KHz, invalid Control field b23 0x%x", ifreq, Control_field); +                                } +                            } +                            else { +                                sprintf(desc, "Frequency not to be used (0)"); +                            } +                            printbuf(desc, indent+3, NULL, 0); +                            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)); +                                    } +                                    sprintf(desc, "%d KHz", ifreq); +                                } +                                else {  // RandM == 8 or 9 +                                    freq = (87.5 + ((float)f[k] * 0.1)); +                                    sprintf(desc, "%.1f MHz", freq); +                                } +                            } +                            else { +                                sprintf(desc, "Frequency not to be used (0)"); +                            } +                            printbuf(desc, indent+3, NULL, 0); +                            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) { +                                sprintf(desc, "%d KHz", ifreq); +                            } +                            else { +                                sprintf(desc, "Frequency not to be used (0)"); +                            } +                            printbuf(desc, indent+3, NULL, 0); +                            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) { +                                sprintf(desc, "%d KHz", ifreq); +                            } +                            else { +                                sprintf(desc, "Frequency not to be used (0)"); +                            } +                            if (RandM == 0x6) { +                                sprintf(tmpbuf, ", DRM Service Id 0x%X", Id_field2); +                                strcat(desc, tmpbuf); +                            } +                            else if (RandM == 0xe) { +                                sprintf(tmpbuf, ", AMSS Service Id 0x%X", Id_field2); +                                strcat(desc, tmpbuf); +                            } +                            if ((f[k+1] & 0x80) == 0x80) { +                                sprintf(tmpbuf, ", invalid Rfu b15 set to 1 instead of 0"); +                                strcat(desc, tmpbuf); +                            } +                            printbuf(desc, indent+3, NULL, 0); +                            k += 3; +                        } +                        break; +                    default: +                        break; +                } +                j += Length_Freq_list; +            } +            i += Length_FI_list; +        } +    } +} + diff --git a/fig0_22.cpp b/fig0_22.cpp new file mode 100644 index 0000000..5c29e8d --- /dev/null +++ b/fig0_22.cpp @@ -0,0 +1,163 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// map for fig 0/22 database +std::map<uint16_t, Lat_Lng> fig0_22_key_Lat_Lng; + +void fig0_22_cleardb() +{ +    fig0_22_key_Lat_Lng.clear(); +} + +// FIG 0/22 Transmitter Identification Information (TII) database +// ETSI EN 300 401 8.1.9 +void fig0_22(fig0_common_t& fig0, int indent) +{ +    Lat_Lng gps_pos = {0, 0}; +    double latitude_sub, longitude_sub; +    int16_t Latitude_coarse, Longitude_coarse; +    uint16_t key, TD; +    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]; +    bool MS; +    const uint8_t Mode_Identity = get_mode_identity(); +    uint8_t* f = fig0.f; + +    while (i < fig0.figlen) { +        // iterate over Transmitter Identification Information (TII) fields +        MS = f[i] >> 7; +        MainId = f[i] & 0x7F; +        key = (fig0.oe() << 8) | (fig0.pd() << 7) | MainId; +        sprintf(desc, "M/S=%d %sidentifier, MainId=0x%X", +                MS, MS?"Sub-":"Main ", 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); +            } +        } +        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); +            } +        } +        // print database key +        sprintf(tmpbuf, ", database key=0x%X", key); +        strcat(desc, tmpbuf); +        i++; +        if (MS == 0) { +            // Main identifier + +            if (i < (fig0.figlen - 4)) { +                Latitude_coarse = (f[i] << 8) | f[i+1]; +                Longitude_coarse = (f[i+2] << 8) | f[i+3]; +                Latitude_fine = f[i+4] >> 4; +                Longitude_fine = f[i+4] & 0x0F; +                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", +                        Latitude_coarse, Longitude_coarse, Latitude_fine, Longitude_fine, +                        gps_pos.latitude, gps_pos.longitude); +                strcat(desc, tmpbuf); +                i += 5; +            } +            else { +                strcat(desc, ", invalid length of Latitude Longitude coarse fine"); +            } +            printbuf(desc, indent+1, NULL, 0); +        } +        else {  // MS == 1 +            // Sub-identifier + +            if (i < fig0.figlen) { +                Rfu = f[i] >> 3; +                Nb_SubId_fields = f[i] & 0x07; +                if (Rfu != 0) { +                    sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +                    strcat(desc, tmpbuf); +                } +                sprintf(tmpbuf, ", Number of SubId fields=%d%s", +                        Nb_SubId_fields, (Nb_SubId_fields == 0)?", CEI":""); +                strcat(desc, tmpbuf); +                printbuf(desc, indent+1, NULL, 0); +                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); +                    // check SubId value +                    if ((SubId == 0) || (SubId > 23)) { +                        strcat(desc, " 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); + +                    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); +                    } +                    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); +                    } +                    printbuf(desc, indent+2, NULL, 0); +                } +                i += (Nb_SubId_fields * 6); +            } +            else { +                strcat(desc, ", invalid fig length or Number of SubId fields length"); +                printbuf(desc, indent+1, NULL, 0); +            } +        } +    } +} + diff --git a/fig0_24.cpp b/fig0_24.cpp new file mode 100644 index 0000000..03642fb --- /dev/null +++ b/fig0_24.cpp @@ -0,0 +1,88 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/24 fig0.oe() Services +// ETSI EN 300 401 8.1.10.2 +void fig0_24(fig0_common_t& fig0, int indent) +{ +    uint64_t key; +    uint32_t SId; +    uint16_t EId; +    uint8_t i = 1, j, Number_of_EIds, CAId; +    char tmpbuf[256]; +    char desc[256]; +    uint8_t* f = fig0.f; +    bool Rfa; + +    while (i < (fig0.figlen - (((uint8_t)fig0.pd() + 1) * 2))) { +        // iterate over other ensembles services +        if (fig0.pd() == 0) { +            SId = ((uint32_t)f[i] << 8) | (uint32_t)f[i+1]; +            i += 2; +        } +        else {  // fig0.pd() == 1 +            SId = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | +                ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; +            i += 4; +        } +        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); +        } +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        // CEI Change Event Indication +        if (Number_of_EIds == 0) { +            sprintf(tmpbuf, ", CEI"); +            strcat(desc, tmpbuf); +        } +        printbuf(desc, indent+1, NULL, 0); +        i++; + +        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, indent+2, NULL, 0); +        } +        i += (Number_of_EIds * 2); +    } +} + diff --git a/fig0_25.cpp b/fig0_25.cpp new file mode 100644 index 0000000..7e6b69b --- /dev/null +++ b/fig0_25.cpp @@ -0,0 +1,91 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/25 fig0.oe() Announcement support +// ETSI EN 300 401 8.1.10.5.1 +void fig0_25(fig0_common_t& fig0, int indent) +{ +    uint32_t key; +    uint16_t SId, Asu_flags, EId; +    uint8_t i = 1, j, Rfu, Number_EIds; +    char tmpbuf[256]; +    char desc[256]; +    uint8_t* f = fig0.f; + +    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]; +        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); +        if (Rfu != 0) { +            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +            strcat(desc, tmpbuf); +        } +        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); +        // CEI Change Event Indication +        if (Number_EIds == 0) { +            sprintf(tmpbuf, ", CEI"); +            strcat(desc, tmpbuf); +        } +        printbuf(desc, indent+1, NULL, 0); +        i += 5; + +        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, indent+2, NULL, 0); +            i += 2; +        } +        if (j < Number_EIds) { +            sprintf(desc, "missing EId, fig length too short !"); +            printbuf(desc, indent+1, NULL, 0); +            fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); +        } + +        // decode fig0.oe() announcement support types +        for(j = 0; j < 16; j++) { +            if (Asu_flags & (1 << j)) { +                sprintf(desc, "fig0.oe() Announcement support=%s", get_announcement_type(j)); +                printbuf(desc, indent+2, NULL, 0); +            } +        } +    } +} + diff --git a/fig0_26.cpp b/fig0_26.cpp new file mode 100644 index 0000000..b519ed8 --- /dev/null +++ b/fig0_26.cpp @@ -0,0 +1,88 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/26 fig0.oe() Announcement switching +// ETSI EN 300 401 8.1.10.5.2 +void fig0_26(fig0_common_t& fig0, int indent) +{ +    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]; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 6)) { +        // iterate over other ensembles announcement switching +        Cluster_Id_Current_Ensemble = f[i]; +        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); +        i += 7; +        if (Region_flag != 0) { +            if (i < fig0.figlen) { +                // get Region Id Other Ensemble +                Rfa = (f[i] >> 6); +                Region_Id_Other_Ensemble = f[i] & 0x3F; +                if (Rfa != 0) { +                    sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +                    strcat(desc, tmpbuf); +                } +                sprintf(tmpbuf, ", Region Id Other Ensemble=0x%X", Region_Id_Other_Ensemble); +                strcat(desc, tmpbuf); +            } +            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); +            } +            i++; +        } +        printbuf(desc, indent+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, indent+2, NULL, 0); +            } +        } +    } +} + diff --git a/fig0_27.cpp b/fig0_27.cpp new file mode 100644 index 0000000..6e906b7 --- /dev/null +++ b/fig0_27.cpp @@ -0,0 +1,83 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/27 FM Announcement support +// ETSI EN 300 401 8.1.11.2.1 +void fig0_27(fig0_common_t& fig0, int indent) +{ +    uint16_t SId, PI; +    uint8_t i = 1, j, Rfu, Number_PI_codes, key; +    char tmpbuf[256]; +    char desc[256]; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 2)) { +        // iterate over FM announcement support +        SId = ((uint16_t)f[i] << 8) | (uint16_t)f[i+1]; +        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); +        if (Rfu != 0) { +            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +            strcat(desc, tmpbuf); +        } +        sprintf(tmpbuf, ", Number of PI codes=%d", Number_PI_codes); +        strcat(desc, tmpbuf); +        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); +        } +        sprintf(tmpbuf, ", database key=0x%02X", key); +        strcat(desc, tmpbuf); +        // 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"); +        } +        printbuf(desc, indent+1, NULL, 0); +        i += 3; +        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, indent+2, NULL, 0); +            i += 2; +        } +        if (j != Number_PI_codes) { +            sprintf(desc, "fig length too short !"); +            printbuf(desc, indent+2, NULL, 0); +            fprintf(stderr, "WARNING: FIG 0/%d length %d too short !\n", fig0.ext(), fig0.figlen); +        } +    } +} + diff --git a/fig0_28.cpp b/fig0_28.cpp new file mode 100644 index 0000000..8c727b9 --- /dev/null +++ b/fig0_28.cpp @@ -0,0 +1,69 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + + +// FIG 0/28 FM Announcement switching +// ETSI EN 300 401 8.1.11.2.2 +void fig0_28(fig0_common_t& fig0, int indent) +{ +    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]; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 3)) { +        // iterate over FM announcement switching +        Cluster_Id_Current_Ensemble = f[i]; +        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); +        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()); +        } +        sprintf(tmpbuf, ", New flag=%d %s announcement", +                New_flag, New_flag?"newly introduced":"repeated"); +        strcat(desc, tmpbuf); +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        sprintf(tmpbuf, ", Region Id Current Ensemble=0x%X, PI=0x%X", Region_Id_Current_Ensemble, PI); +        strcat(desc, tmpbuf); +        printbuf(desc, indent+1, NULL, 0); +        i += 4; +    } +} + diff --git a/fig0_3.cpp b/fig0_3.cpp new file mode 100644 index 0000000..71547b6 --- /dev/null +++ b/fig0_3.cpp @@ -0,0 +1,88 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> + +// FIG 0/3 Service component in packet mode with or without Conditional Access +// ETSI EN 300 401 6.3.2 +void fig0_3(fig0_common_t& fig0, int indent) +{ +    uint16_t SCId, Packet_address, CAOrg; +    uint8_t i = 1, Rfa, DSCTy, SubChId, CAMode, SharedFlag; +    char tmpbuf[256]; +    char desc[256]; +    bool CAOrg_flag, DG_flag, Rfu; + +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 4)) { +        // iterate over service component in packet mode +        SCId = ((uint16_t)f[i] << 4) | ((uint16_t)(f[i+1] >> 4) & 0x0F); +        Rfa = (f[i+1] >> 1) & 0x07; +        CAOrg_flag = f[i+1] & 0x01; +        DG_flag = (f[i+2] >> 7) & 0x01; +        Rfu = (f[i+2] >> 6) & 0x01; +        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); +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        if (Rfu != 0) { +            sprintf(tmpbuf, ", Rfu=%d invalid value", Rfu); +            strcat(desc, tmpbuf); +        } +        i += 5; +        if (CAOrg_flag) { +            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); +            } +            else { +                sprintf(tmpbuf, ", invalid figlen"); +                strcat(desc, tmpbuf); +            } +            i += 2; +        } +        printbuf(desc, indent+1, NULL, 0); +    } +} + diff --git a/fig0_31.cpp b/fig0_31.cpp new file mode 100644 index 0000000..e4c3a92 --- /dev/null +++ b/fig0_31.cpp @@ -0,0 +1,110 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/31 FIC re-direction +// ETSI EN 300 401 8.1.12 +void fig0_31(fig0_common_t& fig0, int indent) +{ +    uint32_t FIG_type0_flag_field = 0, flag_field; +    uint8_t i = 1, j, FIG_type1_flag_field = 0, FIG_type2_flag_field = 0; +    char desc[256]; +    uint8_t* f = fig0.f; + +    if (i < (fig0.figlen - 5)) { +        // Read FIC re-direction +        FIG_type0_flag_field = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | +            ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; +        FIG_type1_flag_field = f[i+4]; +        FIG_type2_flag_field = f[i+5]; + +        sprintf(desc, "FIG type 0 flag field=0x%X, FIG type 1 flag field=0x%X, FIG type 2 flag field=0x%X", +                FIG_type0_flag_field, FIG_type1_flag_field, FIG_type2_flag_field); +        printbuf(desc, indent+1, NULL, 0); + +        for(j = 0; j < 32; j++) { +            // iterate over FIG type 0 re-direction +            flag_field = FIG_type0_flag_field & ((uint32_t)1 << j); +            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, indent+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); +            } +            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, indent+2, NULL, 0); +            } +            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); +                } +                else {  // fig0.oe() == 1 +                    sprintf(desc, "fig0.oe()=%d FIG 0/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); +                } +                printbuf(desc, indent+2, NULL, 0); +            } +        } + +        for(j = 0; j < 8; j++) { +            // iterate over FIG type 1 re-direction +            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); +                } +                else {  // fig0.oe() == 1 +                    sprintf(desc, "fig0.oe()=%d FIG 1/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); +                } +                printbuf(desc, indent+2, NULL, 0); +            } +        } + +        for(j = 0; j < 8; j++) { +            // iterate over FIG type 2 re-direction +            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); +                } +                else {  // fig0.oe() == 1 +                    sprintf(desc, "fig0.oe()=%d FIG 2/%d carried in AIC, may be carried entirely in AIC", fig0.oe(), j); +                } +                printbuf(desc, indent+2, NULL, 0); +            } +        } +    } +    if (fig0.figlen != 7) { +        fprintf(stderr, "WARNING: FIG 0/%d invalid length %d, expecting 7\n", fig0.ext(), fig0.figlen); +    } +} + diff --git a/fig0_5.cpp b/fig0_5.cpp new file mode 100644 index 0000000..f3ef08c --- /dev/null +++ b/fig0_5.cpp @@ -0,0 +1,89 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/5 Service component language +// ETSI EN 300 401 8.1.2 +void fig0_5(fig0_common_t& fig0, int indent) +{ +    uint16_t SCId; +    uint8_t i = 1, SubChId, FIDCId, Language, Rfa; +    char tmpbuf[256]; +    char desc[256]; +    bool LS_flag, MSC_FIC_flag; + +    uint8_t* f = fig0.f; + +    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]; +            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)); +            } +            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)); +            } +            printbuf(desc, indent+1, NULL, 0); +            i += 2; +        } +        else { +            // Long form (L/S = 1) +            if (i < (fig0.figlen - 2)) { +                Rfa = (f[i] >> 4) & 0x07; +                SCId = (((uint16_t)f[i] & 0x0F) << 8) | (uint16_t)f[i+1]; +                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); +                } +                sprintf(tmpbuf, ", SCId=0x%X, Language=0x%X %s", +                        SCId, Language, +                        get_language_name(Language)); +                strcat(desc, tmpbuf); +                printbuf(desc, indent+1, NULL, 0); +            } +            i += 3; +        } +    } +} + diff --git a/fig0_6.cpp b/fig0_6.cpp new file mode 100644 index 0000000..e863951 --- /dev/null +++ b/fig0_6.cpp @@ -0,0 +1,170 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// map between fig 0/6 database key and LA to detect activation and deactivation of links +static std::map<uint16_t, bool> fig0_6_key_la; + +void fig0_6_cleardb() +{ +    fig0_6_key_la.clear(); +} + +// FIG 0/6 Service linking information +// ETSI EN 300 401 8.1.15 +void fig0_6(fig0_common_t& fig0, int indent) +{ +    uint32_t j; +    uint16_t LSN, key; +    uint8_t i = 1, Number_of_Ids, IdLQ; +    char signal_link[256]; +    char desc[256]; +    bool Id_list_flag, LA, SH, ILS, Shd; + +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - 1)) { +        // iterate over service linking +        Id_list_flag  =  (f[i] >> 7) & 0x01; +        LA  = (f[i] >> 6) & 0x01; +        SH  = (f[i] >> 5) & 0x01; +        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; +        strcpy(signal_link, ""); +        // check activation / deactivation +        if ((fig0_6_key_la.count(key) > 0) && (fig0_6_key_la[key] != LA)) { +            if (LA == 0) { +                strcat(signal_link, " deactivated"); +            } +            else { +                strcat(signal_link, " 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"); +            } +            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, indent+1, NULL, 0); +        } +        else {  // Id_list_flag == 1 +            if (i < fig0.figlen) { +                Number_of_Ids = (f[i] & 0x0F); +                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, indent+1, NULL, 0); +                    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: +                            // The IdLQ shall not apply to the first entry in the Id list when fig0.oe() = "0" and  +                            // when the version number of the type 0 field is set to "0" (using the C/N flag, see clause 5.2.2.1) +                            // ... , the first entry in the Id list of each Service linking field shall be  +                            // the SId that applies to the service in the ensemble. +                            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)])); +                            } +                            else if (IdLQ == 1) { +                                sprintf(desc, "RDS PI        0x%X", ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); +                            } +                            else if (IdLQ == 2) { +                                sprintf(desc, "AM-FM service 0x%X", ((f[i+1+(j*2)] << 8) | f[i+2+(j*2)])); +                            } +                            else {  // IdLQ == 3 +                                sprintf(desc, "invalid ILS IdLQ configuration"); +                            } +                            printbuf(desc, indent+2, NULL, 0); +                        } +                        // check deadlink +                        if ((Number_of_Ids == 0) && (IdLQ == 1)) { +                            sprintf(desc, "deadlink"); +                            printbuf(desc, indent+2, NULL, 0); +                        } +                        i += (Number_of_Ids * 2) + 1; +                    } +                    else {  // fig0.pd() == 0 && ILS == 1 +                        // read Id list +                        for(j = 0; ((j < Number_of_Ids) && ((i+3+(j*3)) < fig0.figlen)); j++) { +                            // ETSI EN 300 401 8.1.15: +                            // The IdLQ shall not apply to the first entry in the Id list when fig0.oe() = "0" and  +                            // when the version number of the type 0 field is set to "0" (using the C/N flag, see clause 5.2.2.1) +                            // ... , the first entry in the Id list of each Service linking field shall be  +                            // the SId that applies to the service in the ensemble. +                            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)])); +                            } +                            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)])); +                            } +                            else if (IdLQ == 2) { +                                sprintf(desc, "AM-FM service    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)])); +                            } +                            printbuf(desc, indent+2, NULL, 0); +                        } +                        // check deadlink +                        if ((Number_of_Ids == 0) && (IdLQ == 1)) { +                            sprintf(desc, "deadlink"); +                            printbuf(desc, indent+2, NULL, 0); +                        } +                        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, indent+1, NULL, 0); +                    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, indent+2, NULL, 0); +                        } +                    } +                    i += (Number_of_Ids * 4) + 1; +                } +            } +        } +    } +} + + diff --git a/fig0_8.cpp b/fig0_8.cpp new file mode 100644 index 0000000..7143768 --- /dev/null +++ b/fig0_8.cpp @@ -0,0 +1,117 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// FIG 0/8 Service component global definition +// ETSI EN 300 401 6.3.5 +void fig0_8(fig0_common_t& fig0, int indent) +{ +    uint32_t SId; +    uint16_t SCId; +    uint8_t i = 1, Rfa, SCIdS, SubChId, FIDCId; +    char tmpbuf[256]; +    char desc[256]; +    bool Ext_flag, LS_flag, MSC_FIC_flag; +    uint8_t* f = fig0.f; + +    while (i < (fig0.figlen - (2 + (2 * fig0.pd())))) { +        // iterate over service component global definition +        if (fig0.pd() == 0) { +            // Programme services, 16 bit SId +            SId = (f[i] << 8) | f[i+1]; +            i += 2; +        } +        else { +            // Data services, 32 bit SId +            SId = ((uint32_t)f[i] << 24) | ((uint32_t)f[i+1] << 16) | +                ((uint32_t)f[i+2] << 8) | (uint32_t)f[i+3]; +            i += 4; +        } +        Ext_flag = f[i] >> 7; +        Rfa = (f[i] >> 4) & 0x7; +        SCIdS = f[i] & 0x0F; +        sprintf(desc, "SId=0x%X, fig0.ext() flag=%d 8-bit Rfa %s", SId, Ext_flag, (Ext_flag)?"present":"absent"); +        if (Rfa != 0) { +            sprintf(tmpbuf, ", Rfa=%d invalid value", Rfa); +            strcat(desc, tmpbuf); +        } +        sprintf(tmpbuf, ", SCIdS=0x%X", SCIdS); +        strcat(desc, tmpbuf); +        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); +            if (LS_flag == 0) { +                // Short form +                if (i < (fig0.figlen - Ext_flag)) { +                    MSC_FIC_flag = (f[i] >> 6) & 0x01; +                    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); +                    } +                    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); +                    } +                    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); +                        } +                    } +                } +                i += (1 + Ext_flag); +            } +            else { +                // Long form +                if (i < (fig0.figlen - 1)) { +                    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); +                    } +                    sprintf(tmpbuf, ", SCId=0x%X", SCId); +                    strcat(desc, tmpbuf); +                } +                i += 2; +            } +        } +        printbuf(desc, indent+1, NULL, 0); +    } +} + diff --git a/fig0_9.cpp b/fig0_9.cpp new file mode 100644 index 0000000..9fa4562 --- /dev/null +++ b/fig0_9.cpp @@ -0,0 +1,131 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <cstdio> +#include <cstring> +#include <map> + +// 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 +void fig0_9(fig0_common_t& fig0, int indent) +{ +    uint32_t SId; +    uint8_t i = 1, j, key, Number_of_services, ECC; +    int8_t LTO; +    char tmpbuf[256]; +    char desc[256]; +    bool Ext_flag; +    uint8_t* f = fig0.f; + +    if (i < (fig0.figlen - 2)) { +        // get Ensemble LTO, ECC and International Table Id +        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; +        if (Ensemble_LTO & 0x20) { +            // negative Ensemble LTO +            Ensemble_LTO |= 0xC0; +        } +        sprintf(desc, "fig0.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); +        if (abs(Ensemble_LTO) > 24) { +            sprintf(tmpbuf, " out of range -12 hours to +12 hours"); +            strcat(desc, tmpbuf); +        } +        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, indent+1, NULL, 0); +        i += 3; +        if (Ext_flag == 1) { +            // extended field present +            while (i < fig0.figlen) { +                // iterate over extended sub-field +                Number_of_services = f[i] >> 6; +                LTO = f[i] & 0x3F; +                if (LTO & 0x20) { +                    // 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); +                if (abs(LTO) > 24) { +                    sprintf(tmpbuf, " out of range -12 hours to +12 hours"); +                    strcat(desc, tmpbuf); +                } +                // CEI Change Event Indication +                if ((Number_of_services == 0) && (LTO == 0) /* && (Ext_flag == 1) */) { +                    sprintf(tmpbuf, ", CEI"); +                    strcat(desc, tmpbuf); +                } +                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, indent+2, NULL, 0); +                        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, indent+3, NULL, 0); +                        } +                        i += (Number_of_services * 2); +                    } +                } +                else { +                    // Data services, 32 bit SId +                    printbuf(desc, indent+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, indent+3, NULL, 0); +                    } +                    i += (Number_of_services * 4); +                } +            } +        } +    } +} + diff --git a/figs.cpp b/figs.cpp new file mode 100644 index 0000000..4e7e94c --- /dev/null +++ b/figs.cpp @@ -0,0 +1,112 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "figs.hpp" +#include <stdio.h> +#include <unistd.h> +#include <getopt.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <string> +#include <vector> +#include <map> +#include <sstream> +#include <time.h> +#include "utils.hpp" + + +static uint8_t Mode_Identity = 0; + +void set_mode_identity(uint8_t mid) +{ +    Mode_Identity = mid; +} + +uint8_t get_mode_identity() +{ +    return Mode_Identity; +} + +static size_t International_Table_Id; + +size_t get_international_table(void) +{ +    return International_Table_Id; +} + +void   set_international_table(size_t intl_table) +{ +    International_Table_Id = intl_table; +} + + +void figs_cleardb() +{ +    // remove elements from fig0_6_key_la and fig0_22_key_Lat_Lng map containers +    fig0_22_cleardb(); +    fig0_6_cleardb(); +} + + +void fig0_select(fig0_common_t& fig0, int indent) +{ +    switch (fig0.ext()) { +        case 0: fig0_0(fig0, indent); break; +        case 1: fig0_1(fig0, indent); break; +        case 2: fig0_2(fig0, indent); break; +        case 3: fig0_3(fig0, indent); break; +        case 5: fig0_5(fig0, indent); break; +        case 6: fig0_6(fig0, indent); break; +        case 8: fig0_8(fig0, indent); break; +        case 9: fig0_9(fig0, indent); break; +        case 10: fig0_10(fig0, indent); break; +        case 11: fig0_11(fig0, indent); break; +        case 13: fig0_13(fig0, indent); break; +        case 14: fig0_14(fig0, indent); break; +        case 16: fig0_16(fig0, indent); break; +        case 17: fig0_17(fig0, indent); break; +        case 18: fig0_18(fig0, indent); break; +        case 19: fig0_19(fig0, indent); break; +        case 21: fig0_21(fig0, indent); break; +        case 22: fig0_22(fig0, indent); break; +        case 24: fig0_24(fig0, indent); break; +        case 25: fig0_25(fig0, indent); break; +        case 26: fig0_26(fig0, indent); break; +        case 27: fig0_27(fig0, indent); break; +        case 28: fig0_28(fig0, indent); break; +        case 31: fig0_31(fig0, indent); break; +        default: { +                     char desc[256]; +                     sprintf(desc, "FIG 0/%d: unknown", fig0.ext()); +                     printbuf(desc, indent, fig0.f+1, fig0.figlen-1); +                     break; +                 } +    } +} + diff --git a/figs.hpp b/figs.hpp new file mode 100644 index 0000000..0e2efb8 --- /dev/null +++ b/figs.hpp @@ -0,0 +1,96 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#pragma once + +#include <cstdint> +#include "utils.hpp" +#include "tables.hpp" +#include "watermarkdecoder.hpp" + +void figs_cleardb(void); + +struct fig0_common_t { +    fig0_common_t( +            uint8_t* fig_data, +            uint16_t fig_len, +            WatermarkDecoder &wm_dec) : +        f(fig_data), +        figlen(fig_len), +        wm_decoder(wm_dec) { } + +    uint8_t* f; +    uint16_t figlen; +    WatermarkDecoder &wm_decoder; + +    uint16_t cn(void) { return (f[0] & 0x80) >> 7; } +    uint16_t oe(void) { return (f[0] & 0x40) >> 6; } +    uint16_t pd(void) { return (f[0] & 0x20) >> 5; } +    uint16_t ext(void) { return f[0] & 0x1F; } +}; + +// FIG 0/11 and 0/22 struct +struct Lat_Lng { +    double latitude, longitude; +}; + +// Which international table has been chosen +size_t get_international_table(void); +void   set_international_table(size_t intl_table); + +// MID is used by some FIGs. It is signalled in LIDATA - FC - MID +void set_mode_identity(uint8_t mid); +uint8_t get_mode_identity(); + +void fig0_select(fig0_common_t& fig0, int indent); + +void fig0_0(fig0_common_t& fig0, int indent); +void fig0_1(fig0_common_t& fig0, int indent); +void fig0_2(fig0_common_t& fig0, int indent); +void fig0_3(fig0_common_t& fig0, int indent); +void fig0_5(fig0_common_t& fig0, int indent); +void fig0_6_cleardb(); +void fig0_6(fig0_common_t& fig0, int indent); +void fig0_8(fig0_common_t& fig0, int indent); +void fig0_9(fig0_common_t& fig0, int indent); +void fig0_10(fig0_common_t& fig0, int indent); +void fig0_11(fig0_common_t& fig0, int indent); +void fig0_13(fig0_common_t& fig0, int indent); +void fig0_14(fig0_common_t& fig0, int indent); +void fig0_16(fig0_common_t& fig0, int indent); +void fig0_17(fig0_common_t& fig0, int indent); +void fig0_18(fig0_common_t& fig0, int indent); +void fig0_19(fig0_common_t& fig0, int indent); +void fig0_21(fig0_common_t& fig0, int indent); +void fig0_22_cleardb(); +void fig0_22(fig0_common_t& fig0, int indent); +void fig0_24(fig0_common_t& fig0, int indent); +void fig0_25(fig0_common_t& fig0, int indent); +void fig0_26(fig0_common_t& fig0, int indent); +void fig0_27(fig0_common_t& fig0, int indent); +void fig0_28(fig0_common_t& fig0, int indent); +void fig0_31(fig0_common_t& fig0, int indent); + diff --git a/tables.cpp b/tables.cpp new file mode 100644 index 0000000..ed3ecbe --- /dev/null +++ b/tables.cpp @@ -0,0 +1,311 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "tables.hpp" +#include <string> +#include <vector> +#include <stdexcept> + +static const std::vector<const char*> language_names = { +   "Unknown/not applicable", +   "Albanian", +   "Breton", +   "Catalan", +   "Croatian", +   "Welsh", +   "Czech", +   "Danish", +   "German", +   "English", +   "Spanish", +   "Esperanto", +   "Estonian", +   "Basque", +   "Faroese", +   "French", +   "Frisian", +   "Irish", +   "Gaelic", +   "Galician", +   "Icelandic", +   "Italian", +   "Lappish", +   "Latin", +   "Latvian", +   "Luxembourgian", +   "Lithuanian", +   "Hungarian", +   "Maltese", +   "Dutch", +   "Norwegian", +   "Occitan", +   "Polish", +   "Portuguese", +   "Romanian", +   "Romansh", +   "Serbian", +   "Slovak", +   "Slovene", +   "Finnish", +   "Swedish", +   "Turkish", +   "Flemish", +   "Walloon", +   "rfu", +   "rfu", +   "rfu", +   "rfu", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Reserved for national assignment", +   "Background sound/clean feed", +   "rfu", +   "rfu", +   "rfu", +   "rfu", +   "Zulu", +   "Vietnamese", +   "Uzbek", +   "Urdu", +   "Ukranian", +   "Thai", +   "Telugu", +   "Tatar", +   "Tamil", +   "Tadzhik", +   "Swahili", +   "Sranan Tongo", +   "Somali", +   "Sinhalese", +   "Shona", +   "Serbo-Croat", +   "Rusyn", +   "Russian", +   "Quechua", +   "Pushtu", +   "Punjabi", +   "Persian", +   "Papiamento", +   "Oriya", +   "Nepali", +   "Ndebele", +   "Marathi", +   "Moldavian", +   "Malaysian", +   "Malagasay", +   "Macedonian", +   "Laotian", +   "Korean", +   "Khmer", +   "Kazakh", +   "Kannada", +   "Japanese", +   "Indonesian", +   "Hindi", +   "Hebrew", +   "Hausa", +   "Gurani", +   "Gujurati", +   "Greek", +   "Georgian", +   "Fulani", +   "Dari", +   "Chuvash", +   "Chinese", +   "Burmese", +   "Bulgarian", +   "Bengali", +   "Belorussian", +   "Bambora", +   "Azerbaijani", +   "Assamese", +   "Armenian", +   "Arabic", +   "Amharic", +}; + +const char* get_language_name(size_t language_code) +{ +    if (language_code < language_names.size()) +    { +        return language_names[language_code]; +    } + +    throw std::runtime_error("Invalid language_code!"); +} + +// fig 0/18 0/19 announcement types (ETSI TS 101 756 V1.6.1 (2014-05) table 14 & 15) +const char *announcement_types_str[16] = { +    "Alarm", +    "Road Traffic flash", +    "Transport flash", +    "Warning/Service", +    "News flash", +    "Area weather flash", +    "Event announcement", +    "Special event", +    "Programme Information", +    "Sport report", +    "Financial report", +    "Reserved for future definition", +    "Reserved for future definition", +    "Reserved for future definition", +    "Reserved for future definition", +    "Reserved for future definition" +}; + +const char* get_announcement_type(size_t announcement_type) +{ +    return announcement_types_str[announcement_type]; +} + + +// fig 0/17 Programme type codes +#define INTERNATIONAL_TABLE_SIZE     2 +#define PROGRAMME_TYPE_CODES_SIZE  32 +const char *Programme_type_codes_str[INTERNATIONAL_TABLE_SIZE][PROGRAMME_TYPE_CODES_SIZE] = { +    {   // ETSI TS 101 756 V1.6.1 (2014-05) table 12 +        "No programme type",        "News", +        "Current Affairs",          "Information", +        "Sport",                    "Education", +        "Drama",                    "Culture", +        "Science",                  "Varied", +        "Pop Music",                "Rock Music", +        "Easy Listening Music",     "Light Classical", +        "Serious Classical",        "Other Music", +        "Weather/meteorology",      "Finance/Business", +        "Children's programmes",    "Social Affairs", +        "Religion",                 "Phone In", +        "Travel",                   "Leisure", +        "Jazz Music",               "Country Music", +        "National Music",           "Oldies Music", +        "Folk Music",               "Documentary", +        "Not used",                 "Not used" +    }, +    {   // ETSI TS 101 756 V1.6.1 (2014-05) table 13 +        "No program type",  "News", +        "Information",      "Sports", +        "Talk",             "Rock", +        "Classic Rock",     "Adult Hits", +        "Soft Rock",        "Top 40", +        "Country",          "Oldies", +        "Soft",             "Nostalgia", +        "Jazz",             "Classical", +        "Rhythm and Blues", "Soft Rhythm and Blues", +        "Foreign Language", "Religious Music", +        "Religious Talk",   "Personality", +        "Public",           "College", +        "rfu",              "rfu", +        "rfu",              "rfu", +        "rfu",              "Weather", +        "Not used",         "Not used" +    } +}; + +const char* get_programme_type(size_t int_table_Id, size_t pty) +{ +    if ((int_table_Id - 1) < INTERNATIONAL_TABLE_SIZE) { +       if (pty < PROGRAMME_TYPE_CODES_SIZE) { +           return Programme_type_codes_str[int_table_Id - 1][pty]; +       } +       else { +           return "invalid programme type"; +       } +    } +    else { +        return "unknown international table Id"; +    } +} + + +const char *DSCTy_types_str[64] =  { +    // ETSI TS 101 756 V1.6.1 (2014-05) table 2 +    "Unspecified data",                             "Traffic Message Channel (TMC)", +    "Emergency Warning System (EWS)",               "Interactive Text Transmission System (ITTS)", +    "Paging",                                       "Transparent Data Channel (TDC)", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "MPEG-2 Transport Stream, see ETSI TS 102 427", "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Rfu", +    "Rfu",                                          "Embedded IP packets", +    "Multimedia Object Transfer (MOT)",             "Proprietary service: no DSCTy signalled", +    "Not used",                                     "Not used" +}; + +const char* get_dscty_type(size_t dscty) +{ +    return DSCTy_types_str[dscty]; +} + +// ETSI TS 102 367 V1.2.1 (2006-01) 5.4.1 Conditional Access Mode (CAMode) +// Used in FIG 0/3 +const char *CAMode_str[8] = { +    "Sub-channel CA",   "Data Group CA", +    "MOT CA",           "proprietary CA", +    "reserved",         "reserved", +    "reserved",         "reserved" +}; + +const char* get_ca_mode(size_t ca_mode) +{ +    return CAMode_str[ca_mode]; +} + diff --git a/tables.hpp b/tables.hpp new file mode 100644 index 0000000..992aabd --- /dev/null +++ b/tables.hpp @@ -0,0 +1,43 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#pragma once + +#include "utils.hpp" + +const char* get_language_name(size_t language_code); +const char* get_announcement_type(size_t announcement_type); + +/* get_programme_type_str return the programme type string from international + * table Id and programme type + */ +const char* get_programme_type(size_t int_table_Id, size_t pty); + +// fig 0/2 fig 0/3 DSCTy types string: +const char* get_dscty_type(size_t dscty); + +const char* get_ca_mode(size_t ca_mode); + diff --git a/utils.cpp b/utils.cpp new file mode 100644 index 0000000..71df396 --- /dev/null +++ b/utils.cpp @@ -0,0 +1,154 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    etisnoop.cpp +          Parse ETI NI G.703 file + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#include "utils.hpp" +#include <cstring> + +using namespace std; + +static int verbosity = 0; + +void set_verbosity(int v) +{ +    verbosity = v; +} + +int get_verbosity() +{ +    return verbosity; +} + +void printbuf(string header, +        int indent_level, +        uint8_t* buffer, +        size_t size, +        string desc) +{ +    if (verbosity > 0) { +        for (int i = 0; i < indent_level; i++) { +            printf("\t"); +        } + +        printf("%s", header.c_str()); + +        if (verbosity > 1) { +            if (size != 0) { +                printf(": "); +            } + +            for (size_t i = 0; i < size; i++) { +                printf("%02x ", buffer[i]); +            } +        } + +        if (desc != "") { +            printf(" [%s] ", desc.c_str()); +        } + +        printf("\n"); +    } +} + +void printinfo(string header, +        int indent_level, +        int min_verb) +{ +    if (verbosity >= min_verb) { +        for (int i = 0; i < indent_level; i++) { +            printf("\t"); +        } +        printf("%s\n", header.c_str()); +    } +} + +int sprintfMJD(char *dst, int mjd) { +    // EN 62106 Annex G +    // These formulas are applicable between the inclusive dates: 1st March 1900 to 28th February 2100 +    int y, m, k; +    struct tm timeDate; + +    memset(&timeDate, 0, sizeof(struct tm)); + +    // find Y, M, D from MJD +    y = (int)(((double)mjd - 15078.2) / 365.25); +    m = (int)(((double)mjd - 14956.1 - (int)((double)y * 365.25)) / 30.6001); +    timeDate.tm_mday = mjd - 14956 - (int)((double)y * 365.25) - (int)((double)m * 30.6001); +    if ((m == 14) || (m == 15)) { +        k = 1; +    } +    else { +        k = 0; +    } +    timeDate.tm_year = y + k; +    timeDate.tm_mon = (m - 1 - (k * 12)) - 1; + +    // find WD from MJD +    timeDate.tm_wday = (((mjd + 2) % 7) + 1) % 7; + +    //timeDate.tm_yday = 0; // Number of days since the first day of January not calculated +    timeDate.tm_isdst = -1; // No time print then information not available + +    // print date string +    if ((timeDate.tm_mday < 0) || (timeDate.tm_mon < 0) || (timeDate.tm_year < 0)) { +        return sprintf(dst, "invalid MJD mday=%d mon=%d year=%d", timeDate.tm_mday, timeDate.tm_mon, timeDate.tm_year); +    } +    return strftime(dst, 256, "%a %b %d %Y", &timeDate); +} + +char *strcatPNum(char *dest_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); +    } +    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"); +        } +        else if ((hour == 0) && (minute == 1)) { +            sprintf(tempbuf, "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)"); +        } +        else { +            sprintf(tempbuf, "invalid value"); +        } +    } +    return strcat(dest_str, tempbuf); +} + + diff --git a/utils.hpp b/utils.hpp new file mode 100644 index 0000000..3913f87 --- /dev/null +++ b/utils.hpp @@ -0,0 +1,57 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    etisnoop.cpp +          Parse ETI NI G.703 file + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#pragma once + +#include <string> +#include <cstdint> +#include <inttypes.h> + +void set_verbosity(int v); +int  get_verbosity(void); + +void printbuf(std::string header, +        int indent_level, +        uint8_t* buffer, +        size_t size, +        std::string desc=""); + +void printinfo(std::string header, +        int indent_level, +        int min_verb = 0); + +// 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 +// 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); + diff --git a/watermarkdecoder.hpp b/watermarkdecoder.hpp new file mode 100644 index 0000000..57196e1 --- /dev/null +++ b/watermarkdecoder.hpp @@ -0,0 +1,98 @@ +/* +    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) 2015 Data Path + +    This program is free software: you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation, either version 3 of the License, or +    (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +    GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +    Authors: +         Sergio Sagliocco <sergio.sagliocco@csp.it> +         Matthias P. Braendli <matthias@mpb.li> +                   / |  |-  ')|)  |-|_ _ (|,_   .|  _  ,_ \ +         Data Path \(|(||_(|/_| (||_||(a)_||||(|||.(_()|||/ + +*/ + +#pragma once +#include <vector> +#include <sstream> +#include "utils.hpp" + +class WatermarkDecoder +{ +    public: +        WatermarkDecoder() {} + +        void push_confind_bit(bool confind) +        { +            // The ConfInd of FIG 0/10 contains the CRC-DABMUX and ODR-DabMux watermark +            m_confind_bits.push_back(confind); +        } + +        std::string calculate_watermark() +        { +            // First try to find the 0x55 0x55 sync in the waternark data +            size_t bit_ix; +            int alternance_count = 0; +            bool last_bit = 1; +            for (bit_ix = 0; bit_ix < m_confind_bits.size(); bit_ix++) { +                if (alternance_count == 16) { +                    break; +                } +                else { +                    if (last_bit != m_confind_bits[bit_ix]) { +                        last_bit = m_confind_bits[bit_ix]; +                        alternance_count++; +                    } +                    else { +                        alternance_count = 0; +                        last_bit = 1; +                    } +                } + +            } + +            printf("Found SYNC at offset %zu out of %zu\n", bit_ix - alternance_count, m_confind_bits.size()); + +            std::stringstream watermark_ss; + +            uint8_t b = 0; +            size_t i = 0; +            while (bit_ix < m_confind_bits.size()) { + +                b |= m_confind_bits[bit_ix] << (7 - i); + +                if (i == 7) { +                    watermark_ss << (char)b; + +                    b = 0; +                    i = 0; +                } +                else { +                    i++; +                } + +                bit_ix += 2; +            } + +            return watermark_ss.str(); +        } + +    private: +        const WatermarkDecoder& operator=(const WatermarkDecoder&) = delete; +        WatermarkDecoder(const WatermarkDecoder&) = delete; + +        std::vector<bool> m_confind_bits; +}; + | 
