Code Example: Encode and Decode

In this example shows how to use the API of otacast to implement encoding and decoding.

The example will walk through the basic functionality of class encoder and class decoder, and discuss how to use them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

#include <otacast/decoder.hpp>
#include <otacast/encoder.hpp>
#include <otacast/to_string.hpp>
#include <otacast/version.hpp>

int main()
{
    // Create the encoder/decoder objects with a specific finite field
    otacast::encoder encoder;
    otacast::decoder decoder;

    otacast::finite_field field = otacast::finite_field::binary8;
    std::size_t block_bytes = 1024 * 1000; // 1 MB
    std::size_t symbol_bytes = 1500;       // 1.5 kB
    std::size_t width = 5;

    encoder.configure(field, block_bytes, symbol_bytes, width);
    decoder.configure(field, block_bytes, symbol_bytes, width);

    // Allocate some data to decode
    std::vector<uint8_t> data_in(encoder.block_bytes());

    // For the example - fill data_in with random data
    std::generate(data_in.begin(), data_in.end(), rand);

    // Assign the data buffer to the encoder so that we may start
    // to produce encoded symbols from it
    encoder.set_symbols_storage(data_in.data());

    // Define a data buffer where the symbols should be decoded
    std::vector<uint8_t> data_out(decoder.block_bytes());
    decoder.set_symbols_storage(data_out.data());

    // Initiate a zero-vector for the offset
    std::vector<uint8_t> symbol(encoder.symbol_bytes());

    // The seed can be anything, here it's basically a packet sequence number.
    // Will be used to count transmissions as well
    uint64_t transmissions = 0;

    // Set up some packet loss
    auto loss_probability = 10;

    while (!decoder.can_complete_decoding())
    {
        // Generate an encoded packet using the number of transmissions as seed
        auto offset = encoder.encode(symbol.data(), transmissions);

        // We see if the packet is lost
        if (rand() % 100 < loss_probability)
        {
            std::cout << " - lost" << std::endl;
        }
        else
        {
            // Get the current rank before decoding
            auto old_rank = decoder.rank();

            // Decode the encoded packet using the number of transmissions as
            // seed
            decoder.decode(symbol.data(), transmissions, offset);

            // If decoder rank is unchanged, the packet was useless (linearly
            // dependent)
            if (decoder.rank() == old_rank)
            {
                std::cout << "Packet linearly dependant" << std::endl;
            }
        }
        transmissions++;
    }

    // The decoder is ready for the final decoding
    decoder.complete_decoding();

    // Count the percentage of succesful decoding attempts
    auto decode_percent = (block_bytes / symbol_bytes) * 100 / transmissions;

    // Check if everything went as it should
    if (data_in == data_out)
    {
        std::cout << "Decoding finished successfully!" << std::endl;
        std::cout << "% of Succesful decoding attempts: " << decode_percent
                  << "%" << std::endl;
    }
    else
    {
        std::cout << "Something went wrong!" << std::endl;
    }

    return 0;
}