├── README.md └── src ├── .README.txt.swp ├── LinuxOut ├── LinuxProject │ ├── untitled.sublime-project │ └── untitled.sublime-workspace ├── logRecv.txt ├── logSend.txt ├── testRecv ├── testSend └── testdata.txt ├── Makefile ├── README.md ├── RaptorQ ├── De_Interleaver.hpp ├── Decoder.hpp ├── Encoder.hpp ├── Graph.cpp ├── Graph.hpp ├── Interleaver.hpp ├── Parameters.cpp ├── Parameters.hpp ├── Phase2.hpp ├── Precode_Matrix.cpp ├── Precode_Matrix.hpp ├── Precode_Matrix_solver.cpp ├── Rand.cpp ├── Rand.hpp ├── RaptorQ.hpp ├── cRaptorQ.cpp ├── cRaptorQ.h ├── common.hpp ├── degree.hpp ├── deterministic.cpp ├── multiplication.hpp └── table2.hpp ├── buffersink.c ├── buffersink.h ├── cross_platform.c ├── cross_platform.h ├── err.h ├── iRaptorQ.c ├── iRaptorQ.c.fake ├── iRaptorQ.h ├── iRaptorQ.h.fake ├── io.c ├── io.h ├── lib ├── 32 │ └── RaptorQ_Static.lib ├── 64 │ └── RaptorQ_Static.lib └── RaptorQ_Static.lib ├── network.c ├── network.h ├── parameter.c ├── parameter.h ├── receiver.c ├── receiver.h ├── ringbuffer.c ├── ringbuffer.h ├── test.c ├── testRaptorQ.c ├── testReceive.c ├── testSend.c ├── testStructure.h ├── transmitter.c └── transmitter.h /README.md: -------------------------------------------------------------------------------- 1 | # FEC 2 | 前向纠错码FEC(含喷泉码RaptorQ) 3 | -------------------------------------------------------------------------------- /src/.README.txt.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/.README.txt.swp -------------------------------------------------------------------------------- /src/LinuxOut/LinuxProject/untitled.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /src/LinuxOut/LinuxProject/untitled.sublime-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "auto_complete": 3 | { 4 | "selected_items": 5 | [ 6 | ] 7 | }, 8 | "buffers": 9 | [ 10 | ], 11 | "build_system": "", 12 | "build_system_choices": 13 | [ 14 | ], 15 | "build_varint": "", 16 | "command_palette": 17 | { 18 | "height": 0.0, 19 | "last_filter": "", 20 | "selected_items": 21 | [ 22 | ], 23 | "width": 0.0 24 | }, 25 | "console": 26 | { 27 | "height": 0.0, 28 | "history": 29 | [ 30 | ] 31 | }, 32 | "distraction_free": 33 | { 34 | "menu_visible": true, 35 | "show_minimap": false, 36 | "show_open_files": false, 37 | "show_tabs": false, 38 | "side_bar_visible": false, 39 | "status_bar_visible": false 40 | }, 41 | "file_history": 42 | [ 43 | ], 44 | "find": 45 | { 46 | "height": 0.0 47 | }, 48 | "find_in_files": 49 | { 50 | "height": 0.0, 51 | "where_history": 52 | [ 53 | ] 54 | }, 55 | "find_state": 56 | { 57 | "case_sensitive": false, 58 | "find_history": 59 | [ 60 | ], 61 | "highlight": true, 62 | "in_selection": false, 63 | "preserve_case": false, 64 | "regex": false, 65 | "replace_history": 66 | [ 67 | ], 68 | "reverse": false, 69 | "show_context": true, 70 | "use_buffer2": true, 71 | "whole_word": false, 72 | "wrap": true 73 | }, 74 | "groups": 75 | [ 76 | { 77 | "sheets": 78 | [ 79 | ] 80 | } 81 | ], 82 | "incremental_find": 83 | { 84 | "height": 0.0 85 | }, 86 | "input": 87 | { 88 | "height": 0.0 89 | }, 90 | "layout": 91 | { 92 | "cells": 93 | [ 94 | [ 95 | 0, 96 | 0, 97 | 1, 98 | 1 99 | ] 100 | ], 101 | "cols": 102 | [ 103 | 0.0, 104 | 1.0 105 | ], 106 | "rows": 107 | [ 108 | 0.0, 109 | 1.0 110 | ] 111 | }, 112 | "menu_visible": true, 113 | "output.find_results": 114 | { 115 | "height": 0.0 116 | }, 117 | "pinned_build_system": "", 118 | "project": "untitled.sublime-project", 119 | "replace": 120 | { 121 | "height": 0.0 122 | }, 123 | "save_all_on_build": true, 124 | "select_file": 125 | { 126 | "height": 0.0, 127 | "last_filter": "", 128 | "selected_items": 129 | [ 130 | ], 131 | "width": 0.0 132 | }, 133 | "select_project": 134 | { 135 | "height": 438.0, 136 | "last_filter": "", 137 | "selected_items": 138 | [ 139 | ], 140 | "width": 333.0 141 | }, 142 | "select_symbol": 143 | { 144 | "height": 0.0, 145 | "last_filter": "", 146 | "selected_items": 147 | [ 148 | ], 149 | "width": 0.0 150 | }, 151 | "selected_group": 0, 152 | "settings": 153 | { 154 | }, 155 | "show_minimap": true, 156 | "show_open_files": false, 157 | "show_tabs": true, 158 | "side_bar_visible": true, 159 | "side_bar_width": 131.0, 160 | "status_bar_visible": true, 161 | "template_settings": 162 | { 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/LinuxOut/logRecv.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/LinuxOut/logRecv.txt -------------------------------------------------------------------------------- /src/LinuxOut/logSend.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/LinuxOut/logSend.txt -------------------------------------------------------------------------------- /src/LinuxOut/testRecv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/LinuxOut/testRecv -------------------------------------------------------------------------------- /src/LinuxOut/testSend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/LinuxOut/testSend -------------------------------------------------------------------------------- /src/LinuxOut/testdata.txt: -------------------------------------------------------------------------------- 1 | 1. raptorq encode time: 3~5ms 2 | 2. source time:11~18ms 3 | 3. block collect time:11~12ms 4 | 4. feedback process time: 0~11ms 5 | 5. receive process time: 0ms 6 | 6. decoder create, add packets and decode time : 2~6ms 7 | 7. source priority create time: 0 ms 8 | 8. source initialize part time: 0 ms 9 | 9. decode time : 2~5ms 10 | 10. packet delay: 0~4ms 11 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | src := transmitter.c receiver.c parameter.c io.c ringbuffer.c iRaptorQ.c buffersink.c network.c cross_platform.c 2 | 3 | all: 4 | gcc -O3 -g -o LinuxOut/testSend testSend.c -I /home/xiong/projects/streamingwindows $(src) -lRaptorQ -lpthread 5 | gcc -O3 -g -o LinuxOut/testRecv testReceive.c -I /home/xiong/projects/streamingwindows $(src) -lRaptorQ -lpthread 6 | clean: 7 | rm -rf testRaptorQ *~ 8 | 9 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | This program is the windows version of STREAMING project, it can send video 4 | data that encoded by raptorQ via UDP protocal. The INPUT interface can acqurie 5 | data from socket and store the data in ring buffer. Then the ENCODERs can get 6 | and encode the data and generate the repair packets. Meanwhile, the TRANSMITTER 7 | sends the data to the RECEIVERs. When the RECEIVER acquire the data, they store 8 | the data in ring buffer, count the number of received packets of relative tag 9 | and acknowledge a feedback packets to the TRANSMITTER. Then the DECODERs 10 | decoder the received data and put it to the OUTPUT interface. At last, the 11 | OUTPUT interface send out the data by socket. 12 | 13 | ### DEPENDENCY ### 14 | 15 | libRaptorQ v0.1.9 for windows 16 | 17 | ### USER GUIDE ### 18 | 19 | 1. transmitter 20 | Use the function IOInputInit() to open the input interface. 21 | Use the function TransmitterInit() to start the transmitter. 22 | Use the function TransmitterClose() to stop the transmitter and release the memory. 23 | Use the function IOInputDeInit() to close the input interface and release the memory. 24 | 25 | 2. receiver 26 | Use the function IOOutputInit() to open the output interface. 27 | Use the function ReceiverInit() to start the receiver. 28 | Use the function ReceiverClose() to stop the receiverand release the memory. 29 | Use the function IOOutputDeInit() to close the output interface and release the memory. 30 | 31 | 3. parameter 32 | The parameters are defined in parameter.h 33 | 34 | ### SOURCE TREE ### 35 | 36 | FountainVedio 37 | |-buffersink.c prepaire initialized empty ringbuffers automaticly. 38 | |-buffersink.h 39 | |-err.h formatting the log and error information. 40 | |-io.c data input and output interface. 41 | |-io.h 42 | |-iRaptorQ.c the middle interface to libRaptorQ. 43 | |-iRaptorQ.h 44 | |-network.c manage the socket connection and data transmittion. 45 | |-network.h 46 | |-parameter.h parameters of the program. 47 | |-receiver.c receive data and decode data 48 | |-receiver.h 49 | |-ringbuffer.c ring buffer 50 | |-ringbuffer.h 51 | |-transmitter.c encode data and transmit data 52 | |-transmitter.h 53 | |-test.c test file 54 | 55 | ### Function Discription ### 56 | ---------IO--------- 57 | River Mode: This mode may waste some bit of bandwidth, but it ensure 58 | the source symbol can be constructed no longer than 1ms, though the 59 | symbol may fill some useless byte with a head flag 'F'. 60 | 61 | Direct Distribute: source symbol will be transmitted first, and the 62 | receiver can output the source symbol directly if the id is arrived 63 | sequentially. 64 | 65 | ### Upgrade Log ### 66 | V1.0 67 | An avilable version for straming transmitting. 68 | ------------------------------------------------- 69 | V1.1 70 | This version fix some error,for example, time stamp. 71 | Now the video can be played smoothly. What's more, the 72 | RaptorQ is compiled as a static library, which can reduce 73 | the delay of the generation of the first repair symbol. 74 | -------------------------------------------------------------------------------- /src/RaptorQ/De_Interleaver.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_DE_INTERLEAVING_HPP 22 | #define RAPTORQ_DE_INTERLEAVING_HPP 23 | 24 | #include "common.hpp" 25 | #include "Decoder.hpp" 26 | #include "Interleaver.hpp" 27 | 28 | namespace RaptorQ { 29 | namespace Impl { 30 | 31 | template 32 | class RAPTORQ_LOCAL De_Interleaver 33 | { 34 | public: 35 | De_Interleaver (const DenseMtx *symbols, const Partition sub_blocks, 36 | const uint8_t alignment) 37 | :_symbols (symbols), _sub_blocks (sub_blocks), _al (alignment) 38 | { 39 | IS_FORWARD(Fwd_It, "RaptorQ::Impl::De_Interleaver"); 40 | } 41 | uint64_t operator() (Fwd_It &start, const Fwd_It end, 42 | const uint8_t skip = 0); 43 | private: 44 | const DenseMtx *_symbols; 45 | const Partition _sub_blocks; 46 | const uint8_t _al; 47 | }; 48 | 49 | template 50 | uint64_t De_Interleaver::operator() (Fwd_It &start, const Fwd_It end, 51 | const uint8_t skip) 52 | { 53 | uint64_t written = 0; 54 | uint32_t byte = 0; 55 | uint32_t subsym_byte = 0; 56 | uint16_t esi = 0; 57 | uint16_t sub_blk = 0; 58 | const uint16_t max_esi = static_cast (_symbols->rows()); 59 | uint16_t sub_sym_size = _al *(_sub_blocks.num(0) > 0 ? _sub_blocks.size(0) : 60 | _sub_blocks.size(1)); 61 | // if the Fwd_It::value_type is not aligned with the block size, 62 | // we need to skip a certain amount of data in the first output element 63 | // so that we do not overwrite the old data or add unnecessary zeros 64 | // to (start-1) during the decoding of the previous block. 65 | uint8_t offset_al = skip; 66 | using T = typename std::iterator_traits::value_type; 67 | T element = static_cast (0); 68 | if (skip != 0) { 69 | uint8_t *p = reinterpret_cast (&*start); 70 | for (size_t keep = 0; keep < skip; ++keep) { 71 | element += static_cast (*(p++)) << keep * 8; 72 | } 73 | } 74 | while (start != end && sub_blk < (_sub_blocks.num(0) + _sub_blocks.num(1))){ 75 | element += static_cast (static_cast((*_symbols)( 76 | esi, static_cast (byte)))) 77 | << offset_al * 8; 78 | ++offset_al; 79 | if (offset_al >= sizeof(T)) { 80 | *start = element; 81 | ++start; 82 | ++written; 83 | element = static_cast (0); 84 | offset_al = 0; 85 | } 86 | ++byte; 87 | ++subsym_byte; 88 | if (subsym_byte == sub_sym_size) { 89 | subsym_byte = 0; 90 | ++esi; 91 | if (esi >= max_esi) { 92 | esi = 0; 93 | ++sub_blk; 94 | } 95 | if (sub_blk < _sub_blocks.num (0)) { 96 | sub_sym_size = _sub_blocks.size (0) * _al; 97 | byte = sub_sym_size * sub_blk; 98 | } else { 99 | sub_sym_size = _sub_blocks.size (1) * _al; 100 | byte = _sub_blocks.tot (0) * _al + 101 | sub_sym_size * (sub_blk - _sub_blocks.num (0)); 102 | } 103 | } 104 | } 105 | if (start != end && offset_al != 0) { 106 | // we have more stuff in "al", but not enough to fill 107 | // the iterator. 108 | *start = element; 109 | ++start; 110 | ++written; 111 | } 112 | return written; 113 | } 114 | 115 | } // namespace Impl 116 | } // namespace RaptorQ 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /src/RaptorQ/Decoder.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_DECODER_HPP 22 | #define RAPTORQ_DECODER_HPP 23 | 24 | #include "common.hpp" 25 | #include "Parameters.hpp" 26 | #include "Precode_Matrix.hpp" 27 | #include "Graph.hpp" 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace RaptorQ { 36 | namespace Impl { 37 | 38 | template 39 | class RAPTORQ_API Decoder 40 | { 41 | using Vect = Eigen::Matrix; 42 | using T_in = typename std::iterator_traits::value_type; 43 | public: 44 | Decoder (const uint16_t symbols, const uint16_t symbol_size) 45 | :_symbols (symbols), 46 | precode (Parameters(symbols)), mask (_symbols) 47 | { 48 | 49 | IS_INPUT(In_It, "RaptorQ::Impl::Decoder"); 50 | 51 | // symbol size is in octets, but we save it in "T" sizes. 52 | // so be aware that "symbol_size" != "_symbol_size" for now 53 | source_symbols = DenseMtx (_symbols, symbol_size); 54 | } 55 | 56 | bool add_symbol (In_It &start, const In_It end, const uint32_t esi); 57 | bool decode (); 58 | DenseMtx* get_symbols(); 59 | //std::vector get (const uint16_t symbol) const; 60 | 61 | private: 62 | std::mutex lock; 63 | const uint16_t _symbols; 64 | Precode_Matrix precode; 65 | Bitmask mask; 66 | DenseMtx source_symbols; 67 | 68 | std::vector> received_repair; 69 | }; 70 | 71 | 72 | /////////////////////////////////// 73 | // 74 | // IMPLEMENTATION OF ABOVE TEMPLATE 75 | // 76 | /////////////////////////////////// 77 | 78 | 79 | template 80 | bool Decoder::add_symbol (In_It &start, const In_It end, 81 | const uint32_t esi) 82 | { 83 | // true if added succesfully 84 | 85 | // if we were lucky to get a random access iterator, quickly check that 86 | // the we have enough data for the symbol. 87 | if (std::is_same::iterator_category, 88 | std::random_access_iterator_tag>::value) { 89 | if (static_cast(end - start) * sizeof(T_in) < 90 | static_cast (source_symbols.cols())) 91 | return false; 92 | } 93 | 94 | if (esi >= std::pow (2, 20)) 95 | return false; 96 | 97 | std::lock_guard guard (lock); 98 | UNUSED(guard); 99 | 100 | if (mask.get_holes() == 0) 101 | return false; // not even needed; 102 | if (mask.exists(esi)) 103 | return false; // already present. 104 | 105 | uint16_t col = 0; 106 | if (esi < _symbols) { 107 | for (; start != end && col != source_symbols.cols(); ++start) { 108 | T_in al = *start; 109 | for (uint8_t *p = reinterpret_cast (&al); 110 | p != reinterpret_cast (&al) + sizeof(T_in) 111 | && col != source_symbols.cols(); ++p) { 112 | source_symbols (static_cast (esi), col++) = *p; 113 | } 114 | } 115 | // input iterator might reach end before we get enough data 116 | // for the symbol. 117 | if (col != source_symbols.cols()) 118 | return false; 119 | } else { 120 | Vect v = Vect (source_symbols.cols()); 121 | for (; start != end && col != source_symbols.cols(); ++start) { 122 | T_in al = *start; 123 | for (uint8_t *p = reinterpret_cast (&al); 124 | p != reinterpret_cast (&al) + sizeof(T_in) 125 | && col != source_symbols.cols(); ++p) { 126 | v (col++) = *p; 127 | } 128 | } 129 | // input iterator might reach end before we get enough data 130 | // for the symbol. 131 | if (col != v.cols()) 132 | return false; 133 | received_repair.emplace_back (esi, std::move(v)); 134 | } 135 | mask.add (esi); 136 | 137 | return true; 138 | } 139 | 140 | template 141 | bool Decoder::decode () 142 | { 143 | // rfc 6330: can decode when received >= K_padded 144 | // actually: (K_padded - K) are padding and thus constant and NOT 145 | // transmitted. so really N >= K. 146 | if (mask.get_holes() == 0) 147 | return true; 148 | 149 | if (received_repair.size() < mask.get_holes()) 150 | return false; 151 | 152 | precode.gen (static_cast (received_repair.size() - 153 | mask.get_holes())); 154 | 155 | 156 | DenseMtx D = DenseMtx (precode._params.S + precode._params.H + 157 | precode._params.K_padded + 158 | (received_repair.size() - mask.get_holes()), 159 | source_symbols.cols()); 160 | 161 | // initialize D 162 | for (uint16_t row = 0; row < precode._params.S + precode._params.H; ++row) { 163 | for (uint16_t col = 0; col < D.cols(); ++col) 164 | D (row, col) = 0; 165 | } 166 | // put non-repair symbols (source symbols) in place 167 | lock.lock(); 168 | if (mask.get_holes() == 0) // other thread completed its work before us? 169 | return true; 170 | D.block (precode._params.S + precode._params.H, 0, 171 | source_symbols.rows(), D.cols()) = source_symbols; 172 | 173 | // mask must be copied to avoid threading problems, same with tracking 174 | // the repair esi. 175 | const Bitmask mask_safe = mask; 176 | std::vector repair_esi; 177 | repair_esi.reserve (received_repair.size()); 178 | for (auto rep : received_repair) 179 | repair_esi.push_back (rep.first); 180 | 181 | // fill holes with the first repair symbols available 182 | auto symbol = received_repair.begin(); 183 | for (uint16_t hole = 0; hole < _symbols && symbol != received_repair.end(); 184 | ++hole) { 185 | if (mask_safe.exists (hole)) 186 | continue; 187 | const uint16_t row = precode._params.S + precode._params.H + hole; 188 | D.row (row) = symbol->second; 189 | ++symbol; 190 | } 191 | // fill the padding symbols (always zero) 192 | for (uint16_t row = precode._params.S + precode._params.H + _symbols; 193 | row < precode._params.S + precode._params.H + 194 | precode._params.K_padded; ++row) { 195 | for (uint16_t col = 0; col < D.cols(); ++col) 196 | D (row, col) = 0; 197 | } 198 | // fill the remaining (redundant) repair symbols 199 | for (uint16_t row = 200 | precode._params.S + precode._params.H + precode._params.K_padded; 201 | symbol != received_repair.end(); ++symbol, ++row) { 202 | D.row (row) = symbol->second; 203 | } 204 | lock.unlock(); 205 | 206 | // do not lock this part, as it's the expensive part 207 | DenseMtx missing = precode.intermediate (D, mask_safe, repair_esi); 208 | D = DenseMtx(); // free some memory; 209 | 210 | if (missing.rows() == 0) 211 | return mask.get_holes() == 0; // did other threads do something? 212 | 213 | std::lock_guard guard (lock); 214 | UNUSED(guard); 215 | 216 | if (mask.get_holes() == 0) 217 | return true; // other thread did something 218 | 219 | // put missing symbols into "source_symbols". 220 | // remember: we might have received other symbols while decoding. 221 | uint16_t miss_row = 0; 222 | for (uint16_t row = 0; row < mask_safe._max_nonrepair && 223 | miss_row < missing.rows(); ++row) { 224 | if (mask_safe.exists (row)) 225 | continue; 226 | ++miss_row; 227 | if (mask.exists (row)) 228 | continue; 229 | source_symbols.row (row) = missing.row (miss_row - 1); 230 | mask.add (row); 231 | } 232 | 233 | // free some memory, we don't need recover symbols anymore 234 | received_repair = std::vector>(); 235 | 236 | return true; 237 | } 238 | 239 | template 240 | DenseMtx* Decoder::get_symbols() 241 | { 242 | return &source_symbols; 243 | } 244 | 245 | } //namespace Impl 246 | } // namespace RaptorQ 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /src/RaptorQ/Encoder.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_ENCODER_HPP 22 | #define RAPTORQ_ENCODER_HPP 23 | 24 | #include "common.hpp" 25 | #include "Parameters.hpp" 26 | #include "Precode_Matrix.hpp" 27 | #include "Interleaver.hpp" 28 | #include "Rand.hpp" 29 | #include "multiplication.hpp" 30 | #include 31 | #include 32 | 33 | namespace RaptorQ { 34 | namespace Impl { 35 | 36 | template 37 | class RAPTORQ_API Encoder 38 | { 39 | public: 40 | Encoder (const Interleaver &symbols, const uint8_t SBN) 41 | :precode (Parameters (symbols.source_symbols(SBN))), _symbols(symbols), 42 | _SBN(SBN) 43 | { 44 | IS_RANDOM(Rnd_It, "RaptorQ::Impl::Encoder"); 45 | IS_FORWARD(Fwd_It, "RaptorQ::Impl::Encoder"); 46 | precode.gen(0); 47 | } 48 | uint64_t Enc (const uint32_t ESI, Fwd_It &output, const Fwd_It end) const; 49 | 50 | bool generate_symbols (); 51 | uint16_t padded() const; 52 | private: 53 | Precode_Matrix precode; 54 | const Interleaver _symbols; 55 | const uint8_t _SBN; 56 | 57 | DenseMtx encoded_symbols; 58 | }; 59 | 60 | // 61 | // 62 | // Implementation 63 | // 64 | // 65 | 66 | template 67 | uint16_t Encoder::padded () const 68 | { 69 | return precode._params.K_padded; 70 | } 71 | 72 | template 73 | bool Encoder::generate_symbols () 74 | { 75 | using T = typename std::iterator_traits::value_type; 76 | // do not bother checing for multithread. that is done in RaptorQ.hpp 77 | if (encoded_symbols.cols() != 0) 78 | return true; 79 | DenseMtx D = DenseMtx (precode._params.K_padded + precode._params.S + 80 | precode._params.H, 81 | sizeof(T) * _symbols.symbol_size()); 82 | auto C = _symbols[_SBN]; 83 | 84 | // fill matrix D: full zero for the first S + H symbols 85 | uint16_t row; 86 | for (row = 0; row < precode._params.S + precode._params.H; ++row ) { 87 | for (uint16_t col = 0; col < D.cols(); ++col) 88 | D (row, col) = 0; 89 | } 90 | // now the C[0...K] symbols follow 91 | for (; row < precode._params.S + precode._params.H + 92 | _symbols.source_symbols (_SBN); ++row) { 93 | auto symbol = C[row - (precode._params.S + precode._params.H)]; 94 | uint16_t col = 0; 95 | for (uint16_t i = 0; i < _symbols.symbol_size(); ++i) { 96 | T val = symbol[i]; 97 | uint8_t *octet = reinterpret_cast (&val); 98 | for (uint8_t byte = 0; byte < sizeof(T); ++byte) 99 | D (row, col++) = *(octet++); 100 | } 101 | } 102 | 103 | // finally fill with eventual padding symbols (K...K_padded) 104 | for (; row < D.rows(); ++row ) { 105 | for (uint16_t col = 0; col < D.cols(); ++col) 106 | D (row, col) = 0; 107 | } 108 | 109 | encoded_symbols = precode.intermediate (D); 110 | return encoded_symbols.cols() != 0; 111 | } 112 | 113 | template 114 | uint64_t Encoder::Enc (const uint32_t ESI, Fwd_It &output, 115 | const Fwd_It end) const 116 | { 117 | // ESI means that the first _symbols.source_symbols() are the 118 | // original symbols, and the next ones are repair symbols. 119 | 120 | // The alignment of "Fwd_It" might *NOT* be the alignment of "Rnd_It" 121 | 122 | uint64_t written = 0; 123 | auto non_repair = _symbols.source_symbols (_SBN); 124 | 125 | if (ESI < non_repair) { 126 | // just return the source symbol. 127 | auto block = _symbols[_SBN]; 128 | auto requested_symbol = block[static_cast (ESI)]; 129 | 130 | typedef typename std::iterator_traits::value_type out_al; 131 | size_t byte = 0; 132 | out_al tmp_out = 0; 133 | for (auto al : requested_symbol) { 134 | uint8_t *p; 135 | for (p = reinterpret_cast (&al); 136 | p != reinterpret_cast(&al) + sizeof(al); 137 | ++p) { 138 | tmp_out += static_cast (*p) << (byte * 8); 139 | ++byte; 140 | if (byte % sizeof(out_al) == 0) { 141 | *(output++) = tmp_out; 142 | ++written; 143 | byte = 0; 144 | tmp_out = 0; 145 | if (output == end) 146 | return written; 147 | } 148 | } 149 | } 150 | if (byte % sizeof(out_al) != 0) { 151 | *(output++) = tmp_out; 152 | ++written; 153 | } 154 | } else { 155 | // repair symbol requested. 156 | if (encoded_symbols.cols() == 0) 157 | return false; 158 | auto ISI = ESI + (precode._params.K_padded - 159 | _symbols.source_symbols (_SBN)); 160 | DenseMtx tmp = precode.encode (encoded_symbols, ISI); 161 | 162 | // put "tmp" in output, but the alignment is different 163 | 164 | using T = typename std::iterator_traits::value_type; 165 | T al = static_cast (0); 166 | uint8_t *p = reinterpret_cast (&al); 167 | for (int i = 0; i < tmp.cols(); ++i) { 168 | *p = static_cast (tmp (0, i)); 169 | ++p; 170 | if (p == reinterpret_cast (&al) + sizeof(T)) { 171 | *output = al; 172 | ++output; 173 | al = static_cast (0); 174 | p = reinterpret_cast (&al); 175 | ++written; 176 | if (output == end) 177 | return written; 178 | } 179 | } 180 | if (p != reinterpret_cast (&al) + sizeof(T)) { 181 | // symbol size is not aligned with Fwd_It type 182 | while (p != reinterpret_cast (&al) + sizeof(T)) 183 | *(p++) = 0; 184 | *output = al; 185 | ++output; 186 | ++written; 187 | } 188 | } 189 | return written; 190 | } 191 | 192 | } // namespace Impl 193 | } // namespace RaptorQ 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /src/RaptorQ/Graph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include "Graph.hpp" 22 | 23 | RaptorQ::Impl::Graph::Graph (const uint16_t size) 24 | { 25 | connections.reserve (size); 26 | for (uint16_t i = 0; i < size; ++i) 27 | connections.emplace_back (1, i); 28 | } 29 | 30 | uint16_t RaptorQ::Impl::Graph::find (const uint16_t id) const 31 | { 32 | uint16_t tmp = id; 33 | while (connections[tmp].second != tmp) 34 | tmp = connections[tmp].second; 35 | return tmp; 36 | } 37 | 38 | void RaptorQ::Impl::Graph::connect (const uint16_t node_a, 39 | const uint16_t node_b) 40 | { 41 | uint16_t rep_a = find (node_a), rep_b = find (node_b); 42 | 43 | connections[rep_a] = {connections[rep_a].first + connections[rep_b].first, 44 | rep_a}; 45 | connections[rep_b] = connections[rep_a]; 46 | if (node_a != rep_a) 47 | connections[node_a] = connections[rep_a]; 48 | if (node_b != rep_b) 49 | connections[node_b] = connections[rep_a]; 50 | 51 | if (max_connections < connections[rep_a].first) { 52 | max_connections = connections[rep_a].first; 53 | } 54 | } 55 | 56 | bool RaptorQ::Impl::Graph::is_max (const uint16_t id) const 57 | { 58 | return max_connections == connections[find (id)].first; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/RaptorQ/Graph.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_GRAPH_HPP 22 | #define RAPTORQ_GRAPH_HPP 23 | 24 | #include "common.hpp" 25 | #include 26 | 27 | namespace RaptorQ { 28 | namespace Impl { 29 | 30 | class RAPTORQ_LOCAL Graph 31 | { 32 | public: 33 | explicit Graph (const uint16_t size); 34 | 35 | void connect (const uint16_t node_a, const uint16_t node_b); 36 | bool is_max (const uint16_t id) const; 37 | private: 38 | uint16_t find (const uint16_t id) const; 39 | // pair: conected_nodes, representative. 40 | // remember make-union-find? use it to track connected components 41 | std::vector> connections; 42 | uint16_t max_connections = 1; 43 | }; 44 | 45 | } // namespace Impl 46 | } // namespace RaptorQ 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /src/RaptorQ/Interleaver.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_INTERLEAVER_HPP 22 | #define RAPTORQ_INTERLEAVER_HPP 23 | 24 | #include "common.hpp" 25 | #include "multiplication.hpp" 26 | #include "table2.hpp" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | // force promotion to double in division 35 | namespace { 36 | double RAPTORQ_LOCAL div_floor (const double a, const double b); 37 | double RAPTORQ_LOCAL div_ceil (const double a, const double b); 38 | 39 | double div_floor (const double a, const double b) 40 | { 41 | return std::floor (a / b); 42 | } 43 | double div_ceil (const double a, const double b) 44 | { 45 | return std::ceil (a / b); 46 | } 47 | } 48 | 49 | namespace RaptorQ { 50 | namespace Impl { 51 | 52 | void test (void); 53 | 54 | // 55 | // Partition: see RFC6330: each object is partitioned in 56 | // N1 blocks of size S1, plus N2 blocks of size S2. This class tracks it 57 | // 58 | class RAPTORQ_LOCAL Partition 59 | { 60 | public: 61 | Partition() = default; 62 | // partition something into "num1" partitions of "size1" and "num2" 63 | // of "size2" 64 | // still better than the TL, TS, NL, NL in RFC6330... 65 | Partition (const uint64_t obj_size, const uint16_t partitions) 66 | { 67 | uint16_t size_1, size_2, blocks_1, blocks_2; 68 | 69 | size_1 = static_cast (div_ceil (obj_size, partitions)); 70 | size_2 = static_cast (div_floor (obj_size, partitions)); 71 | blocks_1 = static_cast (obj_size - size_2 * partitions); 72 | blocks_2 = partitions - blocks_1; 73 | 74 | if (blocks_1 == 0) 75 | size_1 = 0; 76 | part1 = {blocks_1, size_1}; 77 | part2 = {blocks_2, size_2}; 78 | } 79 | 80 | uint16_t size (const uint8_t part_number) const 81 | { 82 | assert(part_number < 2 && "partition: only two partitions exists"); 83 | if (part_number == 0) 84 | return std::get<1>(part1); 85 | return std::get<1>(part2); 86 | } 87 | uint16_t num (const uint8_t part_number) const 88 | { 89 | assert(part_number < 2 && "partition: only two partitions exists"); 90 | if (part_number == 0) 91 | return std::get<0>(part1); 92 | return std::get<0>(part2); 93 | } 94 | uint16_t tot (const uint8_t part_number) const 95 | { 96 | assert(part_number < 2 && "partition: only two partitions exists"); 97 | // num * size 98 | if (part_number == 0) 99 | return std::get<0>(part1) * std::get<1>(part1); 100 | return std::get<0>(part2) * std::get<1>(part2); 101 | } 102 | private: 103 | // PAIR: amount, size 104 | std::pair part1, part2; 105 | }; 106 | 107 | template 108 | class RAPTORQ_LOCAL Symbol_Wrap 109 | { 110 | public: 111 | Symbol_Wrap (const uint8_t *raw, const uint16_t size) : _raw (raw), 112 | _size (size) 113 | {} 114 | 115 | Symbol_Wrap& operator= (const Symbol_Wrap &a) 116 | { 117 | assert (_raw != nullptr && "Encoded_Symbol raw == nullptr"); 118 | for (size_t i = 0; i < _size * sizeof(T); ++i) 119 | _raw[i] = a._raw[i]; 120 | return *this; 121 | } 122 | Symbol_Wrap& operator+= (const Symbol_Wrap &a) 123 | { 124 | assert (_raw != nullptr && "Encoded_Symbol raw == nullptr"); 125 | for (size_t i = 0; i < _size * sizeof(T); ++i) 126 | _raw[i] ^= a._raw[i]; 127 | return *this; 128 | } 129 | Symbol_Wrap& operator*= (const Symbol_Wrap &a) 130 | { 131 | assert (_raw != nullptr && "Encoded_Symbol raw == nullptr"); 132 | for (size_t i = 0; i < _size * sizeof(T); ++i) { 133 | if (_raw[i] == 0 || a._raw[i] == 0) { 134 | _raw[i] = 0; 135 | } else { 136 | _raw[i] = Impl::oct_exp[Impl::oct_log[_raw[i]] + 137 | Impl::oct_exp[a._raw[i]]]; 138 | } 139 | } 140 | return *this; 141 | } 142 | Symbol_Wrap& operator/= (const Symbol_Wrap &a) 143 | { 144 | assert (_raw != nullptr && "Encoded_Symbol raw == nullptr"); 145 | for (size_t i = 0; i < _size * sizeof(T); ++i) { 146 | if (_raw[i] != 0) { 147 | _raw[i] = Impl::oct_exp[Impl::oct_log[_raw[i]] - 148 | Impl::oct_exp[a._raw[i]] + 255]; 149 | } 150 | } 151 | return *this; 152 | } 153 | private: 154 | const uint8_t *_raw = nullptr; 155 | const uint16_t _size; 156 | }; 157 | 158 | // 159 | // Symbol: 160 | // Basic unit later on. This is a block of interneaved sub-symbols. 161 | // see RFC 6330 for details 162 | // Padding is included here 163 | // 164 | template 165 | class RAPTORQ_LOCAL Symbol_it 166 | { 167 | public: 168 | Symbol_it (); 169 | Symbol_it (const Rnd_It data_from, const Rnd_It data_to, const size_t start, 170 | const size_t end, const size_t idx, 171 | const Partition sub_blocks, 172 | const uint16_t symbol_size, 173 | const uint16_t symbol_id, 174 | const uint16_t k) 175 | :_data_from (data_from), _data_to (data_to), _start (start), 176 | _end (end), _idx(idx), _sub_blocks (sub_blocks), 177 | _symbol_size (symbol_size), 178 | _symbol_id (symbol_id), _k(k) 179 | {} 180 | 181 | constexpr Symbol_it begin() const 182 | { 183 | return Symbol_it (_data_from, _data_to, _start, _end, 0, 184 | _sub_blocks, _symbol_size, _symbol_id, _k); 185 | } 186 | constexpr Symbol_it end() const 187 | { 188 | return Symbol_it (_data_from, _data_to, _start, _end, 189 | _sub_blocks.tot (0) + _sub_blocks.tot (1), 190 | _sub_blocks, _symbol_size, _symbol_id, _k); 191 | } 192 | using T = typename std::iterator_traits::value_type; 193 | T operator[] (const size_t pos) const 194 | { 195 | size_t i; 196 | if (pos < _sub_blocks.tot (0)) { 197 | auto sub_blk_id = pos / _sub_blocks.size (0); 198 | i = _start + 199 | sub_blk_id * _k * _sub_blocks.size (0) +// right sub block 200 | _symbol_id * _sub_blocks.size (0) + // get right subsymbol 201 | pos % _sub_blocks.size (0); // get right alignment 202 | } else { 203 | auto pos_part2 = pos - _sub_blocks.tot (0); 204 | auto sub_blk_id = pos_part2 / _sub_blocks.size (1); 205 | i = _start + _sub_blocks.tot (0) * _k + // skip previous partition 206 | sub_blk_id * _k * _sub_blocks.size (1) +// right sub block 207 | _symbol_id * _sub_blocks.size (1) + // get right subsymbol 208 | pos_part2 % _sub_blocks.size (1); // get right alignment 209 | } 210 | #pragma clang diagnostic push 211 | #pragma clang diagnostic ignored "-Wshorten-64-to-32" 212 | auto data = _data_from + static_cast(i); 213 | #pragma clang diagnostic pop 214 | if (data >= _data_to) { 215 | // Padding. remember to cast it to the same time as the iterator 216 | // value 217 | return static_cast< 218 | typename std::iterator_traits::value_type> (0); 219 | } 220 | return *data; 221 | } 222 | T operator* () const 223 | { 224 | return (*this)[_idx]; 225 | } 226 | Symbol_it operator++ (int i) const 227 | { 228 | if (_idx + i >= _sub_blocks.tot (0) + _sub_blocks.tot (1)) 229 | return end(); 230 | return Symbol_it (_data_from, _data_to, _start, _end, _idx + i, 231 | _sub_blocks, _symbol_size, _symbol_id, _k); 232 | } 233 | Symbol_it& operator++() 234 | { 235 | if (_idx < _sub_blocks.tot (0) + _sub_blocks.tot (1)) 236 | ++_idx; 237 | return *this; 238 | } 239 | bool operator== (const Symbol_it &s) const 240 | { 241 | return _idx == s._idx; 242 | } 243 | bool operator!= (const Symbol_it &s) const 244 | { 245 | return _idx != s._idx; 246 | } 247 | 248 | private: 249 | const Rnd_It _data_from, _data_to; 250 | const size_t _start, _end; 251 | size_t _idx; 252 | const Partition _sub_blocks; 253 | const uint16_t _symbol_size, _symbol_id, _k; 254 | }; 255 | 256 | // 257 | // Source_Block: 258 | // First unit of partitioning for the object to be transferred. 259 | // 260 | template 261 | class RAPTORQ_LOCAL Source_Block 262 | { 263 | public: 264 | Source_Block (const Rnd_It data_from, const Rnd_It data_to, 265 | const size_t start, 266 | const size_t end, const size_t idx, 267 | const Partition sub_blocks, 268 | const uint16_t symbol_size) 269 | :_data_from (data_from), _data_to (data_to), _start (start), 270 | _end (end), _idx(idx), _sub_blocks(sub_blocks), 271 | _symbol_size (symbol_size), 272 | _symbols ( 273 | static_cast ((end - start) / symbol_size)) 274 | {} 275 | 276 | constexpr Source_Block begin() const 277 | { 278 | return Source_Block (_data_from, _data_to, _start, _end, 0, _sub_blocks, 279 | _symbol_size); 280 | } 281 | constexpr Source_Block end() const 282 | { 283 | return Source_Block (_data_from, _data_to, _start, _end, _end, 284 | _sub_blocks, _symbol_size); 285 | } 286 | const Symbol_it operator[] (const uint16_t symbol_id) const 287 | { 288 | if (symbol_id < _symbols) { 289 | return Symbol_it (_data_from, _data_to, _start, _end, 0, 290 | _sub_blocks, _symbol_size, symbol_id, 291 | _symbols); 292 | } 293 | // out of range. 294 | return Symbol_it (_data_from, _data_to, 0, 0, 0, _sub_blocks, 295 | _symbol_size, 0, 0); 296 | } 297 | const Symbol_it operator* () const 298 | { 299 | return (*this)[_idx]; 300 | } 301 | const Source_Block operator++ (int i) const 302 | { 303 | if (_idx + i >= _symbols) 304 | return end(); 305 | return Source_Block (_data_from, _data_to, _start, _end, 306 | _idx + i, _sub_blocks, _symbol_size); 307 | } 308 | const Source_Block& operator++ () 309 | { 310 | if (_idx < _symbols) 311 | ++_idx; 312 | return *this; 313 | } 314 | private: 315 | const Rnd_It _data_from, _data_to; 316 | const size_t _start, _end; 317 | size_t _idx; 318 | const Partition _sub_blocks; 319 | const uint16_t _symbol_size, _symbols; 320 | }; 321 | 322 | 323 | // 324 | // Interleaver 325 | // Take an object file, and handle the source block, sub block, sub symbol 326 | // and symbol division and interleaving, and padding. 327 | // 328 | template 329 | class RAPTORQ_LOCAL Interleaver 330 | { 331 | public: 332 | operator bool() const; // true => all ok 333 | 334 | Interleaver (const Rnd_It data_from, const Rnd_It data_to, 335 | const uint16_t min_subsymbol_size, 336 | const size_t max_block_decodable, 337 | const uint16_t symbol_syze); 338 | 339 | Source_Block& begin() const; 340 | Source_Block& end() const; 341 | Interleaver& operator++(); 342 | Source_Block operator*() const; 343 | Source_Block operator[] (uint8_t source_block_id) const; 344 | Partition get_partition() const; 345 | uint16_t source_symbols(const uint8_t SBN) const; 346 | uint8_t blocks () const; 347 | uint16_t sub_blocks () const; 348 | uint16_t symbol_size() const; 349 | protected: 350 | private: 351 | const Rnd_It _data_from, _data_to; 352 | const uint16_t _symbol_size; 353 | uint16_t _sub_blocks, _source_symbols, iterator_idx = 0; 354 | uint8_t _alignment, _source_blocks; 355 | 356 | // Please everyone take a moment to tank the RFC6330 guys for 357 | // giving such wonderfully self-explanatory names to *everything*. 358 | // Same names are kept to better track the rfc 359 | // (SIZE, SIZE, BLOCKNUM, BLOCKNUM) for: 360 | Partition _source_part, _sub_part; 361 | }; 362 | 363 | /////////////////////////////////// 364 | // 365 | // IMPLEMENTATION OF ABOVE TEMPLATE 366 | // 367 | /////////////////////////////////// 368 | 369 | template 370 | Interleaver::Interleaver (const Rnd_It data_from, 371 | const Rnd_It data_to, 372 | const uint16_t min_subsymbol_size, 373 | const size_t max_block_decodable, 374 | const uint16_t symbol_size) 375 | :_data_from (data_from), _data_to (data_to), _symbol_size (symbol_size), 376 | _alignment (sizeof(typename std::iterator_traits::value_type)) 377 | { 378 | IS_RANDOM(Rnd_It, "RaptorQ::Impl::Interleaver"); 379 | // all parameters are in octets 380 | assert(_symbol_size >= _alignment && 381 | "RaptorQ: symbol_size must be >= alignment"); 382 | assert((_symbol_size % _alignment) == 0 && 383 | "RaptorQ: symbol_size must be multiple of alignment"); 384 | assert(min_subsymbol_size >= _alignment && 385 | "RaptorQ: minimum subsymbol must be at least aligment"); 386 | assert(min_subsymbol_size <= _symbol_size && 387 | "RaptorQ: minimum subsymbol must be at most symbol_size"); 388 | assert((min_subsymbol_size % _alignment) == 0 && 389 | "RaptorQ: minimum subsymbol must be multiple of alignment"); 390 | // derive number of source blocks and sub blocks. seed RFC 6330, pg 8 391 | std::vector sizes; 392 | size_t iter_size =sizeof(typename std::iterator_traits::value_type); 393 | const double input_size = static_cast(_data_to - _data_from) * 394 | iter_size; 395 | const double Kt = div_ceil (input_size, symbol_size); 396 | const size_t N_max = static_cast (div_floor (_symbol_size, 397 | min_subsymbol_size)); 398 | 399 | // symbol_size must be a multiple of our alignment 400 | if (_symbol_size % _alignment != 0 || min_subsymbol_size < _alignment || 401 | (min_subsymbol_size % _alignment) != 0 || 402 | min_subsymbol_size > symbol_size) { 403 | // nonsense configurations. refuse to work. 404 | _alignment = 0; 405 | return; 406 | } 407 | 408 | // rfc 6330, pg 8 409 | size_t tmp; 410 | sizes.reserve (N_max); 411 | // find our KL(n), for each n 412 | for (tmp = 1; tmp <= N_max; ++tmp) { 413 | auto upper_bound = max_block_decodable / (_alignment * 414 | div_ceil (_symbol_size, _alignment * tmp)); 415 | size_t idx; 416 | for (idx = 0; idx < RaptorQ::Impl::K_padded.size(); ++idx) { 417 | if (RaptorQ::Impl::K_padded[idx] > upper_bound) 418 | break; 419 | } 420 | // NOTE: tmp starts from 1, but "sizes" stores from 0. 421 | sizes.push_back (RaptorQ::Impl::K_padded[idx == 0 ? 0 : --idx]); 422 | } 423 | const uint64_t _test_blocks = static_cast ( 424 | div_ceil (Kt, sizes[N_max - 1])); 425 | if (_test_blocks > std::numeric_limits::max()) { 426 | _alignment = 0; 427 | return; 428 | } 429 | _source_blocks = static_cast (_test_blocks); 430 | tmp = static_cast (div_ceil (Kt, _source_blocks)); 431 | for (size_t i = 0; i < sizes.size(); ++i) { 432 | // rfc: ceil (Kt / Z) <= KL(n) 433 | if (tmp <= sizes[i]) { 434 | _sub_blocks = static_cast (i + 1); // +1: see above note 435 | break; 436 | } 437 | } 438 | assert(div_ceil (div_ceil (input_size, _symbol_size), 439 | _source_blocks) <= K_max && 440 | "RaptorQ: RFC: ceil(ceil(F/T)/Z must be <= K'_max"); 441 | if (_source_blocks == 0 || _sub_blocks == 0 || 442 | symbol_size < _alignment || symbol_size % _alignment != 0 || 443 | div_ceil (div_ceil ( input_size, _symbol_size), 444 | _source_blocks) > K_max) { 445 | _alignment = 0; 446 | return; 447 | } 448 | // blocks and size for source block partitioning 449 | _source_part = Partition (static_cast (Kt), _source_blocks); 450 | 451 | _source_symbols = _source_part.size(0) + _source_part.size(1); 452 | 453 | // blocks and size for sub-block partitioning 454 | _sub_part = Partition (_symbol_size / _alignment, _sub_blocks); 455 | } 456 | 457 | template 458 | Interleaver::operator bool() const 459 | { 460 | // true => all ok 461 | return _alignment != 0; 462 | } 463 | 464 | template 465 | Source_Block Interleaver::operator[] ( 466 | uint8_t source_block_id) const 467 | { 468 | // now we start working with multiples of T. 469 | // identify the start and end of the requested block. 470 | uint16_t al_symbol_size = _symbol_size / 471 | sizeof(typename std::iterator_traits::value_type); 472 | 473 | if (source_block_id < _source_part.num(0)) { 474 | size_t sb_start = source_block_id * _source_part.size(0) * 475 | al_symbol_size; 476 | size_t sb_end = (source_block_id + 1) * _source_part.size(0) * 477 | al_symbol_size; 478 | 479 | return Source_Block (_data_from, _data_to, sb_start, sb_end, 0, 480 | _sub_part, al_symbol_size); 481 | } else if (source_block_id - _source_part.num(0) < _source_part.num(1)) { 482 | // start == all the previous partition 483 | size_t sb_start = _source_part.tot(0) * al_symbol_size + 484 | // plus some blocks of the new partition 485 | (source_block_id - _source_part.num(0)) * 486 | _source_part.size(1) * al_symbol_size; 487 | size_t sb_end = sb_start + _source_part.size(1) * al_symbol_size; 488 | 489 | return Source_Block (_data_from, _data_to, sb_start, sb_end, 0, 490 | _sub_part, al_symbol_size); 491 | } else { 492 | assert(false && "RaptorQ: source_block_id out of range"); 493 | return Source_Block (_data_from, _data_to, 0, 0, 0, _sub_part, 494 | al_symbol_size); 495 | } 496 | } 497 | 498 | template 499 | uint16_t Interleaver::symbol_size() const 500 | { 501 | // return the number of alignments, to make things easier 502 | return _symbol_size / sizeof( 503 | typename std::iterator_traits::value_type); 504 | } 505 | 506 | template 507 | Partition Interleaver::get_partition() const 508 | { 509 | return _source_part; 510 | } 511 | 512 | 513 | template 514 | uint16_t Interleaver::source_symbols (const uint8_t SBN) const 515 | { 516 | if (SBN < _source_part.num (0)) 517 | return _source_part.size (0); 518 | if (SBN - _source_part.num (0) < _source_part.num (1)) 519 | return _source_part.size (1); 520 | return 0; 521 | } 522 | 523 | template 524 | uint8_t Interleaver::blocks () const 525 | { 526 | return static_cast (_source_part.num (0) + _source_part.num (1)); 527 | } 528 | 529 | template 530 | uint16_t Interleaver::sub_blocks () const 531 | { 532 | return _sub_part.num (0) + _sub_part.num (1); 533 | } 534 | 535 | template 536 | Source_Block& Interleaver::begin() const 537 | { 538 | return this[0]; 539 | } 540 | 541 | template 542 | Source_Block& Interleaver::end() const 543 | { 544 | return this[_source_blocks + 1]; 545 | } 546 | 547 | template 548 | Interleaver& Interleaver::operator++() 549 | { 550 | ++iterator_idx; 551 | return *this; 552 | } 553 | 554 | template 555 | Source_Block Interleaver::operator*() const 556 | { 557 | return this[iterator_idx]; 558 | } 559 | 560 | } // namespace Impl 561 | } // namespace RaptorQ 562 | 563 | #endif 564 | -------------------------------------------------------------------------------- /src/RaptorQ/Parameters.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include "degree.hpp" 22 | #include "Parameters.hpp" 23 | #include "Rand.hpp" 24 | 25 | RaptorQ::Impl::Parameters::Parameters(const uint16_t symbols) 26 | { 27 | uint16_t idx; 28 | for (idx = 0; idx < RaptorQ::Impl::K_padded.size(); ++idx) { 29 | if (RaptorQ::Impl::K_padded[idx] >= symbols) { 30 | K_padded = RaptorQ::Impl::K_padded[idx]; 31 | break; 32 | } 33 | } 34 | 35 | J = RaptorQ::Impl::J_K_padded[idx]; 36 | std::tie (S, H, W) = RaptorQ::Impl::S_H_W [idx]; 37 | 38 | L = K_padded + S + H; 39 | P = L - W; 40 | U = P - H; 41 | B = W - S; 42 | P1 = P + 1; // first prime number bigger than P. turns out its 43 | // always between 1 and 14 more numbers. 44 | while (!is_prime (P1)) // so this while will be really quick anyway 45 | ++P1; 46 | } 47 | 48 | bool RaptorQ::Impl::Parameters::is_prime (const uint16_t n) 49 | { 50 | // 1 as prime, don't care. Not in our scope anyway. 51 | // thank you stackexchange for the code 52 | if (n <= 3) 53 | return true; 54 | if (n % 2 == 0 || n % 3 == 0) 55 | return false; 56 | 57 | uint32_t i = 5; 58 | uint32_t w = 2; 59 | while (i * i <= n) { 60 | if (n % i == 0) 61 | return false; 62 | i += w; 63 | w = 6 - w; 64 | } 65 | return true; 66 | } 67 | 68 | 69 | uint16_t RaptorQ::Impl::Parameters::Deg (const uint32_t v) const 70 | { 71 | // rfc 6330, pg 27 72 | 73 | for (uint16_t d = 0; d < RaptorQ::Impl::degree_distribution.size(); ++d) { 74 | if (v < RaptorQ::Impl::degree_distribution[d]) 75 | return (d < (W - 2)) ? d : (W - 2); 76 | } 77 | return 0; // never get here, but don't make the compiler complain 78 | } 79 | 80 | RaptorQ::Impl::Tuple RaptorQ::Impl::Parameters::tuple (const uint32_t ISI) const 81 | { 82 | RaptorQ::Impl::Rand rnd; 83 | RaptorQ::Impl::Tuple ret; 84 | 85 | // taken straight from RFC6330, pg 30 86 | // so thank them for the *beautiful* names 87 | // also, don't get confused with "B": this one is different, 88 | // and thus named "B1" 89 | 90 | size_t A = 53591 + J * 997; 91 | 92 | if (A % 2 == 0) 93 | ++A; 94 | size_t B1 = 10267 * (J + 1); 95 | uint32_t y = static_cast (B1 + ISI * A); 96 | uint32_t v = rnd.get (y, 0, static_cast (std::pow(2, 20))); 97 | ret.d = Deg (v); 98 | ret.a = 1 + static_cast (rnd.get (y, 1, W - 1)); 99 | ret.b = static_cast (rnd.get (y, 2, W)); 100 | if (ret.d < 4) { 101 | ret.d1 = 2 + static_cast (rnd.get (ISI, 3, 2)); 102 | } else { 103 | ret.d1 = 2; 104 | } 105 | ret.a1 = 1 + static_cast (rnd.get (ISI, 4, P1 - 1)); 106 | ret.b1 = static_cast (rnd.get (ISI, 5, P1)); 107 | 108 | return ret; 109 | } 110 | 111 | std::vector RaptorQ::Impl::Parameters::get_idxs (const uint32_t ISI) 112 | const 113 | { 114 | // Needed to generate G_ENC: We need the ids of the symbols we would 115 | // use on a "Enc" call. So this is the "enc algorithm, but returns the 116 | // indexes instead of computing the result. 117 | // rfc6330, pg29 118 | 119 | std::vector ret; 120 | Tuple t = tuple (ISI); 121 | 122 | ret.reserve (t.d + t.d1); 123 | ret.push_back (t.b); 124 | 125 | for (uint16_t j = 1; j < t.d; ++j) { 126 | t.b = (t.b + t.a) % W; 127 | ret.push_back (t.b); 128 | } 129 | while (t.b1 >= P) 130 | t.b1 = (t.b1 + t.a1) % P1; 131 | 132 | ret.push_back (W + t.b1); 133 | for (uint16_t j = 1; j < t.d1; ++j) { 134 | t.b1 = (t.b1 + t.a1) % P1; 135 | while (t.b1 >= P) 136 | t.b1 = (t.b1 + t.a1) % P1; 137 | ret.push_back (W + t.b1); 138 | } 139 | return ret; 140 | } 141 | -------------------------------------------------------------------------------- /src/RaptorQ/Parameters.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_PARAMETERS_HPP 22 | #define RAPTORQ_PARAMETERS_HPP 23 | 24 | #include "common.hpp" 25 | #include "multiplication.hpp" 26 | #include "table2.hpp" 27 | #include 28 | #include 29 | #include 30 | 31 | // 32 | // This implements both phase 1 and phase 2 of the encoding 33 | // algorithm. Phase2 was so small it made no sense splitting them. 34 | // 35 | 36 | namespace RaptorQ { 37 | namespace Impl { 38 | 39 | class RAPTORQ_LOCAL Tuple 40 | { 41 | // d 1-30 LT-degree of encoded symbol 42 | // a 0-(W-1) 43 | // b 0-(W-1) 44 | // d1 PI-degree of encoded symbol (2 or 3) 45 | // a1 0-(P1-1) 46 | // b1 0-(P1-1) 47 | public: 48 | uint16_t d, a, b, d1, a1, b1; // great names. thanks rfc6330! 49 | }; 50 | 51 | class RAPTORQ_API Parameters 52 | { 53 | public: 54 | explicit Parameters (const uint16_t symbols); 55 | uint16_t Deg (const uint32_t v) const; 56 | Tuple tuple (const uint32_t ISI) const; 57 | std::vector get_idxs (const uint32_t ISI) const; 58 | 59 | uint16_t K_padded, S, H, W, L, P, P1, U, B; // RFC 6330, pg 22 60 | uint16_t J; 61 | private: 62 | static bool is_prime (const uint16_t n); 63 | }; 64 | 65 | class RAPTORQ_LOCAL Octet 66 | { 67 | public: 68 | Octet () {} 69 | Octet (const uint8_t val) : data(val) {} 70 | 71 | explicit operator uint8_t() const { return data; } 72 | 73 | Octet& operator-= (const Octet a) 74 | { 75 | data ^= a.data; 76 | return *this; 77 | } 78 | friend Octet operator- (Octet lhs, const Octet rhs) 79 | { 80 | lhs.data ^= rhs.data; 81 | return lhs; 82 | } 83 | Octet& operator+= (const Octet a) 84 | { 85 | data ^= a.data; 86 | return *this; 87 | } 88 | friend Octet operator+ (Octet lhs, const Octet rhs) 89 | { 90 | lhs.data ^= rhs.data; 91 | return lhs; 92 | } 93 | // xor, addition, subtraction... they're the same to me... 94 | Octet& operator^= (const Octet &a) 95 | { 96 | data ^= a.data; 97 | return *this; 98 | } 99 | friend Octet operator^ (Octet lhs, const Octet rhs) 100 | { 101 | lhs.data ^= rhs.data; 102 | return lhs; 103 | } 104 | Octet& operator*= (const Octet a) 105 | { 106 | if (data != 0 && a.data != 0) { 107 | data = RaptorQ::Impl::oct_exp[oct_log[data - 1] + 108 | oct_log[a.data - 1]]; 109 | } else { 110 | data = 0; 111 | } 112 | return *this; 113 | } 114 | friend Octet operator* (Octet lhs, const Octet rhs) 115 | { 116 | if (lhs.data != 0 && rhs.data != 0) { 117 | lhs.data = RaptorQ::Impl::oct_exp[oct_log[lhs.data - 1] + 118 | oct_log[rhs.data - 1]]; 119 | } else { 120 | lhs.data = 0; 121 | } 122 | return lhs; 123 | } 124 | Octet& operator/= (const Octet a) 125 | { 126 | if (a.data != 0 && data != 0) { 127 | data = RaptorQ::Impl::oct_exp[oct_log[data - 1] - 128 | oct_log[a.data - 1] + 255]; 129 | } 130 | return *this; 131 | } 132 | friend Octet operator/ (Octet lhs, const Octet rhs) 133 | { 134 | lhs /= rhs; 135 | return lhs; 136 | } 137 | friend std::ostream &operator<< (std::ostream &os, Octet const &m) { 138 | os << std::hex << static_cast (m.data) << std::dec; 139 | return os; 140 | } 141 | private: 142 | uint8_t data; 143 | }; 144 | 145 | inline uint8_t abs (Octet x) { return static_cast (x); } 146 | 147 | } // namespace Impl 148 | } // namespace RaptorQ 149 | 150 | namespace Eigen { 151 | template<> 152 | struct NumTraits : NumTraits {}; 153 | } 154 | 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/RaptorQ/Phase2.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/RaptorQ/Phase2.hpp -------------------------------------------------------------------------------- /src/RaptorQ/Precode_Matrix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include "Graph.hpp" 22 | #include "multiplication.hpp" 23 | #include "Precode_Matrix.hpp" 24 | #include "Rand.hpp" 25 | 26 | 27 | // force promotion to double in division 28 | namespace { 29 | float RAPTORQ_LOCAL div_floor (const float a, const float b); 30 | float RAPTORQ_LOCAL div_ceil (const float a, const float b); 31 | 32 | float div_floor (const float a, const float b) 33 | { 34 | return std::floor (a / b); 35 | } 36 | float div_ceil (const float a, const float b) 37 | { 38 | return std::ceil (a / b); 39 | } 40 | } 41 | 42 | /////////////////// 43 | // 44 | // Bitmask 45 | // 46 | /////////////////// 47 | 48 | namespace RaptorQ { 49 | namespace Impl { 50 | 51 | Bitmask::Bitmask (const uint16_t symbols) 52 | : _max_nonrepair (symbols) 53 | { 54 | holes = _max_nonrepair; 55 | size_t max_element = static_cast (div_ceil (_max_nonrepair, 56 | sizeof(size_t))); 57 | mask.reserve (max_element + 1); 58 | for (size_t i = 0; i <= max_element; ++i) 59 | mask.push_back (0); 60 | } 61 | 62 | void Bitmask::add (const size_t id) 63 | { 64 | size_t element = static_cast (div_floor (id, sizeof(size_t))); 65 | while (element >= mask.size()) 66 | mask.push_back(0); 67 | if (exists(id)) 68 | return; 69 | 70 | size_t add_mask = 1 << (id - (element * sizeof(size_t))); 71 | mask[element] |= add_mask; 72 | if (id < _max_nonrepair) 73 | --holes; 74 | } 75 | 76 | bool Bitmask::exists (const size_t id ) const 77 | { 78 | size_t element = static_cast (div_floor (id, sizeof(size_t))); 79 | if (element >= mask.size()) 80 | return false; 81 | 82 | size_t check_mask = 1 << (id - (element * sizeof(size_t))); 83 | return (mask[element] & check_mask) != 0; 84 | } 85 | 86 | uint16_t Bitmask::get_holes () const 87 | { 88 | return holes; 89 | } 90 | 91 | /////////////////// 92 | // 93 | // Precode_Matrix 94 | // 95 | /////////////////// 96 | 97 | /// 98 | /// These methods are used to generate the precode matrix. 99 | /// 100 | 101 | void Precode_Matrix::gen (const uint32_t repair_overhead) 102 | { 103 | _repair_overhead = repair_overhead; 104 | A = DenseMtx (_params.L + repair_overhead, _params.L); 105 | 106 | init_LDPC1 (_params.S, _params.B); 107 | add_identity (_params.S, 0, _params.B); 108 | init_LDPC2 (_params.W, _params.S, _params.P); 109 | init_HDPC (); 110 | add_identity (_params.H, _params.S, _params.L - _params.H); 111 | add_G_ENC (); 112 | // G_ENC only fills up to L rows, but we might have overhead. 113 | // initialize it. 114 | for (uint16_t row = _params.L; row < A.rows(); ++row) { 115 | for (uint16_t col = 0; col < A.cols(); ++col) 116 | A(row, col) = 0; 117 | } 118 | } 119 | 120 | void Precode_Matrix::init_LDPC1 (const uint16_t S, const uint16_t B) 121 | { 122 | // The first LDPC1 submatrix is a SxB matrix of SxS submatrixes 123 | // (the last submatrix can have less than S columns) 124 | // each submatrix is full zero, with some exceptions: 125 | // in the first column positions "0", "i + 1" and "2 * (i+1)" are set 126 | // to 1. All next columns are all downshifts of the first. 127 | // which makes each submatrix a circulant matrix) 128 | 129 | // You won't find this directly on the rfc, but you can find it in the book: 130 | // Raptor Codes Foundations and Trends in Communications 131 | // and Information Theory 132 | 133 | uint16_t row, col; 134 | for (row = 0; row < S;++row) { 135 | for (col = 0; col < B; ++col) { 136 | bool zero = true; 137 | uint16_t submtx = col / S; 138 | if ((row == (col % S)) || // column 0 & downshifts 139 | (row == (col + submtx + 1) % S) || // i + 1 & downshifts 140 | (row == (col + 2 * (submtx + 1)) % S)) {// 2* (i+1) & dshift 141 | zero = false ; 142 | } 143 | A (row, col) = (zero ? 0 : 1); 144 | } 145 | } 146 | } 147 | 148 | void Precode_Matrix::add_identity (const uint16_t size, const uint16_t skip_row, 149 | const uint16_t skip_col) 150 | { 151 | auto sub_mtx = A.block (skip_row, skip_col, size, size); 152 | for (uint16_t row = 0; row < sub_mtx.rows(); ++row) { 153 | for (uint16_t col = 0; col < sub_mtx.cols(); ++col) 154 | sub_mtx (row, col) = (row == col ? 1 : 0); 155 | } 156 | } 157 | 158 | void Precode_Matrix::init_LDPC2 (const uint16_t skip, const uint16_t rows, 159 | const uint16_t cols) 160 | { 161 | // this submatrix has two consecutive "1" in the first row, first two 162 | // colums, and then every other row is the previous right shifted. 163 | 164 | // You won't find this easily on the rfc, but you can see this in the book: 165 | // Raptor Codes Foundations and Trends in Communications 166 | // and Information Theory 167 | auto sub_mtx = A.block (0, skip, rows, cols); 168 | for (uint16_t row = 0; row < sub_mtx.rows(); ++row) { 169 | uint16_t start = row % cols; 170 | for (uint16_t col = 0; col < sub_mtx.cols(); ++col) { 171 | if (col == start || col == (start + 1) % cols) { 172 | sub_mtx (row, col) = 1; 173 | } else { 174 | sub_mtx (row, col) = 0; 175 | } 176 | } 177 | } 178 | } 179 | 180 | DenseMtx Precode_Matrix::make_MT() const 181 | { 182 | // rfc 6330, pg 24 183 | Rand rnd; 184 | 185 | DenseMtx MT = DenseMtx (_params.H, _params.K_padded + _params.S); 186 | 187 | for (uint16_t row = 0; row < MT.rows(); ++row) { 188 | uint16_t col; 189 | for (col = 0; col < MT.cols() - 1; ++col) { 190 | auto tmp = rnd.get (col + 1, 6, _params.H); 191 | if ((row == tmp) || (row == 192 | (tmp + rnd.get (col + 1, 7, _params.H - 1) + 1) 193 | % _params.H)) { 194 | MT (row, col) = 1; 195 | } else { 196 | MT (row, col) = 0; 197 | } 198 | } 199 | // last column: alpha ^^ i, as in rfc6330 200 | MT (row, col) = RaptorQ::Impl::oct_exp[row]; 201 | } 202 | return MT; 203 | } 204 | 205 | DenseMtx Precode_Matrix::make_GAMMA() const 206 | { 207 | // rfc 6330, pg 24 208 | DenseMtx GAMMA = DenseMtx (_params.K_padded + _params.S, 209 | _params.K_padded + _params.S); 210 | 211 | for (uint16_t row = 0; row < GAMMA.rows(); ++row) { 212 | uint16_t col; 213 | for (col = 0; col <= row; ++col) 214 | // alpha ^^ (i-j), as in rfc6330, pg24 215 | // rfc only says "i-j", but we could go well over oct_exp size. 216 | // we hope they just missed a modulus :/ 217 | GAMMA (row, col) = RaptorQ::Impl::oct_exp[(row - col) % 218 | RaptorQ::Impl::oct_exp.size()]; 219 | for (; col < GAMMA.cols(); ++col) { 220 | GAMMA (row, col) = 0; 221 | } 222 | } 223 | return GAMMA; 224 | } 225 | 226 | void Precode_Matrix::init_HDPC () 227 | { 228 | // rfc 6330, pg 25 229 | DenseMtx MT = make_MT(); 230 | DenseMtx GAMMA = make_GAMMA(); 231 | 232 | A.block(_params.S, 0, _params.H, GAMMA.rows()) = MT * GAMMA; 233 | } 234 | 235 | void Precode_Matrix::add_G_ENC () 236 | { 237 | // rfc 6330, pg 26 238 | for (uint16_t row = _params.S + _params.H; row < _params.L; ++row) { 239 | // all to zero 240 | for (uint16_t col = 0; col < _params.L; ++col) 241 | A (row, col) = 0; 242 | // only overwrite with ones the columns that need it 243 | auto idxs = _params.get_idxs ((row - _params.S) - _params.H); 244 | for (auto idx : idxs) 245 | A(row, idx) = 1; 246 | } 247 | } 248 | 249 | } // namespace RaptorQ 250 | } // namespace Impl 251 | -------------------------------------------------------------------------------- /src/RaptorQ/Precode_Matrix.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_PRECODE_MATRIX_HPP 22 | #define RAPTORQ_PRECODE_MATRIX_HPP 23 | 24 | #include "common.hpp" 25 | #include "Parameters.hpp" 26 | #include "Rand.hpp" 27 | #include "multiplication.hpp" 28 | #include 29 | 30 | namespace RaptorQ { 31 | namespace Impl { 32 | 33 | // track the bitmask of holes for received symbols. 34 | // also make it easy to know how many non-repair symbols we are missing. 35 | class RAPTORQ_API Bitmask 36 | { 37 | public: 38 | const uint16_t _max_nonrepair; 39 | 40 | Bitmask (const uint16_t symbols); 41 | 42 | void add (const size_t id); 43 | bool exists (const size_t id) const; 44 | uint16_t get_holes () const; 45 | private: 46 | std::vector mask; 47 | uint16_t holes; 48 | }; 49 | 50 | using DenseMtx = Eigen::Matrix; 52 | 53 | class RAPTORQ_API Precode_Matrix 54 | { 55 | public: 56 | const Parameters _params; 57 | 58 | Precode_Matrix(const Parameters ¶ms) 59 | :_params (params) 60 | {} 61 | 62 | void gen (const uint32_t repair_overhead); 63 | 64 | DenseMtx intermediate (DenseMtx &D); 65 | DenseMtx intermediate (DenseMtx &D, const Bitmask &mask, 66 | const std::vector &repair_esi); 67 | DenseMtx encode (const DenseMtx &C, const uint32_t iSI) const; 68 | 69 | private: 70 | DenseMtx A; 71 | uint32_t _repair_overhead = 0; 72 | 73 | // indenting here prepresent which function needs which other. 74 | // not standard, ask me if I care. 75 | void init_LDPC1 (const uint16_t S, const uint16_t B); 76 | void init_LDPC2 (const uint16_t skip, const uint16_t rows, 77 | const uint16_t cols); 78 | void add_identity (const uint16_t size, const uint16_t skip_row, 79 | const uint16_t skip_col); 80 | 81 | void init_HDPC (); 82 | DenseMtx make_MT() const; // rfc 6330, pgg 24, used for HDPC 83 | DenseMtx make_GAMMA() const; // rfc 6330, pgg 24, used for HDPC 84 | void add_G_ENC (); 85 | 86 | 87 | void decode_phase0 (const Bitmask &mask, 88 | const std::vector &repair_esi); 89 | std::tuple decode_phase1 (DenseMtx &X,DenseMtx &D, 90 | std::vector &c); 91 | bool decode_phase2 (DenseMtx &D, const uint16_t i,const uint16_t u); 92 | void decode_phase3 (const DenseMtx &X, DenseMtx &D, const uint16_t i); 93 | void decode_phase4 (DenseMtx &D, const uint16_t i, const uint16_t u); 94 | void decode_phase5 (DenseMtx &D, const uint16_t i); 95 | }; 96 | 97 | } // namespace Impl 98 | } // namespace RaptorQ 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/RaptorQ/Precode_Matrix_solver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include "Graph.hpp" 22 | #include "multiplication.hpp" 23 | #include "Precode_Matrix.hpp" 24 | #include "Rand.hpp" 25 | 26 | /////////////////// 27 | // 28 | // Precode_Matrix 29 | // 30 | /////////////////// 31 | 32 | /// 33 | /// These methods are used to solve the system A * C = D, where we have 34 | /// A and D. By doing this, we generate the intermediate symbols. 35 | /// 36 | 37 | namespace RaptorQ { 38 | namespace Impl { 39 | 40 | DenseMtx Precode_Matrix::intermediate (DenseMtx &D) 41 | { 42 | // rfc 6330, pg 32 43 | // "c" and "d" are used to track row and columns exchange. 44 | // since Eigen should track row exchange without actually swapping 45 | // the data, we can call DenseMtx.row.swap without more overhead 46 | // than actually having "d". so we're left only with "c", 47 | // which is needed 'cause D does not have _params.L columns. 48 | 49 | std::vector c; 50 | 51 | c.clear(); 52 | c.reserve (_params.L); 53 | DenseMtx C, X = A; 54 | 55 | bool success; 56 | uint16_t i, u; 57 | for (i = 0; i < _params.L; ++i) 58 | c.emplace_back (i); 59 | 60 | std::tie (success, i, u) = decode_phase1 (X, D, c); 61 | if (!success) 62 | return C; 63 | success = decode_phase2 (D, i, u); 64 | if (!success) 65 | return C; 66 | // A now should be considered as being LxL from now 67 | decode_phase3 (X, D, i); 68 | X = DenseMtx (); // free some memory, X is not needed anymore. 69 | decode_phase4 (D, i, u); 70 | decode_phase5 (D, i); 71 | // A now must be an LxL identity matrix: check it. 72 | // CHECK DISABLED: phase4 does not modify A, as it's never readed 73 | // again. So the Matrix is *not* an identity anymore. 74 | //auto id_A = A.block (0, 0, _params.L, _params.L); 75 | //for (uint16_t row = 0; row < id_A.rows(); ++row) { 76 | // for (uint16_t col = 0; col < id_A.cols(); ++col) { 77 | // if (static_cast (id_A (row, col)) != (row == col ? 1 : 0)) 78 | // return C; 79 | // } 80 | //} 81 | A = DenseMtx(); // free A memory. 82 | 83 | C = DenseMtx (D.rows(), D.cols()); 84 | for (i = 0; i < _params.L; ++i) 85 | C.row (c[i]) = D.row (i); 86 | 87 | return C; 88 | } 89 | 90 | // Used in decoding 91 | DenseMtx Precode_Matrix::intermediate (DenseMtx &D, const Bitmask &mask, 92 | const std::vector &repair_esi) 93 | { 94 | decode_phase0 (mask, repair_esi); 95 | DenseMtx C = intermediate (D); 96 | 97 | if (C.rows() == 0) { 98 | // error somewhere 99 | return DenseMtx(); 100 | } 101 | 102 | DenseMtx missing = DenseMtx (mask.get_holes(), D.cols()); 103 | uint16_t holes = mask.get_holes(); 104 | uint16_t row = 0; 105 | for (uint16_t hole = 0; hole < mask._max_nonrepair && holes > 0; ++hole) { 106 | if (mask.exists (hole)) 107 | continue; 108 | DenseMtx ret = encode (C, hole); 109 | missing.row (row) = ret.row(0); 110 | ++row; 111 | --holes; 112 | } 113 | return missing; 114 | } 115 | 116 | void Precode_Matrix::decode_phase0 (const Bitmask &mask, 117 | const std::vector &repair_esi) 118 | { 119 | // D was built as follows: 120 | // - non-repair esi in their place 121 | // - for each hole in non-repair esi, put the *first available* repair esi 122 | // in its place 123 | // - compact remaining repair esis 124 | 125 | 126 | // substitute missing symbols in A with appropriate repair line. 127 | // we substituted some symbols with repair ones (rfc 6330, phase1, pg35), 128 | // so we need to fix the corresponding rows in A, to say that a 129 | // repair symbol comes from a set of other symbols. 130 | 131 | const size_t padding = _params.K_padded - mask._max_nonrepair; 132 | 133 | uint16_t holes = mask.get_holes(); 134 | auto r_esi = repair_esi.begin(); 135 | 136 | for (uint16_t hole_from = 0; hole_from < _params.L && holes > 0; 137 | ++hole_from) { 138 | if (mask.exists (hole_from)) 139 | continue; 140 | // now hole_from is the esi hole, and hole_to is our repair sym. 141 | // put the repair dependancy in the hole row 142 | auto depends = _params.get_idxs (static_cast ( 143 | *r_esi + padding)); 144 | ++r_esi; 145 | // erease the line, mark the dependencies of the repair symbol. 146 | const uint16_t row = hole_from + _params.H + _params.S; 147 | for (uint16_t col = 0; col < A.cols(); ++col) { 148 | A (row, col) = 0; 149 | } 150 | for (auto isi: depends) { 151 | A (row, isi) = 1; 152 | } 153 | --holes; 154 | } 155 | // we put the repair symbols in the right places, 156 | // but we still need to do the same modifications to A also for repair 157 | // symbols. And those have been compacted. 158 | 159 | for (uint16_t rep_row = static_cast (A.rows() - 160 | static_cast (_repair_overhead)); 161 | rep_row < A.rows(); ++rep_row) { 162 | auto depends = _params.get_idxs (static_cast ( 163 | *r_esi + padding)); 164 | ++r_esi; 165 | // erease the line, mark the dependencies of the repair symbol. 166 | for (uint16_t col = 0; col < A.cols(); ++col) { 167 | A (rep_row, col) = 0; 168 | } 169 | for (auto isi: depends) { 170 | A (rep_row, isi) = 1; 171 | } 172 | } 173 | } 174 | 175 | std::tuple 176 | Precode_Matrix::decode_phase1 (DenseMtx &X, DenseMtx &D, 177 | std::vector &c) 178 | { 179 | //rfc6330, page 33 180 | 181 | std::vector> tracking; // is_hdpc, row_degree 182 | 183 | // optimization: r_rows tracks the rows that can be chosen, and if the row 184 | // is added to the graph, track also the id of one of the nodes with "1", 185 | // so that it will be easy to verify it. The row represents an edge 186 | // between nodes (1) of a maximum component (see rfc 6330, pg 33-34) 187 | std::vector> r_rows; 188 | 189 | tracking.reserve (static_cast (A.rows())); 190 | 191 | uint16_t i = 0; 192 | uint16_t u = _params.P; 193 | 194 | auto V_tmp = A.block (0, 0, A.rows(), A.cols() - u); 195 | 196 | // track hdpc rows and original degree of each row 197 | for (uint16_t row = 0; row < V_tmp.rows(); ++row) { 198 | size_t original_degree = 0; 199 | for (uint16_t col = 0; col < V_tmp.cols(); ++col) 200 | original_degree += static_cast (V_tmp (row, col)); 201 | bool is_hdpc = (row >= _params.S && row < (_params.S + _params.H)); 202 | tracking.emplace_back (is_hdpc, original_degree);; 203 | } 204 | 205 | while (i + u < _params.L) { 206 | auto V = A.block (i, i, A.rows() - i, (A.cols() - i) - u); 207 | uint16_t chosen = static_cast (V.rows()); 208 | // search for minium "r" (number of nonzero elements in row) 209 | uint16_t non_zero = static_cast (V.cols()) + 1; 210 | bool only_two_ones = false; 211 | r_rows.clear(); 212 | Graph G = Graph (static_cast (V.cols())); 213 | 214 | // build graph, get minimum non_zero and track rows that 215 | // will be needed later 216 | for (uint16_t row = 0; row < V.rows(); ++row) { 217 | uint16_t non_zero_tmp = 0; 218 | // if the row is NOT HDPC and has two ones, 219 | // it represents an edge in a graph between the two columns with "1" 220 | uint16_t ones = 0; 221 | std::array ones_idx = {{0, 0}}; 222 | bool next_row = false; // true => non_zero_tmp > zero_tmp 223 | for (uint16_t col = 0; col < V.cols(); ++col) { 224 | if (static_cast (V (row, col)) != 0) { 225 | if (++non_zero_tmp > non_zero) { 226 | next_row = true; 227 | break; 228 | } 229 | } 230 | if (static_cast (V (row, col)) == 1) { 231 | // count the ones and update ones_idx at the same time 232 | if (++ones <= 2) 233 | ones_idx[ones - 1] = col; 234 | } 235 | } 236 | if (next_row || non_zero_tmp == 0) 237 | continue; 238 | // now non_zero >= non_zero_tmp, and both > 0 239 | 240 | // rationale & optimization, rfc 6330 pg 34 241 | // we need to track the rows that have the least number "r" 242 | // of non-zero elements. 243 | // if r == 2 and even just one row has the two elements to "1", 244 | // then we need to track only the rows with "1" in the two 245 | // non-zero elements. 246 | if (non_zero == non_zero_tmp) { 247 | // do not add if "only_two_ones && ones != 2" 248 | if (!only_two_ones || ones == 2) 249 | r_rows.emplace_back (row, ones_idx[0]); 250 | } else { 251 | // non_zero > non_zero_tmp) 252 | non_zero = non_zero_tmp; 253 | r_rows.clear(); 254 | r_rows.emplace_back (row, ones_idx[0]); 255 | } 256 | 257 | if (ones == 2) { 258 | // track the maximum component in the graph 259 | if (non_zero == 2) { 260 | if (!tracking[row].first) // if not HDPC row 261 | G.connect (ones_idx[0], ones_idx[1]); 262 | if (!only_two_ones) { 263 | // must keep only rows with two ones, 264 | // so delete the other ones. 265 | only_two_ones = true; 266 | r_rows.clear(); 267 | r_rows.emplace_back (row, ones_idx[0]); 268 | } 269 | } 270 | } 271 | } 272 | if (non_zero == V.cols() + 1) 273 | return std::make_tuple (false, 0, 0); // failure 274 | // search for r. 275 | if (non_zero != 2) { 276 | // search for row with minimum original degree. 277 | // Precedence to non-hdpc 278 | uint16_t min_row = static_cast (V.rows()); 279 | uint16_t min_row_hdpc = min_row; 280 | size_t min_degree = ~(static_cast (0)); // max possible 281 | size_t min_degree_hdpc = min_degree; 282 | for (auto row_pair : r_rows) { 283 | uint16_t row = row_pair.first; 284 | if (tracking[row + i].first) { 285 | // HDPC 286 | if (tracking[row + i].second < min_degree_hdpc) { 287 | min_degree_hdpc = tracking[row + i].second; 288 | min_row_hdpc = row; 289 | } 290 | } else { 291 | // NON-HDPC 292 | if (tracking[row + i].second < min_degree) { 293 | min_degree = tracking[row + i].second; 294 | min_row = row; 295 | } 296 | } 297 | } 298 | if (min_row != V.rows()) { 299 | chosen = min_row; 300 | } else { 301 | chosen = min_row_hdpc; 302 | } 303 | } else { 304 | // non_zero == 2 => graph, else any r 305 | if (only_two_ones) { 306 | for (auto id : r_rows) { 307 | if (G.is_max (id.second)) { 308 | chosen = id.first; 309 | break; 310 | } 311 | } 312 | } 313 | if (chosen == V.rows()) { 314 | chosen = r_rows[0].first; 315 | } 316 | } // done choosing 317 | 318 | // swap chosen row and first V row in A (not just in V) 319 | if (chosen != 0) { 320 | A.row (i).swap (A.row (chosen + i)); 321 | X.row (i).swap (X.row (chosen + i)); 322 | D.row (i).swap (D.row (chosen + i)); 323 | std::swap (tracking[i], tracking[chosen + i]); 324 | } 325 | // column swap in A. looking at the first V row, 326 | // the first column must be nonzero, and the other non-zero must be 327 | // put to the last columns of V. 328 | if (static_cast (V (0, 0)) == 0) { 329 | uint16_t idx = 1; 330 | for (; idx < V.cols(); ++idx) { 331 | if (static_cast (V (0, idx)) != 0) 332 | break; 333 | } 334 | A.col (i).swap (A.col (i + idx)); 335 | X.col (i).swap (X.col (i + idx)); 336 | std::swap (c[i], c[i + idx]); // rfc6330, pg32 337 | } 338 | uint16_t col = static_cast (V.cols()) - 1; 339 | uint16_t swap = 1; // at most we swapped V(0,0) 340 | // put all the non-zero cols to the last columns. 341 | for (; col > V.cols() - non_zero; --col) { 342 | if (static_cast (V (0, col)) != 0) 343 | continue; 344 | while (swap < col && static_cast (V (0, swap)) == 0) 345 | ++swap; 346 | 347 | if (swap >= col) 348 | break; // line full of zeros, nothing to swap 349 | // now V(0, col) == 0 and V(0, swap != 0. swap them 350 | A.col (col + i).swap (A.col (swap + i)); 351 | X.col (col + i).swap (X.col (swap + i)); 352 | std::swap (c[col + i], c[swap + i]); //rfc6330, pg32 353 | } 354 | // now add a multiple of the row V(0) to the other rows of *A* so that 355 | // the other rows of *V* have a zero first column. 356 | for (uint16_t row = 1; row < V.rows(); ++row) { 357 | if (static_cast (V (row, 0)) != 0) { 358 | const Octet multiple = V (row, 0) / V (0, 0); 359 | A.row (row + i) += A.row (i) * multiple; 360 | D.row (row + i) += D.row (i) * multiple; //rfc6330, pg32 361 | } 362 | } 363 | 364 | // finally increment i by 1, u by (non_zero - 1) and repeat. 365 | ++i; 366 | u += non_zero - 1; 367 | } 368 | 369 | return std::make_tuple (true, i, u); 370 | } 371 | 372 | bool Precode_Matrix::decode_phase2 (DenseMtx &D, const uint16_t i, 373 | const uint16_t u) 374 | { 375 | // rfc 6330, pg 35 376 | 377 | // U_Lower parameters (u x u): 378 | const uint16_t row_start = i, row_end = static_cast (_params.L); 379 | const uint16_t col_start = static_cast (A.cols() - u); 380 | // try to bring U_Lower to Identity with gaussian elimination. 381 | // remember that all row swaps affect A as well, not just U_Lower 382 | 383 | for (uint16_t row = row_start; row < row_end; ++row) { 384 | // make sure the considered row has nonzero on the diagonal 385 | uint16_t row_nonzero = row; 386 | const uint16_t col_diag = col_start + (row - row_start); 387 | for (; row_nonzero < row_end; ++row_nonzero) { 388 | if (static_cast (A (row_nonzero, col_diag)) != 0) { 389 | break; 390 | } 391 | } 392 | if (row_nonzero == row_end) { 393 | // U_Lower is square, we can return early (rank < u, not solvable) 394 | return false; 395 | } else if (row != row_nonzero) { 396 | A.row (row).swap (A.row (row_nonzero)); 397 | D.row (row).swap (D.row (row_nonzero)); 398 | } 399 | 400 | // U_Lower (row, row) != 0. make it 1. 401 | if (static_cast (A (row, col_diag)) > 1) { 402 | const auto divisor = A (row, col_diag); 403 | A.row (row) /= divisor; 404 | D.row (row) /= divisor; 405 | } 406 | 407 | // make U_Lower and identity up to row 408 | for (uint16_t del_row = row_start; del_row < row_end; ++del_row) { 409 | if (del_row == row) 410 | continue; 411 | // subtrace row "row" to "del_row" enough times to make 412 | // row "del_row" start with zero. but row "row" now starts 413 | // with "1", so this is easy. 414 | const auto multiple = A (del_row, col_diag); 415 | if (static_cast (multiple) != 0) { 416 | A.row (del_row) -= A.row (row) * multiple; 417 | D.row (del_row) -= D.row (row) * multiple; 418 | } 419 | } 420 | } 421 | // A should be resized to LxL. 422 | // we don't really care, as we should not gain that much. 423 | // A.conservativeResize (params.L, params.L); 424 | return true; 425 | } 426 | 427 | void Precode_Matrix::decode_phase3 (const DenseMtx &X, DenseMtx &D, 428 | const uint16_t i) 429 | { 430 | // rfc 6330, pg 35: 431 | // To this end, the matrix X is 432 | // multiplied with the submatrix of A consisting of the first i rows of 433 | // A. After this operation, the submatrix of A consisting of the 434 | // intersection of the first i rows and columns equals to X, whereas the 435 | // matrix U_upper is transformed to a sparse form. 436 | const auto sub_X = X.block (0, 0, i, i); 437 | auto sub_A = A.block (0, 0, i, A.cols()); 438 | sub_A = sub_X * sub_A; 439 | 440 | // Now fix D, too 441 | DenseMtx D_2 = D; 442 | 443 | for (uint16_t row = 0; row < sub_X.rows(); ++row) { 444 | D.row (row) = sub_X.row (row) * D_2.block (0,0, sub_X.cols(), D.cols()); 445 | } 446 | } 447 | 448 | void Precode_Matrix::decode_phase4 (DenseMtx &D, const uint16_t i, 449 | const uint16_t u) 450 | { 451 | // rfc 6330, pg 35: 452 | // For each of the first i rows of U_upper, do the following: if the row 453 | // has a nonzero entry at position j, and if the value of that nonzero 454 | // entry is b, then add to this row b times row j of I_u 455 | 456 | // basically: zero out U_upper. we still need to update D each time, though. 457 | 458 | auto U_upper = A.block (0, A.cols() - u, i, u); 459 | for (uint16_t row = 0; row < U_upper.rows(); ++row) { 460 | for (uint16_t col = 0; col < U_upper.cols(); ++col) { 461 | // col == j 462 | auto multiple = U_upper (row, col); 463 | if (static_cast (multiple) != 0) { 464 | // U_upper is never read again, so we can avoid some writes 465 | //U_upper (row, col) = 0; 466 | 467 | // "b times row j of I_u" => row "j" in U_lower. 468 | // aka: U_upper.rows() + j 469 | D.row (row) += D.row ( 470 | static_cast (U_upper.rows()) + col) * 471 | multiple; 472 | } 473 | } 474 | } 475 | } 476 | 477 | void Precode_Matrix::decode_phase5 (DenseMtx &D, const uint16_t i) 478 | { 479 | // rc 6330, pg 36 480 | for (uint16_t j = 0; j <= i; ++j) { 481 | if (static_cast (A (j, j)) != 1) { 482 | // A(j, j) is actually never 0, by construction. 483 | const auto multiple = A (j, j); 484 | A.row (j) /= multiple; 485 | D.row (j) /= multiple; 486 | } 487 | for (uint16_t tmp = 0; tmp < j; ++tmp) { //tmp == "l" in rfc6330 488 | const auto multiple = A (j, tmp); 489 | if (static_cast (multiple) != 0) { 490 | A.row (j) += A.row (tmp) * multiple; 491 | D.row (j) += D.row (tmp) * multiple; 492 | } 493 | } 494 | } 495 | } 496 | 497 | DenseMtx Precode_Matrix::encode (const DenseMtx &C, const uint32_t ISI) const 498 | { 499 | // Generate repair symbols. same algorithm as "get_idxs" 500 | // rfc6330, pg29 501 | 502 | DenseMtx ret; 503 | 504 | ret = DenseMtx (1, C.cols()); 505 | Tuple t = _params.tuple (ISI); 506 | 507 | ret.row (0) = C.row (t.b); 508 | 509 | for (uint16_t j = 1; j < t.d; ++j) { 510 | t.b = (t.b + t.a) % _params.W; 511 | ret.row (0) += C.row (t.b); 512 | } 513 | while (t.b1 >= _params.P) 514 | t.b1 = (t.b1 + t.a1) % _params.P1; 515 | 516 | ret.row (0) += C.row (_params.W + t.b1); 517 | for (uint16_t j = 1; j < t.d1; ++j) { 518 | t.b1 = (t.b1 + t.a1) % _params.P1; 519 | while (t.b1 >= _params.P) 520 | t.b1 = (t.b1 + t.a1) % _params.P1; 521 | ret.row (0) += C.row (_params.W + t.b1); 522 | } 523 | 524 | return ret; 525 | } 526 | 527 | } // namespace RaptorQ 528 | } // namespace Impl 529 | -------------------------------------------------------------------------------- /src/RaptorQ/Rand.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include 22 | #include "Rand.hpp" 23 | 24 | namespace { 25 | double RAPTORQ_LOCAL div_floor (const double a, const double b); 26 | double div_floor (double a, double b) 27 | { 28 | return std::floor (a / b); 29 | } 30 | } 31 | 32 | namespace RaptorQ { 33 | namespace Impl { 34 | 35 | uint32_t Rand::get (const uint32_t y, const uint8_t i, const uint32_t m) 36 | { 37 | uint32_t mod = static_cast (std::pow (2, 8)); 38 | uint32_t x0 = (y + i) % mod; 39 | uint32_t x1 = static_cast ((div_floor (y, mod) + i)) % mod; 40 | uint32_t x2 = static_cast ((div_floor (y, std::pow (2, 16)) 41 | + i)) % mod; 42 | uint32_t x3 = static_cast ((div_floor (y, std::pow (2, 24)) 43 | + i)) % mod; 44 | 45 | return (V0[x0] ^ V1[x1] ^ V2[x2] ^ V3[x3]) % m; 46 | } 47 | 48 | 49 | #pragma clang diagnostic push 50 | #pragma clang diagnostic ignored "-Wmissing-braces" 51 | #pragma clang diagnostic ignored "-Wglobal-constructors" 52 | #pragma clang diagnostic ignored "-Wexit-time-destructors" 53 | 54 | /* RFC, section 5.5: Random Numbers 55 | * 56 | * The four arrays V0, V1, V2, and V3 used in Section 5.3.5.1 are 57 | * provided below. There are 256 entries in each of the four arrays. 58 | * The indexing into each array starts at 0, and the entries are 32-bit 59 | * unsigned integers. 60 | */ 61 | const std::array Rand::V0 = { 62 | 251291136, 3952231631, 3370958628, 4070167936, 123631495, 63 | 3351110283, 3218676425, 2011642291, 774603218, 2402805061, 64 | 1004366930, 1843948209, 428891132, 3746331984, 1591258008, 65 | 3067016507, 1433388735, 504005498, 2032657933, 3419319784, 66 | 2805686246, 3102436986, 3808671154, 2501582075, 3978944421, 67 | 246043949, 4016898363, 649743608, 1974987508, 2651273766, 68 | 2357956801, 689605112, 715807172, 2722736134, 191939188, 69 | 3535520157, 3277019569, 1470435941, 3763101702, 3232409631, 70 | 122701163, 3920852693, 782246947, 372121310, 2995604341, 71 | 2045698575, 2332962102, 4005368743, 218596347, 3415381967, 72 | 4207612806, 861117671, 3676575285, 2581671944, 3312220480, 73 | 681232419, 307306866, 4112503940, 1158111502, 709227802, 74 | 2724140433, 4201101115, 4215970289, 4048876515, 3031661061, 75 | 1909085522, 510985033, 1361682810, 129243379, 3142379587, 76 | 2569842483, 3033268270, 1658118006, 932109358, 1982290045, 77 | 2983082771, 3007670818, 3448104768, 683749698, 778296777, 78 | 1399125101, 1939403708, 1692176003, 3868299200, 1422476658, 79 | 593093658, 1878973865, 2526292949, 1591602827, 3986158854, 80 | 3964389521, 2695031039, 1942050155, 424618399, 1347204291, 81 | 2669179716, 2434425874, 2540801947, 1384069776, 4123580443, 82 | 1523670218, 2708475297, 1046771089, 2229796016, 1255426612, 83 | 4213663089, 1521339547, 3041843489, 420130494, 10677091, 84 | 515623176, 3457502702, 2115821274, 2720124766, 3242576090, 85 | 854310108, 425973987, 325832382, 1796851292, 2462744411, 86 | 1976681690, 1408671665, 1228817808, 3917210003, 263976645, 87 | 2593736473, 2471651269, 4291353919, 650792940, 1191583883, 88 | 3046561335, 2466530435, 2545983082, 969168436, 2019348792, 89 | 2268075521, 1169345068, 3250240009, 3963499681, 2560755113, 90 | 911182396, 760842409, 3569308693, 2687243553, 381854665, 91 | 2613828404, 2761078866, 1456668111, 883760091, 3294951678, 92 | 1604598575, 1985308198, 1014570543, 2724959607, 3062518035, 93 | 3115293053, 138853680, 4160398285, 3322241130, 2068983570, 94 | 2247491078, 3669524410, 1575146607, 828029864, 3732001371, 95 | 3422026452, 3370954177, 4006626915, 543812220, 1243116171, 96 | 3928372514, 2791443445, 4081325272, 2280435605, 885616073, 97 | 616452097, 3188863436, 2780382310, 2340014831, 1208439576, 98 | 258356309, 3837963200, 2075009450, 3214181212, 3303882142, 99 | 880813252, 1355575717, 207231484, 2420803184, 358923368, 100 | 1617557768, 3272161958, 1771154147, 2842106362, 1751209208, 101 | 1421030790, 658316681, 194065839, 3241510581, 38625260, 102 | 301875395, 4176141739, 297312930, 2137802113, 1502984205, 103 | 3669376622, 3728477036, 234652930, 2213589897, 2734638932, 104 | 1129721478, 3187422815, 2859178611, 3284308411, 3819792700, 105 | 3557526733, 451874476, 1740576081, 3592838701, 1709429513, 106 | 3702918379, 3533351328, 1641660745, 179350258, 2380520112, 107 | 3936163904, 3685256204, 3156252216, 1854258901, 2861641019, 108 | 3176611298, 834787554, 331353807, 517858103, 3010168884, 109 | 4012642001, 2217188075, 3756943137, 3077882590, 2054995199, 110 | 3081443129, 3895398812, 1141097543, 2376261053, 2626898255, 111 | 2554703076, 401233789, 1460049922, 678083952, 1064990737, 112 | 940909784, 1673396780, 528881783, 1712547446, 3629685652, 113 | 1358307511 114 | }; 115 | 116 | const std::array Rand::V1 = { 117 | 807385413, 2043073223, 3336749796, 1302105833, 2278607931, 118 | 541015020, 1684564270, 372709334, 3508252125, 1768346005, 119 | 1270451292, 2603029534, 2049387273, 3891424859, 2152948345, 120 | 4114760273, 915180310, 3754787998, 700503826, 2131559305, 121 | 1308908630, 224437350, 4065424007, 3638665944, 1679385496, 122 | 3431345226, 1779595665, 3068494238, 1424062773, 1033448464, 123 | 4050396853, 3302235057, 420600373, 2868446243, 311689386, 124 | 259047959, 4057180909, 1575367248, 4151214153, 110249784, 125 | 3006865921, 4293710613, 3501256572, 998007483, 499288295, 126 | 1205710710, 2997199489, 640417429, 3044194711, 486690751, 127 | 2686640734, 2394526209, 2521660077, 49993987, 3843885867, 128 | 4201106668, 415906198, 19296841, 2402488407, 2137119134, 129 | 1744097284, 579965637, 2037662632, 852173610, 2681403713, 130 | 1047144830, 2982173936, 910285038, 4187576520, 2589870048, 131 | 989448887, 3292758024, 506322719, 176010738, 1865471968, 132 | 2619324712, 564829442, 1996870325, 339697593, 4071072948, 133 | 3618966336, 2111320126, 1093955153, 957978696, 892010560, 134 | 1854601078, 1873407527, 2498544695, 2694156259, 1927339682, 135 | 1650555729, 183933047, 3061444337, 2067387204, 228962564, 136 | 3904109414, 1595995433, 1780701372, 2463145963, 307281463, 137 | 3237929991, 3852995239, 2398693510, 3754138664, 522074127, 138 | 146352474, 4104915256, 3029415884, 3545667983, 332038910, 139 | 976628269, 3123492423, 3041418372, 2258059298, 2139377204, 140 | 3243642973, 3226247917, 3674004636, 2698992189, 3453843574, 141 | 1963216666, 3509855005, 2358481858, 747331248, 1957348676, 142 | 1097574450, 2435697214, 3870972145, 1888833893, 2914085525, 143 | 4161315584, 1273113343, 3269644828, 3681293816, 412536684, 144 | 1156034077, 3823026442, 1066971017, 3598330293, 1979273937, 145 | 2079029895, 1195045909, 1071986421, 2712821515, 3377754595, 146 | 2184151095, 750918864, 2585729879, 4249895712, 1832579367, 147 | 1192240192, 946734366, 31230688, 3174399083, 3549375728, 148 | 1642430184, 1904857554, 861877404, 3277825584, 4267074718, 149 | 3122860549, 666423581, 644189126, 226475395, 307789415, 150 | 1196105631, 3191691839, 782852669, 1608507813, 1847685900, 151 | 4069766876, 3931548641, 2526471011, 766865139, 2115084288, 152 | 4259411376, 3323683436, 568512177, 3736601419, 1800276898, 153 | 4012458395, 1823982, 27980198, 2023839966, 869505096, 154 | 431161506, 1024804023, 1853869307, 3393537983, 1500703614, 155 | 3019471560, 1351086955, 3096933631, 3034634988, 2544598006, 156 | 1230942551, 3362230798, 159984793, 491590373, 3993872886, 157 | 3681855622, 903593547, 3535062472, 1799803217, 772984149, 158 | 895863112, 1899036275, 4187322100, 101856048, 234650315, 159 | 3183125617, 3190039692, 525584357, 1286834489, 455810374, 160 | 1869181575, 922673938, 3877430102, 3422391938, 1414347295, 161 | 1971054608, 3061798054, 830555096, 2822905141, 167033190, 162 | 1079139428, 4210126723, 3593797804, 429192890, 372093950, 163 | 1779187770, 3312189287, 204349348, 452421568, 2800540462, 164 | 3733109044, 1235082423, 1765319556, 3174729780, 3762994475, 165 | 3171962488, 442160826, 198349622, 45942637, 1324086311, 166 | 2901868599, 678860040, 3812229107, 19936821, 1119590141, 167 | 3640121682, 3545931032, 2102949142, 2828208598, 3603378023, 168 | 4135048896 169 | }; 170 | 171 | const std::array Rand::V2 = { 172 | 1629829892, 282540176, 2794583710, 496504798, 2990494426, 173 | 3070701851, 2575963183, 4094823972, 2775723650, 4079480416, 174 | 176028725, 2246241423, 3732217647, 2196843075, 1306949278, 175 | 4170992780, 4039345809, 3209664269, 3387499533, 293063229, 176 | 3660290503, 2648440860, 2531406539, 3537879412, 773374739, 177 | 4184691853, 1804207821, 3347126643, 3479377103, 3970515774, 178 | 1891731298, 2368003842, 3537588307, 2969158410, 4230745262, 179 | 831906319, 2935838131, 264029468, 120852739, 3200326460, 180 | 355445271, 2296305141, 1566296040, 1760127056, 20073893, 181 | 3427103620, 2866979760, 2359075957, 2025314291, 1725696734, 182 | 3346087406, 2690756527, 99815156, 4248519977, 2253762642, 183 | 3274144518, 598024568, 3299672435, 556579346, 4121041856, 184 | 2896948975, 3620123492, 918453629, 3249461198, 2231414958, 185 | 3803272287, 3657597946, 2588911389, 242262274, 1725007475, 186 | 2026427718, 46776484, 2873281403, 2919275846, 3177933051, 187 | 1918859160, 2517854537, 1857818511, 3234262050, 479353687, 188 | 200201308, 2801945841, 1621715769, 483977159, 423502325, 189 | 3689396064, 1850168397, 3359959416, 3459831930, 841488699, 190 | 3570506095, 930267420, 1564520841, 2505122797, 593824107, 191 | 1116572080, 819179184, 3139123629, 1414339336, 1076360795, 192 | 512403845, 177759256, 1701060666, 2239736419, 515179302, 193 | 2935012727, 3821357612, 1376520851, 2700745271, 966853647, 194 | 1041862223, 715860553, 171592961, 1607044257, 1227236688, 195 | 3647136358, 1417559141, 4087067551, 2241705880, 4194136288, 196 | 1439041934, 20464430, 119668151, 2021257232, 2551262694, 197 | 1381539058, 4082839035, 498179069, 311508499, 3580908637, 198 | 2889149671, 142719814, 1232184754, 3356662582, 2973775623, 199 | 1469897084, 1728205304, 1415793613, 50111003, 3133413359, 200 | 4074115275, 2710540611, 2700083070, 2457757663, 2612845330, 201 | 3775943755, 2469309260, 2560142753, 3020996369, 1691667711, 202 | 4219602776, 1687672168, 1017921622, 2307642321, 368711460, 203 | 3282925988, 213208029, 4150757489, 3443211944, 2846101972, 204 | 4106826684, 4272438675, 2199416468, 3710621281, 497564971, 205 | 285138276, 765042313, 916220877, 3402623607, 2768784621, 206 | 1722849097, 3386397442, 487920061, 3569027007, 3424544196, 207 | 217781973, 2356938519, 3252429414, 145109750, 2692588106, 208 | 2454747135, 1299493354, 4120241887, 2088917094, 932304329, 209 | 1442609203, 952586974, 3509186750, 753369054, 854421006, 210 | 1954046388, 2708927882, 4047539230, 3048925996, 1667505809, 211 | 805166441, 1182069088, 4265546268, 4215029527, 3374748959, 212 | 373532666, 2454243090, 2371530493, 3651087521, 2619878153, 213 | 1651809518, 1553646893, 1227452842, 703887512, 3696674163, 214 | 2552507603, 2635912901, 895130484, 3287782244, 3098973502, 215 | 990078774, 3780326506, 2290845203, 41729428, 1949580860, 216 | 2283959805, 1036946170, 1694887523, 4880696, 466000198, 217 | 2765355283, 3318686998, 1266458025, 3919578154, 3545413527, 218 | 2627009988, 3744680394, 1696890173, 3250684705, 4142417708, 219 | 915739411, 3308488877, 1289361460, 2942552331, 1169105979, 220 | 3342228712, 698560958, 1356041230, 2401944293, 107705232, 221 | 3701895363, 903928723, 3646581385, 844950914, 1944371367, 222 | 3863894844, 2946773319, 1972431613, 1706989237, 29917467, 223 | 3497665928 224 | }; 225 | 226 | const std::array Rand::V3 = { 227 | 1191369816, 744902811, 2539772235, 3213192037, 3286061266, 228 | 1200571165, 2463281260, 754888894, 714651270, 1968220972, 229 | 3628497775, 1277626456, 1493398934, 364289757, 2055487592, 230 | 3913468088, 2930259465, 902504567, 3967050355, 2056499403, 231 | 692132390, 186386657, 832834706, 859795816, 1283120926, 232 | 2253183716, 3003475205, 1755803552, 2239315142, 4271056352, 233 | 2184848469, 769228092, 1249230754, 1193269205, 2660094102, 234 | 642979613, 1687087994, 2726106182, 446402913, 4122186606, 235 | 3771347282, 37667136, 192775425, 3578702187, 1952659096, 236 | 3989584400, 3069013882, 2900516158, 4045316336, 3057163251, 237 | 1702104819, 4116613420, 3575472384, 2674023117, 1409126723, 238 | 3215095429, 1430726429, 2544497368, 1029565676, 1855801827, 239 | 4262184627, 1854326881, 2906728593, 3277836557, 2787697002, 240 | 2787333385, 3105430738, 2477073192, 748038573, 1088396515, 241 | 1611204853, 201964005, 3745818380, 3654683549, 3816120877, 242 | 3915783622, 2563198722, 1181149055, 33158084, 3723047845, 243 | 3790270906, 3832415204, 2959617497, 372900708, 1286738499, 244 | 1932439099, 3677748309, 2454711182, 2757856469, 2134027055, 245 | 2780052465, 3190347618, 3758510138, 3626329451, 1120743107, 246 | 1623585693, 1389834102, 2719230375, 3038609003, 462617590, 247 | 260254189, 3706349764, 2556762744, 2874272296, 2502399286, 248 | 4216263978, 2683431180, 2168560535, 3561507175, 668095726, 249 | 680412330, 3726693946, 4180630637, 3335170953, 942140968, 250 | 2711851085, 2059233412, 4265696278, 3204373534, 232855056, 251 | 881788313, 2258252172, 2043595984, 3758795150, 3615341325, 252 | 2138837681, 1351208537, 2923692473, 3402482785, 2105383425, 253 | 2346772751, 499245323, 3417846006, 2366116814, 2543090583, 254 | 1828551634, 3148696244, 3853884867, 1364737681, 2200687771, 255 | 2689775688, 232720625, 4071657318, 2671968983, 3531415031, 256 | 1212852141, 867923311, 3740109711, 1923146533, 3237071777, 257 | 3100729255, 3247856816, 906742566, 4047640575, 4007211572, 258 | 3495700105, 1171285262, 2835682655, 1634301229, 3115169925, 259 | 2289874706, 2252450179, 944880097, 371933491, 1649074501, 260 | 2208617414, 2524305981, 2496569844, 2667037160, 1257550794, 261 | 3399219045, 3194894295, 1643249887, 342911473, 891025733, 262 | 3146861835, 3789181526, 938847812, 1854580183, 2112653794, 263 | 2960702988, 1238603378, 2205280635, 1666784014, 2520274614, 264 | 3355493726, 2310872278, 3153920489, 2745882591, 1200203158, 265 | 3033612415, 2311650167, 1048129133, 4206710184, 4209176741, 266 | 2640950279, 2096382177, 4116899089, 3631017851, 4104488173, 267 | 1857650503, 3801102932, 445806934, 3055654640, 897898279, 268 | 3234007399, 1325494930, 2982247189, 1619020475, 2720040856, 269 | 885096170, 3485255499, 2983202469, 3891011124, 546522756, 270 | 1524439205, 2644317889, 2170076800, 2969618716, 961183518, 271 | 1081831074, 1037015347, 3289016286, 2331748669, 620887395, 272 | 303042654, 3990027945, 1562756376, 3413341792, 2059647769, 273 | 2823844432, 674595301, 2457639984, 4076754716, 2447737904, 274 | 1583323324, 625627134, 3076006391, 345777990, 1684954145, 275 | 879227329, 3436182180, 1522273219, 3802543817, 1456017040, 276 | 1897819847, 2970081129, 1382576028, 3820044861, 1044428167, 277 | 612252599, 3340478395, 2150613904, 3397625662, 3573635640, 278 | 3432275192 279 | }; 280 | 281 | #pragma clang diagnostic pop 282 | 283 | } // namespace Impl 284 | } // namespace RaptorQ 285 | -------------------------------------------------------------------------------- /src/RaptorQ/Rand.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | /* RFC, section 5.5: Random Numbers 22 | * 23 | * The four arrays V0, V1, V2, and V3 used in Section 5.3.5.1 are 24 | * provided below. There are 256 entries in each of the four arrays. 25 | * The indexing into each array starts at 0, and the entries are 32-bit 26 | * unsigned integers. 27 | */ 28 | 29 | #ifndef RAPTORQ_RAND_H 30 | #define RAPTORQ_RAND_H 31 | 32 | #include 33 | #include "common.hpp" 34 | 35 | namespace RaptorQ { 36 | namespace Impl { 37 | 38 | class RAPTORQ_LOCAL Rand { 39 | public: 40 | Rand() {} 41 | Rand (const Rand&) = delete; // Don't Implement 42 | Rand& operator= (const Rand&) = delete;// Don't implement 43 | Rand (Rand &&) = delete; // Don't Implement 44 | Rand& operator= (Rand &&) = delete;// Don't implement 45 | 46 | static uint32_t get (const uint32_t y, const uint8_t i, const uint32_t m); 47 | private: 48 | static const std::array V0, V1, V2, V3; 49 | }; 50 | 51 | } // namespace Impl 52 | } // namespace RaptorQ 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/RaptorQ/cRaptorQ.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_C_H 22 | #define RAPTORQ_C_H 23 | 24 | #include "common.hpp" 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" 31 | { 32 | #endif 33 | typedef uint64_t RaptorQ_OTI_Common_Data; 34 | typedef uint32_t RaptorQ_OTI_Scheme_Specific_Data; 35 | 36 | typedef enum { NONE = 0, ENC_8 = 1, ENC_16 = 2, ENC_32 = 3, ENC_64 = 4, 37 | DEC_8 = 5, DEC_16 = 6, DEC_32 = 7, DEC_64 = 8} 38 | RaptorQ_type; 39 | 40 | struct RAPTORQ_LOCAL RaptorQ_ptr; 41 | 42 | RAPTORQ_API struct RaptorQ_ptr* RaptorQ_Enc (const RaptorQ_type type, 43 | void *data, 44 | const uint64_t size, 45 | const uint16_t min_subsymbol_size, 46 | const uint16_t symbol_size, 47 | const size_t max_memory); 48 | RAPTORQ_API struct RaptorQ_ptr* RaptorQ_Dec (const RaptorQ_type type, 49 | const RaptorQ_OTI_Common_Data common, 50 | const RaptorQ_OTI_Scheme_Specific_Data scheme); 51 | 52 | /////////// 53 | // Encoding 54 | /////////// 55 | 56 | RaptorQ_OTI_Common_Data RAPTORQ_API RaptorQ_OTI_Common ( 57 | struct RaptorQ_ptr *enc); 58 | RaptorQ_OTI_Scheme_Specific_Data RAPTORQ_API RaptorQ_OTI_Scheme ( 59 | struct RaptorQ_ptr *enc); 60 | 61 | uint16_t RAPTORQ_API RaptorQ_symbol_size (struct RaptorQ_ptr *ptr); 62 | uint8_t RAPTORQ_API RaptorQ_blocks (struct RaptorQ_ptr *ptr); 63 | uint32_t RAPTORQ_API RaptorQ_block_size (struct RaptorQ_ptr *ptr, 64 | const uint8_t sbn); 65 | uint16_t RAPTORQ_API RaptorQ_symbols (struct RaptorQ_ptr *ptr, 66 | const uint8_t sbn); 67 | uint32_t RAPTORQ_API RaptorQ_max_repair (struct RaptorQ_ptr *enc, 68 | const uint8_t sbn); 69 | size_t RAPTORQ_API RaptorQ_precompute_max_memory (struct RaptorQ_ptr *enc); 70 | 71 | void RAPTORQ_API RaptorQ_precompute (struct RaptorQ_ptr *enc, 72 | const uint8_t threads, 73 | const bool background); 74 | 75 | uint64_t RAPTORQ_API RaptorQ_encode_id (struct RaptorQ_ptr *enc, 76 | void **data, 77 | const uint64_t size, 78 | const uint32_t id); 79 | uint64_t RAPTORQ_API RaptorQ_encode (struct RaptorQ_ptr *enc, void **data, 80 | const uint64_t size, 81 | const uint32_t esi, 82 | const uint8_t sbn); 83 | uint32_t RAPTORQ_API RaptorQ_id (const uint32_t esi, const uint8_t sbn); 84 | 85 | 86 | /////////// 87 | // Decoding 88 | /////////// 89 | 90 | uint64_t RAPTORQ_API RaptorQ_bytes (struct RaptorQ_ptr *dec); 91 | 92 | uint64_t RAPTORQ_API RaptorQ_decode (struct RaptorQ_ptr *dec, void **data, 93 | const size_t size); 94 | uint64_t RAPTORQ_API RaptorQ_decode_block (struct RaptorQ_ptr *dec, 95 | void **data, 96 | const size_t size, 97 | const uint8_t sbn); 98 | 99 | bool RAPTORQ_API RaptorQ_add_symbol_id (struct RaptorQ_ptr *dec,void **data, 100 | const uint32_t size, 101 | const uint32_t id); 102 | bool RAPTORQ_API RaptorQ_add_symbol (struct RaptorQ_ptr *dec, void **data, 103 | const uint32_t size, 104 | const uint32_t esi, 105 | const uint8_t sbn); 106 | 107 | /////////////////////// 108 | // General: free memory 109 | /////////////////////// 110 | 111 | void RAPTORQ_API RaptorQ_free (struct RaptorQ_ptr **ptr); 112 | void RAPTORQ_API RaptorQ_free_block (struct RaptorQ_ptr *ptr, 113 | const uint8_t sbn); 114 | 115 | #ifdef __cplusplus 116 | } // extern "C" 117 | #endif 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/RaptorQ/common.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_H 22 | #define RAPTORQ_H 23 | 24 | 25 | // These macros were taken from http://gcc.gnu.org/wiki/Visibility 26 | // Generic helper definitions for shared library support 27 | 28 | #if defined _WIN32 || defined __CYGWIN__ 29 | #define RAPTORQ_HELPER_DLL_IMPORT __declspec (dllimport) 30 | #define RAPTORQ_HELPER_DLL_EXPORT __declspec (dllexport) 31 | #define RAPTORQ_HELPER_DLL_LOCAL 32 | #else 33 | #if __GNUC__ >= 4 34 | #define RAPTORQ_HELPER_DLL_IMPORT __attribute__ ((visibility ("default"))) 35 | #define RAPTORQ_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) 36 | #define RAPTORQ_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) 37 | #else 38 | #define RAPTORQ_HELPER_DLL_IMPORT 39 | #define RAPTORQ_HELPER_DLL_EXPORT 40 | #define RAPTORQ_HELPER_DLL_LOCAL 41 | #endif 42 | #endif 43 | 44 | // Now we use the generic helper definitions above to define RAPTORQ_API 45 | // and RAPTORQ_LOCAL. 46 | // RAPTORQ_API is used for the public API symbols. 47 | // It either DLL imports or DLL exports (or does nothing for static build) 48 | // RAPTORQ_LOCAL is used for non-api symbols. 49 | 50 | #ifdef RAPTORQ_DLL // defined if RAPTORQ is compiled as a DLL 51 | #ifdef RAPTORQ_DLL_EXPORTS // if we are building the RAPTORQ DLL (not using it) 52 | #define RAPTORQ_API RAPTORQ_HELPER_DLL_EXPORT 53 | #else 54 | #define RAPTORQ_API RAPTORQ_HELPER_DLL_IMPORT 55 | #endif // RAPTORQ_DLL_EXPORTS 56 | #define RAPTORQ_LOCAL RAPTORQ_HELPER_DLL_LOCAL 57 | #else // RAPTORQ_DLL is not defined: this means RAPTORQ is a static lib. 58 | #define RAPTORQ_API 59 | #define RAPTORQ_LOCAL 60 | #endif // RAPTORQ_DLL 61 | 62 | 63 | #ifdef __cplusplus 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | #define UNUSED(x) ((void)x) 70 | 71 | #define IS_RANDOM(IT, CLASS) \ 72 | static_assert ( \ 73 | std::is_same::iterator_category, \ 74 | std::random_access_iterator_tag>::value, \ 75 | CLASS " is supposed to get a RANDOM ACCESS iterator\n"); 76 | #define IS_INPUT(IT, CLASS) \ 77 | static_assert ( \ 78 | std::is_same::iterator_category, \ 79 | std::input_iterator_tag>::value || \ 80 | std::is_same::iterator_category, \ 81 | std::forward_iterator_tag>::value || \ 82 | std::is_same::iterator_category, \ 83 | std::bidirectional_iterator_tag>::value || \ 84 | std::is_same::iterator_category, \ 85 | std::random_access_iterator_tag>::value, \ 86 | CLASS " is supposed to get an INPUT iterator\n"); 87 | #define IS_FORWARD(IT, CLASS) \ 88 | static_assert ( \ 89 | std::is_same::iterator_category, \ 90 | std::forward_iterator_tag>::value || \ 91 | std::is_same::iterator_category, \ 92 | std::bidirectional_iterator_tag>::value || \ 93 | std::is_same::iterator_category, \ 94 | std::random_access_iterator_tag>::value, \ 95 | CLASS " is supposed to get a FORWARD iterator\n"); 96 | #endif 97 | 98 | #endif 99 | 100 | -------------------------------------------------------------------------------- /src/RaptorQ/degree.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_DEGREE_HPP 22 | #define RAPTORQ_DEGREE_HPP 23 | 24 | #include 25 | 26 | namespace RaptorQ { 27 | namespace Impl { 28 | 29 | #pragma clang diagnostic push 30 | #pragma clang diagnostic ignored "-Wmissing-braces" 31 | #pragma clang diagnostic ignored "-Wglobal-constructors" 32 | #pragma clang diagnostic ignored "-Wexit-time-destructors" 33 | 34 | static const std::array degree_distribution = { 35 | 0, 5243, 529531, 704294, 791675, 844104, 36 | 879057, 904023, 922747, 937311, 948962, 958494, 37 | 966438, 973160, 978921, 983914, 988283, 992138, 38 | 995565, 998631, 1001391, 1003887, 1006157, 1008229, 39 | 1010129, 1011876, 1013490, 1014983, 1016370, 1017662, 40 | 1048576}; 41 | 42 | #pragma clang diagnostic pop 43 | 44 | } // namespace Impl 45 | } // namespace RaptorQ 46 | 47 | #endif 48 | 49 | -------------------------------------------------------------------------------- /src/RaptorQ/deterministic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | // 26 | // We work on the "ar" format. refer to 27 | // http://en.wikipedia.org/wiki/Ar_%28Unix%29 28 | // for more details. 29 | // we ned to delete the timestamps and uids/gids in the archive. 30 | // 31 | 32 | uint64_t erase (const uint64_t offset, std::fstream &lib); 33 | uint64_t erase (const uint64_t offset, std::fstream &lib) 34 | { 35 | // ar header format: 36 | // offset, length, description 37 | // 0 16 File name, ASCII 38 | // 16 12 File modification timestamp, Decimal 39 | // 28 6 Owner ID, Decimal 40 | // 34 6 Group ID, Decimal 41 | // 40 8 File mode, Octal 42 | // 48 10 File size in bytes, Decimal 43 | // 58 2 File magic, 0x60 0x0A 44 | 45 | // we will use this a lot. this are right-padded. 46 | const char zero = 0x30; 47 | const char pad = 0x20; 48 | 49 | // first of all, archive creation timestamp goes to zero 50 | lib.seekp (static_cast (offset + 16)); 51 | lib.put (zero); 52 | for (size_t i = 0; i < 11; ++i) 53 | lib.put (pad); 54 | 55 | // now the uid: 56 | lib.seekp (static_cast (offset + 28)); 57 | lib.put (zero); 58 | for (size_t i = 0; i < 5; ++i) 59 | lib.put (pad); 60 | // and gid 61 | lib.seekp (static_cast (offset + 34)); 62 | lib.put (zero); 63 | for (size_t i = 0; i < 5; ++i) 64 | lib.put (pad); 65 | 66 | // return the size: 67 | lib.seekg (static_cast (offset + 48)); 68 | char size[10]; 69 | lib.read (size, 10); 70 | //for (int i = 9; i >= 0; --i) { 71 | for (int i = 9; i >= 0; --i) { 72 | if (size[i] == pad) 73 | size[i] = '\0'; 74 | } 75 | uint64_t ret = static_cast (std::atol (size)); 76 | if (ret % 2 != 0) 77 | ++ret; // everything is aligned to uint16_t, but file size is the 78 | // actual file size. 79 | ret += 60; // add header size 80 | return ret; 81 | } 82 | 83 | int main (const int argc, const char **argv) 84 | { 85 | if (argc != 2) { 86 | std::cout << "Usage: " << argv[0] << " static_library.a\n"; 87 | return 1; 88 | } 89 | 90 | std::string filename (argv[1]); 91 | std::fstream lib; 92 | 93 | lib.open (filename); 94 | if (!lib.is_open()) { 95 | std::cout << "Can not open the library\n"; 96 | std::cout << "Usage: " << argv[0] << " static_library.a\n"; 97 | return 1; 98 | } 99 | 100 | // check the magic number for the file: 101 | std::string magic (8, '\0'); 102 | lib.read (&magic[0], 8); 103 | if (magic.compare("!\n") != 0) { 104 | std::cout << "This is not a static library. Can't do anything here.\n"; 105 | return 1; 106 | } 107 | 108 | // get file size 109 | lib.seekg (0, std::ios_base::end); 110 | uint64_t file_size = static_cast (lib.tellg()); 111 | 112 | // we have a static library. now start deleting the timestamps and uid/gid. 113 | uint64_t offset = 8; 114 | while (offset < file_size) 115 | offset += erase (offset, lib); 116 | 117 | 118 | 119 | lib.close(); 120 | std::cout << "Static library archive is deterministic now.\n"; 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /src/RaptorQ/multiplication.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of "libRaptorQ".namespace <#name#>=<#namespace#> * 3 | * libRaptorQ is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU Lesser General Public License as 5 | * published by the Free Software Foundation, either version 3 6 | * of the License, or (at your option) any later version.namespace <#name#>=<#namespace#> * 7 | * libRaptorQ is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details.namespace <#name#>=<#namespace#> * 11 | * You should have received a copy of the GNU General Public License 12 | * and a copy of the GNU Lesser General Public License 13 | * along with libRaptorQ. If not, see . 14 | */ 15 | 16 | #ifndef RAPTORQ_MULTIPLICATION_HPP 17 | #define RAPTORQ_MULTIPLICATION_HPP 18 | 19 | #include 20 | #include 21 | 22 | namespace RaptorQ { 23 | namespace Impl { 24 | 25 | #pragma clang diagnostic push 26 | #pragma clang diagnostic ignored "-Wmissing-braces" 27 | #pragma clang diagnostic ignored "-Wglobal-constructors" 28 | #pragma clang diagnostic ignored "-Wexit-time-destructors" 29 | 30 | static const std::array oct_exp = { 31 | 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 32 | 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 33 | 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 34 | 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 35 | 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 36 | 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 37 | 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 38 | 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 39 | 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 40 | 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 41 | 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 42 | 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 43 | 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 44 | 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 45 | 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 46 | 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 47 | 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 48 | 142, 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 49 | 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 50 | 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 51 | 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 52 | 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 53 | 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 54 | 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 55 | 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 56 | 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 57 | 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 58 | 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 59 | 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 60 | 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 61 | 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 62 | 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 63 | 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 64 | 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 65 | 142}; 66 | 67 | static const std::array oct_log = { 68 | 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 69 | 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 70 | 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 71 | 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 72 | 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 73 | 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 74 | 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 75 | 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 76 | 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 77 | 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 78 | 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 79 | 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 80 | 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 81 | 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 82 | 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 83 | 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 84 | 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 85 | 88, 175}; 86 | 87 | #pragma clang diagnostic pop 88 | 89 | } // namespace Impl 90 | } // namespace RaptorQ 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /src/RaptorQ/table2.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, Luca Fulchir, All rights reserved. 3 | * 4 | * This file is part of "libRaptorQ". 5 | * 6 | * libRaptorQ is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 3 9 | * of the License, or (at your option) any later version. 10 | * 11 | * libRaptorQ is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * and a copy of the GNU Lesser General Public License 18 | * along with libRaptorQ. If not, see . 19 | */ 20 | 21 | #ifndef RAPTORQ_TABLE2_HPP 22 | #define RAPTORQ_TABLE2_HPP 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace RaptorQ { 29 | namespace Impl { 30 | 31 | #ifdef USING_CLANG 32 | #pragma clang diagnostic push 33 | #pragma clang diagnostic ignored "-Wmissing-braces" 34 | #pragma clang diagnostic ignored "-Wglobal-constructors" 35 | #pragma clang diagnostic ignored "-Wexit-time-destructors" 36 | #endif //using_clang 37 | 38 | // I know, I know. Not exactly 80 colums. You format this, it's just the 39 | // 3 tables from RFC6330, pages 41-62 40 | 41 | static const std::array K_padded = {10, 12, 18, 20, 26, 30, 32, 36, 42, 46, 48, 49, 55, 60, 62, 69, 75, 84, 88, 91, 95, 97, 101, 114, 119, 125, 127, 138, 140, 149, 153, 160, 166, 168, 179, 181, 185, 187, 200, 213, 217, 225, 236, 242, 248, 257, 263, 269, 280, 295, 301, 305, 324, 337, 341, 347, 355, 362, 368, 372, 380, 385, 393, 405, 418, 428, 434, 447, 453, 466, 478, 486, 491, 497, 511, 526, 532, 542, 549, 557, 563, 573, 580, 588, 594, 600, 606, 619, 633, 640, 648, 666, 675, 685, 693, 703, 718, 728, 736, 747, 759, 778, 792, 802, 811, 821, 835, 845, 860, 870, 891, 903, 913, 926, 938, 950, 963, 977, 989, 1002, 1020, 1032, 1050, 1074, 1085, 1099, 1111, 1136, 1152, 1169, 1183, 1205, 1220, 1236, 1255, 1269, 1285, 1306, 1347, 1361, 1389, 1404, 1420, 1436, 1461, 1477, 1502, 1522, 1539, 1561, 1579, 1600, 1616, 1649, 1673, 1698, 1716, 1734, 1759, 1777, 1800, 1824, 1844, 1863, 1887, 1906, 1926, 1954, 1979, 2005, 2040, 2070, 2103, 2125, 2152, 2195, 2217, 2247, 2278, 2315, 2339, 2367, 2392, 2416, 2447, 2473, 2502, 2528, 2565, 2601, 2640, 2668, 2701, 2737, 2772, 2802, 2831, 2875, 2906, 2938, 2979, 3015, 3056, 3101, 3151, 3186, 3224, 3265, 3299, 3344, 3387, 3423, 3466, 3502, 3539, 3579, 3616, 3658, 3697, 3751, 3792, 3840, 3883, 3924, 3970, 4015, 4069, 4112, 4165, 4207, 4252, 4318, 4365, 4418, 4468, 4513, 4567, 4626, 4681, 4731, 4780, 4838, 4901, 4954, 5008, 5063, 5116, 5172, 5225, 5279, 5334, 5391, 5449, 5506, 5566, 5637, 5694, 5763, 5823, 5896, 5975, 6039, 6102, 6169, 6233, 6296, 6363, 6427, 6518, 6589, 6655, 6730, 6799, 6878, 6956, 7033, 7108, 7185, 7281, 7360, 7445, 7520, 7596, 7675, 7770, 7855, 7935, 8030, 8111, 8194, 8290, 8377, 8474, 8559, 8654, 8744, 8837, 8928, 9019, 9111, 9206, 9303, 9400, 9497, 9601, 9708, 9813, 9916, 10017, 10120, 10241, 10351, 10458, 10567, 10676, 10787, 10899, 11015, 11130, 11245, 11358, 11475, 11590, 11711, 11829, 11956, 12087, 12208, 12333, 12460, 12593, 12726, 12857, 13002, 13143, 13284, 13417, 13558, 13695, 13833, 13974, 14115, 14272, 14415, 14560, 14713, 14862, 15011, 15170, 15325, 15496, 15651, 15808, 15977, 16161, 16336, 16505, 16674, 16851, 17024, 17195, 17376, 17559, 17742, 17929, 18116, 18309, 18503, 18694, 18909, 19126, 19325, 19539, 19740, 19939, 20152, 20355, 20564, 20778, 20988, 21199, 21412, 21629, 21852, 22073, 22301, 22536, 22779, 23010, 23252, 23491, 23730, 23971, 24215, 24476, 24721, 24976, 25230, 25493, 25756, 26022, 26291, 26566, 26838, 27111, 27392, 27682, 27959, 28248, 28548, 28845, 29138, 29434, 29731, 30037, 30346, 30654, 30974, 31285, 31605, 31948, 32272, 32601, 32932, 33282, 33623, 33961, 34302, 34654, 35031, 35395, 35750, 36112, 36479, 36849, 37227, 37606, 37992, 38385, 38787, 39176, 39576, 39980, 40398, 40816, 41226, 41641, 42067, 42490, 42916, 43388, 43840, 44279, 44729, 45183, 45638, 46104, 46574, 47047, 47523, 48007, 48489, 48976, 49470, 49978, 50511, 51017, 51530, 52062, 52586, 53114, 53650, 54188, 54735, 55289, 55843, 56403}; 42 | 43 | static const uint16_t K_max = K_padded[476]; 44 | 45 | static const std::array J_K_padded = {254,630,682,293,80,566,860,267,822,506,589,87,520,159,235,157,502,334,583,66,352,365,562,5,603,721,28,660,829,900,930,814,661,693,780,605,551,777,491,396,764,843,646,557,608,265,505,722,263,999,874,160,575,210,513,503,558,932,404,520,846,485,728,554,471,641,732,193,934,864,790,912,617,587,800,923,998,92,497,559,667,912,262,152,526,268,212,45,898,527,558,460,5,895,996,282,513,865,870,239,452,862,852,643,543,447,321,287,12,251,30,621,555,127,400,91,916,935,691,299,282,824,536,596,28,947,162,536,1000,251,673,559,923,81,478,198,137,75,29,231,532,58,60,964,624,502,636,986,950,735,866,203,83,14,522,226,282,88,636,860,324,424,999,682,814,979,538,278,580,773,911,506,628,282,309,858,442,654,82,428,442,283,538,189,438,912,1,167,272,209,927,386,653,669,431,793,588,777,939,864,627,265,976,988,507,640,15,667,24,877,240,720,93,919,635,174,647,820,56,485,210,124,546,954,262,927,957,726,583,782,37,758,777,104,476,113,313,102,501,332,786,99,658,794,37,471,94,873,918,945,211,341,11,578,494,694,252,451,83,689,488,214,17,469,263,309,984,123,360,863,122,522,539,181,64,387,967,843,999,76,142,599,576,176,392,332,291,913,608,212,696,931,326,228,706,144,83,743,187,654,359,493,369,981,276,647,389,80,396,580,873,15,976,584,267,876,642,794,78,736,882,251,434,204,256,106,375,148,496,88,826,71,925,760,130,641,400,480,76,665,910,467,964,625,362,759,728,343,113,137,308,800,177,961,958,72,732,145,577,305,50,351,175,727,902,409,776,586,451,287,246,222,563,839,897,409,618,439,95,448,133,938,423,90,640,922,250,367,447,559,121,623,450,253,106,863,148,427,138,794,247,562,53,135,21,201,169,70,386,226,3,769,590,672,713,967,368,348,119,503,181,394,189,210,62,273,554,936,483,397,241,500,12,958,524,8,100,339,804,510,18,412,394,830,535,199,27,298,368,755,379,73,387,457,761,855,370,261,299,920,269,862,349,103,115,93,982,432,340,173,421,330,624,233,362,963,471}; 46 | 47 | static const std::array, 477> S_H_W = {std::make_tuple(7, 10, 17), std::make_tuple(7, 10, 19), std::make_tuple(11, 10, 29), std::make_tuple(11, 10, 31), std::make_tuple(11, 10, 37), std::make_tuple(11, 10, 41), std::make_tuple(11, 10, 43), std::make_tuple(11, 10, 47), std::make_tuple(11, 10, 53), std::make_tuple(13, 10, 59), std::make_tuple(13, 10, 61), std::make_tuple(13, 10, 61), std::make_tuple(13, 10, 67), std::make_tuple(13, 10, 71), std::make_tuple(13, 10, 73), std::make_tuple(13, 10, 79), std::make_tuple(17, 10, 89), std::make_tuple(17, 10, 97), std::make_tuple(17, 10, 101), std::make_tuple(17, 10, 103), std::make_tuple(17, 10, 107), std::make_tuple(17, 10, 109), std::make_tuple(17, 10, 113), std::make_tuple(19, 10, 127), std::make_tuple(19, 10, 131), std::make_tuple(19, 10, 137), std::make_tuple(19, 10, 139), std::make_tuple(19, 10, 149), std::make_tuple(19, 10, 151), std::make_tuple(23, 10, 163), std::make_tuple(23, 10, 167), std::make_tuple(23, 10, 173), std::make_tuple(23, 10, 179), std::make_tuple(23, 10, 181), std::make_tuple(23, 10, 191), std::make_tuple(23, 10, 193), std::make_tuple(23, 10, 197), std::make_tuple(23, 10, 199), std::make_tuple(23, 10, 211), std::make_tuple(23, 10, 223), std::make_tuple(29, 10, 233), std::make_tuple(29, 10, 241), std::make_tuple(29, 10, 251), std::make_tuple(29, 10, 257), std::make_tuple(29, 10, 263), std::make_tuple(29, 10, 271), std::make_tuple(29, 10, 277), std::make_tuple(29, 10, 283), std::make_tuple(29, 10, 293), std::make_tuple(29, 10, 307), std::make_tuple(29, 10, 313), std::make_tuple(29, 10, 317), std::make_tuple(31, 10, 337), std::make_tuple(31, 10, 349), std::make_tuple(31, 10, 353), std::make_tuple(31, 10, 359), std::make_tuple(31, 10, 367), std::make_tuple(31, 10, 373), std::make_tuple(31, 10, 379), std::make_tuple(37, 10, 389), std::make_tuple(37, 10, 397), std::make_tuple(37, 10, 401), std::make_tuple(37, 10, 409), std::make_tuple(37, 10, 421), std::make_tuple(37, 10, 433), std::make_tuple(37, 10, 443), std::make_tuple(37, 10, 449), std::make_tuple(37, 10, 461), std::make_tuple(37, 10, 467), std::make_tuple(37, 10, 479), std::make_tuple(37, 10, 491), std::make_tuple(37, 10, 499), std::make_tuple(37, 10, 503), std::make_tuple(37, 10, 509), std::make_tuple(37, 10, 523), std::make_tuple(41, 10, 541), std::make_tuple(41, 10, 547), std::make_tuple(41, 10, 557), std::make_tuple(41, 10, 563), std::make_tuple(41, 10, 571), std::make_tuple(41, 10, 577), std::make_tuple(41, 10, 587), std::make_tuple(41, 10, 593), std::make_tuple(41, 10, 601), std::make_tuple(41, 10, 607), std::make_tuple(41, 10, 613), std::make_tuple(41, 10, 619), std::make_tuple(41, 10, 631), std::make_tuple(43, 10, 647), std::make_tuple(43, 10, 653), std::make_tuple(43, 10, 661), std::make_tuple(47, 10, 683), std::make_tuple(47, 10, 691), std::make_tuple(47, 10, 701), std::make_tuple(47, 10, 709), std::make_tuple(47, 10, 719), std::make_tuple(47, 10, 733), std::make_tuple(47, 10, 743), std::make_tuple(47, 10, 751), std::make_tuple(47, 10, 761), std::make_tuple(47, 10, 773), std::make_tuple(53, 10, 797), std::make_tuple(53, 10, 811), std::make_tuple(53, 10, 821), std::make_tuple(53, 10, 829), std::make_tuple(53, 10, 839), std::make_tuple(53, 10, 853), std::make_tuple(53, 10, 863), std::make_tuple(53, 10, 877), std::make_tuple(53, 10, 887), std::make_tuple(53, 10, 907), std::make_tuple(53, 10, 919), std::make_tuple(53, 10, 929), std::make_tuple(53, 10, 941), std::make_tuple(53, 10, 953), std::make_tuple(59, 10, 971), std::make_tuple(59, 10, 983), std::make_tuple(59, 10, 997), std::make_tuple(59, 10, 1009), std::make_tuple(59, 10, 1021), std::make_tuple(59, 10, 1039), std::make_tuple(59, 10, 1051), std::make_tuple(59, 11, 1069), std::make_tuple(59, 11, 1093), std::make_tuple(59, 11, 1103), std::make_tuple(59, 11, 1117), std::make_tuple(59, 11, 1129), std::make_tuple(59, 11, 1153), std::make_tuple(61, 11, 1171), std::make_tuple(61, 11, 1187), std::make_tuple(61, 11, 1201), std::make_tuple(61, 11, 1223), std::make_tuple(61, 11, 1237), std::make_tuple(67, 11, 1259), std::make_tuple(67, 11, 1277), std::make_tuple(67, 11, 1291), std::make_tuple(67, 11, 1307), std::make_tuple(67, 11, 1327), std::make_tuple(67, 11, 1367), std::make_tuple(67, 11, 1381), std::make_tuple(67, 11, 1409), std::make_tuple(67, 11, 1423), std::make_tuple(67, 11, 1439), std::make_tuple(71, 11, 1459), std::make_tuple(71, 11, 1483), std::make_tuple(71, 11, 1499), std::make_tuple(71, 11, 1523), std::make_tuple(71, 11, 1543), std::make_tuple(71, 11, 1559), std::make_tuple(73, 11, 1583), std::make_tuple(73, 11, 1601), std::make_tuple(73, 11, 1621), std::make_tuple(73, 11, 1637), std::make_tuple(73, 11, 1669), std::make_tuple(79, 11, 1699), std::make_tuple(79, 11, 1723), std::make_tuple(79, 11, 1741), std::make_tuple(79, 11, 1759), std::make_tuple(79, 11, 1783), std::make_tuple(79, 11, 1801), std::make_tuple(79, 11, 1823), std::make_tuple(79, 11, 1847), std::make_tuple(79, 11, 1867), std::make_tuple(83, 11, 1889), std::make_tuple(83, 11, 1913), std::make_tuple(83, 11, 1931), std::make_tuple(83, 11, 1951), std::make_tuple(83, 11, 1979), std::make_tuple(83, 11, 2003), std::make_tuple(83, 11, 2029), std::make_tuple(89, 11, 2069), std::make_tuple(89, 11, 2099), std::make_tuple(89, 11, 2131), std::make_tuple(89, 11, 2153), std::make_tuple(89, 11, 2179), std::make_tuple(89, 11, 2221), std::make_tuple(89, 11, 2243), std::make_tuple(89, 11, 2273), std::make_tuple(97, 11, 2311), std::make_tuple(97, 11, 2347), std::make_tuple(97, 11, 2371), std::make_tuple(97, 11, 2399), std::make_tuple(97, 11, 2423), std::make_tuple(97, 11, 2447), std::make_tuple(97, 11, 2477), std::make_tuple(97, 11, 2503), std::make_tuple(97, 11, 2531), std::make_tuple(97, 11, 2557), std::make_tuple(97, 11, 2593), std::make_tuple(101, 11, 2633), std::make_tuple(101, 11, 2671), std::make_tuple(101, 11, 2699), std::make_tuple(101, 11, 2731), std::make_tuple(101, 11, 2767), std::make_tuple(101, 11, 2801), std::make_tuple(103, 11, 2833), std::make_tuple(103, 11, 2861), std::make_tuple(107, 11, 2909), std::make_tuple(107, 11, 2939), std::make_tuple(107, 11, 2971), std::make_tuple(107, 11, 3011), std::make_tuple(109, 11, 3049), std::make_tuple(109, 11, 3089), std::make_tuple(113, 11, 3137), std::make_tuple(113, 11, 3187), std::make_tuple(113, 11, 3221), std::make_tuple(113, 11, 3259), std::make_tuple(113, 11, 3299), std::make_tuple(127, 11, 3347), std::make_tuple(127, 11, 3391), std::make_tuple(127, 11, 3433), std::make_tuple(127, 11, 3469), std::make_tuple(127, 11, 3511), std::make_tuple(127, 11, 3547), std::make_tuple(127, 11, 3583), std::make_tuple(127, 11, 3623), std::make_tuple(127, 11, 3659), std::make_tuple(127, 11, 3701), std::make_tuple(127, 11, 3739), std::make_tuple(127, 11, 3793), std::make_tuple(127, 11, 3833), std::make_tuple(127, 11, 3881), std::make_tuple(127, 11, 3923), std::make_tuple(131, 11, 3967), std::make_tuple(131, 11, 4013), std::make_tuple(131, 11, 4057), std::make_tuple(131, 11, 4111), std::make_tuple(137, 11, 4159), std::make_tuple(137, 11, 4211), std::make_tuple(137, 11, 4253), std::make_tuple(137, 11, 4297), std::make_tuple(137, 11, 4363), std::make_tuple(137, 11, 4409), std::make_tuple(139, 11, 4463), std::make_tuple(139, 11, 4513), std::make_tuple(149, 11, 4567), std::make_tuple(149, 11, 4621), std::make_tuple(149, 11, 4679), std::make_tuple(149, 11, 4733), std::make_tuple(149, 11, 4783), std::make_tuple(149, 11, 4831), std::make_tuple(149, 11, 4889), std::make_tuple(149, 11, 4951), std::make_tuple(149, 11, 5003), std::make_tuple(151, 11, 5059), std::make_tuple(151, 11, 5113), std::make_tuple(157, 11, 5171), std::make_tuple(157, 11, 5227), std::make_tuple(157, 11, 5279), std::make_tuple(157, 11, 5333), std::make_tuple(157, 11, 5387), std::make_tuple(157, 11, 5443), std::make_tuple(163, 11, 5507), std::make_tuple(163, 11, 5563), std::make_tuple(163, 11, 5623), std::make_tuple(163, 11, 5693), std::make_tuple(163, 11, 5749), std::make_tuple(167, 11, 5821), std::make_tuple(167, 11, 5881), std::make_tuple(167, 11, 5953), std::make_tuple(173, 11, 6037), std::make_tuple(173, 11, 6101), std::make_tuple(173, 11, 6163), std::make_tuple(173, 11, 6229), std::make_tuple(179, 11, 6299), std::make_tuple(179, 11, 6361), std::make_tuple(179, 11, 6427), std::make_tuple(179, 11, 6491), std::make_tuple(179, 11, 6581), std::make_tuple(181, 11, 6653), std::make_tuple(181, 11, 6719), std::make_tuple(191, 11, 6803), std::make_tuple(191, 11, 6871), std::make_tuple(191, 11, 6949), std::make_tuple(191, 11, 7027), std::make_tuple(191, 11, 7103), std::make_tuple(191, 11, 7177), std::make_tuple(191, 11, 7253), std::make_tuple(193, 11, 7351), std::make_tuple(197, 11, 7433), std::make_tuple(197, 11, 7517), std::make_tuple(197, 11, 7591), std::make_tuple(199, 11, 7669), std::make_tuple(211, 11, 7759), std::make_tuple(211, 11, 7853), std::make_tuple(211, 11, 7937), std::make_tuple(211, 11, 8017), std::make_tuple(211, 11, 8111), std::make_tuple(211, 11, 8191), std::make_tuple(211, 11, 8273), std::make_tuple(211, 11, 8369), std::make_tuple(223, 11, 8467), std::make_tuple(223, 11, 8563), std::make_tuple(223, 11, 8647), std::make_tuple(223, 11, 8741), std::make_tuple(223, 11, 8831), std::make_tuple(223, 11, 8923), std::make_tuple(223, 11, 9013), std::make_tuple(223, 11, 9103), std::make_tuple(227, 11, 9199), std::make_tuple(227, 11, 9293), std::make_tuple(229, 11, 9391), std::make_tuple(233, 11, 9491), std::make_tuple(233, 11, 9587), std::make_tuple(239, 11, 9697), std::make_tuple(239, 11, 9803), std::make_tuple(239, 11, 9907), std::make_tuple(239, 11, 10009), std::make_tuple(241, 11, 10111), std::make_tuple(251, 11, 10223), std::make_tuple(251, 11, 10343), std::make_tuple(251, 11, 10453), std::make_tuple(251, 11, 10559), std::make_tuple(251, 11, 10667), std::make_tuple(257, 11, 10781), std::make_tuple(257, 11, 10891), std::make_tuple(257, 12, 11003), std::make_tuple(257, 12, 11119), std::make_tuple(263, 12, 11239), std::make_tuple(263, 12, 11353), std::make_tuple(269, 12, 11471), std::make_tuple(269, 12, 11587), std::make_tuple(269, 12, 11701), std::make_tuple(269, 12, 11821), std::make_tuple(271, 12, 11941), std::make_tuple(277, 12, 12073), std::make_tuple(277, 12, 12203), std::make_tuple(277, 12, 12323), std::make_tuple(281, 12, 12451), std::make_tuple(281, 12, 12577), std::make_tuple(293, 12, 12721), std::make_tuple(293, 12, 12853), std::make_tuple(293, 12, 12983), std::make_tuple(293, 12, 13127), std::make_tuple(293, 12, 13267), std::make_tuple(307, 12, 13421), std::make_tuple(307, 12, 13553), std::make_tuple(307, 12, 13693), std::make_tuple(307, 12, 13829), std::make_tuple(307, 12, 13967), std::make_tuple(307, 12, 14107), std::make_tuple(311, 12, 14251), std::make_tuple(311, 12, 14407), std::make_tuple(313, 12, 14551), std::make_tuple(317, 12, 14699), std::make_tuple(317, 12, 14851), std::make_tuple(331, 12, 15013), std::make_tuple(331, 12, 15161), std::make_tuple(331, 12, 15319), std::make_tuple(331, 12, 15473), std::make_tuple(331, 12, 15643), std::make_tuple(337, 12, 15803), std::make_tuple(337, 12, 15959), std::make_tuple(337, 12, 16127), std::make_tuple(347, 12, 16319), std::make_tuple(347, 12, 16493), std::make_tuple(347, 12, 16661), std::make_tuple(349, 12, 16831), std::make_tuple(353, 12, 17011), std::make_tuple(353, 12, 17183), std::make_tuple(359, 12, 17359), std::make_tuple(359, 12, 17539), std::make_tuple(367, 12, 17729), std::make_tuple(367, 12, 17911), std::make_tuple(367, 12, 18097), std::make_tuple(373, 12, 18289), std::make_tuple(373, 12, 18481), std::make_tuple(379, 12, 18679), std::make_tuple(379, 12, 18869), std::make_tuple(383, 12, 19087), std::make_tuple(389, 12, 19309), std::make_tuple(389, 12, 19507), std::make_tuple(397, 12, 19727), std::make_tuple(397, 12, 19927), std::make_tuple(401, 12, 20129), std::make_tuple(401, 12, 20341), std::make_tuple(409, 12, 20551), std::make_tuple(409, 12, 20759), std::make_tuple(419, 13, 20983), std::make_tuple(419, 13, 21191), std::make_tuple(419, 13, 21401), std::make_tuple(419, 13, 21613), std::make_tuple(431, 13, 21841), std::make_tuple(431, 13, 22063), std::make_tuple(431, 13, 22283), std::make_tuple(433, 13, 22511), std::make_tuple(439, 13, 22751), std::make_tuple(439, 13, 22993), std::make_tuple(443, 13, 23227), std::make_tuple(449, 13, 23473), std::make_tuple(457, 13, 23719), std::make_tuple(457, 13, 23957), std::make_tuple(457, 13, 24197), std::make_tuple(461, 13, 24443), std::make_tuple(467, 13, 24709), std::make_tuple(467, 13, 24953), std::make_tuple(479, 13, 25219), std::make_tuple(479, 13, 25471), std::make_tuple(479, 13, 25733), std::make_tuple(487, 13, 26003), std::make_tuple(487, 13, 26267), std::make_tuple(491, 13, 26539), std::make_tuple(499, 13, 26821), std::make_tuple(499, 13, 27091), std::make_tuple(503, 13, 27367), std::make_tuple(509, 13, 27653), std::make_tuple(521, 13, 27953), std::make_tuple(521, 13, 28229), std::make_tuple(521, 13, 28517), std::make_tuple(523, 13, 28817), std::make_tuple(541, 13, 29131), std::make_tuple(541, 13, 29423), std::make_tuple(541, 13, 29717), std::make_tuple(541, 13, 30013), std::make_tuple(547, 13, 30323), std::make_tuple(547, 13, 30631), std::make_tuple(557, 14, 30949), std::make_tuple(557, 14, 31267), std::make_tuple(563, 14, 31583), std::make_tuple(569, 14, 31907), std::make_tuple(571, 14, 32251), std::make_tuple(577, 14, 32579), std::make_tuple(587, 14, 32917), std::make_tuple(587, 14, 33247), std::make_tuple(593, 14, 33601), std::make_tuple(593, 14, 33941), std::make_tuple(599, 14, 34283), std::make_tuple(607, 14, 34631), std::make_tuple(607, 14, 34981), std::make_tuple(613, 14, 35363), std::make_tuple(619, 14, 35731), std::make_tuple(631, 14, 36097), std::make_tuple(631, 14, 36457), std::make_tuple(641, 14, 36833), std::make_tuple(641, 14, 37201), std::make_tuple(643, 14, 37579), std::make_tuple(653, 14, 37967), std::make_tuple(653, 14, 38351), std::make_tuple(659, 14, 38749), std::make_tuple(673, 14, 39163), std::make_tuple(673, 14, 39551), std::make_tuple(677, 14, 39953), std::make_tuple(683, 14, 40361), std::make_tuple(691, 15, 40787), std::make_tuple(701, 15, 41213), std::make_tuple(701, 15, 41621), std::make_tuple(709, 15, 42043), std::make_tuple(709, 15, 42467), std::make_tuple(719, 15, 42899), std::make_tuple(727, 15, 43331), std::make_tuple(727, 15, 43801), std::make_tuple(733, 15, 44257), std::make_tuple(739, 15, 44701), std::make_tuple(751, 15, 45161), std::make_tuple(751, 15, 45613), std::make_tuple(757, 15, 46073), std::make_tuple(769, 15, 46549), std::make_tuple(769, 15, 47017), std::make_tuple(787, 15, 47507), std::make_tuple(787, 15, 47981), std::make_tuple(787, 15, 48463), std::make_tuple(797, 15, 48953), std::make_tuple(809, 15, 49451), std::make_tuple(809, 15, 49943), std::make_tuple(821, 15, 50461), std::make_tuple(821, 16, 50993), std::make_tuple(827, 16, 51503), std::make_tuple(839, 16, 52027), std::make_tuple(853, 16, 52571), std::make_tuple(853, 16, 53093), std::make_tuple(857, 16, 53623), std::make_tuple(863, 16, 54163), std::make_tuple(877, 16, 54713), std::make_tuple(877, 16, 55259), std::make_tuple(883, 16, 55817), std::make_tuple(907, 16, 56393), std::make_tuple(907, 16, 56951)}; 48 | 49 | #ifdef USING_CLANG 50 | #pragma clang diagnostic pop 51 | #endif //using_clang 52 | 53 | } // namespace Impl 54 | } // namespace RaptorQ 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /src/buffersink.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : buffersink.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | This module can initialize/destory a buffer sink which can 7 | store specific number of ring buffers. You can get an empty ring 8 | buffer from the buffer sink without waitting for the buffer to 9 | be initizlized because this progress has been processed by one 10 | thread of the buffer sink automaticly. Once the sink is not full, 11 | it can be replenished immediately. 12 | ------------------------------------------------------------------*/ 13 | 14 | #include"buffersink.h" 15 | 16 | static uint32_t sinkCount = 0; // The current number of buffer sink 17 | 18 | iThreadStdCall_t _SinkBufferSupplyThread(LPVOID lpParam); 19 | /* 20 | Name: BufferSinkGetBuffer 21 | Description: Get an address of a empty buffer, of which the parameters 22 | of the new buffer is defined in _pSink. 23 | Parameter: 24 | @_pSink: The structure of the buffer sink. 25 | Return: The address of the empty buffer. 26 | */ 27 | ringBuffer_t *BufferSinkGetBuffer(bufferSink_t* _pSink) 28 | { 29 | ringBuffer_t *pRb=NULL; 30 | if (_pSink->id>0) { 31 | RingBufferGet(_pSink->rbSink, &pRb); 32 | } 33 | return pRb; 34 | } 35 | 36 | /* 37 | Name: BufferSinkDestorySink 38 | Description: Destory the specified buffer sink and release the memory. 39 | Parameter: 40 | @_pSink: The structure of the buffer sink. 41 | Return: 42 | */ 43 | void BufferSinkDestorySink(bufferSink_t *_pSink) 44 | { 45 | ringBuffer_t *pRb; 46 | /* terminate thread */ 47 | _pSink->id = 0; 48 | iThreadJoin(_pSink->hWnd); 49 | iThreadClose(_pSink->hWnd); 50 | /* destory ring buffer */ 51 | while (RingBufferTryGet(_pSink->rbSink,&pRb)) 52 | { 53 | RingBufferDestroy(pRb); 54 | } 55 | RingBufferDestroy(_pSink->rbSink); 56 | sinkCount--; 57 | free(_pSink); 58 | } 59 | /* 60 | Name: _SinkBufferSupplyThread 61 | Description: The thread to initilize new ring buffers to replenished 62 | the not full sink. 63 | Parameter: 64 | @lpParam: The pointer of the structure of the buffer sink. 65 | Return: 66 | */ 67 | iThreadStdCall_t _SinkBufferSupplyThread(LPVOID lpParam) 68 | { 69 | bufferSink_t *pSink=(bufferSink_t*)lpParam; 70 | ringBuffer_t *pRb; 71 | while (pSink->id) { 72 | pRb = RingBufferInit(pSink->buffLen, pSink->buffUnitSize); 73 | RingBufferPut(pSink->rbSink, &pRb); 74 | } 75 | return 0; 76 | } 77 | /* 78 | Name: BufferSinkInit 79 | Description: Initialize a new buffer sink . 80 | Parameter: 81 | @_sinkLen: The max number of buffer in the sink. 82 | @_buffLen: The number of storage unit in a buffer. 83 | @_buffUnitSize: The size of one storage unit in buffer. 84 | Return: the pointer of the structure of the buffer sink 85 | */ 86 | bufferSink_t *BufferSinkInit(uint32_t _sinkLen, uint32_t _buffLen, uint32_t _buffUnitSize) 87 | { 88 | bufferSink_t *pSink = (bufferSink_t *)malloc(sizeof(bufferSink_t)); 89 | if (pSink == NULL) { 90 | perror("Error: malloc sink unsuccessfully.\r\n "); 91 | exit(1); 92 | } 93 | /* set values */ 94 | pSink->id = ++sinkCount; 95 | pSink->sinkLen = _sinkLen; 96 | pSink->buffLen = _buffLen; 97 | pSink->buffUnitSize = _buffUnitSize; 98 | 99 | /* initialize address ring buffer */ 100 | ringBuffer_t *pRb = RingBufferInit(pSink->sinkLen, sizeof(ringBuffer_t*)); 101 | if (pRb == NULL) { 102 | perror("can not init sink buffer! \r\n"); 103 | exit(1); 104 | } 105 | pSink->rbSink = pRb; 106 | /* create buffer-supply thread */ 107 | iCreateThread(pSink->hWnd, _SinkBufferSupplyThread, pSink); 108 | 109 | return pSink; 110 | } -------------------------------------------------------------------------------- /src/buffersink.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : buffersink.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | This module can initialize/destory a buffer sink which can 7 | store specific number of ring buffers. You can get an empty ring 8 | buffer from the buffer sink without waitting for the buffer to 9 | be initizlized because this progress has been processed by one 10 | thread of the buffer sink automaticly. Once the sink is not full, 11 | it can be replenished immediately. 12 | ------------------------------------------------------------------*/ 13 | #pragma once 14 | 15 | #include"cross_platform.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include"ringbuffer.h" 22 | 23 | //#define BUFFSINK_COUNT_MAX 16 // The max number of buffer sink that can be initialized. 24 | /* 25 | Name: bufferSink_t 26 | Description: The structure of the buffer sink. 27 | */ 28 | typedef struct bufferSink_t 29 | { 30 | uint32_t id; // ID of this buffer sink. 31 | iThread_t hWnd; // Handle of the thread of this buffer sink. 32 | ringBuffer_t *rbSink; // A buffer to store the address of generated buffer. 33 | uint32_t sinkLen; // The max number of buffer in the sink. 34 | uint32_t buffLen; // The number of storage unit in a buffer. 35 | uint32_t buffUnitSize; // The size of one storage unit in buffer. 36 | }bufferSink_t; 37 | 38 | /* 39 | Name: BufferSinkInit 40 | Description: Initialize a new buffer sink . 41 | Parameter: 42 | @_sinkLen: The max number of buffer in the sink. 43 | @_buffLen: The number of storage unit in a buffer. 44 | @_buffUnitSize: The size of one storage unit in buffer. 45 | Return: the pointer of the structure of the buffer sink 46 | */ 47 | bufferSink_t *BufferSinkInit(uint32_t _sinkLen, uint32_t _buffLen, uint32_t _buffUnitSize); 48 | 49 | /* 50 | Name: BufferSinkGetBuffer 51 | Description: Get an address of a empty buffer, of which the parameters 52 | of the new buffer is defined in _pSink. 53 | Parameter: 54 | @_pSink: The structure of the buffer sink. 55 | Return: The address of the empty buffer. 56 | */ 57 | ringBuffer_t *BufferSinkGetBuffer(bufferSink_t* _pSink); 58 | 59 | /* 60 | Name: BufferSinkDestorySink 61 | Description: Destory the specified buffer sink and release the memory. 62 | Parameter: 63 | @_pSink: The structure of the buffer sink. 64 | Return: 65 | */ 66 | void BufferSinkDestorySink(bufferSink_t *_pSink); 67 | -------------------------------------------------------------------------------- /src/cross_platform.c: -------------------------------------------------------------------------------- 1 | #include"cross_platform.h" 2 | 3 | static struct timeval sysStartTime={0,0}; 4 | 5 | #ifdef OS_WINDOWS 6 | /* 7 | Name: _USleep 8 | Description: microseconds sleep 9 | Parameter: 10 | @_delayTime: The time of sleep. 11 | Return: 12 | */ 13 | void _USleep(uint64_t _delayTime) { 14 | LARGE_INTEGER m_liPerfFreq = { 0 }; 15 | LARGE_INTEGER m_liPerfStart = { 0 }; 16 | QueryPerformanceCounter(&m_liPerfStart); 17 | LARGE_INTEGER liPerfNow = { 0 }; 18 | double time; 19 | for (;;) 20 | { 21 | QueryPerformanceCounter(&liPerfNow); 22 | time = (((liPerfNow.QuadPart - 23 | m_liPerfStart.QuadPart) * 1000000) / (double)m_liPerfFreq.QuadPart); 24 | if (time >= _delayTime) 25 | break; 26 | } 27 | } 28 | 29 | #endif 30 | 31 | 32 | #ifdef OS_LINUX 33 | uint64_t getTimeOfProcess() 34 | { 35 | struct timeval tv; 36 | gettimeofday(&tv,NULL); 37 | tv.tv_sec=tv.tv_sec-sysStartTime.tv_sec; 38 | tv.tv_usec=tv.tv_usec-sysStartTime.tv_usec; 39 | return ((uint32_t)tv.tv_sec*1000+tv.tv_usec/1000); 40 | } 41 | 42 | void initStartTime() 43 | { 44 | gettimeofday(&sysStartTime,NULL); 45 | } 46 | #endif -------------------------------------------------------------------------------- /src/cross_platform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include"stdint.h" 3 | #define OS_WINDOWS 4 | //#define OS_LINUX 5 | 6 | #ifdef OS_WINDOWS 7 | #include 8 | #ifndef _WINSOCKAPI_ 9 | #define _WINSOCKAPI_ 10 | #endif 11 | #include 12 | #include 13 | #endif //OS_WINDOWS 14 | #ifdef OS_LINUX 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #endif // OS_LINUX 23 | 24 | #ifdef OS_WINDOWS 25 | #define iMUTEX_INIT_VALUE NULL 26 | #define iSEMAPHORE_INIT_VALUE NULL 27 | #define iThread_t HANDLE 28 | #define iMutex_t HANDLE 29 | #define iSemaphore_t HANDLE 30 | #define iThreadStdCall_t DWORD WINAPI 31 | #define iClock_t clock_t 32 | #define iCreateThread(hwnd,func,param) hwnd=CreateThread(NULL, 0, func, (LPVOID)param, 0, NULL) 33 | #define iThreadJoin(hwnd) WaitForSingleObject(hwnd, INFINITE) 34 | #define iThreadClose(hwnd) CloseHandle(hwnd) 35 | #define iCreateMutex(mutex,owner) mutex=CreateMutex(NULL,owner,NULL) 36 | #define iMutexLock(mutex) WaitForSingleObject(mutex, INFINITE) 37 | #define iMutexTryLock(mutex) WaitForSingleObject(mutex,0L) 38 | #define iMutexUnlock(mutex) ReleaseMutex(mutex) 39 | #define iMutexDestory(mutex) CloseHandle(mutex) 40 | #define iCreateSemaphore(sema,initCtn,maxCtn) sema=CreateSemaphore(NULL, initCtn, maxCtn, NULL) 41 | #define iSemaphoreWait(sema) WaitForSingleObject(sema, INFINITE) 42 | #define iSemaphoreTryWait(sema) WaitForSingleObject(sema, 0L) 43 | #define iSemaphoreTimedWait(sema,_timeOut) WaitForSingleObject(sema,_timeOut) //add for function RingBufferTimedGet 44 | #define iSemaphorePost(sema,num) ReleaseSemaphore(sema, num, NULL) 45 | #define iSemaphoreDestory(sema) CloseHandle(sema) 46 | #define iSleep(time) Sleep(time) 47 | #define iGetTime() clock() 48 | #define iCloseSocket(sock) closesocket(sock) 49 | 50 | void _USleep(uint64_t _delayTime); 51 | 52 | #endif // OS_WINDOWS 53 | 54 | #ifdef OS_LINUX 55 | 56 | #define iMUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER 57 | #define iSEMAPHORE_INIT_VALUE (0) 58 | #define WAIT_OBJECT_0 (0) 59 | #define SOCKET_ERROR (-1) 60 | typedef void* LPVOID; 61 | typedef int SOCKET; 62 | typedef struct sockaddr_in SOCKADDR_IN; 63 | typedef struct sockaddr SOCKADDR; 64 | typedef int SOCKET; 65 | #define iThread_t pthread_t 66 | #define iMutex_t pthread_mutex_t 67 | #define iSemaphore_t sem_t 68 | #define iThreadStdCall_t void* 69 | #define iClock_t uint64_t 70 | #define iCreateThread(hwnd,func,param) pthread_create(&hwnd, NULL, func, param)//hwnd=CreateThread(NULL, 0, ptr, (LPVOID)param, 0, NULL) 71 | #define iThreadJoin(hwnd) pthread_join(hwnd, NULL) 72 | #define iThreadClose(hwnd) pthread_cancel(hwnd) 73 | #define iCreateMutex(mutex,owner) pthread_mutex_init(&mutex, NULL) 74 | #define iMutexLock(mutex) pthread_mutex_lock(&mutex) 75 | #define iMutexTryLock(mutex) pthread_mutex_trylock(&mutex) 76 | #define iMutexUnlock(mutex) pthread_mutex_unlock(&mutex) 77 | #define iMutexDestory(mutex) pthread_mutex_destroy(&mutex) 78 | #define iCreateSemaphore(sema,initCtn,maxCtn) sem_init(&sema, 0, initCtn) 79 | #define iSemaphoreWait(sema) sem_wait(&sema) 80 | #define iSemaphoreTryWait(sema) sem_trywait(&sema) 81 | #define iSemaphoreTimedWait(sema,_timeOut) sem_trywait(&sema,_timeOut) //add for function RingBufferTimedGet 82 | #define iSemaphorePost(sema,num) sem_post(&sema) 83 | #define iSemaphoreDestory(sema) sem_destroy(&sema) 84 | 85 | #define iSleep(time) usleep((long)time*1000) 86 | #define iGetTime() getTimeOfProcess() 87 | #define iCloseSocket(sock) close(sock) 88 | 89 | uint64_t getTimeOfProcess(); 90 | void initStartTime(); 91 | 92 | #endif // 93 | 94 | -------------------------------------------------------------------------------- /src/err.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : err.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | To print the log or error information with a defined format. 7 | ------------------------------------------------------------------*/ 8 | #pragma once 9 | #include "cross_platform.h" 10 | 11 | #include 12 | 13 | #define pr_error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) // print the error information 14 | 15 | #define pr_info(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) // print the log 16 | 17 | #define debug(fmt, ...) do { \ 18 | printf("[%.3f]"fmt, (float)iGetTime()/1000, ##__VA_ARGS__); \ 19 | } while (0) // print the log with a time stamp 20 | 21 | -------------------------------------------------------------------------------- /src/iRaptorQ.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : iRaptorQ.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Support the middle interface between this Project and 7 | libRaptorQ . 8 | ------------------------------------------------------------------*/ 9 | #include"iRaptorQ.h" 10 | static raptorQ_OTI_t OTI; 11 | 12 | void iRaptorQ_pre() 13 | { 14 | struct RaptorQ_ptr *enc; 15 | void *blk; 16 | 17 | if ((blk = malloc(BLOCK_SIZE)) == NULL) { 18 | printf("fail to allocate space\n"); 19 | exit(1); 20 | } 21 | 22 | if ((enc = RaptorQ_Enc(ENC_8, blk, BLOCK_SIZE, SYMBOL_SIZE, SYMBOL_SIZE, MAX_MEM)) == NULL) { 23 | printf("fail to initialize encoder\n"); 24 | exit(1); 25 | } 26 | 27 | if (RaptorQ_blocks(enc) != 1) { 28 | printf("Number of blocks != 1\n"); 29 | exit(1); 30 | } 31 | 32 | OTI.OTI_Comm = RaptorQ_OTI_Common(enc); 33 | OTI.OTI_Spec = RaptorQ_OTI_Scheme(enc); 34 | 35 | RaptorQ_free(&enc); 36 | 37 | free(blk); 38 | } 39 | 40 | uint8_t iRaptorQ_GetOTI(struct RaptorQ_ptr *_enc, raptorQ_OTI_t *myOTI) 41 | { 42 | uint8_t res; 43 | if ((res=RaptorQ_blocks(_enc)) != 1) { 44 | printf("[ERR]Number of blocks != 1 oti\n"); 45 | perror("Number of blocks != 1 oti\n"); 46 | exit(1); 47 | } 48 | myOTI->OTI_Comm = RaptorQ_OTI_Common(_enc); 49 | myOTI->OTI_Spec = RaptorQ_OTI_Scheme(_enc); 50 | return res; 51 | } 52 | 53 | struct RaptorQ_ptr *iRaptorQ_Enc(void *data, int len) 54 | { 55 | return RaptorQ_Enc(ENC_8, data, len, SYMBOL_SIZE, SYMBOL_SIZE, MAX_MEM); 56 | } 57 | 58 | struct RaptorQ_ptr *iRaptorQ_Dec(raptorQ_OTI_t _myOTI) 59 | { 60 | return RaptorQ_Dec(DEC_8, _myOTI.OTI_Comm, _myOTI.OTI_Spec); 61 | } 62 | 63 | void iRaptorQ_encode_id(struct RaptorQ_ptr *enc, raptorQPacket_t *ppac, uint32_t tag, uint8_t sbn, uint32_t esi) 64 | { 65 | ppac->tag = tag; 66 | ppac->id = RaptorQ_id(esi, sbn); 67 | 68 | void *ptr = ppac->data; 69 | 70 | if (RaptorQ_encode_id(enc, (void **)&ptr, SYMBOL_SIZE, ppac->id) != SYMBOL_SIZE) { 71 | perror("failed to encode symbol\n"); 72 | exit(1); 73 | } 74 | } 75 | 76 | int iRaptorQ_add_symbol_id(struct RaptorQ_ptr *dec, raptorQPacket_t *ppac) 77 | { 78 | void *ptr = ppac->data; 79 | return RaptorQ_add_symbol_id(dec, (void **)&ptr, SYMBOL_SIZE, ppac->id); 80 | } 81 | 82 | int iRaptorQ_decode(struct RaptorQ_ptr *dec, raptorQBlock_t *pblk,uint64_t block_size) 83 | { 84 | void *ptr = pblk->data; 85 | return (RaptorQ_decode(dec, (void **)&ptr, (size_t)block_size) == (size_t)block_size); 86 | } 87 | void iRaptorQCreateBlock(raptorQBlock_t *_pBlock, uint8_t *_pBlockData, uint32_t _tag) 88 | { 89 | _pBlock->tag = _tag; 90 | memcpy(_pBlock->data, _pBlockData, BLOCK_SIZE); 91 | } 92 | void iRaptorQPack(ringBuffer_t * _pRb, uint8_t *data, uint32_t _tag, uint32_t _id, uint8_t _foreBSN) 93 | { 94 | raptorQPacket_t pPacket; 95 | pPacket.tag = _tag; 96 | pPacket.id = _id; 97 | pPacket.oti = OTI; 98 | pPacket.forTagBSN = _foreBSN; 99 | pPacket.type = PACKET_TYPE_SOURCE; 100 | pPacket.block_symbol_number = BLOCK_SYMBOL_NUMBER; 101 | memcpy(pPacket.data,data,SYMBOL_SIZE); 102 | RingBufferPut(_pRb,&pPacket); 103 | } -------------------------------------------------------------------------------- /src/iRaptorQ.c.fake: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : iRaptorQ.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Support the middle interface between this Project and 7 | libRaptorQ . 8 | ------------------------------------------------------------------*/ 9 | #include"iRaptorQ.h" 10 | void iRaptorQ_pre() 11 | { 12 | 13 | } 14 | 15 | struct RaptorQ_ptr *iRaptorQ_Enc(void *data, int len) 16 | { 17 | return NULL; 18 | } 19 | 20 | struct RaptorQ_ptr *iRaptorQ_Dec() 21 | { 22 | return NULL; 23 | } 24 | 25 | void iRaptorQ_encode_id(struct RaptorQ_ptr *enc, raptorQPacket_t *ppac, uint32_t tag, uint8_t sbn, uint32_t esi) 26 | { 27 | ppac->tag = tag; 28 | ppac->id = esi;//RaptorQ_id(esi, sbn); 29 | void *ptr = ppac->data; 30 | 31 | //if (RaptorQ_encode_id(enc, (void **)&ptr, SYMBOL_SIZE, ppac->id) != SYMBOL_SIZE) 32 | // pr_error("failed to encode symbol\n"); 33 | } 34 | 35 | int iRaptorQ_add_symbol_id(struct RaptorQ_ptr *dec, raptorQPacket_t *ppac) 36 | { 37 | void *ptr = ppac->data; 38 | 39 | //return RaptorQ_add_symbol_id(dec, (void **)&ptr, SYMBOL_SIZE, ppac->id); 40 | return 1; 41 | } 42 | 43 | int iRaptorQ_decode(struct RaptorQ_ptr *dec, raptorQBlock_t *pblk) 44 | { 45 | void *ptr = pblk->data; 46 | 47 | //return (RaptorQ_decode(dec, (void **)&ptr, BLOCK_SIZE) == BLOCK_SIZE); 48 | return 1; 49 | } 50 | void iRaptorQCreateBlock(raptorQBlock_t *_pBlock, uint8_t *_pBlockData, uint32_t _tag) 51 | { 52 | _pBlock->tag = _tag; 53 | memcpy(_pBlock->data, _pBlockData, BLOCK_SIZE); 54 | } 55 | void iRaptorQPack(ringBuffer_t * _pRb, raptorQBlock_t *pBlock) 56 | { 57 | raptorQPacket_t packet; 58 | uint8_t *pSymbol = pBlock->data; 59 | for (int esi = 0; esi < BLOCK_SYMBOL_NUMBER; esi++) 60 | { 61 | packet.tag = pBlock->tag; 62 | //packet.id = RaptorQ_id(esi, 0); 63 | packet.id = esi; 64 | memcpy(packet.data,pSymbol,SYMBOL_SIZE); 65 | RingBufferPut(_pRb,&packet); 66 | pSymbol += SYMBOL_SIZE; 67 | } 68 | 69 | } 70 | uint32_t iRaptorQ_max_repair(struct RaptorQ_ptr *enc, int xx) 71 | { 72 | return 0xFFFFFFFF; 73 | } -------------------------------------------------------------------------------- /src/iRaptorQ.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : iRaptorQ.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Support the middle interface between this Project and 7 | libRaptorQ . 8 | ------------------------------------------------------------------*/ 9 | #pragma once 10 | #include"cross_platform.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include"RaptorQ/cRaptorQ.h" 17 | #include"parameter.h" 18 | #include"ringbuffer.h" 19 | 20 | enum PACKET_TYPE 21 | { 22 | PACKET_TYPE_SOURCE, 23 | PACKET_TYPE_SOURCE_FINISHED, 24 | PACKET_TYPE_REPAIR, 25 | PACKET_TYPE_BSN, 26 | }; 27 | 28 | typedef struct raptorQ_OTI_t { 29 | RaptorQ_OTI_Common_Data OTI_Comm; 30 | RaptorQ_OTI_Scheme_Specific_Data OTI_Spec; 31 | } raptorQ_OTI_t; 32 | 33 | typedef struct raptorQPacket_t { 34 | uint32_t tag; 35 | uint32_t id; 36 | iClock_t ts[4]; 37 | raptorQ_OTI_t oti; 38 | uint8_t block_symbol_number; 39 | uint8_t forTagBSN; 40 | uint8_t type; 41 | uint8_t data[SYMBOL_SIZE]; 42 | }raptorQPacket_t; 43 | 44 | typedef struct raptorQFeedbackInfo_t { 45 | uint32_t feedbackID; //identify a feedback of the same packet which has the same tag and id 46 | uint32_t tag; 47 | uint32_t id; 48 | iClock_t ts[4]; 49 | uint32_t count; 50 | }raptorQFeedbackInfo_t; 51 | 52 | typedef struct raptorQBlock_t { 53 | uint32_t tag; 54 | uint8_t data[BLOCK_SIZE]; 55 | }raptorQBlock_t; 56 | 57 | /* 58 | * necessary preparations before initializing encoder/decoder 59 | */ 60 | void iRaptorQ_pre(); 61 | 62 | /* 63 | * Initialize a RaptorQ encoder 64 | * @data: point to the data that will be encoded 65 | * @len: specify the original data length 66 | */ 67 | struct RaptorQ_ptr *iRaptorQ_Enc(void *data, int len); 68 | 69 | /* 70 | * Initialize a RaptorQ decoder 71 | */ 72 | struct RaptorQ_ptr *iRaptorQ_Dec(raptorQ_OTI_t _myOTI); 73 | 74 | /* 75 | * generate an encoded symbol 76 | * @enc: the RaptorQ encoder instance used for encoding 77 | * @ppac: where the generated symbol would be stored 78 | * @tag: specify which data block this packet belongs to 79 | * @sbn: set 0 only 80 | * @esi: identify the symbol 81 | */ 82 | void iRaptorQ_encode_id(struct RaptorQ_ptr *enc, raptorQPacket_t *ppac, 83 | uint32_t tag, uint8_t sbn, uint32_t esi); 84 | 85 | /* 86 | * add an encoded symbol to the RaptorQ decoder instance 87 | * @dec: the RaptorQ decoder instance used for decoding 88 | * @ppac: where the received symbol is stored 89 | */ 90 | int iRaptorQ_add_symbol_id(struct RaptorQ_ptr *dec, raptorQPacket_t *ppac); 91 | 92 | /* 93 | * recover the original data block 94 | * @dec: the RaptorQ decoder instance used for decoding 95 | * @pblk: where the recovered original data block would be stored 96 | */ 97 | int iRaptorQ_decode(struct RaptorQ_ptr *dec, raptorQBlock_t *pblk,uint64_t block_size); 98 | void iRaptorQCreateBlock(raptorQBlock_t *_pBlock, uint8_t *_pBlockData, uint32_t _tag); 99 | void iRaptorQPack(ringBuffer_t * _pRb, uint8_t *data, uint32_t _tag, uint32_t _id, uint8_t _foreBSN); 100 | uint8_t iRaptorQ_GetOTI(struct RaptorQ_ptr *_enc, raptorQ_OTI_t *myOTI); 101 | -------------------------------------------------------------------------------- /src/iRaptorQ.h.fake: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : iRaptorQ.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Support the middle interface between this Project and 7 | libRaptorQ . 8 | ------------------------------------------------------------------*/ 9 | #pragma once 10 | #ifndef _WINSOCKAPI_ 11 | #define _WINSOCKAPI_ 12 | #endif 13 | #include 14 | #include 15 | #include 16 | #include"parameter.h" 17 | #include"ringbuffer.h" 18 | //#include 19 | #define FAKE_RAPTORQ 20 | typedef struct raptorQPacket_t { 21 | uint32_t tag; 22 | uint32_t id; 23 | uint8_t data[SYMBOL_SIZE]; 24 | clock_t ts[4]; 25 | uint32_t feedbackID; //identiy the ID of received feedback 26 | }raptorQPacket_t; 27 | 28 | typedef struct raptorQFeedbackInfo_t { 29 | uint32_t feedbackID; //identify a feedback of the same packet which has the same tag and id 30 | uint32_t tag; 31 | uint32_t id; 32 | clock_t ts[4]; 33 | uint32_t count; 34 | }raptorQFeedbackInfo_t; 35 | 36 | typedef struct raptorQBlock_t { 37 | uint32_t tag; 38 | uint8_t data[BLOCK_SIZE]; 39 | }raptorQBlock_t; 40 | 41 | struct RaptorQ_ptr { 42 | int a; 43 | }; 44 | /* 45 | * necessary preparations before initializing encoder/decoder 46 | */ 47 | void iRaptorQ_pre(); 48 | 49 | 50 | /* 51 | * Initialize a RaptorQ encoder 52 | * @data: point to the data that will be encoded 53 | * @len: specify the original data length 54 | */ 55 | struct RaptorQ_ptr *iRaptorQ_Enc(void *data, int len); 56 | 57 | 58 | /* 59 | * Initialize a RaptorQ decoder 60 | */ 61 | struct RaptorQ_ptr *iRaptorQ_Dec(); 62 | 63 | 64 | /* 65 | * generate an encoded symbol 66 | * @enc: the RaptorQ encoder instance used for encoding 67 | * @ppac: where the generated symbol would be stored 68 | * @tag: specify which data block this packet belongs to 69 | * @sbn: set 0 only 70 | * @esi: identify the symbol 71 | */ 72 | void iRaptorQ_encode_id(struct RaptorQ_ptr *enc, raptorQPacket_t *ppac, 73 | uint32_t tag, uint8_t sbn, uint32_t esi); 74 | 75 | 76 | /* 77 | * add an encoded symbol to the RaptorQ decoder instance 78 | * @dec: the RaptorQ decoder instance used for decoding 79 | * @ppac: where the received symbol is stored 80 | */ 81 | int iRaptorQ_add_symbol_id(struct RaptorQ_ptr *dec, raptorQPacket_t *ppac); 82 | 83 | 84 | /* 85 | * recover the original data block 86 | * @dec: the RaptorQ decoder instance used for decoding 87 | * @pblk: where the recovered original data block would be stored 88 | */ 89 | int iRaptorQ_decode(struct RaptorQ_ptr *dec, raptorQBlock_t *pblk); 90 | void iRaptorQCreateBlock(raptorQBlock_t *_pBlock, uint8_t *_pBlockData, uint32_t _tag); 91 | void iRaptorQPack(ringBuffer_t * _pRb, raptorQBlock_t *pBlock); 92 | uint32_t iRaptorQ_max_repair(struct RaptorQ_ptr *enc,int xx); -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : io.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | The interface between the source data and this program. At 7 | present, UDP interfaces are supported to input the source data 8 | to encode or output the decoded data. 9 | ------------------------------------------------------------------*/ 10 | #pragma once 11 | 12 | #include"cross_platform.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include"ringbuffer.h" 19 | #include"parameter.h" 20 | #include"network.h" 21 | #include"iRaptorQ.h" 22 | 23 | //#define _IO_TEST_ //if defined , the input and output data is artificial data 24 | 25 | #define IO_INPUT_RBUFF_NUMBER (30000) 26 | #define IO_OUTPUT_RBUFF_NUMBER (30000) 27 | #define IO_RTCP_Back_RBUFF_NUMBER (3000)//edited by fanli 28 | 29 | enum PUT_BLOCK 30 | { 31 | PUT_BLOCK_START, // start to put a block in to output buffer 32 | PUT_BLOCK_CURRENT, // put a packet is id is expected, otherwise it may be stored in array 33 | PUT_BLOCK_REST // put the rest of packets. 34 | }; 35 | 36 | typedef struct IOPacket_t{ 37 | char flag; 38 | uint16_t len; 39 | #ifdef IO_NETWORK_MODE 40 | uint8_t data[SYMBOL_SIZE+sizeof(iClock_t)]; 41 | #else 42 | uint8_t data[SYMBOL_SIZE]; 43 | #endif 44 | }IOPacket_t; 45 | typedef struct IODataInfo_t { 46 | uint32_t len; 47 | uint8_t data[SYMBOL_SIZE]; 48 | }IODataInfo_t; 49 | 50 | typedef struct Data_t { 51 | uint32_t id; 52 | uint32_t len; 53 | iClock_t ts; 54 | 55 | uint8_t data[600]; 56 | 57 | }Data_t; 58 | typedef struct DataFb_t { 59 | uint32_t id; 60 | iClock_t ts; 61 | }DataFb_t; 62 | 63 | /* 64 | Name: IOInputInit 65 | Description: Initialize the Input interface. 66 | Parameter: 67 | Return: 68 | */ 69 | void IOInputInit(); 70 | 71 | /* 72 | Name: IOOutputInit 73 | Description: Initialize the Output interface. 74 | Parameter: 75 | Return: 76 | */ 77 | void IOOutputInit(); 78 | 79 | 80 | void RTCP_Forward_Send_Init(); 81 | 82 | void RTCP_Forward_Recv_Init(); 83 | //edited by fanli 84 | void RTCP_Back_Send_Init(); 85 | 86 | //edited by fanli 87 | void RTCP_Back_Recv_Init(); 88 | /* 89 | Name: IOInputDeInit 90 | Description: Stop and destory the Input interface. 91 | Parameter: 92 | Return: 93 | */ 94 | void IOInputDeInit(); 95 | 96 | /* 97 | Name: IOOutputDeInit 98 | Description: Stop and destory the Output interface. 99 | Parameter: 100 | Return: 101 | */ 102 | void IOOutputDeInit(); 103 | 104 | /* 105 | Name: IOInputDataGetBlock 106 | Description: Get a block of data from the Input interface. 107 | Parameter: 108 | @_pBlock : a pointer store one block of data. 109 | Return: 110 | */ 111 | uint32_t IOInputDataGetBlock(ringBuffer_t *_pRb, uint8_t* _pBlock, uint32_t _tag, uint8_t _foreBSN); 112 | 113 | /* 114 | Name: IOOutputDataPutBlock 115 | Description: Output a block of data to the Output interface. 116 | Parameter: 117 | @_pBlock : a pointer store one block of data. 118 | Return: 119 | */ 120 | uint32_t IOOutputDataPutBlock(int _command, uint8_t* _pData, uint32_t blockSymbolNumber); 121 | void IOOutputDataPutSymbol(uint8_t *pPut); 122 | 123 | void IO_InputData(IODataInfo_t *_dataInfo); 124 | void IO_OutputData(IODataInfo_t *_dataInfo); 125 | -------------------------------------------------------------------------------- /src/lib/32/RaptorQ_Static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/lib/32/RaptorQ_Static.lib -------------------------------------------------------------------------------- /src/lib/64/RaptorQ_Static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/lib/64/RaptorQ_Static.lib -------------------------------------------------------------------------------- /src/lib/RaptorQ_Static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/lib/RaptorQ_Static.lib -------------------------------------------------------------------------------- /src/network.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/network.c -------------------------------------------------------------------------------- /src/network.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : network.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Instruction: Use this module you can set some UDP sockets, 7 | sendrate-controllable data or read size-specified datavia UDP. 8 | ------------------------------------------------------------------*/ 9 | #pragma once 10 | #include"cross_platform.h" 11 | #include 12 | #include 13 | #include 14 | #ifdef OS_WINDOWS 15 | #pragma comment(lib,"ws2_32.lib") 16 | #endif //OS_WINDOWS 17 | 18 | #include"parameter.h" 19 | /* 20 | Name: tokenBucket_t 21 | Description: A structure to store the information of a token bucket 22 | */ 23 | typedef struct tokenBucket_t { 24 | uint32_t tokenNum; 25 | iClock_t produceTime; 26 | double limitFlowSpeed; 27 | uint32_t limitMaxFlowSpeed; 28 | }tokenBucket_t; 29 | 30 | /* 31 | Name: netAddr_t 32 | Description: A structure to store the ip and port 33 | */ 34 | typedef struct netAddr_t 35 | { 36 | char ip[16]; 37 | uint16_t port; 38 | }netAddr_t; 39 | /* 40 | Name: netInfo_t 41 | Description: A structure to store the information of a socket 42 | */ 43 | typedef struct netInfo_t 44 | { 45 | SOCKET hSocket; // The handle of the socket 46 | uint16_t netID; // The id of the socket in this module. 47 | tokenBucket_t tokenBucket; // The structure of the token bucket for this socket 48 | }netInfo_t; 49 | 50 | /* 51 | Name: NetworkUDPInit 52 | Description: 53 | and set a UDP socket 54 | Parameter: 55 | @_hostAddr : The ip and port of host PC. 56 | @_remoteAddr : The ip and port of remote PC. 57 | Return: The socket descriptor that has been set. 58 | */ 59 | netInfo_t* NetworkUDPInit(const netAddr_t *_localAddr, const netAddr_t *_remoteAddr); 60 | /* 61 | Name: NetworkUDPClose 62 | Description: Close a UDP socket adn release the memory. 63 | Parameter: 64 | @_serSocket : The structure of the socket information. 65 | Return: 66 | */ 67 | void NetworkUDPClose(netInfo_t *_serSocket); 68 | 69 | /* 70 | Name: NetworkUDPSendLimit 71 | Description: Send a serial of data, of which the length is specified and 72 | the byte rate is limitted. 73 | Parameter: 74 | @_socket : The socket descriptor. 75 | @_data : A pointer to the data. 76 | @_len : The length of data. 77 | @_rate : The data rate of transmisstion. Byte per second. 78 | Return: The return value of send() function of system. 79 | */ 80 | int NetworkUDPSendLimit(netInfo_t* _socket, void *_data, uint32_t _len, uint32_t _rate); 81 | 82 | /* 83 | Name: NetworkUDPSend 84 | Description: Send a serial of data, of which the length is specified. 85 | Parameter: 86 | @_socket : The socket descriptor. 87 | @_data : A pointer to the data. 88 | @_len : The length of data. 89 | Return: The return value of send() function of system. 90 | */ 91 | void NetworkUDPSend(netInfo_t* _socket, void *_data, uint32_t _len); 92 | 93 | /* 94 | Name: NetworkUDPReceive 95 | Description: Receive a serial of data. 96 | Parameter: 97 | @_socket : The socket descriptor. 98 | @_data : A pointer to the data. 99 | @_len : The length of data. 100 | Return: -1 when meet error 101 | */ 102 | int NetworkUDPReceive(netInfo_t *_socket, void *_data, uint32_t _len); 103 | int _GetToken(tokenBucket_t *_bucket, uint32_t _need); 104 | 105 | /* 106 | Name: _GetWaitTime 107 | Description: To calculate the time of sleep. 108 | @_bucket: The structure of the token bucket. 109 | @_need : The number of tokens needed to be comsumed. 110 | Return: The time of sleep(microsecond). 111 | */ 112 | long _GetWaitTime(tokenBucket_t *_bucket, uint32_t _need); -------------------------------------------------------------------------------- /src/parameter.c: -------------------------------------------------------------------------------- 1 | #include "parameter.h" 2 | char *ipTx[] = { 3 | IP_TX_0, 4 | IP_BACK_LOOP, 5 | IP_BACK_LOOP, 6 | IP_BACK_LOOP 7 | }; 8 | char *ipRx[] = { 9 | IP_RX_0, 10 | IP_BACK_LOOP, 11 | IP_BACK_LOOP, 12 | IP_BACK_LOOP 13 | }; 14 | -------------------------------------------------------------------------------- /src/parameter.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/parameter.h -------------------------------------------------------------------------------- /src/receiver.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : receiver.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Encode the source data and transmit via UDP toreceiver. 7 | Check the feedback and coordinate the encode and transmitte 8 | pace. 9 | 10 | ------------------------------------------------------------------*/ 11 | #include"receiver.h" 12 | #ifdef DELAY_MEASURE 13 | #include 14 | #include"err.h" 15 | #endif // DELAY_MEASURE 16 | 17 | enum RECV_INFO_STATE 18 | { 19 | RECV_INFO_STATE_IDLE, 20 | RECV_INFO_STATE_DECODE, 21 | RECV_INFO_STATE_OUTPUT 22 | }; 23 | 24 | typedef struct recvInfo_t { 25 | uint32_t tag; 26 | uint32_t ctn; 27 | bool isSetForeBSN; 28 | uint8_t state; 29 | iSemaphore_t semaDec; 30 | iMutex_t mutex; 31 | ringBuffer_t *rbRecv; 32 | }recvInfo_t; 33 | typedef struct decInfo_t { 34 | uint32_t decTag; 35 | uint32_t decCount; 36 | uint32_t BSN; 37 | uint32_t esiExpect; 38 | bool isSetOTI; 39 | raptorQ_OTI_t OTI; 40 | ringBuffer_t *rbDec; 41 | ringBuffer_t *rbOut; 42 | }decInfo_t; 43 | extern char *ipTx[]; 44 | extern char *ipRx[]; 45 | static bool stateRun = true; 46 | 47 | static netInfo_t *sockRecv[CHANNEL_NUMBER],*sockFeedback[CHANNEL_NUMBER]; 48 | static recvInfo_t recvInfoList[RECV_INFO_LIST_LEN]; 49 | static bufferSink_t *bufferSink; 50 | 51 | static ringBuffer_t *rbSwitcher = NULL; 52 | static uint32_t floorTag = 0; // a number identify the tag that is about to be decoded 53 | static uint32_t curTag = 0; // a number identify the tag that is about to be put in output buffer. 54 | // tag < curTag indicates that the block with this tag has been decoded. 55 | //static raptorQFeedbackInfo_t *pFeedbackInfo; 56 | static iMutex_t mutexCurTag = iMUTEX_INIT_VALUE; 57 | static iMutex_t mutexFloorTag = iMUTEX_INIT_VALUE; 58 | 59 | static iThread_t hThreadDecoder[DECODER_NUMBER]; 60 | static iThread_t hThreadReceiver[DATA_RX_NUMBER]; 61 | static iThread_t hThreadFeedback[FEEDBACK_TX_NUMBER]; 62 | static iThread_t hThreadOutput; 63 | 64 | iThreadStdCall_t _DataReceiverThread(LPVOID lpParam); 65 | iThreadStdCall_t _FeedbackNotifierThread(LPVOID lpParam); 66 | iThreadStdCall_t _DecoderThread(LPVOID lpParam); 67 | iThreadStdCall_t _OutputThread(LPVOID lpParam); 68 | 69 | void _RecvInfoDeInit(recvInfo_t* _pInfo) { 70 | _pInfo->tag = 0; 71 | _pInfo->ctn = 0; 72 | _pInfo->isSetForeBSN = false; 73 | _pInfo->state = RECV_INFO_STATE_IDLE; 74 | 75 | iSemaphoreDestory(_pInfo->semaDec); 76 | iCreateSemaphore(_pInfo->semaDec, 0, 1); 77 | 78 | RingBufferFlush(_pInfo->rbRecv); 79 | RingBufferDestroy(_pInfo->rbRecv); 80 | _pInfo->rbRecv = NULL; 81 | } 82 | void _RecvInfoInit(recvInfo_t* _pInfo,uint32_t _tag) { 83 | _pInfo->tag = _tag; 84 | _pInfo->ctn = 0; 85 | _pInfo->isSetForeBSN = false; 86 | _pInfo->state = RECV_INFO_STATE_DECODE; 87 | 88 | if (_pInfo->rbRecv != NULL) { 89 | RingBufferFlush(_pInfo->rbRecv); 90 | RingBufferDestroy(_pInfo->rbRecv); 91 | } 92 | _pInfo->rbRecv = BufferSinkGetBuffer(bufferSink); 93 | iSemaphorePost(_pInfo->semaDec, 1); 94 | } 95 | 96 | void _RecvInfoListInit() { 97 | for (int i = 0; i < RECV_INFO_LIST_LEN; i++) { 98 | recvInfo_t *pInfo = &recvInfoList[i]; 99 | pInfo->tag = 0; 100 | pInfo->ctn = 0; 101 | pInfo->isSetForeBSN = false; 102 | pInfo->state = RECV_INFO_STATE_IDLE; 103 | iCreateSemaphore(pInfo->semaDec, 0, 1); 104 | pInfo->rbRecv = NULL; 105 | iCreateMutex(pInfo->mutex, false); 106 | } 107 | } 108 | 109 | /* 110 | Name: _DataReceiverThread 111 | Description: The thread to receive and sotre the data . 112 | Parameter: 113 | @lpParam : The id of receiver. 114 | Return: 115 | */ 116 | 117 | iThreadStdCall_t _DataReceiverThread(LPVOID lpParam) 118 | { 119 | uint32_t rxID = (uint32_t)lpParam%CHANNEL_NUMBER; 120 | raptorQFeedbackInfo_t *pFeedbackInfo = (raptorQFeedbackInfo_t*)malloc(sizeof(raptorQFeedbackInfo_t)); 121 | raptorQPacket_t *packetRecv=(raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 122 | raptorQPacket_t *packetBSN = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 123 | while (stateRun) { 124 | /* recveive data */ 125 | NetworkUDPReceive(sockRecv[rxID], packetRecv,sizeof(raptorQPacket_t)); 126 | #ifdef DELAY_MEASURE 127 | packetRecv->ts[1] = iGetTime(); 128 | #endif // DELAY_MEASURE 129 | 130 | /* filter */ // do no need lock for tag because the symmmetry protect window 131 | iMutexLock(mutexCurTag); 132 | if ((curTag > RECV_WINDOW_LEN && packetRecv->tag < (curTag - RECV_WINDOW_LEN)) || (packetRecv->tag > curTag+RECV_WINDOW_LEN)) { 133 | iMutexUnlock(mutexCurTag); 134 | continue; 135 | } 136 | iMutexUnlock(mutexCurTag); 137 | /* set the value of recvBuffInfo */ 138 | recvInfo_t* pRecvInfo = &recvInfoList[packetRecv->tag % RECV_INFO_LIST_LEN]; 139 | 140 | iMutexLock(pRecvInfo->mutex);//-->lock recvInfo 141 | if (pRecvInfo->state == RECV_INFO_STATE_IDLE) { 142 | _RecvInfoInit(pRecvInfo,packetRecv->tag); 143 | } 144 | 145 | if (packetRecv->tag == pRecvInfo->tag) { 146 | 147 | pRecvInfo->ctn++; 148 | /* ------------ set feedback info ---------------- */ 149 | pFeedbackInfo->count = pRecvInfo->ctn; 150 | pFeedbackInfo->tag = packetRecv->tag; 151 | pFeedbackInfo->id = packetRecv->id; 152 | pFeedbackInfo->ts[0] = packetRecv->ts[0]; 153 | pFeedbackInfo->ts[1] = packetRecv->ts[1]; 154 | pFeedbackInfo->ts[2] = iGetTime(); 155 | NetworkUDPSend(sockFeedback[rxID], pFeedbackInfo, sizeof(*pFeedbackInfo)); 156 | /* ------------ store in buffer ---------------------------*/ 157 | if (pRecvInfo->state == RECV_INFO_STATE_DECODE) { 158 | 159 | if (!pRecvInfo->isSetForeBSN && packetRecv->tag>0) { 160 | recvInfo_t* pForeRecvInfo = &recvInfoList[(packetRecv->tag - 1) % RECV_INFO_LIST_LEN]; 161 | if (pForeRecvInfo->state == RECV_INFO_STATE_DECODE) { 162 | packetBSN->tag = packetRecv->tag - 1; 163 | packetBSN->block_symbol_number = packetRecv->forTagBSN; 164 | packetBSN->type = PACKET_TYPE_BSN; 165 | if (RingBufferTryPut(pForeRecvInfo->rbRecv, packetBSN)) { 166 | pRecvInfo->isSetForeBSN = true; 167 | } 168 | } 169 | } 170 | RingBufferTryPut(pRecvInfo->rbRecv, packetRecv); 171 | } 172 | } 173 | iMutexUnlock(pRecvInfo->mutex); 174 | #ifdef DEBUG_RX 175 | debug("\t\t\t[RX %u]tag:%ld id:%ld count:%d BSN:%d foreTagBSN:%d\r\n", rxID, packetRecv->tag, 176 | packetRecv->id, pFeedbackInfo->count,packetRecv->block_symbol_number,packetRecv->forTagBSN); 177 | #endif //DEBUG_RX 178 | } 179 | free(packetBSN); 180 | free(packetRecv); 181 | return 0; 182 | } 183 | /* 184 | Name: _FeedbackNotifierThread 185 | Description: The thread to send feedback information . 186 | Parameter: 187 | @lpParam : The id of the FeedbackNotifier. 188 | Return: 189 | */ 190 | iThreadStdCall_t _FeedbackNotifierThread(LPVOID lpParam) 191 | { 192 | raptorQFeedbackInfo_t *pFeedbackInfo = (raptorQFeedbackInfo_t*)malloc(sizeof(raptorQFeedbackInfo_t)); 193 | 194 | while (stateRun) { 195 | /* get feedback info */ 196 | if (pFeedbackInfo->count > 0) { 197 | /* send feedback with limit rate */ 198 | NetworkUDPSend(sockFeedback[0], pFeedbackInfo,sizeof(*pFeedbackInfo)); 199 | } 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | /* 206 | Name: _DecoderThread 207 | Description: The thread to decode the data. 208 | Parameter: 209 | @lpParam : The id of the Decoder. 210 | Return: 211 | */ 212 | 213 | iThreadStdCall_t _DecoderThread(LPVOID lpParam) 214 | { 215 | struct RaptorQ_ptr *hDec = NULL; 216 | uint32_t decID = (uint32_t)lpParam; 217 | raptorQBlock_t *pBlock = (raptorQBlock_t*)malloc(sizeof(raptorQBlock_t)); 218 | raptorQPacket_t *packetRecv = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 219 | recvInfo_t *pRecvInfo = NULL;; 220 | bool isFinished = false; 221 | 222 | while (stateRun) 223 | { 224 | /* get the pointer to current ring buffer */ 225 | 226 | iMutexLock(mutexFloorTag); //-->lock floorTag 227 | isFinished = false; 228 | decInfo_t *decInfo = (decInfo_t*)malloc(sizeof(decInfo_t)); 229 | decInfo->decTag = floorTag++; 230 | decInfo->decCount = 0; 231 | decInfo->isSetOTI = false; 232 | decInfo->BSN = BLOCK_SYMBOL_NUMBER; 233 | decInfo->esiExpect = 0; 234 | 235 | decInfo->rbDec = RingBufferInit(BLOCK_SYMBOL_NUMBER * 2, sizeof(raptorQPacket_t)); 236 | decInfo->rbOut = RingBufferInit(BLOCK_SYMBOL_NUMBER + 1, SYMBOL_SIZE); 237 | 238 | RingBufferPut(rbSwitcher, &decInfo); 239 | #ifdef DEBUG_DEC_START 240 | debug("[DEC_START%u]decTag:%u \r\n", decID, decInfo->decTag); 241 | #endif // DEBUG_DEC_START 242 | iMutexUnlock(mutexFloorTag);//-->unlock floorTag 243 | 244 | pRecvInfo = &recvInfoList[decInfo->decTag % RECV_INFO_LIST_LEN]; 245 | 246 | iSemaphoreWait(pRecvInfo->semaDec);// the receiver get a new tag will post this semaphore 247 | assert(pRecvInfo->tag == decInfo->decTag); 248 | 249 | while (stateRun) 250 | { 251 | /* get the package */ 252 | 253 | RingBufferGet(pRecvInfo->rbRecv, packetRecv); 254 | assert(packetRecv->tag == decInfo->decTag); 255 | 256 | /* if is notify BSN packet*/ 257 | if (packetRecv->type == PACKET_TYPE_BSN) { 258 | decInfo->BSN = packetRecv->block_symbol_number; 259 | if (decInfo->esiExpect == decInfo->BSN) isFinished = true; 260 | } 261 | else { 262 | /* block symbol number */ 263 | if (packetRecv->block_symbol_number < decInfo->BSN) { //set BSI 264 | decInfo->BSN = packetRecv->block_symbol_number; 265 | } 266 | if (packetRecv->type == PACKET_TYPE_REPAIR && !decInfo->isSetOTI) { //set OTI of raptore dec 267 | decInfo->OTI = packetRecv->oti; 268 | decInfo->isSetOTI = true; 269 | } 270 | 271 | /* put source symbol to output buffer */ 272 | if (decInfo->esiExpect < decInfo->BSN && decInfo->esiExpect == packetRecv->id && packetRecv->type== PACKET_TYPE_SOURCE) { 273 | RingBufferPut(decInfo->rbOut, packetRecv->data); 274 | decInfo->esiExpect++; 275 | } 276 | /* decode */ 277 | decInfo->decCount++; 278 | if (decInfo->decCount < decInfo->BSN + OVERHEAD) { 279 | /* decode add */ 280 | RingBufferPut(decInfo->rbDec, packetRecv); 281 | if (decInfo->esiExpect == decInfo->BSN) { 282 | isFinished = true; 283 | } 284 | } 285 | else 286 | { 287 | if (decInfo->decCount == decInfo->BSN + OVERHEAD) { 288 | assert(decInfo->isSetOTI); 289 | 290 | hDec = iRaptorQ_Dec(decInfo->OTI); // get decode handle 291 | raptorQPacket_t *packetDec = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 292 | for (uint32_t esi = 1; esi < decInfo->decCount; esi++) { 293 | RingBufferGet(decInfo->rbDec, packetDec); 294 | iRaptorQ_add_symbol_id(hDec, packetDec); 295 | } 296 | free(packetDec); 297 | } 298 | iRaptorQ_add_symbol_id(hDec, packetRecv); 299 | //ts=iGetTime(); 300 | if (decInfo->esiExpect == decInfo->BSN || iRaptorQ_decode(hDec, pBlock, decInfo->BSN*SYMBOL_SIZE)) { 301 | isFinished = true; 302 | RaptorQ_free(&hDec); 303 | // debug("[DECODED]tag:%d,esiExpect:%d,bsn:%d time:%d \r\n", decInfo->decTag,decInfo->esiExpect, decInfo->BSN,iGetTime()-ts); 304 | } 305 | } 306 | } 307 | if (isFinished) { 308 | iMutexLock(pRecvInfo->mutex); 309 | pRecvInfo->state = RECV_INFO_STATE_OUTPUT; 310 | iMutexUnlock(pRecvInfo->mutex); 311 | 312 | #ifdef DEBUG_Decode 313 | debug("\t\t\t\t\t[Decode %d] curTag:%u esiExpect:%u bsn:%u decTag:%u \r\n", 314 | (int)lpParam, curTag, decInfo->esiExpect, decInfo->BSN, decInfo->decTag); 315 | #endif // DEBUG_Decode 316 | 317 | /* store in output buffer */ 318 | if (decInfo->esiExpect != decInfo->BSN) { // output the rest of decode symbol 319 | for (uint32_t esi = decInfo->esiExpect; esi < decInfo->BSN; esi++) { 320 | RingBufferPut(decInfo->rbOut, pBlock->data + esi*SYMBOL_SIZE); 321 | } 322 | } 323 | 324 | RingBufferPut(decInfo->rbOut, pBlock->data); 325 | /* process after a block of decoding */ 326 | iMutexLock(mutexCurTag); 327 | curTag++; 328 | iMutexUnlock(mutexCurTag); 329 | 330 | if (pRecvInfo->tag >= RECV_WINDOW_LEN) { 331 | pRecvInfo = &recvInfoList[(pRecvInfo->tag - RECV_WINDOW_LEN) % RECV_INFO_LIST_LEN]; 332 | iMutexLock(pRecvInfo->mutex);//-->lock recvInfo 333 | _RecvInfoDeInit(pRecvInfo); 334 | iMutexUnlock(pRecvInfo->mutex); 335 | } 336 | 337 | break; // go to next decode progress 338 | } 339 | } 340 | 341 | #ifndef FAKE_RAPTORQ 342 | RaptorQ_free(&hDec); 343 | #endif 344 | 345 | } 346 | free(packetRecv); 347 | free(pBlock); 348 | 349 | return 0; 350 | } 351 | 352 | iThreadStdCall_t _OutputThread(LPVOID lpParam) { 353 | decInfo_t *decInfo=NULL; 354 | uint8_t pSymbol[SYMBOL_SIZE]; 355 | while (stateRun) 356 | { 357 | RingBufferGet(rbSwitcher, &decInfo); 358 | for (uint32_t esi = 0;;esi++) 359 | { 360 | RingBufferGet(decInfo->rbOut, pSymbol); 361 | if (esi < decInfo->BSN) { 362 | IOOutputDataPutSymbol(pSymbol); 363 | } 364 | else{ 365 | break; 366 | } 367 | } 368 | RingBufferDestroy(decInfo->rbDec); 369 | RingBufferDestroy(decInfo->rbOut); 370 | free(decInfo); 371 | 372 | } 373 | 374 | return 0; 375 | } 376 | /* 377 | Name: ReceiverInit 378 | Description: Initialize the Receiver. 379 | Parameter: 380 | Return: 381 | */ 382 | void ReceiverInit() 383 | { 384 | /* initialize values */ 385 | 386 | /* initialize locks */ 387 | 388 | iCreateMutex(mutexFloorTag, false); 389 | 390 | /* initialize ring buffers */ 391 | rbSwitcher = RingBufferInit(DECODER_NUMBER*3,sizeof(decInfo_t*)); 392 | 393 | /* initialize buffer sinks */ 394 | bufferSink=BufferSinkInit(5, BLOCK_SYMBOL_NUMBER * 2, sizeof(raptorQPacket_t)); 395 | 396 | /* initialize receive info list */ 397 | _RecvInfoListInit(); 398 | 399 | /* initialize sockets */ 400 | netAddr_t addrSend, addrRecv; 401 | 402 | #ifndef RELAY_MODE 403 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 404 | strcpy(addrSend.ip, ipTx[i]); 405 | addrSend.port = PORT_DATA_TX + i; 406 | strcpy(addrRecv.ip, ipRx[i]); 407 | addrRecv.port = PORT_DATA_RX + i; 408 | sockRecv[i] = NetworkUDPInit(&addrRecv, &addrSend);// receive 409 | } 410 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 411 | strcpy(addrSend.ip, ipRx[i]); 412 | addrSend.port = PORT_FEEDBACK_TX + i; 413 | strcpy(addrRecv.ip, ipTx[i]); 414 | addrRecv.port = PORT_FEEDBACK_RX + i; 415 | sockFeedback[i] = NetworkUDPInit(&addrSend, &addrRecv);// feedback send 416 | } 417 | #else 418 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 419 | strcpy(addrSend.ip, IP_RELAY); 420 | addrSend.port = PORT_RELAY_TX + i; 421 | strcpy(addrRecv.ip, ipRx[i]); 422 | addrRecv.port = PORT_DATA_RX + i; 423 | sockRecv[i] = NetworkUDPInit(&addrRecv, &addrSend);// receive 424 | } 425 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 426 | strcpy(addrSend.ip, ipRx[i]); 427 | addrSend.port = PORT_FEEDBACK_TX + i; 428 | strcpy(addrRecv.ip, IP_RELAY); 429 | addrRecv.port = PORT_RELAY_FEEDBACK_RX + i; 430 | sockFeedback[i] = NetworkUDPInit(&addrSend, &addrRecv);// feedback send 431 | } 432 | #endif // ! RELAY_MODE 433 | 434 | /* create a RTCPFeedback route */ 435 | RTCP_Forward_Recv_Init(); 436 | RTCP_Back_Send_Init(); 437 | /* RaptorQ pre */ 438 | iRaptorQ_pre(); 439 | 440 | /* Run I/O */ 441 | IOOutputInit(); 442 | /* create threads */ 443 | for (int i = 0; i < DATA_RX_NUMBER;i++) { 444 | iCreateThread(hThreadReceiver[i] , _DataReceiverThread, (LPVOID)i); 445 | } 446 | 447 | for (int i = 0; i < DECODER_NUMBER; i++) { 448 | iCreateThread(hThreadDecoder[i], _DecoderThread, (LPVOID)i); 449 | } 450 | iCreateThread(hThreadOutput, _OutputThread, NULL); 451 | } 452 | 453 | /* 454 | Name: ReceiverClose 455 | Description: Close the Receiver and release the memory. 456 | Parameter: 457 | Return: 458 | */ 459 | void ReceiverClose() 460 | { 461 | stateRun = false; 462 | for (int i = 0; i < CHANNEL_NUMBER;i++) { 463 | iThreadJoin(hThreadReceiver[i]); 464 | iThreadClose(hThreadReceiver[i]); 465 | iThreadJoin(hThreadFeedback[i]); 466 | iThreadClose(hThreadFeedback[i]); 467 | } 468 | 469 | for (int i = 0; i < DECODER_NUMBER; i++) { 470 | iThreadJoin(hThreadDecoder[i]); 471 | iThreadClose(hThreadDecoder[i]); 472 | } 473 | 474 | /* destory socket */ 475 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 476 | NetworkUDPClose(sockRecv[i]); 477 | NetworkUDPClose(sockFeedback[i]); 478 | } 479 | 480 | /* close buffer sink */ 481 | BufferSinkDestorySink(bufferSink); 482 | /* destory receive buffer list */ 483 | /* destory lock */ 484 | /* Close I/O */ 485 | IOOutputDeInit(); 486 | } 487 | -------------------------------------------------------------------------------- /src/receiver.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : receiver.h 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Encode the source data and transmit via UDP toreceiver. 7 | Check the feedback and coordinate the encode and transmitte 8 | pace. 9 | 10 | ------------------------------------------------------------------*/ 11 | #pragma once 12 | #include"cross_platform.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include"network.h" 22 | #include"ringbuffer.h" 23 | #include"iRaptorQ.h" 24 | #include"parameter.h" 25 | #include"io.h" 26 | #include"buffersink.h" 27 | 28 | /* 29 | Name: ReceiverInit 30 | Description: Initialize the Receiver. 31 | Parameter: 32 | Return: 33 | */ 34 | void ReceiverInit(); 35 | 36 | /* 37 | Name: ReceiverClose 38 | Description: Close the Receiver and release the memory. 39 | Parameter: 40 | Return: 41 | */ 42 | void ReceiverClose(); -------------------------------------------------------------------------------- /src/ringbuffer.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/ringbuffer.c -------------------------------------------------------------------------------- /src/ringbuffer.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : ringbuffer.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | You can use this module to create and initialize some ring 7 | buffers and get or put data to the buffer. 8 | ------------------------------------------------------------------*/ 9 | #pragma once 10 | 11 | #include"cross_platform.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | /* 19 | Name: ringBuffer_t 20 | Description: The data structure of ring buffer 21 | */ 22 | typedef struct ringBuffer_t 23 | { 24 | uint32_t number; // the number of storage unit in ring buffer 25 | uint32_t head, tail; // the index points to the head node and tail node. 26 | uint32_t unitSize; // the size of the storage unit 27 | iMutex_t hMutexHead; // lock the operation on the buffer 28 | iMutex_t hMutexTail; 29 | iSemaphore_t semEmpty; // the singal related to the number of empty and occupied storage unit 30 | iSemaphore_t semOccupied; 31 | void *buff[0]; // sotrage units 32 | }ringBuffer_t; 33 | 34 | /* 35 | Name: RingBufferInit 36 | Description: Allocate a ring buffer, of which the number and the 37 | size of storage unit are specified by the parameter. 38 | Parameter: 39 | @_number: the number of storage unit in a ringbuffer. 40 | @_size : the size of each storage unit. 41 | Return: A pointer to the allocated ring buffer. 42 | */ 43 | ringBuffer_t *RingBufferInit(uint32_t _number, uint32_t _sizeUnit); 44 | 45 | /* 46 | Name: RingBufferPut 47 | Description: Put data with specified length into a ring buffer. 48 | Parameter: 49 | @_pRb : A pointer to the ringbuffer. 50 | @_data : The address of data to be storeed in the ring buffer. 51 | Return: 52 | */ 53 | void RingBufferPut(ringBuffer_t *_pRb, void *_data); 54 | uint32_t RingBufferTryPut(ringBuffer_t *_pRb, void *_data); 55 | /* 56 | Name: RingBufferPut 57 | Description: Get data with specified length from a ring buffer. 58 | Parameter: 59 | @_pRb : A pointer to the ringbuffer. 60 | @_data : the address to stroe the got data. 61 | Return: 62 | */ 63 | void RingBufferGet(ringBuffer_t *_pRb, void *_data); 64 | 65 | /* 66 | Name: RingBufferTryGet 67 | Description: Get data with specified length from a ring buffer. 68 | If no data can be acquired, it will return immediately. 69 | Parameter: 70 | @_pRb : A pointer to the ringbuffer. 71 | @_data : the address to stroe the got data. 72 | Return: 73 | */ 74 | uint32_t RingBufferTryGet(ringBuffer_t *_pRb, void *_data); 75 | 76 | /* 77 | Name: RingBufferFlush 78 | Description: Flush the data stored in the buffer 79 | Parameter: 80 | @_pRb : A pointer to the ringbuffer. 81 | Return: 82 | */ 83 | void RingBufferFlush(ringBuffer_t *_pRb); 84 | 85 | /* 86 | Name: RingBufferDestroy 87 | Description: Destory the ring buffer and release the memory 88 | Parameter: 89 | @_pRb : A pointer to the ringbuffer. 90 | Return: 91 | */ 92 | void RingBufferDestroy(ringBuffer_t *_pRb); 93 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/976154779/FEC/4234f740107379f346f62395b9411055031cea4f/src/test.c -------------------------------------------------------------------------------- /src/testRaptorQ.c: -------------------------------------------------------------------------------- 1 | #include"iRaptorQ.h" 2 | #include"io.h" 3 | #include"err.h" 4 | #include 5 | 6 | DWORD WINAPI _EncThread1(LPVOID lpParam) { 7 | uint8_t encID = (uint8_t)lpParam; 8 | uint32_t esi; 9 | uint8_t *pBlockData = malloc(BLOCK_SIZE); 10 | raptorQBlock_t *pBlock = (raptorQBlock_t*)malloc(sizeof(raptorQBlock_t)); 11 | raptorQPacket_t *packetRepair = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 12 | struct RaptorQ_ptr *enc; 13 | 14 | for (int i = 0; i < 1; i++) { 15 | uint32_t BSN = rand() % 30 + 2; 16 | BSN = 32; 17 | printf("[%u][start%u] a tag:%u BSN:%d\r\n", (uint32_t)clock(), encID, i,BSN); 18 | /* RaptorQ pre */ 19 | //printf("[%u][start%u] b tag:%u\r\n", (uint32_t)clock(), encID, i); 20 | enc = iRaptorQ_Enc(pBlock->data, BSN*SYMBOL_SIZE); 21 | raptorQ_OTI_t myOTI; 22 | uint8_t res = iRaptorQ_GetOTI(enc, &myOTI); 23 | //printf("[%u][start%u] c tag:%u res=%d\r\n", (uint32_t)clock(), encID, i,res); 24 | RaptorQ_precompute(enc, 0, TRUE); 25 | //Sleep(40); 26 | //printf("[%u][start%u] d tag:%u\r\n", (uint32_t)clock(), encID, i); 27 | esi = BSN; 28 | while (1) { 29 | if (esi < BSN + 10) { 30 | printf("[%u][enc%u] esi:%u tag:%u\r\n", (uint32_t)clock(), encID, esi, i); 31 | iRaptorQ_encode_id(enc, packetRepair, pBlock->tag, 0, esi++); //generate repair symbols. 32 | printf("[%u][over%u] esi:%u tag:%u\r\n", (uint32_t)clock(), encID, esi - 1, i); 33 | } 34 | else 35 | { 36 | break; 37 | } 38 | } 39 | /* free to idle state */ 40 | RaptorQ_free(&enc); 41 | } 42 | _endthreadex(0); 43 | return 0; 44 | } 45 | 46 | 47 | void main() 48 | { 49 | HWND hThreadEnc[16]; 50 | printf("start!\r\n"); 51 | iRaptorQ_pre(); 52 | 53 | for (int i = 0; i < 8; i++) 54 | { 55 | hThreadEnc[i] = (HWND)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)_EncThread1, (void*)i, 0, NULL); // returns the thread identifier 56 | } 57 | for (int i = 0; i < 8; i++) 58 | { 59 | WaitForSingleObject(hThreadEnc[i],INFINITE); 60 | CloseHandle(hThreadEnc[i]); 61 | } 62 | printf("over!\r\n"); 63 | } -------------------------------------------------------------------------------- /src/testReceive.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : videoSend.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Set the I/O interface and start the vedio realtime 7 | transmit program. 8 | ------------------------------------------------------------------*/ 9 | #include"cross_platform.h" 10 | #include"ringbuffer.h" 11 | #include"transmitter.h" 12 | #include"receiver.h" 13 | #include"io.h" 14 | #include"err.h" 15 | 16 | iThread_t hThreadRecv; 17 | 18 | static netInfo_t* sockSend=NULL; 19 | 20 | iThreadStdCall_t RecvThread(LPVOID lpParam) 21 | { 22 | Data_t myData; 23 | IODataInfo_t myDataInfo; 24 | DataFb_t myDataFb; 25 | 26 | while (1) 27 | { 28 | IO_OutputData(&myDataInfo); 29 | memcpy(&myData, myDataInfo.data, myDataInfo.len); 30 | myDataFb.id = myData.id; 31 | myDataFb.ts = myData.ts; 32 | NetworkUDPSend(sockSend,&myDataFb,sizeof(myDataFb)); 33 | //debug("[DATA_OUT] id=%d ,strLen:%d\r\n",myData.id, myData.len); 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | void main() 40 | { 41 | 42 | #ifdef OS_LINUX 43 | initStartTime(); 44 | #endif 45 | 46 | #ifdef IO_NETWORK_MODE 47 | #ifdef OS_WINDOWS 48 | //WinExec("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe udp://@127.0.0.1:1150 :network-caching=2000", SW_SHOWNORMAL); 49 | #endif 50 | #endif // IO_NETWORK_MODE 51 | #ifndef IO_NETWORK_MODE 52 | netAddr_t addrSend, addrRecv; 53 | strcpy(addrSend.ip,IP_RX_0); 54 | addrSend.port = 3510; 55 | strcpy(addrRecv.ip, IP_TX_0); 56 | addrRecv.port = 3520; 57 | sockSend = NetworkUDPInit(&addrSend, &addrRecv); 58 | #endif 59 | ReceiverInit(); 60 | printf("ReceiverInit ok!\r\n"); 61 | #ifndef IO_NETWORK_MODE 62 | iCreateThread(hThreadRecv, RecvThread,0); // returns the thread identifier 63 | #endif 64 | #ifdef IO_NETWORK_MODE 65 | #ifdef OS_WINDOWS 66 | #ifdef X64 67 | system("E:\\lab\\sw\\RQS\\x64\\Debug\\vlcR.bat"); 68 | #else 69 | //system("E:\\lab\\src\\FountainVideo\\Debug\\vlcR.bat"); 70 | #endif // X64 71 | #endif 72 | #endif // IO_NETWORK_MODE 73 | 74 | #ifdef OS_WINDOWS 75 | system("pause"); 76 | #endif 77 | #ifdef OS_LINUX 78 | pause(); 79 | #endif 80 | ReceiverClose(); 81 | printf("ReceiverClose ok!\r\n"); 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/testSend.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : videoSend.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Set the I/O interface and start the vedio realtime 7 | transmit program. 8 | ------------------------------------------------------------------*/ 9 | #include"ringbuffer.h" 10 | #include"transmitter.h" 11 | #include"receiver.h" 12 | #include"io.h" 13 | #include"err.h" 14 | #include"cross_platform.h" 15 | 16 | static netInfo_t *sockRecv=NULL; 17 | 18 | iThread_t hThreadSend; 19 | iThread_t hThreadFbChecher; 20 | 21 | iThreadStdCall_t SendThread(LPVOID lpParam) 22 | { 23 | Data_t myData; 24 | IODataInfo_t myDataInfo; 25 | uint32_t id = 0; 26 | tokenBucket_t myBucket; 27 | myBucket.tokenNum = 0; 28 | myBucket.produceTime = 0; 29 | myBucket.limitFlowSpeed = BYTE_RATE_DEFAULT / 1000 / 2; 30 | myBucket.limitMaxFlowSpeed = (uint32_t)BYTE_RATE_DEFAULT / 2; 31 | 32 | char myStr[] = "HelloWord "; 33 | while (1) 34 | { 35 | myData.len = strlen(myStr); 36 | myData.id = id++; 37 | strcpy(myData.data, myStr); 38 | myDataInfo.len = sizeof(myData); 39 | while (_GetToken(&myBucket, myDataInfo.len) == 0) { 40 | iSleep(1); 41 | } 42 | //debug("[DATA_IN] id=%d\r\n", myData.id); 43 | myData.ts = iGetTime(); 44 | memcpy(myDataInfo.data, &myData, myDataInfo.len); 45 | IO_InputData(&myDataInfo); 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | iThreadStdCall_t FbChecherThread(LPVOID lpParam) { 52 | DataFb_t myDataFb; 53 | while (1) 54 | { 55 | int res=NetworkUDPReceive(sockRecv,&myDataFb,sizeof(myDataFb)); 56 | debug("[DataFb] id=%ld,delay=%ld \r\n", myDataFb.id, iGetTime() - myDataFb.ts); 57 | } 58 | } 59 | 60 | void main() 61 | { 62 | #ifdef OS_LINUX 63 | initStartTime(); 64 | #endif // OS_LINUX 65 | #ifndef IO_NETWORK_MODE 66 | netAddr_t addrSend, addrRecv; 67 | strcpy(addrSend.ip, IP_RX_0); 68 | addrSend.port = 3510; 69 | strcpy(addrRecv.ip, IP_TX_0); 70 | addrRecv.port = 3520; 71 | sockRecv = NetworkUDPInit(&addrRecv, &addrSend); 72 | #endif // ! IO_NETWORK_MODE 73 | TransmitterInit(); 74 | printf("TransmitterInit ok! \r\n"); 75 | #ifndef IO_NETWORK_MODE 76 | iCreateThread(hThreadSend, SendThread, NULL); // returns the thread identifier 77 | iCreateThread(hThreadFbChecher, FbChecherThread, NULL); // returns the thread identifier 78 | #endif // ! IO_NETWORK_MODE 79 | #ifdef IO_NETWORK_MODE 80 | #ifdef OS_WINDOWS 81 | #ifdef X64 82 | system("E:\\lab\\sw\\RQS\\x64\\Debug\\vlcT.bat"); 83 | #else 84 | //system("E:\\lab\\src\\FountainVideo\\Debug\\vlcT.bat"); 85 | #endif // X64 86 | #endif 87 | #endif // IO_NETWORK_MODE 88 | #ifdef OS_WINDOWS 89 | system("pause"); 90 | #endif 91 | #ifdef OS_LINUX 92 | pause(); 93 | #endif 94 | TransmitterClose(); 95 | printf("TransmitterClose ok!\r\n"); 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/testStructure.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | -------------------------------------------------------------------------------- /src/transmitter.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : transmitter.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Receive the encoded data form transmitter and decode it and 7 | send feedback to transmitter immediately. 8 | ------------------------------------------------------------------*/ 9 | #include"transmitter.h" 10 | #include"cross_platform.h" 11 | #include"err.h" 12 | #ifdef DELAY_MEASURE 13 | #include 14 | #endif // DELAY_MEASURE 15 | 16 | enum ENC_STATE 17 | { 18 | ENC_STATE_IDLE, 19 | ENC_STATE_SOURCE, 20 | ENC_STATE_REPAIR, 21 | ENC_STATE_OVER, 22 | ENC_STATE_OVER_PROC 23 | }; 24 | 25 | typedef struct encInfo_t { 26 | uint32_t encTag; 27 | uint32_t BSN; 28 | uint32_t foreTagBSN; 29 | //ringBuffer_t *rbSource; 30 | ringBuffer_t *rbRepair; 31 | uint8_t priority; 32 | uint8_t encState; 33 | raptorQ_OTI_t myOTI; 34 | iMutex_t mutexEncState; 35 | uint8_t nOverHead; 36 | uint8_t *pBlockData; 37 | struct RaptorQ_ptr *enc; 38 | struct encInfo_t *back; 39 | struct encInfo_t *next; 40 | }encInfo_t; 41 | 42 | extern char *ipTx[]; 43 | extern char *ipRx[]; 44 | 45 | static bool stateRun = true; 46 | static iThread_t hThreadFeedbackChecker[FEEDBACK_RX_NUMBER]; 47 | static iThread_t hThreadTransmitter[DATA_TX_NUMBER]; 48 | static iThread_t hThreadEncoder[ENCODER_NUMBER]; 49 | static iThread_t hThreadSource[SOURCE_NUMBER]; 50 | static netInfo_t *sockFeedback[CHANNEL_NUMBER]; 51 | static netInfo_t *sockTransmit[CHANNEL_NUMBER]; 52 | static ringBuffer_t *rbEncode=NULL; 53 | static ringBuffer_t *rbSource=NULL; 54 | static uint8_t foreTagBSN=0; 55 | static int encBuffState[ENCODER_NUMBER] = { 0 }; // if '1' the encode buffer is not empty. 56 | static int encPriority[ENCODER_NUMBER] = {0}; 57 | 58 | static uint32_t curTag = 0; 59 | static uint32_t floorTag = 0; 60 | static iMutex_t mutexEncTag = iMUTEX_INIT_VALUE; //mutex for get encode block, store encoder ID, increase floorTag 61 | static iMutex_t mutexFloorTag = iMUTEX_INIT_VALUE; 62 | static iSemaphore_t semaSource ; 63 | 64 | static iMutex_t mutexFbc = iMUTEX_INIT_VALUE; 65 | static iMutex_t mutexPriority = iMUTEX_INIT_VALUE; 66 | 67 | static encInfo_t *encInfoIndex[ENCODER_INFO_INDEX_LEN]; 68 | static encInfo_t *priorityHead = NULL; 69 | static encInfo_t *priorityTail = NULL; 70 | static encInfo_t *priorityCur = NULL; //current encInfo 71 | static uint8_t priorityMax=0; 72 | 73 | void _PriorityNew(encInfo_t *_encInfo); 74 | void _PriorityDelete(encInfo_t *_encInfo); 75 | void _PriorityDecrease(encInfo_t* _encInfo); 76 | 77 | iThreadStdCall_t _SourceThread(LPVOID lpParam); 78 | iThreadStdCall_t _EncoderThread(LPVOID lpParam); 79 | iThreadStdCall_t _DataTransmitterThread(LPVOID lpParam); 80 | iThreadStdCall_t _FeedbackCheckerThread(LPVOID lpParam); 81 | 82 | void _PriorityNew(encInfo_t *_encInfo) { 83 | 84 | iMutexLock(mutexPriority); //lock all the priority 85 | encInfo_t *pInfo = priorityHead; 86 | while (pInfo !=NULL) 87 | { 88 | pInfo->priority++; 89 | pInfo = pInfo->next; 90 | } 91 | _encInfo->priority = 1; 92 | 93 | if (priorityHead == NULL) { 94 | _encInfo->next = NULL; 95 | _encInfo->back = NULL; 96 | priorityHead = _encInfo; 97 | priorityTail = _encInfo; 98 | priorityCur = _encInfo; 99 | } 100 | else 101 | { 102 | _encInfo->next = NULL; 103 | _encInfo->back = priorityTail; 104 | priorityTail->next = _encInfo; 105 | priorityTail = _encInfo; 106 | } 107 | 108 | iMutexUnlock(mutexPriority); 109 | } 110 | 111 | void _PriorityDecrease(encInfo_t *_encInfo) 112 | { 113 | if(_encInfo->priority>1)_encInfo->priority--; 114 | encInfo_t *pNext = _encInfo->next; 115 | if (pNext == NULL) { 116 | return; 117 | } 118 | while (pNext != NULL) 119 | { 120 | /* search node */ 121 | if ((pNext->priority < _encInfo->priority)|| 122 | (pNext->priority == _encInfo->priority && pNext->encTag>_encInfo->encTag)){ 123 | 124 | if (pNext == _encInfo->next)break; 125 | /* priorityCur */ 126 | if (priorityCur == _encInfo) { 127 | priorityCur = _encInfo->next; 128 | } 129 | /* delete node */ 130 | _encInfo->next->back = _encInfo->back; 131 | if (_encInfo->back != NULL) { 132 | _encInfo->back->next = _encInfo->next; 133 | }else{ 134 | priorityHead = _encInfo->next; 135 | } 136 | /* insert node */ 137 | _encInfo->back = pNext->back; 138 | _encInfo->next = pNext; 139 | 140 | pNext->back->next = _encInfo; 141 | pNext->back = _encInfo; 142 | 143 | return; 144 | } 145 | pNext = pNext->next; 146 | } 147 | if (pNext == NULL) { 148 | if (priorityCur == _encInfo) { 149 | priorityCur = _encInfo->next; 150 | } 151 | /* delete node */ 152 | _encInfo->next->back = _encInfo->back; 153 | if (_encInfo->back != NULL) { 154 | _encInfo->back->next = _encInfo->next; 155 | } 156 | else { 157 | priorityHead = _encInfo->next; 158 | } 159 | /* insert node */ 160 | _encInfo->next = NULL; 161 | _encInfo->back = priorityTail; 162 | 163 | priorityTail->next = _encInfo; 164 | priorityTail = _encInfo; 165 | } 166 | 167 | } 168 | 169 | void _PriorityDelete(encInfo_t *_encInfo) 170 | { 171 | iMutexLock(mutexPriority); //lock all the priority 172 | 173 | if (_encInfo->back == NULL) { // first node 174 | priorityHead = _encInfo->next; 175 | } 176 | else{ 177 | _encInfo->back->next = _encInfo->next; 178 | } 179 | 180 | if (_encInfo->next == NULL) { // last node 181 | priorityTail = _encInfo->back; 182 | } 183 | else{ 184 | _encInfo->next->back= _encInfo->back; 185 | } 186 | if (priorityCur == _encInfo) { 187 | priorityCur = (_encInfo->next==NULL?priorityHead: _encInfo->next); 188 | } 189 | iMutexUnlock(mutexPriority); 190 | } 191 | 192 | iThreadStdCall_t _SourceThread(LPVOID lpParam) { 193 | uint8_t *pBlockData = (uint8_t*)malloc(BLOCK_SIZE); 194 | raptorQPacket_t *packetRepair = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 195 | 196 | while (stateRun) 197 | { 198 | 199 | encInfo_t *encInfo = (encInfo_t*)malloc(sizeof(encInfo_t)); 200 | encInfo->nOverHead = BLOCK_SYMBOL_NUMBER; 201 | iCreateMutex(encInfo->mutexEncState, false); 202 | encInfo->BSN = BLOCK_SYMBOL_NUMBER; //must be initilized with a maxmum value first. 203 | //encInfo->rbSource = RingBufferInit(BLOCK_SYMBOL_NUMBER + 1, sizeof(raptorQPacket_t)); 204 | encInfo->rbRepair = RingBufferInit(OVERHEAD, sizeof(raptorQPacket_t)); 205 | encInfo->pBlockData = (uint8_t*)malloc(BLOCK_SIZE); 206 | 207 | iMutexLock(mutexFloorTag); 208 | iSemaphoreWait(semaSource); 209 | 210 | encInfo->encTag = floorTag++; 211 | encInfo->foreTagBSN = foreTagBSN; 212 | encInfo->encState = ENC_STATE_IDLE; 213 | //set index array 214 | encInfoIndex[encInfo->encTag%ENCODER_INFO_INDEX_LEN] = encInfo; 215 | //add to priority link list 216 | encInfo->encState = ENC_STATE_SOURCE; 217 | _PriorityNew(encInfo); 218 | 219 | encInfo->BSN = IOInputDataGetBlock(rbSource, encInfo->pBlockData, encInfo->encTag,encInfo->foreTagBSN); //return the real Block Symbol Number 220 | // put a encInfo to rbRepair to start encoding 221 | foreTagBSN = encInfo->BSN; 222 | debug("[SOURCE]tag:%d bsn:%d\r\n",encInfo->encTag,encInfo->BSN); 223 | RingBufferPut(rbEncode, &encInfo); 224 | 225 | iMutexUnlock(mutexFloorTag); 226 | 227 | } 228 | free(packetRepair); 229 | free(pBlockData); 230 | 231 | return 0; 232 | } 233 | 234 | /* 235 | Name: _EncoderThread 236 | Description: Thread to encoded data. 237 | Parameter: 238 | @lpParam : The id of the encoder. 239 | Return: 240 | */ 241 | iThreadStdCall_t _EncoderThread(LPVOID lpParam) 242 | { 243 | uint8_t encID = (uint8_t)lpParam; 244 | encInfo_t *encInfo = NULL; 245 | 246 | raptorQPacket_t *packetRepair = (raptorQPacket_t*)malloc(sizeof(raptorQPacket_t)); 247 | 248 | uint32_t esi=0; 249 | 250 | while (stateRun) 251 | { 252 | RingBufferGet(rbEncode, &encInfo); 253 | 254 | encInfo->enc = iRaptorQ_Enc(encInfo->pBlockData, encInfo->BSN * SYMBOL_SIZE); 255 | iRaptorQ_GetOTI(encInfo->enc, &encInfo->myOTI); 256 | #ifdef DEBUG_ENC 257 | debug("[ENC %u]enc tag:%d \r\n", (uint32_t)encID, encInfo->encTag); 258 | #endif // DEBUG_ENC_REPAIR 259 | RaptorQ_precompute(encInfo->enc, 0, true); 260 | 261 | esi = encInfo->BSN; 262 | 263 | while (stateRun) { 264 | if (esi < RaptorQ_max_repair(encInfo->enc, 0)) { 265 | 266 | #ifdef DEBUG_ENC_REPAIR 267 | debug("[ENC_REPAIR %u]enc tag:%d esi:%d\r\n", (uint32_t)encID, encInfo->encTag, esi); 268 | #endif // DEBUG_ENC_REPAIR 269 | 270 | iRaptorQ_encode_id(encInfo->enc, packetRepair, encInfo->encTag, 0, esi); //generate repair symbols. 271 | packetRepair->block_symbol_number = encInfo->BSN; 272 | packetRepair->forTagBSN = encInfo->foreTagBSN; 273 | packetRepair->oti = encInfo->myOTI; 274 | packetRepair->type = PACKET_TYPE_REPAIR; 275 | if (esi < encInfo->BSN + OVERHEAD + 2) { 276 | RingBufferPut(rbSource,packetRepair); 277 | } 278 | else { 279 | RingBufferPut(encInfo->rbRepair, packetRepair); //sotre in ring buffer 280 | } 281 | esi++; 282 | 283 | if (encInfo->encState == ENC_STATE_OVER) { 284 | /* free to idle state */ 285 | encInfo->encState = ENC_STATE_OVER_PROC; 286 | RaptorQ_free(&encInfo->enc); 287 | free(encInfo->pBlockData); 288 | free(encInfo); 289 | break; 290 | } 291 | } 292 | else { 293 | perror("out of max repair id! \r\n"); 294 | exit(1); 295 | } 296 | } 297 | } 298 | 299 | return 0; 300 | } 301 | /* 302 | Name: _DataTransmitterThread 303 | Description: Thread to transmit the encoded data. 304 | Parameter: 305 | @lpParam : The id of the transmitter. 306 | Return: 307 | */ 308 | iThreadStdCall_t _DataTransmitterThread(LPVOID lpParam) 309 | { 310 | raptorQPacket_t packetSend; 311 | uint32_t txID = (uint32_t)lpParam % CHANNEL_NUMBER; 312 | encInfo_t *pInfo = NULL; 313 | bool isGet = false; 314 | iClock_t ts; 315 | while (stateRun) { 316 | isGet = false; 317 | ts=iGetTime(); 318 | if(RingBufferTryGet(rbSource,&packetSend)){ 319 | isGet = true; 320 | } 321 | else{ 322 | if(iMutexTryLock(mutexPriority)==0){ 323 | if (priorityCur != NULL ){ 324 | pInfo = priorityCur; //gei the pointor at the currentnode need to be process 325 | priorityCur = (priorityCur->next == NULL ? priorityCur = priorityHead : priorityCur->next); 326 | if(RingBufferTryGet(pInfo->rbRepair, &packetSend)){ 327 | isGet = true; 328 | if (--pInfo->nOverHead == 0) { // Finishing sending a number of overhead repair packets, the priority decressed. 329 | pInfo->nOverHead = OVERHEAD; 330 | _PriorityDecrease(pInfo); 331 | } 332 | if (priorityCur != NULL && pInfo->priority != priorityCur->priority)priorityCur = priorityHead; // Current node is not the maxmum priority node, then the priority jump to the head of node list 333 | } 334 | } 335 | iMutexUnlock(mutexPriority); 336 | } 337 | } 338 | if (isGet) { 339 | #ifdef DEBUG_TX 340 | debug("\t\t[TX%u] tag:%ld id:%ld time:%d\r\n", (uint32_t)lpParam, packetSend.tag, packetSend.id,iGetTime()-ts); 341 | #endif //DEBUG_TX 342 | NetworkUDPSendLimit(sockTransmit[txID], &packetSend, sizeof(packetSend), (uint32_t)BYTE_RATE_DEFAULT); 343 | } 344 | } 345 | return 0; 346 | } 347 | 348 | /* 349 | Name: _FeedbackCheckerThread 350 | Description: Thread to check the feedback. 351 | Parameter: 352 | @lpParam : The id of the feeddback checker. 353 | Return: 354 | */ 355 | 356 | iThreadStdCall_t _FeedbackCheckerThread(LPVOID lpParam) 357 | { 358 | int fbrID = (uint32_t)lpParam % CHANNEL_NUMBER; 359 | int oldID = 0; 360 | int recvN = 0; 361 | raptorQFeedbackInfo_t pFeedbackInfo; 362 | raptorQPacket_t packet; 363 | encInfo_t *encInfo = NULL; 364 | 365 | while (stateRun) 366 | { 367 | /* receive feedback */ 368 | recvN = NetworkUDPReceive(sockFeedback[fbrID], &pFeedbackInfo, sizeof(raptorQFeedbackInfo_t)); 369 | if (recvN>0) { 370 | 371 | #ifdef DELAY_MEASURE 372 | pFeedbackInfo.ts[3] = iGetTime(); 373 | #endif // DELAY_MEASURE 374 | 375 | encInfo = encInfoIndex[pFeedbackInfo.tag % ENCODER_INFO_INDEX_LEN]; 376 | 377 | iMutexLock(mutexFbc); //different tag do not use the same mutex 378 | /* filter: pass the old feedback */ 379 | if (encInfoIndex[pFeedbackInfo.tag % ENCODER_INFO_INDEX_LEN] == NULL || 380 | encInfo->encTag != pFeedbackInfo.tag) { 381 | iMutexUnlock(mutexFbc); //unlock mutexEncState 382 | continue; 383 | } 384 | /* check the feedback */ 385 | if (pFeedbackInfo.count >= encInfo->BSN + OVERHEAD){ 386 | _PriorityDelete(encInfo); 387 | encInfoIndex[pFeedbackInfo.tag % ENCODER_INFO_INDEX_LEN] = NULL; 388 | iMutexUnlock(mutexFbc); //unlock mutexEncState 389 | iSemaphorePost(semaSource, 1); 390 | ringBuffer_t *rbRepair = encInfo->rbRepair; 391 | encInfo->encState = ENC_STATE_OVER; // must be sure the new buffer is ready ,then initialize the old encoder thread. 392 | 393 | while (encInfo->encState == ENC_STATE_OVER){ 394 | RingBufferTryGet(rbRepair, &packet); 395 | } 396 | RingBufferDestroy(rbRepair); 397 | } 398 | else{ 399 | iMutexUnlock(mutexFbc); //unlock curTag 400 | } 401 | #ifdef DEBUG_FB 402 | //if (iGetTime()-pFeedbackInfo.ts[0]>1) { 403 | debug("\t\t\t\t[FB%u]tag:%ld id:%ld count:%ld \tdelayOut:%ld \t(a:%ld,b:%ld,c:%ld,d:%ld) \r\n", 404 | (uint32_t)lpParam, 405 | pFeedbackInfo.tag, 406 | pFeedbackInfo.id, 407 | pFeedbackInfo.count, 408 | iGetTime() - pFeedbackInfo.ts[0], // delay: out 409 | pFeedbackInfo.ts[1] - pFeedbackInfo.ts[0], //delay: send 410 | pFeedbackInfo.ts[2] - pFeedbackInfo.ts[1], //delay: receive and process 411 | pFeedbackInfo.ts[3] - pFeedbackInfo.ts[2], //delay: feedback send 412 | iGetTime() - pFeedbackInfo.ts[3] 413 | ); //delay: feedback check progress 414 | 415 | #endif //DEBUG 416 | } 417 | } 418 | return 0; 419 | } 420 | /* 421 | Name: TransmitterInit 422 | Description: Initialize the transmitter 423 | Parameter: 424 | Return: 425 | */ 426 | void TransmitterInit() 427 | { 428 | /* initialize value */ 429 | 430 | /* initialize lock */ 431 | 432 | iCreateMutex(mutexFloorTag, false ); 433 | iCreateMutex(mutexPriority, false ); 434 | iCreateMutex(mutexFbc, false); 435 | iCreateSemaphore(semaSource, ENCODER_WINDOW_LEN, ENCODER_WINDOW_LEN); 436 | /* initialize encoder ring buffer and variants */ 437 | 438 | rbEncode = RingBufferInit(ENCODER_WINDOW_LEN,sizeof(encInfo_t*)); 439 | rbSource = RingBufferInit(ENCODER_WINDOW_LEN*BLOCK_SYMBOL_NUMBER,sizeof(raptorQPacket_t)); 440 | /* create and set up socket */ 441 | netAddr_t addrSend; 442 | netAddr_t addrRecv; 443 | #ifndef RELAY_MODE 444 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 445 | strcpy(addrSend.ip, ipTx[i]); 446 | addrSend.port = PORT_DATA_TX + i; 447 | strcpy(addrRecv.ip, ipRx[i]); 448 | addrRecv.port = PORT_DATA_RX + i; 449 | sockTransmit[i] = NetworkUDPInit(&addrSend, &addrRecv); //send 450 | } 451 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 452 | strcpy(addrSend.ip, ipRx[i]); 453 | addrSend.port = PORT_FEEDBACK_TX + i; 454 | strcpy(addrRecv.ip, ipTx[i]); 455 | addrRecv.port = PORT_FEEDBACK_RX + i; 456 | sockFeedback[i] = NetworkUDPInit(&addrRecv, &addrSend); //feedback receive 457 | } 458 | #else 459 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 460 | strcpy(addrSend.ip, ipTx[i]); 461 | addrSend.port = PORT_DATA_TX + i; 462 | strcpy(addrRecv.ip, IP_RELAY); 463 | addrRecv.port = PORT_RELAY_RX+i; 464 | sockTransmit[i] = NetworkUDPInit(&addrSend, &addrRecv); //send 465 | } 466 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 467 | strcpy(addrSend.ip, IP_RELAY); 468 | addrSend.port = PORT_RELAY_FEEDBACK_TX + i; 469 | strcpy(addrRecv.ip, ipTx[i]); 470 | addrRecv.port = PORT_FEEDBACK_RX + i; 471 | sockFeedback[i] = NetworkUDPInit(&addrRecv, &addrSend); //feedback receive 472 | } 473 | #endif // !RELAY_MODE 474 | 475 | RTCP_Forward_Send_Init(); 476 | RTCP_Back_Recv_Init(); 477 | 478 | /* RaptorQ pre */ 479 | iRaptorQ_pre(); 480 | /* Run I/O */ 481 | IOInputInit(); 482 | /* create thread */ 483 | for (int i = 0; i < ENCODER_NUMBER; i++) { 484 | iCreateThread(hThreadEncoder[i], _EncoderThread,(LPVOID)i); 485 | } 486 | 487 | /* Main Thread */ 488 | for (int i = 0; i < DATA_TX_NUMBER; i++) { 489 | iCreateThread(hThreadTransmitter[i], _DataTransmitterThread,(LPVOID)i); 490 | } 491 | for (int i = 0; i < FEEDBACK_RX_NUMBER; i++) { 492 | iCreateThread(hThreadFeedbackChecker[i], _FeedbackCheckerThread,(LPVOID)i); 493 | } 494 | 495 | for (int i = 0; i < SOURCE_NUMBER; i++) { 496 | iCreateThread(hThreadSource[i], _SourceThread,(LPVOID)i); 497 | } 498 | 499 | } 500 | /* 501 | Name: TransmitterInit 502 | Description: Close the transmitter and release the memory 503 | Parameter: 504 | Return: 505 | */ 506 | void TransmitterClose() 507 | { 508 | stateRun = false; 509 | for (int i = 0; i < FEEDBACK_RX_NUMBER; i++) { 510 | iThreadJoin(hThreadFeedbackChecker[i]); 511 | iThreadClose(hThreadFeedbackChecker[i]); 512 | } 513 | for (int i = 0; i < ENCODER_NUMBER; i++) { 514 | iThreadJoin(hThreadEncoder[i]); 515 | iThreadClose(hThreadEncoder[i]); 516 | } 517 | for (int i = 0; i < DATA_TX_NUMBER; i++) { 518 | iThreadJoin(hThreadTransmitter[i]); 519 | iThreadClose(hThreadTransmitter[i]); 520 | } 521 | /* destory socket */ 522 | for (int i = 0; i < CHANNEL_NUMBER; i++) { 523 | NetworkUDPClose(sockTransmit[i]); 524 | NetworkUDPClose(sockFeedback[i]); 525 | } 526 | /* destory buffer */ 527 | 528 | /* destory lock */ 529 | 530 | /* Close I/O */ 531 | IOInputDeInit(); 532 | } 533 | -------------------------------------------------------------------------------- /src/transmitter.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------- 2 | File Name : transmitter.c 3 | Author : Winglab 4 | Data : 2016-12-29 5 | Description: 6 | Receive the encoded data form transmitter and decode it and 7 | send feedback to transmitter immediately. 8 | ------------------------------------------------------------------*/ 9 | #pragma once 10 | #include"cross_platform.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include"network.h" 18 | #include"ringbuffer.h" 19 | #include"iRaptorQ.h" 20 | #include"parameter.h" 21 | #include"io.h" 22 | 23 | /* 24 | Name: TransmitterInit 25 | Description: Initialize the transmitter 26 | Parameter: 27 | Return: 28 | */ 29 | void TransmitterInit(); 30 | 31 | /* 32 | Name: TransmitterInit 33 | Description: Close the transmitter and release the memory 34 | Parameter: 35 | Return: 36 | */ 37 | void TransmitterClose(); 38 | --------------------------------------------------------------------------------