Menu

UseFEC.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2009-2010 Philipp Werner <philipp.werner@st.ovgu.de>
00004  * All rights reserved.
00005  *
00006  *    Redistribution and use in source and binary forms, with or without
00007  *    modification, are permitted provided that the following conditions
00008  *    are met:
00009  *
00010  *    * Redistributions of source code must retain the above copyright
00011  *      notice, this list of conditions and the following disclaimer.
00012  *
00013  *    * Redistributions in binary form must reproduce the above copyright
00014  *      notice, this list of conditions and the following disclaimer in
00015  *      the documentation and/or other materials provided with the
00016  *      distribution.
00017  *
00018  *    * Neither the name of the copyright holders nor the names of
00019  *      contributors may be used to endorse or promote products derived
00020  *      from this software without specific prior written permission.
00021  *
00022  *
00023  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00025  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00026  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *
00036  * $Id$
00037  *
00038  ******************************************************************************/
00039 
00040 
00041 #ifndef __USEFEC_H_C5A7E8776574FE__
00042 #define __USEFEC_H_C5A7E8776574FE__
00043 
00044 
00045 #if !defined(__AVR__)
00046 // Non-AVR version
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 // Forward error correction library (packet erasure code based on vandermonde matrices)
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                             // Following is very expensive for big k and n... in case many events with
00189                             // same k and n are sent, it would be nice to have fec_code sharing (low priority TODO)
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                             // Make it same size for encoding library and pad with zero.
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             } // namespace frag
00263         } // namespace afp
00264     } // namespace mw
00265 } // namespace famouso
00266 
00267 
00268 #else
00269 // AVR version
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             } // namespace frag
00282         } // namespace afp
00283     } // namespace mw
00284 } // namespace famouso
00285 
00286 #endif
00287 
00288 
00289 #endif // __USEFEC_H_C5A7E8776574FE__
00290