1 /*!
2  * \file      FragDecoder.c
3  *
4  * \brief     Implements the LoRa-Alliance fragmentation decoder
5  *            Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf
6  *
7  * \copyright Revised BSD License, see section \ref LICENSE.
8  *
9  * \code
10  *                ______                              _
11  *               / _____)             _              | |
12  *              ( (____  _____ ____ _| |_ _____  ____| |__
13  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
14  *               _____) ) ____| | | || |_| ____( (___| | | |
15  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
16  *              (C)2013-2018 Semtech
17  *
18  * \endcode
19  *
20  * \author    Fabien Holin ( Semtech )
21  * \author    Miguel Luis ( Semtech )
22  */
23 #include <stddef.h>
24 #include <stdbool.h>
25 #include "utilities.h"
26 #include "FragDecoder.h"
27 
28 #define DBG_TRACE                                   0
29 
30 #if DBG_TRACE == 1
31     #include <stdio.h>
32     /*!
33      * Works in the same way as the printf function does.
34      */
35     #define DBG( ... )                               \
36         do                                           \
37         {                                            \
38             printf( __VA_ARGS__ );                   \
39         }while( 0 )
40 #else
41     #define DBG( fmt, ... )
42 #endif
43 
44 
45 /*
46  *=============================================================================
47  * Fragmentation decoder algorithm utilities
48  *=============================================================================
49  */
50 
51 typedef struct
52 {
53 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
54     FragDecoderCallbacks_t *Callbacks;
55 #else
56     uint8_t *File;
57     uint32_t FileSize;
58 #endif
59     uint16_t FragNb;
60     uint8_t FragSize;
61 
62     uint32_t M2BLine;
63     uint8_t MatrixM2B[( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY];
64     uint16_t FragNbMissingIndex[FRAG_MAX_NB];
65 
66     uint8_t S[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
67 
68     FragDecoderStatus_t Status;
69 }FragDecoder_t;
70 
71 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
72 /*!
73  * \brief Sets a row from source into file destination
74  *
75  * \param [IN] src  Source buffer pointer
76  * \param [IN] row  Destination index of the row to be copied
77  * \param [IN] size Source number of bytes to be copied
78  */
79 static void SetRow( uint8_t *src, uint16_t row, uint16_t size );
80 #else
81 /*!
82  * \brief Sets a row from source into destination
83  *
84  * \param [IN] dst  Destination buffer pointer
85  * \param [IN] src  Source buffer pointer
86  * \param [IN] row  Destination index of the row to be copied
87  * \param [IN] size Source number of bytes to be copied
88  */
89 static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size );
90 #endif
91 
92 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
93 /*!
94  * \brief Gets a row from source and stores it into file destination
95  *
96  * \param [IN] src  Source buffer pointer
97  * \param [IN] row  Source index of the row to be copied
98  * \param [IN] size Source number of bytes to be copied
99  */
100 static void GetRow( uint8_t *src, uint16_t row, uint16_t size );
101 #else
102 /*!
103  * \brief Gets a row from source and stores it into destination
104  *
105  * \param [IN] dst  Destination buffer pointer
106  * \param [IN] src  Source buffer pointer
107  * \param [IN] row  Source index of the row to be copied
108  * \param [IN] size Source number of bytes to be copied
109  */
110 static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size );
111 #endif
112 
113 /*!
114  * \brief Gets the parity value from a given row of the parity matrix
115  *
116  * \param [IN] index      The index of the row to be computed
117  * \param [IN] matrixRow  Pointer to the parity matrix (parity bit array)
118  *
119  * \retval parity         Parity value at the given index
120  */
121 static uint8_t GetParity( uint16_t index, uint8_t *matrixRow  );
122 
123 /*!
124  * \brief Sets the parity value on the given row of the parity matrix
125  *
126  * \param [IN]     index     The index of the row to be computed
127  * \param [IN/OUT] matrixRow Pointer to the parity matrix.
128  * \param [IN]     parity    The parity value to be set in the parity matrix
129  */
130 static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity );
131 
132 /*!
133  * \brief Check if the provided value is a power of 2
134  *
135  * \param [IN] x  Value to be tested
136  *
137  * \retval status Return true if frame is a power of two
138  */
139 static bool IsPowerOfTwo( uint32_t x );
140 
141 /*!
142  * \brief XOrs two data lines
143  *
144  * \param [IN]  line1  1st Data line to be XORed
145  * \param [IN]  line2  2nd Data line to be XORed
146  * \param [IN]  size   Number of elements in line1
147  *
148  * \param [OUT] result XOR( line1, line2 ) result stored in line1
149  */
150 static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size );
151 
152 /*!
153  * \brief XORs two parity lines
154  *
155  * \param [IN]  line1  1st Parity line to be XORed
156  * \param [IN]  line2  2nd Parity line to be XORed
157  * \param [IN]  size   Number of elements in line1
158  *
159  * \param [OUT] result XOR( line1, line2 ) result stored in line1
160  */
161 static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size );
162 
163 /*!
164  * \brief Generates a pseudo random number : PRBS23
165  *
166  * \param [IN] value The input of the PRBS23 generator
167  *
168  * \retval nextValue Returns the next pseudo random number
169  */
170 static int32_t FragPrbs23( int32_t value );
171 
172 /*!
173  * \brief Gets and fills the parity matrix
174  *
175  * \param [IN]  n         Fragment N
176  * \param [IN]  m         Fragment number
177  * \param [OUT] matrixRow Parity matrix
178  */
179 static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow );
180 
181 /*!
182  * \brief Finds the index of the first one in a bit array
183  *
184  * \param [IN] bitArray Pointer to the bit array
185  * \param [IN] size     Bit array size
186  * \retval index        The index of the first 1 in the bit array
187  */
188 static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size );
189 
190 /*!
191  * \brief Checks if the provided bit array only contains zeros
192  *
193  * \param [IN] bitArray Pointer to the bit array
194  * \param [IN] size     Bit array size
195  * \retval isAllZeros   [0: Contains ones, 1: Contains all zeros]
196  */
197 static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t  size );
198 
199 /*!
200  * \brief Finds & marks missing fragments
201  *
202  * \param [IN]  counter Current fragment counter
203  * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place
204  */
205 static void FragFindMissingFrags( uint16_t counter );
206 
207 /*!
208  * \brief Finds the index (frag counter) of the x th missing frag
209  *
210  * \param [IN] x   x th missing frag
211  *
212  * \retval counter The counter value associated to the x th missing frag
213  */
214 static uint16_t FragFindMissingIndex( uint16_t x );
215 
216 /*!
217  * \brief Extacts a row from the binary matrix and expands it to a bitArray
218  *
219  * \param [IN] bitArray  Pointer to the bit array
220  * \param [IN] rowIndex  Matrix row index
221  * \param [IN] bitsInRow Number of bits in one row
222  */
223 static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow );
224 
225 /*!
226  * \brief Collapses and Pushs a row of a bit array to the matrix
227  *
228  * \param [IN] bitArray  Pointer to the bit array
229  * \param [IN] rowIndex  Matrix row index
230  * \param [IN] bitsInRow Number of bits in one row
231  */
232 static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow );
233 
234 /*
235  *=============================================================================
236  * Fragmentation decoder algorithm
237  *=============================================================================
238  */
239 
240 static FragDecoder_t FragDecoder;
241 
242 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoderInit(uint16_t fragNb,uint8_t fragSize,FragDecoderCallbacks_t * callbacks)243 void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks )
244 #else
245 void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize )
246 #endif
247 {
248 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
249     FragDecoder.Callbacks = callbacks;
250 #else
251     FragDecoder.File = file;
252     FragDecoder.FileSize = fileSize;
253 #endif
254     FragDecoder.FragNb = fragNb;                                // FragNb = FRAG_MAX_SIZE
255     FragDecoder.FragSize = fragSize;                            // number of byte on a row
256     FragDecoder.Status.FragNbLastRx = 0;
257     FragDecoder.Status.FragNbLost = 0;
258     FragDecoder.M2BLine = 0;
259 
260     // Initialize missing fragments index array
261     for( uint16_t i = 0; i < FRAG_MAX_NB; i++ )
262     {
263         FragDecoder.FragNbMissingIndex[i] = 1;
264     }
265 
266     // Initialize parity matrix
267     for( uint32_t i = 0; i < ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); i++ )
268     {
269         FragDecoder.S[i] = 0;
270     }
271 
272     for( uint32_t i = 0; i < ( ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY ); i++ )
273     {
274        FragDecoder.MatrixM2B[i] = 0xFF;
275     }
276 
277     // Initialize final uncoded data buffer ( FRAG_MAX_NB * FRAG_MAX_SIZE )
278     for( uint32_t i = 0; i < ( fragNb * fragSize ); i++ )
279     {
280 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
281         if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) )
282         {
283             uint8_t buffer[1] = { 0xFF };
284             FragDecoder.Callbacks->FragDecoderWrite( i, buffer, 1 );
285         }
286 #else
287         FragDecoder.File[i] = 0xFF;
288 #endif
289     }
290     FragDecoder.Status.FragNbLost = 0;
291     FragDecoder.Status.FragNbLastRx = 0;
292 }
293 
294 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoderGetMaxFileSize(void)295 uint32_t FragDecoderGetMaxFileSize( void )
296 {
297     return FRAG_MAX_NB * FRAG_MAX_SIZE;
298 }
299 #endif
300 
FragDecoderProcess(uint16_t fragCounter,uint8_t * rawData)301 int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData )
302 {
303     uint16_t firstOneInRow = 0;
304     int32_t first = 0;
305     int32_t noInfo = 0;
306 
307     uint8_t matrixRow[(FRAG_MAX_NB >> 3 ) + 1];
308     uint8_t matrixDataTemp[FRAG_MAX_SIZE];
309     uint8_t dataTempVector[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
310     uint8_t dataTempVector2[( FRAG_MAX_REDUNDANCY >> 3 ) + 1];
311 
312     memset1( matrixRow, 0, ( FRAG_MAX_NB >> 3 ) + 1 );
313     memset1( matrixDataTemp, 0, FRAG_MAX_SIZE );
314     memset1( dataTempVector, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 );
315     memset1( dataTempVector2, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 );
316 
317     FragDecoder.Status.FragNbRx = fragCounter;
318 
319     if( fragCounter < FragDecoder.Status.FragNbLastRx )
320     {
321         return FRAG_SESSION_ONGOING;  // Drop frame out of order
322     }
323 
324     // The M (FragNb) first packets aren't encoded or in other words they are
325     // encoded with the unitary matrix
326     if( fragCounter < ( FragDecoder.FragNb + 1 ) )
327     {
328         // The M first frame are not encoded store them
329 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
330         SetRow( rawData, fragCounter - 1, FragDecoder.FragSize );
331 #else
332         SetRow( FragDecoder.File, rawData, fragCounter - 1, FragDecoder.FragSize );
333 #endif
334 
335         FragDecoder.FragNbMissingIndex[fragCounter - 1] = 0;
336 
337         // Update the FragDecoder.FragNbMissingIndex with the loosing frame
338         FragFindMissingFrags( fragCounter );
339     }
340     else
341     {
342         if( FragDecoder.Status.FragNbLost > FRAG_MAX_REDUNDANCY )
343         {
344            FragDecoder.Status.MatrixError = 1;
345            return FRAG_SESSION_FINISHED;
346         }
347         // At this point we receive encoded frames and the number of loosing frames
348         // is well known: FragDecoder.FragNbLost - 1;
349 
350         // In case of the end of true data is missing
351         FragFindMissingFrags( fragCounter );
352 
353         if( FragDecoder.Status.FragNbLost == 0 )
354         {
355             // the case : all the M(FragNb) first rows have been transmitted with no error
356             return FragDecoder.Status.FragNbLost;
357         }
358 
359         // fragCounter - FragDecoder.FragNb
360         FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow );
361 
362         for( int32_t i = 0; i < FragDecoder.FragNb; i++ )
363         {
364             if( GetParity( i , matrixRow ) == 1 )
365             {
366                 if( FragDecoder.FragNbMissingIndex[i] == 0 )
367                 {
368                     // XOR with already receive frag
369                     SetParity( i, matrixRow, 0 );
370 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
371                     GetRow( matrixDataTemp, i, FragDecoder.FragSize );
372 #else
373                     GetRow( matrixDataTemp, FragDecoder.File, i, FragDecoder.FragSize );
374 #endif
375                     XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize );
376                 }
377                 else
378                 {
379                     // Fill the "little" boolean matrix m2b
380                     SetParity( FragDecoder.FragNbMissingIndex[i] - 1, dataTempVector, 1 );
381                     if( first == 0 )
382                     {
383                         first = 1;
384                     }
385                 }
386             }
387         }
388 
389         firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost );
390 
391         if( first > 0 )
392         {
393             int32_t li;
394             int32_t lj;
395 
396             // Manage a new line in MatrixM2B
397             while( GetParity( firstOneInRow, FragDecoder.S ) == 1 )
398             {
399                 // Row already diagonalized exist & ( FragDecoder.MatrixM2B[firstOneInRow][0] )
400                 FragExtractLineFromBinaryMatrix( dataTempVector2, firstOneInRow, FragDecoder.Status.FragNbLost );
401                 XorParityLine( dataTempVector, dataTempVector2, FragDecoder.Status.FragNbLost );
402                 // Have to store it in the mi th position of the missing frag
403                 li = FragFindMissingIndex( firstOneInRow );
404 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
405                 GetRow( matrixDataTemp, li, FragDecoder.FragSize );
406 #else
407                 GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize );
408 #endif
409                 XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize );
410                 if( BitArrayIsAllZeros( dataTempVector, FragDecoder.Status.FragNbLost ) )
411                 {
412                     noInfo = 1;
413                     break;
414                 }
415                 firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost );
416             }
417 
418             if( noInfo == 0 )
419             {
420                 FragPushLineToBinaryMatrix( dataTempVector, firstOneInRow, FragDecoder.Status.FragNbLost );
421                 li = FragFindMissingIndex( firstOneInRow );
422 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
423                 SetRow( rawData, li, FragDecoder.FragSize );
424 #else
425                 SetRow( FragDecoder.File, rawData, li, FragDecoder.FragSize );
426 #endif
427                 SetParity( firstOneInRow, FragDecoder.S, 1 );
428                 FragDecoder.M2BLine++;
429             }
430 
431             if( FragDecoder.M2BLine == FragDecoder.Status.FragNbLost )
432             {
433                 // Then last step diagonalized
434                 if( FragDecoder.Status.FragNbLost > 1 )
435                 {
436                     int32_t i, j;
437 
438                     for( i = ( FragDecoder.Status.FragNbLost - 2 ); i >= 0 ; i-- )
439                     {
440                         li = FragFindMissingIndex( i );
441 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
442                         GetRow( matrixDataTemp, li, FragDecoder.FragSize );
443 #else
444                         GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize );
445 #endif
446                         for( j = ( FragDecoder.Status.FragNbLost - 1 ); j > i; j--)
447                         {
448                             FragExtractLineFromBinaryMatrix( dataTempVector2, i, FragDecoder.Status.FragNbLost );
449                             FragExtractLineFromBinaryMatrix( dataTempVector, j, FragDecoder.Status.FragNbLost );
450                             if( GetParity( j, dataTempVector2 ) == 1 )
451                             {
452                                 XorParityLine( dataTempVector2, dataTempVector, FragDecoder.Status.FragNbLost );
453 
454                                 lj = FragFindMissingIndex( j );
455 
456 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
457                                 GetRow( rawData, lj, FragDecoder.FragSize );
458 #else
459                                 GetRow( rawData, FragDecoder.File, lj, FragDecoder.FragSize );
460 #endif
461                                 XorDataLine( matrixDataTemp , rawData , FragDecoder.FragSize );
462                             }
463                         }
464 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
465                         SetRow( matrixDataTemp, li, FragDecoder.FragSize );
466 #else
467                         SetRow( FragDecoder.File, matrixDataTemp, li, FragDecoder.FragSize );
468 #endif
469                     }
470                     return FragDecoder.Status.FragNbLost;
471                 }
472                 else
473                 {
474                     //If not ( FragDecoder.FragNbLost > 1 )
475                     return FragDecoder.Status.FragNbLost;
476                 }
477             }
478         }
479     }
480     return FRAG_SESSION_ONGOING;
481 }
482 
FragDecoderGetStatus(void)483 FragDecoderStatus_t FragDecoderGetStatus( void )
484 {
485     return FragDecoder.Status;
486 }
487 
488 /*
489  *=============================================================================
490  * Fragmentation decoder algorithm utilities
491  *=============================================================================
492  */
493 
494 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
SetRow(uint8_t * src,uint16_t row,uint16_t size)495 static void SetRow( uint8_t *src, uint16_t row, uint16_t size )
496 {
497     if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) )
498     {
499         FragDecoder.Callbacks->FragDecoderWrite( row * size, src, size );
500     }
501 }
502 
GetRow(uint8_t * dst,uint16_t row,uint16_t size)503 static void GetRow( uint8_t *dst, uint16_t row, uint16_t size )
504 {
505     if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderRead != NULL ) )
506     {
507         FragDecoder.Callbacks->FragDecoderRead( row * size, dst, size );
508     }
509 }
510 #else
SetRow(uint8_t * dst,uint8_t * src,uint16_t row,uint16_t size)511 static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size )
512 {
513     memcpy1( &dst[row * size], src, size );
514 }
515 
GetRow(uint8_t * dst,uint8_t * src,uint16_t row,uint16_t size)516 static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size )
517 {
518     memcpy1( dst, &src[row * size], size );
519 }
520 #endif
521 
GetParity(uint16_t index,uint8_t * matrixRow)522 static uint8_t GetParity( uint16_t index, uint8_t *matrixRow  )
523 {
524     uint8_t parity;
525     parity = matrixRow[index >> 3];
526     parity = ( parity >> ( 7 - ( index % 8 ) ) ) & 0x01;
527     return parity;
528 }
529 
SetParity(uint16_t index,uint8_t * matrixRow,uint8_t parity)530 static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity )
531 {
532     uint8_t mask = 0xFF - ( 1 << ( 7 - ( index % 8 ) ) );
533     parity = parity << ( 7 - ( index % 8 ) );
534     matrixRow[index >> 3] = ( matrixRow[index >> 3] & mask ) + parity;
535 }
536 
IsPowerOfTwo(uint32_t x)537 static bool IsPowerOfTwo( uint32_t x )
538 {
539     uint8_t sumBit = 0;
540 
541     for( uint8_t i = 0; i < 32; i++ )
542     {
543         sumBit += ( x & ( 1 << i ) ) >> i;
544     }
545     if( sumBit == 1 )
546     {
547         return true;
548     }
549     return false;
550 }
551 
XorDataLine(uint8_t * line1,uint8_t * line2,int32_t size)552 static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size )
553 {
554     for( int32_t i = 0; i < size; i++ )
555     {
556         line1[i] = line1[i] ^ line2[i];
557     }
558 }
559 
XorParityLine(uint8_t * line1,uint8_t * line2,int32_t size)560 static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size )
561 {
562     for( int32_t i = 0; i < size; i++ )
563     {
564         SetParity( i, line1, ( GetParity( i, line1 ) ^ GetParity( i, line2 ) ) );
565     }
566 }
567 
FragPrbs23(int32_t value)568 static int32_t FragPrbs23( int32_t value )
569 {
570     int32_t b0 = value & 0x01;
571     int32_t b1 = ( value & 0x20 ) >> 5;
572     return ( value >> 1 ) + ( ( b0 ^ b1 ) << 22 );
573 }
574 
FragGetParityMatrixRow(int32_t n,int32_t m,uint8_t * matrixRow)575 static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow )
576 {
577     int32_t mTemp;
578     int32_t x;
579     int32_t nbCoeff = 0;
580     int32_t r;
581 
582     if( IsPowerOfTwo( m ) != false )
583     {
584         mTemp = 1;
585     }
586     else
587     {
588         mTemp = 0;
589     }
590 
591     x = 1 + ( 1001 * n );
592     for( uint16_t i = 0; i < ( ( m >> 3 ) + 1 ); i++ )
593     {
594         matrixRow[i] = 0;
595     }
596     while( nbCoeff < ( m >> 1 ) )
597     {
598         r = 1 << 16;
599         while( r >= m )
600         {
601             x = FragPrbs23( x );
602             r = x % ( m + mTemp );
603         }
604         SetParity( r, matrixRow, 1 );
605         nbCoeff += 1;
606     }
607 }
608 
BitArrayFindFirstOne(uint8_t * bitArray,uint16_t size)609 static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size )
610 {
611     for( uint16_t i = 0; i < size; i++)
612     {
613         if ( GetParity( i, bitArray ) == 1 )
614         {
615             return i;
616         }
617     }
618     return 0;
619 }
620 
BitArrayIsAllZeros(uint8_t * bitArray,uint16_t size)621 static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t  size )
622 {
623     for( uint16_t i = 0; i < size; i++ )
624     {
625         if( GetParity( i, bitArray ) == 1 )
626         {
627             return 0;
628         }
629     }
630     return 1;
631 }
632 
633 /*!
634  * \brief Finds & marks missing fragments
635  *
636  * \param [IN]  counter Current fragment counter
637  * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place
638  */
FragFindMissingFrags(uint16_t counter)639 static void FragFindMissingFrags( uint16_t counter )
640 {
641     int32_t i;
642     for( i = FragDecoder.Status.FragNbLastRx; i < ( counter - 1 ); i++ )
643     {
644         if( i < FragDecoder.FragNb )
645         {
646             FragDecoder.Status.FragNbLost++;
647             FragDecoder.FragNbMissingIndex[i] = FragDecoder.Status.FragNbLost;
648         }
649     }
650     if( i < FragDecoder.FragNb )
651     {
652         FragDecoder.Status.FragNbLastRx = counter;
653     }
654     else
655     {
656         FragDecoder.Status.FragNbLastRx = FragDecoder.FragNb + 1;
657     }
658     DBG( "RECEIVED    : %5d / %5d Fragments\n", FragDecoder.Status.FragNbRx, FragDecoder.FragNb );
659     DBG( "              %5d / %5d Bytes\n", FragDecoder.Status.FragNbRx * FragDecoder.FragSize, FragDecoder.FragNb * FragDecoder.FragSize );
660     DBG( "LOST        :       %7d Fragments\n\n", FragDecoder.Status.FragNbLost );
661 }
662 
663 /*!
664  * \brief Finds the index (frag counter) of the x th missing frag
665  *
666  * \param [IN] x   x th missing frag
667  *
668  * \retval counter The counter value associated to the x th missing frag
669  */
FragFindMissingIndex(uint16_t x)670 static uint16_t FragFindMissingIndex( uint16_t x )
671 {
672     for( uint16_t i = 0; i < FragDecoder.FragNb; i++ )
673     {
674         if( FragDecoder.FragNbMissingIndex[i] == ( x + 1 ) )
675         {
676             return i;
677         }
678     }
679     return 0;
680 }
681 
682 /*!
683  * \brief Extacts a row from the binary matrix and expands it to a bitArray
684  *
685  * \param [IN] bitArray  Pointer to the bit array
686  * \param [IN] rowIndex  Matrix row index
687  * \param [IN] bitsInRow Number of bits in one row
688  */
FragExtractLineFromBinaryMatrix(uint8_t * bitArray,uint16_t rowIndex,uint16_t bitsInRow)689 static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow )
690 {
691     uint32_t findByte = 0;
692     uint32_t findBitInByte = 0;
693 
694     if( rowIndex > 0 )
695     {
696         findByte      = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3;
697         findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8;
698     }
699     if( rowIndex > 0 )
700     {
701         for( uint16_t i = 0; i < rowIndex; i++ )
702         {
703             SetParity( i, bitArray, 0 );
704         }
705     }
706     for( uint16_t i = rowIndex; i < bitsInRow; i++ )
707     {
708         SetParity( i,
709                    bitArray,
710                    ( FragDecoder.MatrixM2B[findByte] >> ( 7 - findBitInByte ) ) & 0x01 );
711 
712         findBitInByte++;
713         if( findBitInByte == 8 )
714         {
715             findBitInByte = 0;
716             findByte++;
717         }
718     }
719 }
720 
721 /*!
722  * \brief Collapses and Pushs a row of a bit array to the matrix
723  *
724  * \param [IN] bitArray  Pointer to the bit array
725  * \param [IN] rowIndex  Matrix row index
726  * \param [IN] bitsInRow Number of bits in one row
727  */
FragPushLineToBinaryMatrix(uint8_t * bitArray,uint16_t rowIndex,uint16_t bitsInRow)728 static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow )
729 {
730     uint32_t findByte = 0;
731     uint32_t findBitInByte = 0;
732 
733     if ( rowIndex > 0) {
734         findByte      = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3;
735         findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8;
736 
737     }
738     for( uint16_t i = rowIndex; i < bitsInRow; i++ )
739     {
740         if( GetParity( i, bitArray ) == 0 )
741         {
742             FragDecoder.MatrixM2B[findByte] = FragDecoder.MatrixM2B[findByte] & ( 0xFF - ( 1 << ( 7 - findBitInByte ) ) );
743         }
744         findBitInByte++;
745         if( findBitInByte == 8 )
746         {
747             findBitInByte = 0;
748             findByte++;
749         }
750     }
751 }
752