aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2014-11-09 11:33:11 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2014-11-09 11:33:11 +0100
commit639951285591ab6e8d1158e336a3f6c19477cc4f (patch)
tree40c6090f564539cd2bb201b85e4ffa53ddd4b880
parent588a749b8544afce1824d9bcda80f2c5a44524e5 (diff)
downloadetisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.tar.gz
etisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.tar.bz2
etisnoop-639951285591ab6e8d1158e336a3f6c19477cc4f.zip
ETISnoop search for firecode
-rw-r--r--Makefile7
-rw-r--r--dabplussnoop.cpp180
-rw-r--r--dabplussnoop.h101
-rw-r--r--etisnoop.cpp84
-rw-r--r--firecode.c50
-rw-r--r--firecode.h32
6 files changed, 427 insertions, 27 deletions
diff --git a/Makefile b/Makefile
index 4fe3609..f6a68b1 100644
--- a/Makefile
+++ b/Makefile
@@ -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