diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2014-11-09 11:33:11 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2014-11-09 11:33:11 +0100 |
commit | 639951285591ab6e8d1158e336a3f6c19477cc4f (patch) | |
tree | 40c6090f564539cd2bb201b85e4ffa53ddd4b880 | |
parent | 588a749b8544afce1824d9bcda80f2c5a44524e5 (diff) | |
download | etisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.tar.gz etisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.tar.bz2 etisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.zip |
ETISnoop search for firecode
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | dabplussnoop.cpp | 180 | ||||
-rw-r--r-- | dabplussnoop.h | 101 | ||||
-rw-r--r-- | etisnoop.cpp | 84 | ||||
-rw-r--r-- | firecode.c | 50 | ||||
-rw-r--r-- | firecode.h | 32 |
6 files changed, 427 insertions, 27 deletions
@@ -1,10 +1,13 @@ CC=g++ +SOURCES=etisnoop.cpp dabplussnoop.cpp lib_crc.c firecode.c +HEADERS=dabplussnoop.h lib_crc.h firecode.h + all: etisnoop -etisnoop: etisnoop.cpp lib_crc.c lib_crc.h - $(CC) -Wall -ggdb etisnoop.cpp lib_crc.c -o etisnoop +etisnoop: $(SOURCES) $(HEADERS) + $(CC) -Wall -ggdb $(SOURCES) $(HEADERS) -o etisnoop clean: rm -f etisnoop *.o diff --git a/dabplussnoop.cpp b/dabplussnoop.cpp new file mode 100644 index 0000000..83f646e --- /dev/null +++ b/dabplussnoop.cpp @@ -0,0 +1,180 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + dabplussnoop.cpp + Parse DAB+ frames from a ETI file + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <sstream> +#include "dabplussnoop.h" +#include "firecode.h" + +#define DPS_INDENT "\t\t" +#define DPS_PREFIX "DABPLUS:" + +using namespace std; + +void DabPlusSnoop::push(uint8_t* streamdata, size_t streamsize) +{ + size_t original_size = m_data.size(); + m_data.resize(original_size + streamsize); + + memcpy(&m_data[original_size], streamdata, streamsize); + + check(); +} + +// Idea and some code taken from Xpadxpert +int DabPlusSnoop::check() +{ + if (m_data.size() < 10) { + // Not enough data + return -1; + } + + bool crc_ok = false; + int i; + + for (i = 0; i < m_data.size() - 10; i++) { + uint8_t* b = &m_data[i]; + + // the three bytes after the firecode must not be zero + // (simple plausibility check to avoid sync in zero byte region) + if (b[3] != 0x00 || (b[4] & 0xF0) != 0x00) { + uint16_t header_firecode = (b[0] << 8) | b[1]; + uint16_t calculated_firecode = firecode_crc(b+2, 9); + + if (header_firecode == calculated_firecode) { + crc_ok = true; + break; + } + } + } + + if (crc_ok) { + fprintf(stderr, DPS_PREFIX " Found valid FireCode at %d\n", i); + + m_data.erase(m_data.begin(), m_data.begin() + i); + return decode(); + } + else { + fprintf(stderr, DPS_PREFIX " No valid FireCode found\n"); + return -1; + } +} + +int DabPlusSnoop::decode() +{ + if (m_subchannel_index && m_data.size() >= m_subchannel_index * 110) { + fprintf(stderr, DPS_PREFIX " We have %zu bytes of data\n", m_data.size()); + + uint8_t* b = &m_data[0]; + + // -- Parse he_aac_super_frame + // ---- Parse he_aac_super_frame_header + // ------ Parse firecode and audio params + uint16_t header_firecode = (b[0] << 8) | b[1]; + uint8_t audio_params = b[2]; + int rfa = (audio_params & 0x80) ? 1 : 0; + int dac_rate = (audio_params & 0x40) ? 1 : 0; + int sbr_flag = (audio_params & 0x20) ? 1 : 0; + int aac_channel_mode = (audio_params & 0x10) ? 1 : 0; + int ps_flag = (audio_params & 0x08) ? 1 : 0; + int mpeg_surround_config = (audio_params & 0x07) ? 1 : 0; + + int num_aus; + if ((dac_rate == 0) && (sbr_flag == 1)) num_aus = 2; + // AAC core sampling rate 16 kHz + else if ((dac_rate == 1) && (sbr_flag == 1)) num_aus = 3; + // AAC core sampling rate 24 kHz + else if ((dac_rate == 0) && (sbr_flag == 0)) num_aus = 4; + // AAC core sampling rate 32 kHz + else if ((dac_rate == 1) && (sbr_flag == 0)) num_aus = 6; + // AAC core sampling rate 48 kHz + + fprintf(stderr, + DPS_INDENT DPS_PREFIX "\n" + DPS_INDENT "\tfirecode 0x%x\n" + DPS_INDENT "\trfa %d\n" + DPS_INDENT "\tdac_rate %d\n" + DPS_INDENT "\tsbr_flag %d\n" + DPS_INDENT "\taac_channel_mode %d\n" + DPS_INDENT "\tps_flag %d\n" + DPS_INDENT "\tmpeg_surround_config %d\n" + DPS_INDENT "\tnum_aus %d\n", + header_firecode, rfa, dac_rate, sbr_flag, aac_channel_mode, + ps_flag, mpeg_surround_config, num_aus); + + + // ------ Parse au_start + b += 3; + + vector<uint8_t> au_start_nibbles(3*(num_aus-1)); + + size_t nib = 0; + for (int i = 0; i < (num_aus-1)*3/2; i++) { + au_start_nibbles[nib] = b[i] >> 4; + au_start_nibbles[nib+1] = 0x0F & (b[i]); + nib += 2; + fprintf(stderr, "0x%1x 0x%1x ", b[i] >> 4, 0x0F & b[i]); + } + fprintf(stderr, "\n"); + + vector<int> au_start(num_aus); + + if (num_aus == 2) + au_start[0] = 5; + else if (num_aus == 3) + au_start[0] = 6; + else if (num_aus == 4) + au_start[0] = 8; + else if (num_aus == 6) + au_start[0] = 11; + + + nib = 0; + fprintf(stderr, DPS_INDENT DPS_PREFIX " AU start\n"); + for (int au = 1; au < num_aus; au++) { + au_start[au] = au_start_nibbles[nib] << 8 | \ + au_start_nibbles[nib+1] << 4 | \ + au_start_nibbles[nib+2]; + + nib += 3; + } + + for (int au = 0; au < num_aus; au++) { + fprintf(stderr, DPS_INDENT "\tAU[%d] %d 0x%x\n", au, + au_start[au], + au_start[au]); + } + + m_data.clear(); + + return 0; + } + else { + return -1; + } +} + diff --git a/dabplussnoop.h b/dabplussnoop.h new file mode 100644 index 0000000..6a386eb --- /dev/null +++ b/dabplussnoop.h @@ -0,0 +1,101 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + dabplussnoop.cpp + Parse DAB+ frames from a ETI file + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +/* From the spec: + +subchannel_index = MSC sub-channel size (kbps) / 8 +audio_super_frame_size (bytes) = subchannel_index * 110 + + +he_aac_super_frame(subchannel_index) +{ + he_aac_super_frame_header() + { + header_firecode 16 + rfa 1 + dac_rate 1 + sbr_flag 1 + aac_channel_mode 1 + ps_flag 1 + mpeg_surround_config 3 + + // end of audio parameters + if ((dac_rate == 0) && (sbr_flag == 1)) num_aus = 2; + // AAC core sampling rate 16 kHz + if ((dac_rate == 1) && (sbr_flag == 1)) num_aus = 3; + // AAC core sampling rate 24 kHz + if ((dac_rate == 0) && (sbr_flag == 0)) num_aus = 4; + // AAC core sampling rate 32 kHz + if ((dac_rate == 1) && (sbr_flag == 0)) num_aus = 6; + // AAC core sampling rate 48 kHz + + for (n = 1; n < num_aus; n++) { + au_start[n]; 12 + } + + if !((dac_rate == 1) && (sbr_flag == 1)) + alignment 4 + } + + for (n = 0; n < num_aus; n++) { + au[n] 8 * au_size[n] + au_crc[n] 16 + } +} +*/ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <sstream> +#include <vector> + +#ifndef __DABPLUSSNOOP_H_ +#define __DABPLUSSNOOP_H_ + +class DabPlusSnoop +{ + public: + DabPlusSnoop() : + m_subchannel_index(0), + m_data(0) {} + + void set_subchannel_index(unsigned subchannel_index) + { + m_subchannel_index = subchannel_index; + } + + void push(uint8_t* streamdata, size_t streamsize); + + private: + int decode(void); + int check(void); + + unsigned m_subchannel_index; + std::vector<uint8_t> m_data; +}; + +#endif + diff --git a/etisnoop.cpp b/etisnoop.cpp index de9672a..22248d5 100644 --- a/etisnoop.cpp +++ b/etisnoop.cpp @@ -15,7 +15,7 @@ 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.c + etisnoop.cpp Parse ETI NI G.703 file Authors: @@ -34,9 +34,13 @@ #include <fcntl.h> #include <string.h> #include <string> +#include <vector> +#include <map> #include <sstream> #include "lib_crc.h" +#include "dabplussnoop.h" + #define ETINIPACKETSIZE 6144 @@ -53,9 +57,15 @@ void decodeFIG(unsigned char* figdata, unsigned short int figtype, unsigned short int indent); -int eti_analyse(int etifd, - int verbosity, - bool ignore_error); +struct eti_analyse_config_t { + int etifd; + int verbosity; + bool ignore_error; + std::map<int, DabPlusSnoop> streams_to_decode; +}; + +int eti_analyse(eti_analyse_config_t& config); + #define no_argument 0 #define required_argument 1 @@ -64,8 +74,8 @@ const struct option longopts[] = { {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, {"ignore-error", no_argument, 0, 'e'}, - {"input", required_argument, 0, 'i'}, - {"save-msc", required_argument, 0, 's'} + {"decode-stream", required_argument, 0, 'd'}, + {"input", required_argument, 0, 'i'} }; void usage(void) @@ -74,7 +84,7 @@ void usage(void) "ETISnoop analyser\n\n" "The ETSnoop analyser decodes and prints out a RAW ETI file in a\n" "form that makes analysis easier.\n" - "Usage: etisnoop [-v] [-i filename]\n"); + "Usage: etisnoop [-v] [-i filename] [-d stream_index]\n"); } int main(int argc, char *argv[]) @@ -82,13 +92,23 @@ int main(int argc, char *argv[]) int index; int ch = 0; string file_name("-"); + map<int, DabPlusSnoop> streams_to_decode; int verbosity = 0; bool ignore_error = false; while(ch != -1) { - ch = getopt_long(argc, argv, "hvi:s:", longopts, &index); + ch = getopt_long(argc, argv, "d:ehvi:s:", longopts, &index); switch (ch) { + case 'd': + { + DabPlusSnoop dps; + streams_to_decode[atoi(optarg)] = dps; + } + break; + case 'e': + ignore_error = true; + break; case 'i': file_name = optarg; break; @@ -97,9 +117,6 @@ int main(int argc, char *argv[]) case 'v': verbosity++; break; - case 'e': - ignore_error = true; - break; case 'h': usage(); return 1; @@ -120,11 +137,17 @@ int main(int argc, char *argv[]) } } - eti_analyse(etifd, verbosity, ignore_error); + eti_analyse_config_t config = { + .etifd = etifd, + .verbosity = verbosity, + .ignore_error = ignore_error, + .streams_to_decode = streams_to_decode + }; + eti_analyse(config); close(etifd); } -int eti_analyse(int etifd, int verbosity, bool ignore_error) +int eti_analyse(eti_analyse_config_t& config) { unsigned char p[ETINIPACKETSIZE]; string desc; @@ -138,7 +161,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) while (1) { - int ret = read(etifd, p, ETINIPACKETSIZE); + int ret = read(config.etifd, p, ETINIPACKETSIZE); if (ret != ETINIPACKETSIZE) { fprintf(stderr, "End of ETI\n"); break; @@ -155,7 +178,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) else { desc = "Error"; printbuf("ERR", 1, p, 1, desc); - if (!ignore_error) { + if (!config.ignore_error) { break; } } @@ -204,7 +227,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) { stringstream ss; - ss << ficf; + ss << (int)ficf; if (ficf == 1) { ss << "- FIC Information are present"; } @@ -219,7 +242,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) nst = p[5] & 0x7F; { stringstream ss; - ss << nst; + ss << (int)nst; printbuf("NST - Number of streams", 2, NULL, 0, ss.str()); } @@ -227,7 +250,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) fp = (p[6] & 0xE0) >> 5; { stringstream ss; - ss << fp; + ss << (int)fp; printbuf("FP - Frame Phase", 2, &fp, 1, ss.str()); } @@ -237,7 +260,7 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) stringstream ss; ss << "Mode "; if (mid != 0) { - ss << mid; + ss << (int)mid; } else { ss << "4"; @@ -308,16 +331,22 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) plevelstr = ss.str(); } sprintf(sdesc, "0x%02x - Equal Error Protection. %s", tpl, plevelstr.c_str()); - } else { + } + else { unsigned char tsw, uepidx; tsw = (tpl & 0x08); uepidx = tpl & 0x07; sprintf(sdesc, "0x%02x - Unequal Error Protection. Table switch %d, UEP index %d", tpl, tsw, uepidx); } printbuf("TPL - Sub-channel Type and Protection Level", 3, NULL, 0, sdesc); - stl[i] = (p[10+4*i] & 0x03) * 256 + p[11+4*i]; + stl[i] = (p[10+4*i] & 0x03) * 256 + \ + p[11+4*i]; sprintf(sdesc, "%d => %d kbit/s", stl[i], stl[i]*8/3); printbuf("STL - Sub-channel Stream Length", 3, NULL, 0, sdesc); + + if (config.streams_to_decode.count(i) > 0) { + config.streams_to_decode[i].set_subchannel_index(stl[i]/3); + } } // EOH @@ -402,8 +431,13 @@ int eti_analyse(int etifd, int verbosity, bool ignore_error) unsigned char streamdata[684*8]; memcpy(streamdata, p + 12 + 4*nst + ficf*ficl*4 + offset, stl[i]*8); offset += stl[i] * 8; - sprintf(sdesc, "%d", i); + sprintf(sdesc, "id %d, len %d", i, stl[i]*8); printbuf("Stream Data", 1, streamdata, stl[i]*8, sdesc); + + if (config.streams_to_decode.count(i) > 0) { + config.streams_to_decode[i].push(streamdata, stl[i]*8); + } + } // EOF @@ -584,7 +618,7 @@ void decodeFIG(unsigned char* f, unsigned char figlen,unsigned short int figtype else if (scty == 1) sprintf(sctydesc, "MPEG Background sound (%d)", scty); else if (scty == 2) - sprintf(sctydesc, "Multi Chaneel sound (%d)", scty); + sprintf(sctydesc, "Multi Channel sound (%d)", scty); else if (scty == 63) sprintf(sctydesc, "AAC sound (%d)", scty); else @@ -594,7 +628,7 @@ void decodeFIG(unsigned char* f, unsigned char figlen,unsigned short int figtype printbuf(desc, indent+3, NULL, 0); } else if (timd == 1) { - //MSC stream data + // MSC stream data sprintf(sctydesc, "DSCTy=%d", 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); @@ -606,7 +640,7 @@ void decodeFIG(unsigned char* f, unsigned char figlen,unsigned short int figtype printbuf(desc, indent+3, NULL, 0); } else if (timd == 3) { - // MSC PAcket mode + // 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); } diff --git a/firecode.c b/firecode.c new file mode 100644 index 0000000..fd13dec --- /dev/null +++ b/firecode.c @@ -0,0 +1,50 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + firecode.c + Implement a FireCode CRC calculator + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +#include "firecode.h" + +uint16_t firecode_crc(uint8_t* buf, size_t size) +{ + int crc; + int gen_poly; + + crc = 0x0000; + gen_poly = 0x782F; // 0111 1000 0010 1111 (16, 14, 13, 12, 11, 5, 3, 2, 1, 0) + + for (int len = 0; len < size; len++) { + for (int i = 0x80; i != 0; i >>= 1) { + if ((crc & 0x8000) != 0) { + crc = (crc << 1) ^ gen_poly; + } + else { + crc = crc << 1; + } + if ((buf[len] & i) != 0) { + crc ^= gen_poly; + } + } + } + + return crc & 0xFFFF; +} + diff --git a/firecode.h b/firecode.h new file mode 100644 index 0000000..3bfe6a6 --- /dev/null +++ b/firecode.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2014 Matthias P. Braendli (http://www.opendigitalradio.org) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + firecode.c + Implement a FireCode CRC calculator + + Authors: + Matthias P. Braendli <matthias@mpb.li> +*/ + +#ifndef _FIRECODE_H_ +#define _FIRECODE_H_ + +#include <stdint.h> +#include <stdlib.h> + +uint16_t firecode_crc(uint8_t* buf, size_t size); + +#endif |