aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-12-21 20:53:19 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-12-21 20:53:19 +0100
commit2d71a31f547c87e146adeafc3012aa5ff3cc07a1 (patch)
tree5ddc5dcd934d9df314c6c50c1885a1f5bf3e7058
parent65168f6253a73596f437990ff5b56489c1b3eff1 (diff)
downloadodr-edilib-2d71a31f547c87e146adeafc3012aa5ff3cc07a1.tar.gz
odr-edilib-2d71a31f547c87e146adeafc3012aa5ff3cc07a1.tar.bz2
odr-edilib-2d71a31f547c87e146adeafc3012aa5ff3cc07a1.zip
Improve handling of Reed-Solomon recovery
-rw-r--r--decoder/PFT.cpp134
-rw-r--r--decoder/PFT.hpp31
2 files changed, 99 insertions, 66 deletions
diff --git a/decoder/PFT.cpp b/decoder/PFT.cpp
index 5557b85..981b8d9 100644
--- a/decoder/PFT.cpp
+++ b/decoder/PFT.cpp
@@ -190,10 +190,11 @@ size_t Fragment::loadData(const std::vector<uint8_t> &buf)
}
-void AFBuilder::init(pseq_t Pseq, findex_t Fcount)
+AFBuilder::AFBuilder(pseq_t Pseq, findex_t Fcount, int lifetime)
{
_Pseq = Pseq;
_Fcount = Fcount;
+ lifeTime = lifetime;
}
void AFBuilder::pushPFTFrag(const Fragment &frag)
@@ -236,10 +237,14 @@ bool Fragment::checkConsistency(const Fragment& other) const
}
-bool AFBuilder::canAttemptToDecode() const
+AFBuilder::decode_attempt_result_t AFBuilder::canAttemptToDecode() const
{
if (_fragments.empty()) {
- return false;
+ return AFBuilder::decode_attempt_result_t::no;
+ }
+
+ if (_fragments.size() == _Fcount) {
+ return AFBuilder::decode_attempt_result_t::yes;
}
/* Check that all fragments are consistent */
@@ -261,33 +266,30 @@ bool AFBuilder::canAttemptToDecode() const
frag_it++;
if (frag_it == _fragments.end()) {
- return false;
+ return AFBuilder::decode_attempt_result_t::no;
}
}
const Fragment& frag = frag_it->second;
- const uint16_t _Plen = frag.Plen();
-
if ( frag.FEC() )
{
- const uint8_t RSk = frag.RSk();
+ const uint16_t _Plen = frag.Plen();
/* max number of RS chunks that may have been sent */
- const uint32_t _cmax = (_Fcount*_Plen) / (RSk+48);
+ const uint32_t _cmax = (_Fcount*_Plen) / (frag.RSk()+48);
+ assert(_cmax > 0);
/* Receiving _rxmin fragments does not guarantee that decoding
* will succeed! */
const uint32_t _rxmin = _Fcount - (_cmax*48)/_Plen;
- const bool decode_possible = _cmax > 0 and
- _fragments.size() >= _rxmin;
-
- return decode_possible;
- }
- else {
- return _fragments.size() == _Fcount;
+ if (_fragments.size() >= _rxmin) {
+ return AFBuilder::decode_attempt_result_t::maybe;
+ }
}
+
+ return AFBuilder::decode_attempt_result_t::no;
}
std::vector<uint8_t> AFBuilder::extractAF() const
@@ -298,7 +300,7 @@ std::vector<uint8_t> AFBuilder::extractAF() const
bool ok = false;
- if (canAttemptToDecode()) {
+ if (canAttemptToDecode() != AFBuilder::decode_attempt_result_t::no) {
auto frag_it = _fragments.begin();
if (frag_it->second.Fcount() == _Fcount - 1) {
@@ -386,13 +388,19 @@ std::vector<uint8_t> AFBuilder::extractAF() const
}
if (errors_corrected == -1) {
- debug("uncorrectable\n");
+ _af_packet.clear();
return {};
}
+#if 0
if (errors_corrected > 0) {
- debug("Corrected %d errors\n", errors_corrected);
+ debug("Corrected %d errors at ", errors_corrected);
+ for (const auto &index : erasures[i]) {
+ debug(" %d", index);
+ }
+ debug("\n");
}
+#endif
_af_packet.insert(_af_packet.end(), chunk.begin(), chunk.begin() + RSk);
}
@@ -447,12 +455,20 @@ void PFT::pushPFTFrag(const Fragment &fragment)
}
if (m_afbuilders.count(fragment.Pseq()) == 0) {
- AFBuilder af_builder;
- af_builder.init(fragment.Pseq(), fragment.Fcount());
- m_afbuilders[fragment.Pseq()] = af_builder;
+ // The AFBuilder wants to know the lifetime in number of fragments,
+ // we know the delay in number of AF packets. Every AF packet
+ // is cut into Fcount fragments.
+ const int lifetime = fragment.Fcount() * m_max_delay;
+
+ // Build the afbuilder in the map in-place
+ m_afbuilders.emplace(std::piecewise_construct,
+ /* key */
+ std::forward_as_tuple(fragment.Pseq()),
+ /* builder */
+ std::forward_as_tuple(fragment.Pseq(), fragment.Fcount(), lifetime));
}
- auto& p = m_afbuilders[fragment.Pseq()];
+ auto& p = m_afbuilders.at(fragment.Pseq());
p.pushPFTFrag(fragment);
#if 0
@@ -467,49 +483,49 @@ void PFT::pushPFTFrag(const Fragment &fragment)
std::vector<uint8_t> PFT::getNextAFPacket()
{
- /* Function flowgraph:
- * Is m_next_seq complete?
- * - Yes: build AF and increment m_next_seq
- * - No: check if any later than m_next_seq + m_max_delay is complete?
- * - Yes: consider m_next_seq to be timed out and drop it,
- * increment m_next_seq, do this again.
- * - No: wait longer
- */
+ if (m_afbuilders.count(m_next_pseq) == 0) {
+ assert(m_afbuilders.empty());
+ return {};
+ }
- while (true) {
- if (isPacketBuildable(m_next_pseq)) {
- const auto &p = m_afbuilders.at(m_next_pseq);
- std::vector<uint8_t> af = p.extractAF();
- incrementNextPseq();
- return af;
- }
- else {
- // We need to define some arbitrary limit for "any later" than
- // m_next_pseq + m_max_delay
- const int num_pseq_to_test = 2 * m_max_delay;
-
- bool timeout = false;
- for (pseq_t pseq = m_next_pseq + m_max_delay;
- pseq < m_next_pseq + m_max_delay + num_pseq_to_test;
- pseq++) {
- if (isPacketBuildable(pseq)) {
- // We consider m_next_pseq to be timed out
- timeout = true;
- break;
- }
- }
+ auto &builder = m_afbuilders.at(m_next_pseq);
+ //const auto lt = builder.lifeTime;
+ //const auto nf = builder.numberOfFragments();
- if (timeout) {
- debug("pseq %d timed out\n", m_next_pseq);
- incrementNextPseq();
- continue;
- }
+ using dar_t = AFBuilder::decode_attempt_result_t;
+ if (builder.canAttemptToDecode() == dar_t::yes) {
+ //debug("pseq %d (%d %d/%d) yes\n", m_next_pseq, lt, nf.first, nf.second);
+ auto afpacket = builder.extractAF();
+ assert(not afpacket.empty());
+ incrementNextPseq();
+ return afpacket;
+ }
+ else if (builder.canAttemptToDecode() == dar_t::maybe) {
+ //debug("pseq %d (%d %d/%d) maybe\n", m_next_pseq, lt, nf.first, nf.second);
+ builder.lifeTime--;
+ if (builder.lifeTime == 0) {
+ // Attempt Reed-Solomon decoding
+ auto afpacket = builder.extractAF();
+
+ if (afpacket.empty()) {
+ debug("pseq %d timed out after RS\n", m_next_pseq);
+ }
+ incrementNextPseq();
+ return afpacket;
+ }
+ }
+ else {
+ //debug("pseq %d (%d %d/%d) no\n", m_next_pseq, lt, nf.first, nf.second);
+ builder.lifeTime--;
+ if (builder.lifeTime == 0) {
+ debug("pseq %d timed out\n", m_next_pseq);
+ incrementNextPseq();
}
- return {};
}
-}
+ return {};
+}
void PFT::setMaxDelay(int num_af_packets)
{
diff --git a/decoder/PFT.hpp b/decoder/PFT.hpp
index 5a881ce..9be0426 100644
--- a/decoder/PFT.hpp
+++ b/decoder/PFT.hpp
@@ -77,19 +77,36 @@ class Fragment
class AFBuilder
{
public:
- void init(pseq_t Pseq, findex_t Fcount);
+ enum class decode_attempt_result_t {
+ yes, // The AF packet can be build because all fragments are present
+ maybe, // RS decoding may correctly decode the AF packet
+ no, // Not enough fragments present to permit RS
+ };
+
+ AFBuilder(pseq_t Pseq, findex_t Fcount, int lifetime);
void pushPFTFrag(const Fragment &frag);
- /*! Try to build the AF with received fragments.
- * Apply error correction if necessary (missing packets/CRC errors)
+ /* Assess if it may be possible to decode this AF packet */
+ decode_attempt_result_t canAttemptToDecode() const;
+
+ /* 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::pair<findex_t, findex_t>
+ numberOfFragments(void) const {
+ return {_fragments.size(), _Fcount};
+ }
+
+ /* The user of this instance can keep track of the lifetime of this
+ * builder
+ */
+ int lifeTime;
+
private:
- /* \return true if enough fragments are received */
- bool canAttemptToDecode() const;
// A map from fragment index to fragment
std::map<findex_t, Fragment> _fragments;
@@ -106,14 +123,14 @@ class PFT
public:
void pushPFTFrag(const Fragment &fragment);
- /*! Try to build the AF packet for the next pseq. This might
+ /* Try to build the AF packet for the next pseq. This might
* skip one pseq according to the maximum delay setting.
*
* \return an empty vector if building the AF is not possible
*/
std::vector<uint8_t> getNextAFPacket(void);
- /*! Set the maximum delay in number of AF Packets before we
+ /* Set the maximum delay in number of AF Packets before we
* abandon decoding a given pseq.
*/
void setMaxDelay(int num_af_packets);