UseFEC.h
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifndef __USEFEC_H_C5A7E8776574FE__
00042 #define __USEFEC_H_C5A7E8776574FE__
00043
00044
00045 #if !defined(__AVR__)
00046
00047
00048 #include "debug.h"
00049 #include "util/endianness.h"
00050
00051 #include "mw/afp/shared/expandrange_cast.h"
00052 #include "mw/afp/shared/div_round_up.h"
00053
00054 #include <string.h>
00055
00056
00057 namespace famouso {
00058 namespace mw {
00059 namespace afp {
00060 namespace frag {
00061
00062
00063 namespace vandermonde_fec {
00064 extern "C" {
00065
00066 #include "fec.h"
00067 }
00068 }
00069
00070
00078 template <class FCP>
00079 class UseFEC {
00080
00081 typedef typename FCP::SizeProp::elen_t elen_t;
00082 typedef typename FCP::SizeProp::flen_t flen_t;
00083 typedef typename FCP::SizeProp::fcount_t fcount_t;
00084
00085 typedef typename FCP::FECRedundancy Redundancy;
00086 typedef typename FCP::Allocator Allocator;
00087
00088
00090 elen_t event_length;
00091
00093 fcount_t k;
00094
00096 fcount_t n;
00097
00099 const uint8_t ** nonred_fragments;
00100
00102 fcount_t next_fragment_idx;
00103
00105 bool smaller_fragment;
00106
00108 flen_t payload_length;
00109
00111 void * fec_code;
00112
00114 struct __attribute__((packed)) Header1001 {
00115 uint8_t head;
00116 uint8_t red;
00117 uint32_t k;
00118 uint16_t len_rest;
00119 };
00120
00122 uint16_t header_len_rest;
00123
00124
00126 static fcount_t get_redundancy_fragment_count(fcount_t k, uint8_t redundancy) {
00127 return shared::div_round_up(shared::expandrange_cast(k) * redundancy,
00128 shared::expandrange_cast((fcount_t)100));
00129 }
00130
00131 public:
00132
00134 enum { header_length = sizeof(Header1001) };
00135
00136
00142 static fcount_t k2n(fcount_t k) {
00143 return k + get_redundancy_fragment_count(k, Redundancy::value());
00144 }
00145
00147 UseFEC() :
00148 nonred_fragments(0), next_fragment_idx(0),
00149 smaller_fragment(false), fec_code(0) {
00150 }
00151
00153 ~UseFEC() {
00154 if (smaller_fragment)
00155 Allocator::free(const_cast<uint8_t *>(nonred_fragments[k-1]));
00156 if (fec_code)
00157 vandermonde_fec::fec_free(fec_code);
00158 if (nonred_fragments)
00159 Allocator::free_array(nonred_fragments);
00160 }
00161
00168 void init(elen_t event_length, flen_t payload_length, fcount_t k) {
00169 FAMOUSO_ASSERT(payload_length > 0);
00170
00171 this->event_length = event_length;
00172 this->k = k;
00173 this->n = k2n(k);
00174 this->payload_length = payload_length;
00175 this->nonred_fragments = Allocator::template alloc_array<const uint8_t *>(k);
00176 FAMOUSO_ASSERT(nonred_fragments);
00177
00178 ::logging::log::emit< ::logging::Info>()
00179 << PROGMEMSTRING("AFP: Fragmenter FEC: ")
00180 << ::logging::log::dec << (unsigned long)k
00181 << PROGMEMSTRING(" data fragments, ")
00182 << (unsigned long)(n - k)
00183 << PROGMEMSTRING(" redundancy fragments (from ")
00184 << (unsigned long)Redundancy::value()
00185 << PROGMEMSTRING("% red)")
00186 << ::logging::log::endl;
00187
00188
00189
00190 fec_code = vandermonde_fec::fec_new(k, n);
00191 FAMOUSO_ASSERT(fec_code);
00192
00193 header_len_rest = htons(((event_length - 1) % payload_length) + 1);
00194 }
00195
00201 void get_header(uint8_t * data, bool more_headers) {
00202 Header1001 * h = reinterpret_cast<Header1001 *>(data);
00203 h->head = (more_headers ? 0x40 | 0x29 : 0x29);
00204 h->red = Redundancy::value();
00205 h->k = htonl(k);
00206 h->len_rest = header_len_rest;
00207 }
00208
00209
00216 void put_nonred_fragment(const uint8_t * data) {
00217 FAMOUSO_ASSERT(next_fragment_idx < k);
00218 nonred_fragments[next_fragment_idx++] = data;
00219 }
00220
00229 void put_smaller_nonred_fragment(const uint8_t * data, flen_t length) {
00230 FAMOUSO_ASSERT(next_fragment_idx == k - 1);
00231 FAMOUSO_ASSERT(length < payload_length);
00232 FAMOUSO_ASSERT(event_length % payload_length == length);
00233
00234
00235 uint8_t * last_nonred_frag = Allocator::alloc(payload_length);
00236 FAMOUSO_ASSERT(nonred_fragments);
00237 memcpy(last_nonred_frag, data, length);
00238 memset(last_nonred_frag + length, 0, payload_length - length);
00239
00240 nonred_fragments[next_fragment_idx++] = last_nonred_frag;
00241 smaller_fragment = true;
00242 }
00243
00248 void get_red_fragment(uint8_t * data) {
00249 FAMOUSO_ASSERT(next_fragment_idx < n);
00250
00251 vandermonde_fec::fec_encode(fec_code,
00252 reinterpret_cast<void **>(
00253 const_cast<uint8_t **>(nonred_fragments)
00254 ),
00255 data,
00256 next_fragment_idx++,
00257 payload_length);
00258 }
00259 };
00260
00261
00262 }
00263 }
00264 }
00265 }
00266
00267
00268 #else
00269
00270
00271 #include "assert/staticerror.h"
00272
00273 namespace famouso {
00274 namespace mw {
00275 namespace afp {
00276 namespace frag {
00277 template <class FCP>
00278 class UseFEC {
00279 FAMOUSO_STATIC_ASSERT_ERROR(false, FEC_not_supported_on_AVR, ());
00280 };
00281 }
00282 }
00283 }
00284 }
00285
00286 #endif
00287
00288
00289 #endif // __USEFEC_H_C5A7E8776574FE__
00290