aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--decoder/ETIDecoder.cpp37
-rw-r--r--decoder/ETIDecoder.hpp28
-rw-r--r--decoder/ETIWriter.cpp6
-rw-r--r--decoder/ETIWriter.hpp20
-rw-r--r--decoder/STIDecoder.cpp27
-rw-r--r--decoder/STIDecoder.hpp18
-rw-r--r--decoder/common.cpp65
-rw-r--r--decoder/common.hpp24
-rw-r--r--test/main.cpp6
9 files changed, 158 insertions, 73 deletions
diff --git a/decoder/ETIDecoder.cpp b/decoder/ETIDecoder.cpp
index 1fa9c3c..88a7333 100644
--- a/decoder/ETIDecoder.cpp
+++ b/decoder/ETIDecoder.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -30,9 +30,9 @@ namespace EdiDecoder {
using namespace std;
-ETIDecoder::ETIDecoder(ETIDataCollector& data_collector, bool verbose) :
+ETIDecoder::ETIDecoder(ETIDataCollector& data_collector) :
m_data_collector(data_collector),
- m_dispatcher(std::bind(&ETIDecoder::packet_completed, this), verbose)
+ m_dispatcher(std::bind(&ETIDecoder::packet_completed, this))
{
using std::placeholders::_1;
using std::placeholders::_2;
@@ -44,6 +44,12 @@ ETIDecoder::ETIDecoder(ETIDataCollector& data_collector, bool verbose) :
std::bind(&ETIDecoder::decode_estn, this, _1, _2));
m_dispatcher.register_tag("*dmy",
std::bind(&ETIDecoder::decode_stardmy, this, _1, _2));
+ m_dispatcher.register_tagpacket_handler(std::bind(&ETIDecoder::decode_tagpacket, this, _1));
+}
+
+void ETIDecoder::set_verbose(bool verbose)
+{
+ m_dispatcher.set_verbose(verbose);
}
void ETIDecoder::push_bytes(const vector<uint8_t> &buf)
@@ -63,7 +69,7 @@ void ETIDecoder::setMaxDelay(int num_af_packets)
#define AFPACKET_HEADER_LEN 10 // includes SYNC
-bool ETIDecoder::decode_starptr(const vector<uint8_t> &value, uint16_t)
+bool ETIDecoder::decode_starptr(const std::vector<uint8_t>& value, const tag_name_t& n)
{
if (value.size() != 0x40 / 8) {
etiLog.log(warn, "Incorrect length %02lx for *PTR", value.size());
@@ -83,7 +89,7 @@ bool ETIDecoder::decode_starptr(const vector<uint8_t> &value, uint16_t)
return true;
}
-bool ETIDecoder::decode_deti(const vector<uint8_t> &value, uint16_t)
+bool ETIDecoder::decode_deti(const std::vector<uint8_t>& value, const tag_name_t& n)
{
/*
uint16_t detiHeader = fct | (fcth << 8) | (rfudf << 13) | (ficf << 14) | (atstf << 15);
@@ -145,6 +151,8 @@ bool ETIDecoder::decode_deti(const vector<uint8_t> &value, uint16_t)
i += 4;
m_data_collector.update_edi_time(utco, seconds);
+ m_received_tagpacket.timestamp.utco = utco;
+ m_received_tagpacket.timestamp.seconds = seconds;
fc.tsta = read_24b(value.begin() + i);
i += 3;
@@ -152,8 +160,12 @@ bool ETIDecoder::decode_deti(const vector<uint8_t> &value, uint16_t)
else {
// Null timestamp, ETSI ETS 300 799, C.2.2
fc.tsta = 0xFFFFFF;
+ m_received_tagpacket.timestamp.utco = 0;
+ m_received_tagpacket.timestamp.seconds = 0;
}
+ m_received_tagpacket.timestamp.tsta = fc.tsta;
+
if (fc.ficf) {
vector<uint8_t> fic(fic_length);
@@ -183,12 +195,13 @@ bool ETIDecoder::decode_deti(const vector<uint8_t> &value, uint16_t)
return true;
}
-bool ETIDecoder::decode_estn(const vector<uint8_t> &value, uint16_t n)
+bool ETIDecoder::decode_estn(const std::vector<uint8_t>& value, const tag_name_t& name)
{
uint32_t sstc = read_24b(value.begin());
eti_stc_data stc;
+ const uint8_t n = name[3];
stc.stream_index = n - 1; // n is 1-indexed
stc.scid = (sstc >> 18) & 0x3F;
stc.sad = (sstc >> 8) & 0x3FF;
@@ -207,14 +220,22 @@ bool ETIDecoder::decode_estn(const vector<uint8_t> &value, uint16_t n)
return true;
}
-bool ETIDecoder::decode_stardmy(const vector<uint8_t>& /*value*/, uint16_t)
+bool ETIDecoder::decode_stardmy(const std::vector<uint8_t>&, const tag_name_t&)
+{
+ return true;
+}
+
+bool ETIDecoder::decode_tagpacket(const std::vector<uint8_t>& value)
{
+ m_received_tagpacket.tagpacket = value;
return true;
}
void ETIDecoder::packet_completed()
{
- m_data_collector.assemble();
+ ReceivedTagPacket tp;
+ swap(tp, m_received_tagpacket);
+ m_data_collector.assemble(move(tp));
}
}
diff --git a/decoder/ETIDecoder.hpp b/decoder/ETIDecoder.hpp
index f5d0b81..ffa9037 100644
--- a/decoder/ETIDecoder.hpp
+++ b/decoder/ETIDecoder.hpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -57,6 +57,12 @@ struct eti_stc_data {
uint16_t stl(void) const { return mst.size() / 8; }
};
+struct ReceivedTagPacket {
+ std::vector<uint8_t> tagpacket;
+ frame_timestamp_t timestamp;
+};
+
+
/* A class that receives multiplex data must implement the interface described
* in the ETIDataCollector. This can be e.g. a converter to ETI, or something that
* prepares data structures for a modulator.
@@ -87,8 +93,9 @@ class ETIDataCollector {
virtual void add_subchannel(eti_stc_data&& stc) = 0;
- // Tell the ETIWriter that the AFPacket is complete
- virtual void assemble(void) = 0;
+ // Tell the consumer that the AFPacket is complete, and include
+ // the raw received TAGs
+ virtual void assemble(ReceivedTagPacket&& tagpacket) = 0;
};
/* The ETIDecoder takes care of decoding the EDI TAGs related to the transport
@@ -99,7 +106,9 @@ class ETIDataCollector {
*/
class ETIDecoder {
public:
- ETIDecoder(ETIDataCollector& data_collector, bool verbose);
+ ETIDecoder(ETIDataCollector& data_collector);
+
+ void set_verbose(bool verbose);
/* Push bytes into the decoder. The buf can contain more
* than a single packet. This is useful when reading from streams
@@ -118,16 +127,19 @@ class ETIDecoder {
void setMaxDelay(int num_af_packets);
private:
- bool decode_starptr(const std::vector<uint8_t> &value, uint16_t);
- bool decode_deti(const std::vector<uint8_t> &value, uint16_t);
- bool decode_estn(const std::vector<uint8_t> &value, uint16_t n);
- bool decode_stardmy(const std::vector<uint8_t> &value, uint16_t);
+ bool decode_starptr(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_deti(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_estn(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_stardmy(const std::vector<uint8_t>& value, const tag_name_t& n);
+
+ bool decode_tagpacket(const std::vector<uint8_t>& value);
void packet_completed();
ETIDataCollector& m_data_collector;
TagDispatcher m_dispatcher;
+ ReceivedTagPacket m_received_tagpacket;
};
}
diff --git a/decoder/ETIWriter.cpp b/decoder/ETIWriter.cpp
index 784c73b..3f79acc 100644
--- a/decoder/ETIWriter.cpp
+++ b/decoder/ETIWriter.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -140,8 +140,10 @@ void ETIWriter::add_subchannel(eti_stc_data&& stc)
}
-void ETIWriter::assemble()
+void ETIWriter::assemble(ReceivedTagPacket&& tagpacket)
{
+ (void)tagpacket;
+
if (not m_proto_valid) {
throw std::logic_error("Cannot assemble ETI before protocol");
}
diff --git a/decoder/ETIWriter.hpp b/decoder/ETIWriter.hpp
index b990942..d950240 100644
--- a/decoder/ETIWriter.hpp
+++ b/decoder/ETIWriter.hpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -47,29 +47,29 @@ class ETIWriter : public ETIDataCollector {
virtual void update_protocol(
const std::string& proto,
uint16_t major,
- uint16_t minor);
+ uint16_t minor) override;
// Update the data for the frame characterisation
- virtual void update_fc_data(const eti_fc_data& fc_data);
+ virtual void update_fc_data(const eti_fc_data& fc_data) override;
- virtual void update_fic(std::vector<uint8_t>&& fic);
+ virtual void update_fic(std::vector<uint8_t>&& fic) override;
- virtual void update_err(uint8_t err);
+ virtual void update_err(uint8_t err) override;
// In addition to TSTA in ETI, EDI also transports more time
// stamp information.
virtual void update_edi_time(
uint32_t utco,
- uint32_t seconds);
+ uint32_t seconds) override;
- virtual void update_mnsc(uint16_t mnsc);
+ virtual void update_mnsc(uint16_t mnsc) override;
- virtual void update_rfu(uint16_t rfu);
+ virtual void update_rfu(uint16_t rfu) override;
- virtual void add_subchannel(eti_stc_data&& stc);
+ virtual void add_subchannel(eti_stc_data&& stc) override;
// Tell the ETIWriter that the AFPacket is complete
- virtual void assemble(void);
+ virtual void assemble(ReceivedTagPacket&& tagpacket) override;
private:
std::function<void(eti_frame_t&&)> m_frame_callback;
diff --git a/decoder/STIDecoder.cpp b/decoder/STIDecoder.cpp
index a911947..8f35df1 100644
--- a/decoder/STIDecoder.cpp
+++ b/decoder/STIDecoder.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -30,9 +30,9 @@ namespace EdiDecoder {
using namespace std;
-STIDecoder::STIDecoder(STIDataCollector& data_collector, bool verbose) :
+STIDecoder::STIDecoder(STIDataCollector& data_collector) :
m_data_collector(data_collector),
- m_dispatcher(std::bind(&STIDecoder::packet_completed, this), verbose)
+ m_dispatcher(std::bind(&STIDecoder::packet_completed, this))
{
using std::placeholders::_1;
using std::placeholders::_2;
@@ -50,6 +50,11 @@ STIDecoder::STIDecoder(STIDataCollector& data_collector, bool verbose) :
std::bind(&STIDecoder::decode_odrversion, this, _1, _2));
}
+void STIDecoder::set_verbose(bool verbose)
+{
+ m_dispatcher.set_verbose(verbose);
+}
+
void STIDecoder::push_bytes(const vector<uint8_t> &buf)
{
m_dispatcher.push_bytes(buf);
@@ -67,7 +72,7 @@ void STIDecoder::setMaxDelay(int num_af_packets)
#define AFPACKET_HEADER_LEN 10 // includes SYNC
-bool STIDecoder::decode_starptr(const vector<uint8_t> &value, uint16_t)
+bool STIDecoder::decode_starptr(const std::vector<uint8_t>& value, const tag_name_t& n)
{
if (value.size() != 0x40 / 8) {
etiLog.log(warn, "Incorrect length %02lx for *PTR", value.size());
@@ -89,7 +94,7 @@ bool STIDecoder::decode_starptr(const vector<uint8_t> &value, uint16_t)
return true;
}
-bool STIDecoder::decode_dsti(const vector<uint8_t> &value, uint16_t)
+bool STIDecoder::decode_dsti(const std::vector<uint8_t>& value, const tag_name_t& n)
{
size_t offset = 0;
@@ -159,10 +164,14 @@ bool STIDecoder::decode_dsti(const vector<uint8_t> &value, uint16_t)
return true;
}
-bool STIDecoder::decode_ssn(const vector<uint8_t> &value, uint16_t n)
+bool STIDecoder::decode_ssn(const std::vector<uint8_t>& value, const tag_name_t& name)
{
sti_payload_data sti;
+ uint16_t n = 0;
+ n = (uint16_t)(name[2]) << 8;
+ n |= (uint16_t)(name[3]);
+
sti.stream_index = n - 1; // n is 1-indexed
etiLog.log(debug, "STI SSn=%d", n);
sti.rfa = value[0] >> 3;
@@ -187,12 +196,12 @@ bool STIDecoder::decode_ssn(const vector<uint8_t> &value, uint16_t n)
return true;
}
-bool STIDecoder::decode_stardmy(const vector<uint8_t>& /*value*/, uint16_t)
+bool STIDecoder::decode_stardmy(const std::vector<uint8_t>&, const tag_name_t&)
{
return true;
}
-bool STIDecoder::decode_odraudiolevel(const vector<uint8_t>& value, uint16_t)
+bool STIDecoder::decode_odraudiolevel(const std::vector<uint8_t>& value, const tag_name_t& n)
{
constexpr size_t expected_length = 2 * sizeof(int16_t);
@@ -215,7 +224,7 @@ bool STIDecoder::decode_odraudiolevel(const vector<uint8_t>& value, uint16_t)
return true;
}
-bool STIDecoder::decode_odrversion(const vector<uint8_t>& value, uint16_t)
+bool STIDecoder::decode_odrversion(const std::vector<uint8_t>& value, const tag_name_t& n)
{
const auto vd = parse_odr_version_data(value);
m_data_collector.update_odr_version(vd);
diff --git a/decoder/STIDecoder.hpp b/decoder/STIDecoder.hpp
index e2aa850..9d55728 100644
--- a/decoder/STIDecoder.hpp
+++ b/decoder/STIDecoder.hpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -98,7 +98,9 @@ class STIDataCollector {
*/
class STIDecoder {
public:
- STIDecoder(STIDataCollector& data_collector, bool verbose);
+ STIDecoder(STIDataCollector& data_collector);
+
+ void set_verbose(bool verbose);
/* Push bytes into the decoder. The buf can contain more
* than a single packet. This is useful when reading from streams
@@ -117,13 +119,13 @@ class STIDecoder {
void setMaxDelay(int num_af_packets);
private:
- bool decode_starptr(const std::vector<uint8_t> &value, uint16_t);
- bool decode_dsti(const std::vector<uint8_t> &value, uint16_t);
- bool decode_ssn(const std::vector<uint8_t> &value, uint16_t n);
- bool decode_stardmy(const std::vector<uint8_t> &value, uint16_t);
+ bool decode_starptr(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_dsti(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_ssn(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_stardmy(const std::vector<uint8_t>& value, const tag_name_t& n);
- bool decode_odraudiolevel(const std::vector<uint8_t> &value, uint16_t);
- bool decode_odrversion(const std::vector<uint8_t> &value, uint16_t);
+ bool decode_odraudiolevel(const std::vector<uint8_t>& value, const tag_name_t& n);
+ bool decode_odrversion(const std::vector<uint8_t>& value, const tag_name_t& n);
void packet_completed();
diff --git a/decoder/common.cpp b/decoder/common.cpp
index 0c87081..d8a37e3 100644
--- a/decoder/common.cpp
+++ b/decoder/common.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -26,6 +26,7 @@
#include <cassert>
#include <cmath>
#include <cstdio>
+#include <cctype>
namespace EdiDecoder {
@@ -111,10 +112,30 @@ std::chrono::system_clock::time_point frame_timestamp_t::to_system_clock() const
return ts;
}
+std::string tag_name_to_human_readable(const tag_name_t& name)
+{
+ std::string s;
+ for (const uint8_t c : name) {
+ if (isprint(c)) {
+ s += (char)c;
+ }
+ else {
+ char escaped[5];
+ snprintf(escaped, 5, "\\x%02x", c);
+ s += escaped;
+ }
+ }
+ return s;
+}
TagDispatcher::TagDispatcher(
- std::function<void()>&& af_packet_completed, bool verbose) :
- m_af_packet_completed(move(af_packet_completed))
+ std::function<void()>&& af_packet_completed) :
+ m_af_packet_completed(move(af_packet_completed)),
+ m_tagpacket_handler([](const std::vector<uint8_t>& ignore){})
+{
+}
+
+void TagDispatcher::set_verbose(bool verbose)
{
m_pft.setVerbose(verbose);
}
@@ -295,6 +316,11 @@ void TagDispatcher::register_tag(const std::string& tag, tag_handler&& h)
m_handlers[tag] = move(h);
}
+void TagDispatcher::register_tagpacket_handler(tagpacket_handler&& h)
+{
+ m_tagpacket_handler = move(h);
+}
+
bool TagDispatcher::decode_tagpacket(const vector<uint8_t> &payload)
{
@@ -317,6 +343,8 @@ bool TagDispatcher::decode_tagpacket(const vector<uint8_t> &payload)
}
taglength /= 8;
+ length = taglength;
+
const size_t calculated_length = i + 8 + taglength;
if (calculated_length > payload.size()) {
etiLog.log(warn, "Invalid EDI tag length: tag larger %zu than tagpacket %zu!",
@@ -324,34 +352,23 @@ bool TagDispatcher::decode_tagpacket(const vector<uint8_t> &payload)
break;
}
-
- length = taglength;
-
+ const array<uint8_t, 4> tag_name({
+ (uint8_t)tag_sz[0], (uint8_t)tag_sz[1], (uint8_t)tag_sz[2], (uint8_t)tag_sz[3]
+ });
vector<uint8_t> tag_value(taglength);
copy( payload.begin() + i+8,
payload.begin() + i+8+taglength,
tag_value.begin());
- bool tagsuccess = false;
+ bool tagsuccess = true;
bool found = false;
for (auto tag_handler : m_handlers) {
- if (tag_handler.first.size() == 4 and tag_handler.first == tag) {
+ if ( (tag_handler.first.size() == 4 and tag == tag_handler.first) or
+ (tag_handler.first.size() == 3 and tag.substr(0, 3) == tag_handler.first) or
+ (tag_handler.first.size() == 2 and tag.substr(0, 2) == tag_handler.first) or
+ (tag_handler.first.size() == 1 and tag.substr(0, 1) == tag_handler.first)) {
found = true;
- tagsuccess = tag_handler.second(tag_value, 0);
- }
- else if (tag_handler.first.size() == 3 and
- tag.substr(0, 3) == tag_handler.first) {
- found = true;
- uint8_t n = tag_sz[3];
- tagsuccess = tag_handler.second(tag_value, n);
- }
- else if (tag_handler.first.size() == 2 and
- tag.substr(0, 2) == tag_handler.first) {
- found = true;
- uint16_t n = 0;
- n = (uint16_t)(tag_sz[2]) << 8;
- n |= (uint16_t)(tag_sz[3]);
- tagsuccess = tag_handler.second(tag_value, n);
+ tagsuccess &= tag_handler.second(tag_value, tag_name);
}
}
@@ -367,6 +384,8 @@ bool TagDispatcher::decode_tagpacket(const vector<uint8_t> &payload)
}
}
+ m_tagpacket_handler(payload);
+
return success;
}
diff --git a/decoder/common.hpp b/decoder/common.hpp
index 2a9c683..c149421 100644
--- a/decoder/common.hpp
+++ b/decoder/common.hpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2019
+ Copyright (C) 2020
Matthias P. Braendli, matthias.braendli@mpb.li
http://opendigitalradio.org
@@ -55,6 +55,10 @@ struct decode_state_t {
size_t num_bytes_consumed;
};
+using tag_name_t = std::array<uint8_t, 4>;
+
+std::string tag_name_to_human_readable(const tag_name_t& name);
+
/* The TagDispatcher takes care of decoding EDI, with or without PFT, and
* will call functions when TAGs are encountered.
*
@@ -63,7 +67,10 @@ struct decode_state_t {
*/
class TagDispatcher {
public:
- TagDispatcher(std::function<void()>&& af_packet_completed, bool verbose);
+ TagDispatcher(std::function<void()>&& af_packet_completed);
+
+ void set_verbose(bool verbose);
+
/* Push bytes into the decoder. The buf can contain more
* than a single packet. This is useful when reading from streams
@@ -81,9 +88,19 @@ class TagDispatcher {
*/
void setMaxDelay(int num_af_packets);
- using tag_handler = std::function<bool(std::vector<uint8_t>, uint16_t)>;
+ /* Handler function for a tag. The first argument contains the tag value,
+ * the second argument contains the tag name */
+ using tag_handler = std::function<bool(const std::vector<uint8_t>&, const tag_name_t&)>;
+
+ /* Register a handler for a tag. If the tag string can be length 0, 1, 2, 3 or 4.
+ * If is shorter than 4, it will perform a longest match on the tag name.
+ */
void register_tag(const std::string& tag, tag_handler&& h);
+ /* The complete tagpacket can also be retrieved */
+ using tagpacket_handler = std::function<void(const std::vector<uint8_t>&)>;
+ void register_tagpacket_handler(tagpacket_handler&& h);
+
private:
decode_state_t decode_afpacket(const std::vector<uint8_t> &input_data);
bool decode_tagpacket(const std::vector<uint8_t> &payload);
@@ -93,6 +110,7 @@ class TagDispatcher {
std::vector<uint8_t> m_input_data;
std::map<std::string, tag_handler> m_handlers;
std::function<void()> m_af_packet_completed;
+ tagpacket_handler m_tagpacket_handler;
};
// Data carried inside the ODRv EDI TAG
diff --git a/test/main.cpp b/test/main.cpp
index 7885d60..0c8d984 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -193,7 +193,8 @@ int main(int argc, char **argv)
};
EdiDecoder::ETIWriter eti_writer(eti_cb);
- EdiDecoder::ETIDecoder eti_decoder(eti_writer, options.verbose > 1);
+ EdiDecoder::ETIDecoder eti_decoder(eti_writer);
+ eti_decoder.set_verbose(options.verbose > 1);
deque<vector<uint8_t> > aac_frames;
AACDecoder aac_decoder("edilib-aac.wav");
@@ -222,7 +223,8 @@ int main(int argc, char **argv)
};
EdiDecoder::STIWriter sti_writer(sti_cb);
- EdiDecoder::STIDecoder sti_decoder(sti_writer, options.verbose > 1);
+ EdiDecoder::STIDecoder sti_decoder(sti_writer);
+ sti_decoder.set_verbose(options.verbose > 1);
if (options.max_delay) {
eti_decoder.setMaxDelay(options.max_delay);