Search code examples
cbinarycrc

BCH -CRC help in C


I am trying to get this working in C Calculation of CRC in C seems easy but my CRC/BCH routine is not generating the same answer as in the link for the first codeword, even when I tried calculating manually and even that is not matching with what is given in the link.

My manual calculation was as

           11101101001    101010011010000010100
                          111011010010000000000
                          010001001000000010100
                           11101101001
                           01100100001000010100
                            11101101001
                            0010010101100010100
                              11101101001
                              01111000101010100
                               11101101001
                               0001100001110100
                                  11101101001
                                  0010111010000
                                    11101101001
                                    01010111001 ---- remainder (should match with BCH(31,21) value in the link)

I am not sure where I am wrong. Here's my code

int calc_bch_and_parity( int cw_e ) 
{ 
    int bit=0; 
    int local_cw = 0;  
    int parity = 0; 

    local_cw = cw_e;  
    for( bit=1; bit<=21; bit++, cw_e <<= 1 ) 
        if (cw_e & 0x80000000) 
            cw_e ^= 0xED200000; 

    local_cw |= (cw_e >> 21); 
    cw_e =local_cw; 
    for( bit=1; bit<=32; bit++, cw_e <<= 1 ) 
        if (cw_e & 0x80000000) 
            parity++; 

   return (parity%2) ? local_cw+1 : local_cw; 
} 

******************************edited code to get more visibility of the process **************

 int bit=0;
  int local_cw = 0;
  int parity = 0;
 // int try;
  int  answer;
 // int genpoly = 0x1DA400;
  local_cw=cw;  /* bch */

  for(bit=1; bit<=21; bit++, cw <<= 1)
    {
    if (cw & 0x80000000) 
    {   
    cw ^= 0xED200000;
    printf ("mod2 remainder is %x\n", cw);

    }

    }
    printf ("original data is %x\n", local_cw);
  local_cw |= (cw >> 21);
    printf ("21 bit right shifted remainder is %x\n",cw>>21);

  cw =local_cw;  /* parity */
  for(bit=1; bit<=32; bit++, cw<<=1)
    if (cw & 0x80000000) parity++;
{

   if(parity%2) 
    {
     printf("codeword is %x \n",local_cw+1 );
    answer = local_cw+1;
    }
   else
    {
     printf("codeword is %x \n",local_cw );
     answer =local_cw;
    }   
}

    return answer;

The expected reminder is 1001111100

Another example of BCH .

One another thing I have tried is this http://www.codeproject.com/Articles/13189/POCSAG-Encoder , sorry I have to rely on external link as I can not post the image yet, in this link in the image you will see that there is a pre-encoded message visible in hex and the actual message is word "Salam, I managed to successfully transmit the message to a pager using this pre-encoded message (fed it to a transmitter as array of hex integers), But even this message, ie. the word "Salam" is not visible (at least the first or last or any 20 consecutive bits) in the encoded message. I converted the whole hex message in binary and the word "Salam" in binary and tried to find first or last 20 bits of the word "Salam" in the encoded message. Now that is very odd for a CRC (which basically BCH is), CRCs don't suppose to encode/twist the actual message it should just append it with remainder and parity (in case of BCH) . So the actual message should be visible as is, first or last 20 bits, I even tried changing endianess but no joy. Here are the details of my effort with this new example

Salam : 01010011 01100001 01101100 01100001 01101101

gx: 10010110111

Salam_reversed_by_byte: 11001010 10000110 00110110 10000110 10110110

Salam_ rev : 10110110 10000110 00110110 10000110 11001010

1234567 : 00110001001100100011001100110100001101010011011000110111

1234567_reverse :11101100011011001010110000101100110011000100110010001100

first 20 bits of Salam : 01010011011000010110 First20_reverse of Salam : 01101000011011001010

Hex CW : 0x4B5A1A25,0xE5866E6E,0x7CD215D8,0xE1DB221B,0x84081630

0x4B5A1A25 : 01001011010110100001101000100101

0xE5866E6E : 11100101100001100110111001101110

0xE1DB221B : 11100001110110110010001000011011

0x84081630 : 10000100000010000001011000110000


Solution

  • Works for me, all I did is pad the dividend out to 32bits

    10101001101000001010000000000000
    11101101001
    01000100100000001010000000000000
     11101101001
    00110010000100001010000000000000
      11101101001
    00001001010110001010000000000000
        11101101001
    00000111100010101010000000000000
         11101101001
    00000000111000111010000000000000
            11101101001
    00000000000011101000000000000000
                11101101001
    00000000000000000101001000000000
                     11101101001
    00000000000000000010010010010000
                      11101101001
    00000000000000000001111111011000
                       11101101001
    00000000000000000000001001111100
    

    Here's the code that does the calculation "by hand"

    #include <stdio.h>
    #include <string.h>
    
    char blank[]    = "                                ";
    char dividend[] = "10101001101000001010000000000000";
    char divisor[]  = "11101101001";
    
    int main( void )
    {
        int i, j;
    
        int N = strlen( dividend );
        int M = strlen( divisor );
        printf( "%d %d\n", N, M );
    
        for ( i = 0; i < N - M; i++ )
        {
            if ( dividend[i] == '1' )
            {
                printf( "%s\n", dividend );
                printf( "%s%s\n", &blank[N-i], divisor );
                for ( j = 0; j < M; j++ )
                {
                    if ( dividend[i+j] == divisor[j] )
                        dividend[i+j] = '0';
                    else
                        dividend[i+j] = '1';
                }
            }
        }
        printf( "%s\n", dividend );
    }
    

    And here's the same thing twiddling bits

    #include <stdio.h>
    #include <stdint.h>
    
    int main( void )
    {
        uint32_t dividend  = 0x153414;
        uint32_t generator = 0x769;
        uint32_t mask;
    
        dividend  <<= 11;                   // pad the dividend with 11 zeros
        generator <<= 21;                   // left justify the generator
        mask = 1 << 31;                     // start the mask at the MSB
        for ( int i = 0; i < 21; i++ )
        {
            if ( dividend & mask )          // if the dividend has 1 at the current mask position
                dividend ^= generator;      // "subtract" the generator
            generator >>= 1;                
            mask >>= 1;                     // move to the next bit
        }
    
        printf( "%08x\n", dividend );       // whatever's left is the remainder
    }