Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FUOTAv2 FragGetParityMatrixRow implementation incorrect? #106

Open
brocaar opened this issue Mar 14, 2025 · 4 comments
Open

FUOTAv2 FragGetParityMatrixRow implementation incorrect? #106

brocaar opened this issue Mar 14, 2025 · 4 comments

Comments

@brocaar
Copy link

brocaar commented Mar 14, 2025

I'm testing FUOTA v2 and on FragSessionStatusAns I'm getting MIC errors. What I'm testing:

  • Uplink of multiple fragments with redundancy
  • During the multicast downlinks I'm triggering a device uplink (pressing blue button of EVK board) such that it misses one or two multicast downlinks
  • The device reports that after receiving the redundant packets reconstructed the payload
Current fragment index = 0,
Current fragment counter = 15,
Number of missed packets = 2,
 FILE RECONSTRUCTS SUCCESSFULLY !

However, on FragSessionStatusReq, it prints that the MIC is incorrect. After printing the reconstructed payload vs the actual payload that was sent, I notice that the reconstructed bytes are incorrect (only the parts that were reconstructed using the FEC scheme). This might be an issue with my implementation or it might be an issue in the LBM firmware, that I do not know yet.

However, after looking at the FragGetParityMatrixRow function, I noticed there might be something missing:

static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t* matrixRow )
{
    int32_t mTemp;
    int32_t x;
    int32_t nbCoeff = 0;
    int32_t r;

    if( IsPowerOfTwo( m ) != false )
    {
        mTemp = 1;
    }
    else
    {
        mTemp = 0;
    }

    x = 1 + ( 1001 * n );
    for( int32_t i = 0; i < ( ( m >> 3 ) + 1 ); i++ )
    {
        matrixRow[i] = 0;
    }
    while( nbCoeff < ( m >> 1 ) )
    {
        r = 1 << 16;
        while( r >= m )
        {
            x = FragPrbs23( x );
            r = x % ( m + mTemp );
        }
        if( GetParity( r, matrixRow ) == 0 )
        {
            SetParity( r, matrixRow, 1 );
            nbCoeff += 1;
        }
    }
}

The specs contains an if (N <= M) line, which does not seem to be implemented:

Image

@brocaar
Copy link
Author

brocaar commented Mar 14, 2025

An other observation, this function is called in the v2 implementation as:

        // fragCounter - FragDecoder.FragNb
        FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow );

This is equal to the v1 implementation of the LBM.

However, the implementation seems to have changed between v1 and v2:

v1 implementation

Image

CODED_F is an array which is 2 * w, where w is the number of uncoded fragments (thus redundancy is equal to w).
There are two for loops:

  1. Adding the UNCODED_F fragments to CODED_F
  2. Adding the coded fragments to CODED_F note that the variable y is in the range from 1 .. w

v2 implementation

Image

CODED_F is an array which is 2 * w, where w is the number of uncoded fragments (thus again the redundancy is equal to w).
There is only 1 loop where the variable y is in the range of 1 .. (2 * w)

Now looking again at:

        // fragCounter - FragDecoder.FragNb
        FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow );

I think this is not correct, it should probably be just fragCounter as if I understand the MATLAB code correctly, the expected range is 1 .. (number of fragments + redundant fragments).

@brocaar brocaar changed the title FUOTAv2 FragGetParityMatrixRow implementation correct? FUOTAv2 FragGetParityMatrixRow implementation incorrect? Mar 14, 2025
@lbm-team
Copy link
Contributor

The LBM implementation is a direct translation of the MATLAB code. Let me explain:

Handling of Fragments

In the LBM implementation, the uncoded fragments are handled separately, and only the coded fragments (where N > M) are managed by calling the function FragGetParityMatrixRow. That is why this function does not check the case N <= M, unlike the MATLAB code.

MATLAB Specification

In the specification, the MATLAB code for both V1 and V2 is essentially the same, just written in two different ways. The core idea remains: the output is the CODED_F fragments, where the first M fragments are equal to UNCODED_F, and the following M fragments are a combination of those uncoded fragments. Thus, the result is:

CODED_F = [UNCODED_F CODED_F]

In the V1 MATLAB Implementation:

  • CODED_F directly copies UNCODED_F for the first M fragments.
  • Then, lines 697 to 705 handle the second set of M fragments by combining the uncoded fragments.

In the V2 MATLAB Implementation:

  • There is no direct copy of UNCODED_F. Instead, it is done implicitly because the combination matrix is an identity matrix for the first M fragments, resulting in CODED_F = UNCODED_F for those fragments.
  • The following M fragments are also a combination of the uncoded fragments, since the matrix is no longer the identity in that portion.

Summary

Both V1 and V2 behave identically; the only difference is in the way the combination matrix is constructed—V2 includes more ones in the matrix compared to V1.

I also believe that the LBM implementation exhibits the same behavior.

@brocaar
Copy link
Author

brocaar commented Mar 27, 2025

In the specification, the MATLAB code for both V1 and V2 is essentially the same, just written in two different ways.

Are you sure? I think the x variable is calculated different because the arguments to matrix_line are different in v1 and v2:

x= 1+1001*N; %initialize the seed differently for each line

In the v1 MATLAB example:

  • The MATLAB code iterates twice over the range 1:w (two for y=1:w loops)
  • For calculating the first redundant fragment, the matrix_line function is called with the following arguments matrix_line(1, 32)
  • This means N=1, M=32, and x is calculated as x=1+1001*1

In v2:

  • The MATLAB code iterates once over the range 1:w*2 (one for y=1:w*2 loop)
  • If N <= M, matrix_line returns early
  • If N > M, matrix_line generates the parity check vector
  • This means that for calculating the first redundancy fragment, the matrix_line function is called with the following arguments matrix_line(33, 32)
  • This means N=33, M=32, and x is calculated as x=1+1001*33

@brocaar
Copy link
Author

brocaar commented Mar 27, 2025

I think in the LBM stack, this line:

FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow );

Should therefore be something like this for v2:

FragGetParityMatrixRow( fragCounter, FragDecoder.FragNb, matrixRow );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants