Calculating FCS(CRC) for HDLC frame

后端 未结 3 967
北海茫月
北海茫月 2021-02-04 21:22

I have the following frame:

7e  01 00  00  01  00  18  ef  00  00  00   b5   20 c1 05 10 02 71 2e 1a c2 05 10 01 71 00 6e 87 02 00 01 42 71 2e 1a 01 96 27 be 27          


        
相关标签:
3条回答
  • 2021-02-04 21:35

    First of all, CRC value is 0xac93

    Use this calculator: http://www.zorc.breitbandkatze.de/crc.html

    • Set CRC order 16
    • Polynomial 1021
    • Initial value ffff
    • Final value ffff
    • "reverse data bytes"
    • "reverse CRC result before Final XOR"
    • Enter your sequence as:

      %01%00%00%01%00%18%ef%00%00%00%b5%20%c1%05%10%02%71%2e%1a%c2%05%10%01%71%00%6e%87%02%00%01%42%71%2e%1a%01%96%27%be%27%54%17%3d%b9
      
    • Press "calculate" and you get 0xAC93
    0 讨论(0)
  • 2021-02-04 21:45

    This is simple Python script for HDLC CRC calculation. You can use it for DLMS

    def byte_mirror(c):
    
        c = (c & 0xF0) >> 4 | (c & 0x0F) << 4
        c = (c & 0xCC) >> 2 | (c & 0x33) << 2
        c = (c & 0xAA) >> 1 | (c & 0x55) << 1
    
        return c
    
    CRC_INIT=0xffff
    POLYNOMIAL=0x1021
    DATA_VALUE=0xA0
    
    SNRM_request=[ 0x7E, 0xA0, 0x08, 0x03, 0x02, 0xFF, 0x93, 0xCA, 0xE4, 0x7E]
    
    print("sent>>", end=" ")
    
    for x in SNRM_request:
      if x>15:
           print(hex(x), end=" ")
      else:
           a=str(hex(x))
           a = a[:2] + "0" + a[2:]
           print(a, end=" ")
    
    lenn=len(SNRM_request)
    print(" ")
    
    crc = CRC_INIT
    
    
    
    for i in range(lenn):
    
        if( (i!=0) and (i!=(lenn-1)) and (i!=(lenn-2)) and (i!=(lenn-3)) ):
    
            print("i>>",i)
    
            c=SNRM_request[i]
            c=byte_mirror(c)
            c = c << 8
        
            print(hex(c))
    
            for j in range(8):
      
                print(hex(c))
                print("CRC",hex(crc))
    
                if (crc ^ c) & 0x8000:
                    crc = (crc << 1) ^ POLYNOMIAL
                else:
                    crc = crc << 1
    
                c = c << 1   
                crc=crc%65536
                c  =c%65536
    
    
    print("CRC-CALC",hex(crc))
    
    crc=0xFFFF-crc          
    print("CRC- NOT",hex(crc))
    
    crc_HI=crc//256
    crc_LO=crc%256
    
    print("CRC-HI",hex(crc_HI))
    print("CRC-LO",hex(crc_LO))
    
    crc_HI=byte_mirror(crc_HI)
    crc_LO=byte_mirror(crc_LO)
    
    print("CRC-HI-zrc",hex(crc_HI))
    print("CRC-LO-zrc",hex(crc_LO))
    
    crc=256*crc_HI+crc_LO
    print("CRC-END",hex(crc))
    
    0 讨论(0)
  • 2021-02-04 21:54

    Answering rather for others who got here while searching for advice.

    The key is what several points in the closely related ITU-T recommendations (e.g. Q.921, available online for quite some time already) say:

    1. the lowest order bit is transmitted (and thus received) first

    This legacy behaviour is in contrary to the daily life conventions where highest order digits are written first in the order of reading, and all the generic online calculators and libraries perform the calculation using the conventional order and provide optional settings to facilitate the reversed one. Therefore, you must ask the online calculator

    • to reverse the order of bits in the message you've input in the "conventional" format before performing the calculation,
    • to reverse the order of bits of the result so that you get them in the same order like in the message itself

    Quite reasonably, some calculators offer just a single common setting for both.

    This reasons the settings "reverse data bytes" and "reverse CRC result before Final XOR" recommended in the previous answer;

    2. the result of the CRC calculation must be bit-inverted before sending

    Bit inversion is another name of "xor by 0xffff...". There is a purpose in bit-inverting the CRC calculation result before sending it as the message FCS (the last two bytes of the message, the '93 ac' in your example). See point 4 for details.

    This reasons the setting "Final value ffff", whose name is quite misleading as it actually defines the pattern to be for xor'ed with the result of the calculation. As such operation is required by several CRC types, only the xor patterns vary from 0 (no op) through 0xfff... (complete inversion), generic calculators/libraries offer it for simplicity of use.

    3. the calculation must include processing of a leading sequence of 0xffff

    This reasons the point "initial value ffff".

    4. on the receiving (checking) side, it is recommended to push the complete message, i.e. including the FCS, through the CRC calculation, and expect the result to be 0x1d0f

    There is some clever thinking behind this:

    • the intrinsic property of the CRC algorithm is that

      CRC( x.CRC(x) )

      is always 0 (x represents the original message and "." represents concatenation).

    • running the complete message through the calculation rather than calculating only the message itself and comparing with the FCS received separately means much simpler algorithm (or even circuitry) at the receiving side.

    • however, it is too easy to make a coding mistake causing a result to become 0. Luckily, thanks to the CRC algorithm intrinsic properties again,

      CRC( x.(CRC(x))' )

      yields a constant value independent of x and different from 0 (at least for CRC-CCITT, which we talk about here). The "'" sign represents the bit inversion as required in point 2.

    0 讨论(0)
提交回复
热议问题