diff options
| -rw-r--r-- | lib/edi/ETIDecoder.cpp | 4 | ||||
| -rw-r--r-- | lib/edi/PFT.cpp | 63 | ||||
| -rw-r--r-- | lib/edi/PFT.hpp | 19 | ||||
| -rw-r--r-- | lib/edi/common.cpp | 26 | ||||
| -rw-r--r-- | lib/edi/common.hpp | 14 | 
5 files changed, 85 insertions, 41 deletions
diff --git a/lib/edi/ETIDecoder.cpp b/lib/edi/ETIDecoder.cpp index 656f50b..a377692 100644 --- a/lib/edi/ETIDecoder.cpp +++ b/lib/edi/ETIDecoder.cpp @@ -69,7 +69,7 @@ void ETIDecoder::setMaxDelay(int num_af_packets)  #define AFPACKET_HEADER_LEN 10 // includes SYNC -bool ETIDecoder::decode_starptr(const std::vector<uint8_t>& value, const tag_name_t& n) +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()); @@ -89,7 +89,7 @@ bool ETIDecoder::decode_starptr(const std::vector<uint8_t>& value, const tag_nam      return true;  } -bool ETIDecoder::decode_deti(const std::vector<uint8_t>& value, const tag_name_t& n) +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); diff --git a/lib/edi/PFT.cpp b/lib/edi/PFT.cpp index 85d6b63..25f2d1f 100644 --- a/lib/edi/PFT.cpp +++ b/lib/edi/PFT.cpp @@ -1,6 +1,6 @@  /* ------------------------------------------------------------------   * Copyright (C) 2017 AVT GmbH - Fabien Vercasson - * Copyright (C) 2017 Matthias P. Braendli + * Copyright (C) 2021 Matthias P. Braendli   *                    matthias.braendli@mpb.li   *   * http://opendigitalradio.org @@ -126,7 +126,7 @@ size_t Fragment::loadData(const std::vector<uint8_t> &buf, int received_on_port)      // Parse PFT Fragment Header (ETSI TS 102 821 V1.4.1 ch7.1)      if (not (buf[0] == 'P' and buf[1] == 'F') ) { -        throw invalid_argument("Invalid PFT SYNC bytes"); +        throw runtime_error("Invalid PFT SYNC bytes");      }      index += 2; // Psync @@ -208,15 +208,30 @@ AFBuilder::AFBuilder(pseq_t Pseq, findex_t Fcount, size_t lifetime)  void AFBuilder::pushPFTFrag(const Fragment &frag)  { -    if (_Pseq != frag.Pseq() or _Fcount != frag.Fcount()) { -        throw invalid_argument("Invalid PFT fragment Pseq or Fcount"); +    if (_Pseq != frag.Pseq()) { +        throw logic_error("Invalid PFT fragment Pseq");      } -    const auto Findex = frag.Findex(); -    const bool fragment_already_received = _fragments.count(Findex); -    if (not fragment_already_received) -    { -        _fragments[Findex] = frag; +    if (_Fcount != frag.Fcount()) { +        etiLog.level(warn) << "Discarding fragment with invalid fcount"; +    } +    else { +        const auto Findex = frag.Findex(); +        const bool fragment_already_received = _fragments.count(Findex); + +        if (not fragment_already_received) { +            bool consistent = true; +            if (_fragments.size() > 0) { +                consistent = frag.checkConsistency(_fragments.cbegin()->second); +            } + +            if (consistent) { +                _fragments[Findex] = frag; +            } +            else { +                etiLog.level(warn) << "Discard fragment"; +            } +        }      }  } @@ -246,7 +261,7 @@ bool Fragment::checkConsistency(const Fragment& other) const  } -AFBuilder::decode_attempt_result_t AFBuilder::canAttemptToDecode() const +AFBuilder::decode_attempt_result_t AFBuilder::canAttemptToDecode()  {      if (_fragments.empty()) {          return AFBuilder::decode_attempt_result_t::no; @@ -263,7 +278,8 @@ AFBuilder::decode_attempt_result_t AFBuilder::canAttemptToDecode() const                  const Fragment& frag = pair.second;                  return first.checkConsistency(frag) and _Pseq == frag.Pseq();              }) ) { -        throw invalid_argument("Inconsistent PFT fragments"); +        _fragments.clear(); +        throw runtime_error("Inconsistent PFT fragments");      }      // Calculate the minimum number of fragments necessary to apply FEC. @@ -301,7 +317,7 @@ AFBuilder::decode_attempt_result_t AFBuilder::canAttemptToDecode() const      return AFBuilder::decode_attempt_result_t::no;  } -std::vector<uint8_t> AFBuilder::extractAF() const +std::vector<uint8_t> AFBuilder::extractAF()  {      if (not _af_packet.empty()) {          return _af_packet; @@ -310,13 +326,12 @@ std::vector<uint8_t> AFBuilder::extractAF() const      bool ok = false;      if (canAttemptToDecode() != AFBuilder::decode_attempt_result_t::no) { -          auto frag_it = _fragments.begin();          if (frag_it->second.Fcount() == _Fcount - 1) {              frag_it++;              if (frag_it == _fragments.end()) { -                throw std::runtime_error("Invalid attempt at extracting AF"); +                throw runtime_error("Invalid attempt at extracting AF");              }          } @@ -343,12 +358,14 @@ std::vector<uint8_t> AFBuilder::extractAF() const                      const auto& fragment = _fragments.at(j).payload();                      if (j != _Fcount - 1 and fragment.size() != Plen) { +                        _fragments.clear();                          throw runtime_error("Incorrect fragment length " +                                  to_string(fragment.size()) + " " +                                  to_string(Plen));                      }                      if (j == _Fcount - 1 and fragment.size() > Plen) { +                        _fragments.clear();                          throw runtime_error("Incorrect last fragment length " +                                  to_string(fragment.size()) + " " +                                  to_string(Plen)); @@ -453,7 +470,7 @@ std::vector<uint8_t> AFBuilder::extractAF() const      return _af_packet;  } -std::string AFBuilder::visualise() const +std::string AFBuilder::visualise()  {      stringstream ss;      ss << "|"; @@ -525,7 +542,7 @@ void PFT::pushPFTFrag(const Fragment &fragment)      if (m_verbose) {          etiLog.log(debug, "Got frag %u:%u, afbuilders: ",                  fragment.Pseq(), fragment.Findex()); -        for (const auto &k : m_afbuilders) { +        for (auto &k : m_afbuilders) {              const bool isNextPseq = (m_next_pseq == k.first);              etiLog.level(debug) << (isNextPseq ? "->" : "  ") <<                  k.first << " " << k.second.visualise(); @@ -534,15 +551,17 @@ void PFT::pushPFTFrag(const Fragment &fragment)  } -std::vector<uint8_t> PFT::getNextAFPacket() +afpacket_pft_t PFT::getNextAFPacket()  { +    afpacket_pft_t af; +      if (m_afbuilders.count(m_next_pseq) == 0) {          if (m_afbuilders.size() > m_max_delay) {              m_afbuilders.clear();              etiLog.level(debug) << " Reinit";          } -        return {}; +        return af;      }      auto &builder = m_afbuilders.at(m_next_pseq); @@ -555,8 +574,9 @@ std::vector<uint8_t> PFT::getNextAFPacket()          if (m_verbose) {              etiLog.level(debug) << "Fragment origin stats: " << builder.visualise_fragment_origins();          } +        af.pseq = m_next_pseq; +        af.af_packet = afpacket;          incrementNextPseq(); -        return afpacket;      }      else if (builder.canAttemptToDecode() == dar_t::maybe) {          if (builder.lifeTime > 0) { @@ -573,8 +593,9 @@ std::vector<uint8_t> PFT::getNextAFPacket()              if (m_verbose) {                  etiLog.level(debug) << "Fragment origin stats: " << builder.visualise_fragment_origins();              } +            af.pseq = m_next_pseq; +            af.af_packet = afpacket;              incrementNextPseq(); -            return afpacket;          }      }      else { @@ -588,7 +609,7 @@ std::vector<uint8_t> PFT::getNextAFPacket()          }      } -    return {}; +    return af;  }  void PFT::setMaxDelay(size_t num_af_packets) diff --git a/lib/edi/PFT.hpp b/lib/edi/PFT.hpp index 08dca45..aa5b9d3 100644 --- a/lib/edi/PFT.hpp +++ b/lib/edi/PFT.hpp @@ -1,6 +1,6 @@  /* ------------------------------------------------------------------   * Copyright (C) 2017 AVT GmbH - Fabien Vercasson - * Copyright (C) 2017 Matthias P. Braendli + * Copyright (C) 2021 Matthias P. Braendli   *                    matthias.braendli@mpb.li   *   * http://opendigitalradio.org @@ -101,20 +101,20 @@ class AFBuilder          void pushPFTFrag(const Fragment &frag);          /* Assess if it may be possible to decode this AF packet */ -        decode_attempt_result_t canAttemptToDecode() const; +        decode_attempt_result_t canAttemptToDecode();          /* Try to build the AF with received fragments.           * Apply error correction if necessary (missing packets/CRC errors)           * \return an empty vector if building the AF is not possible           */ -        std::vector<uint8_t> extractAF(void) const; +        std::vector<uint8_t> extractAF();          std::pair<findex_t, findex_t>              numberOfFragments(void) const {                  return {_fragments.size(), _Fcount};              } -        std::string visualise() const; +        std::string visualise();          std::string visualise_fragment_origins() const; @@ -135,6 +135,13 @@ class AFBuilder          findex_t _Fcount;  }; +struct afpacket_pft_t +{ +    // validity of the struct is given by af_packet begin empty or not. +    std::vector<uint8_t> af_packet; +    pseq_t pseq = 0; +}; +  class PFT  {      public: @@ -145,7 +152,7 @@ class PFT           *           * \return an empty vector if building the AF is not possible           */ -        std::vector<uint8_t> getNextAFPacket(void); +        afpacket_pft_t getNextAFPacket();          /* Set the maximum delay in number of AF Packets before we           * abandon decoding a given pseq. @@ -156,7 +163,7 @@ class PFT          void setVerbose(bool enable);      private: -        void incrementNextPseq(void); +        void incrementNextPseq();          pseq_t m_next_pseq;          size_t m_max_delay = 10; // in AF packets diff --git a/lib/edi/common.cpp b/lib/edi/common.cpp index 7907656..2f20391 100644 --- a/lib/edi/common.cpp +++ b/lib/edi/common.cpp @@ -132,7 +132,7 @@ std::string tag_name_to_human_readable(const tag_name_t& name)  TagDispatcher::TagDispatcher(          std::function<void()>&& af_packet_completed) :      m_af_packet_completed(move(af_packet_completed)), -    m_tagpacket_handler([](const std::vector<uint8_t>& ignore){}) +    m_tagpacket_handler([](const std::vector<uint8_t>& /*ignore*/){})  {  } @@ -145,7 +145,7 @@ void TagDispatcher::push_bytes(const vector<uint8_t> &buf)  {      if (buf.empty()) {          m_input_data.clear(); -        m_last_seq_valid = false; +        m_last_sequences.seq_valid = false;          return;      } @@ -168,6 +168,7 @@ void TagDispatcher::push_bytes(const vector<uint8_t> &buf)                  m_input_data = remaining_data;              } +            m_last_sequences.pseq_valid = false;              if (st.complete) {                  m_af_packet_completed();              } @@ -192,8 +193,10 @@ void TagDispatcher::push_bytes(const vector<uint8_t> &buf)              }              auto af = m_pft.getNextAFPacket(); -            if (not af.empty()) { -                decode_state_t st = decode_afpacket(af); +            if (not af.af_packet.empty()) { +                const decode_state_t st = decode_afpacket(af.af_packet); +                m_last_sequences.pseq = af.pseq; +                m_last_sequences.pseq_valid = true;                  if (st.complete) {                      m_af_packet_completed(); @@ -217,6 +220,7 @@ void TagDispatcher::push_packet(const Packet &packet)      if (buf[0] == 'A' and buf[1] == 'F') {          const decode_state_t st = decode_afpacket(buf); +        m_last_sequences.pseq_valid = false;          if (st.complete) {              m_af_packet_completed(); @@ -232,8 +236,10 @@ void TagDispatcher::push_packet(const Packet &packet)          }          auto af = m_pft.getNextAFPacket(); -        if (not af.empty()) { -            const decode_state_t st = decode_afpacket(af); +        if (not af.af_packet.empty()) { +            const decode_state_t st = decode_afpacket(af.af_packet); +            m_last_sequences.pseq = af.pseq; +            m_last_sequences.pseq_valid = true;              if (st.complete) {                  m_af_packet_completed(); @@ -272,8 +278,8 @@ decode_state_t TagDispatcher::decode_afpacket(      }      // SEQ wraps at 0xFFFF, unsigned integer overflow is intentional -    if (m_last_seq_valid) { -        const uint16_t expected_seq = m_last_seq + 1; +    if (m_last_sequences.seq_valid) { +        const uint16_t expected_seq = m_last_sequences.seq + 1;          if (expected_seq != seq) {              etiLog.level(warn) << "EDI AF Packet sequence error, " << seq;              m_ignored_tags.clear(); @@ -281,9 +287,9 @@ decode_state_t TagDispatcher::decode_afpacket(      }      else {          etiLog.level(info) << "EDI AF Packet initial sequence number: " << seq; -        m_last_seq_valid = true; +        m_last_sequences.seq_valid = true;      } -    m_last_seq = seq; +    m_last_sequences.seq = seq;      bool has_crc = (input_data[8] & 0x80) ? true : false;      uint8_t major_revision = (input_data[8] & 0x70) >> 4; diff --git a/lib/edi/common.hpp b/lib/edi/common.hpp index 14b91ba..e8c57c1 100644 --- a/lib/edi/common.hpp +++ b/lib/edi/common.hpp @@ -68,6 +68,13 @@ struct Packet {      Packet() {}  }; +struct seq_info_t { +    bool seq_valid = false; +    uint16_t seq = 0; +    bool pseq_valid = false; +    uint16_t pseq = 0; +}; +  /* The TagDispatcher takes care of decoding EDI, with or without PFT, and   * will call functions when TAGs are encountered.   * @@ -110,13 +117,16 @@ class TagDispatcher {          using tagpacket_handler = std::function<void(const std::vector<uint8_t>&)>;          void register_tagpacket_handler(tagpacket_handler&& h); +        seq_info_t get_seq_info() const { +            return m_last_sequences; +        } +      private:          decode_state_t decode_afpacket(const std::vector<uint8_t> &input_data);          bool decode_tagpacket(const std::vector<uint8_t> &payload);          PFT::PFT m_pft; -        bool m_last_seq_valid = false; -        uint16_t m_last_seq = 0; +        seq_info_t m_last_sequences;          std::vector<uint8_t> m_input_data;          std::map<std::string, tag_handler> m_handlers;          std::function<void()> m_af_packet_completed;  | 
