Encode Decode On-the-flyΒΆ

This example shows how to to perform on-the-fly encoding. The encoder can start to generate encoded packets from a block before all symbols are specified. This can be useful when the symbols are produced on-the-fly.

The complete example code is shown below.

  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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright Steinwurf ApS 2018.
// Distributed under the "STEINWURF EVALUATION LICENSE 1.0".
// See accompanying file LICENSE.rst or
// http://www.steinwurf.com/licensing

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <kodo_rlnc_c/encoder.h>
#include <kodo_rlnc_c/decoder.h>

/// @example encode_decode_on_the_fly.c
///
/// This example shows how to use a storage aware encoder which will
/// allow you to encode from a block before all symbols have been
/// specified. This can be useful in cases where the symbols that
/// should be encoded are produced on-the-fly. The decoder will also
/// allow you to detect whether the symbols have been partially decoded.

int main()
{
    // Seed random number generator to produce different results every time
    srand(time(NULL));

    // Set the number of symbols (i.e. the generation size in RLNC
    // terminology) and the size of a symbol in bytes
    uint32_t symbols = 10;
    uint32_t symbol_size = 100;

    // Here we select the finite field to use.
    // Some common choices are: krlnc_binary, krlnc_binary4, krlnc_binary8
    int32_t finite_field = krlnc_binary8;

    krlnc_encoder_factory_t encoder_factory = krlnc_new_encoder_factory(
        finite_field, symbols, symbol_size);

    krlnc_decoder_factory_t decoder_factory = krlnc_new_decoder_factory(
        finite_field, symbols, symbol_size);

    krlnc_encoder_t encoder = krlnc_encoder_factory_build(encoder_factory);
    krlnc_decoder_t decoder = krlnc_decoder_factory_build(decoder_factory);

    uint32_t payload_size = krlnc_encoder_payload_size(encoder);
    uint8_t* payload = (uint8_t*)malloc(payload_size);

    uint32_t block_size = krlnc_encoder_block_size(encoder);
    uint8_t* data_in = (uint8_t*)malloc(block_size);
    uint8_t* data_out = (uint8_t*)malloc(block_size);

    krlnc_decoder_set_mutable_symbols(decoder, data_out, block_size);

    // Keeps track of which symbols have been decoded
    uint8_t* decoded = (uint8_t*)malloc(sizeof(uint8_t)*symbols);

    uint32_t i = 0;
    for (i = 0; i < block_size; ++i)
        data_in[i] = rand() % 256;

    // Zero initialize the decoded array
    memset(decoded, '\0', sizeof(uint8_t)*symbols);

    // We are starting the encoding / decoding loop without having
    // added any data to the encoder - we will add symbols on-the-fly
    while (!krlnc_decoder_is_complete(decoder))
    {
        uint32_t bytes_used;
        // Randomly choose to add a new symbol (with 50% probability)
        // if the encoder rank is less than the maximum number of symbols
        if ((rand() % 2) && krlnc_encoder_rank(encoder) < symbols)
        {
            // The rank of an encoder indicates how many symbols have been added,
            // i.e. how many symbols are available for encoding
            uint32_t rank = krlnc_encoder_rank(encoder);

            // Calculate the offset to the next symbol to insert
            uint8_t* symbol = data_in + rank * symbol_size;
            krlnc_encoder_set_const_symbol(encoder, rank, symbol, symbol_size);
        }

        bytes_used = krlnc_encoder_write_payload(encoder, payload);
        printf("Payload generated by encoder, rank = %d, bytes used = %d\n",
               krlnc_encoder_rank(encoder), bytes_used);

        // Send the data to the decoders, here we just for fun
        // simulate that we are loosing 50% of the packets
        if (rand() % 2)
        {
            printf("Packet dropped\n");
            continue;
        }

        // Packet got through - pass that packet to the decoder
        krlnc_decoder_read_payload(decoder, payload);

        // The rank of a decoder indicates how many symbols have been
        // decoded or partially decoded
        printf("Payload processed by decoder, current rank = %d\n",
               krlnc_decoder_rank(decoder));

        // Check the decoder whether it is partially complete
        if (krlnc_decoder_is_partially_complete(decoder))
        {
            uint32_t i = 0;
            for (; i < symbols; ++i)
            {
                if (!decoded[i] && krlnc_decoder_is_symbol_uncoded(decoder, i))
                {
                    uint8_t* original = data_in + i * symbol_size;
                    uint8_t* target = data_out + i * symbol_size;

                    // Update that this symbol now has been decoded
                    printf("Symbol %d was decoded\n", i);
                    decoded[i] = 1;

                    // Verify the symbol against the original data
                    if (memcmp(original, target, symbol_size) == 0)
                    {
                        printf("Symbol %d decoded correctly\n", i);
                    }
                    else
                    {
                        printf("SYMBOL %d DECODING FAILED.\n", i);
                    }
                }
            }
        }
    }

    if (memcmp(data_in, data_out, block_size) == 0)
    {
        printf("Data decoded correctly\n");
    }
    else
    {
        printf("Unexpected failure to decode, please file a bug report :)\n");
    }

    free(data_in);
    free(data_out);
    free(payload);

    krlnc_delete_encoder(encoder);
    krlnc_delete_decoder(decoder);

    krlnc_delete_encoder_factory(encoder_factory);
    krlnc_delete_decoder_factory(decoder_factory);

    return 0;
}