Automatische Lokanmeldung mit DCC/Railcom

CRC4

    In der automatischen Anmeldung werden Dekoder-ID und Hash an die Zentrale übermittelt. Inbesondere die Übermittlung der DekoderID ist Übertragungsfehlern ausgesetzt, da ja auf die Nachricht LOGON_ENABLE fallweise mehrere Dekoder zugleich antworten können.
    Deswegen werden diese Nachrichten zusätzlich zur Gewichtskodierung (Hamminggewicht von 4 je Byte) mit einer Prüfsumme gesichert. Verwendet wird CRC4/ITU.
    Polynom: x4 + x1 + 1
    Initwert:0

Berechnungstool

    Eingaben:
    
        Vendor:      Serial: 
        Berechnung: Please enable JavaScript
        
        resultierendes Railcom-Paket:
        Ch1 .....Ch2......
        F_ __ __ __ __ __
        || || || || || ||
        || || +---------+--  Produktkennung
        || ++--------------  Herstellerkennung
        |+-----------------  CRC4-Prüfnibble
        +------------------  Railcom ID15
        

Beispielcode

  • Implementierung mit bitweiser Berechnung:
         uint8_t crc4itu_bit(const uint8_t *data)
          {
            uint8_t crc = 0;                        // init
            uint8_t length = 5;                     // length fix auf 5 Bytes
            for (uint8_t i=0; i<length; i++)
              {
                for (uint8_t s=0; s<8; s++)
                  {
                    if ((crc & 1) ^ ((data[i] >> s) & 1))
                        crc = (crc >> 1) ^ 0b1100; // reflected lsbs of polynomial
                    else
                        crc = crc >> 1;
                  }
              }
            return crc;
          }
      
  • Implementierung mit nibbleweiser Berechnung (schneller, kleine Tabelle)
        uint8_t crc4itu_nibble(const uint8_t *data)
          {
            uint8_t table[] = { 0x0, 0xd, 0x3, 0xe, 0x6, 0xb, 0x5, 0x8, 0xc, 0x1, 0xf, 0x2, 0xa, 0x7, 0x9, 0x4 };
            uint8_t crc = 0;
            uint8_t length = 5;
    
            for (uint8_t i=0; i<length; i++)
              {
                crc = table[(crc ^ (data[i] >> 0)) & 0xf];
                crc = table[(crc ^ (data[i] >> 4)) & 0xf];
              }
            return crc;
          }
      
  • Implementierung mit byteweiser Berechnung (schnell, Tabelle mit 256 Bytes)
        const unsigned char crc4_array[256] =
          {
            0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc, 0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6,
            0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1, 0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb,
            0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf, 0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5,
            0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2, 0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8,
            0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa, 0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0,
            0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7, 0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd,
            0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9, 0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3,
            0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4, 0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe,
            0xc, 0xb, 0x2, 0x5, 0x9, 0xe, 0x7, 0x0, 0x6, 0x1, 0x8, 0xf, 0x3, 0x4, 0xd, 0xa,
            0x1, 0x6, 0xf, 0x8, 0x4, 0x3, 0xa, 0xd, 0xb, 0xc, 0x5, 0x2, 0xe, 0x9, 0x0, 0x7,
            0xf, 0x8, 0x1, 0x6, 0xa, 0xd, 0x4, 0x3, 0x5, 0x2, 0xb, 0xc, 0x0, 0x7, 0xe, 0x9,
            0x2, 0x5, 0xc, 0xb, 0x7, 0x0, 0x9, 0xe, 0x8, 0xf, 0x6, 0x1, 0xd, 0xa, 0x3, 0x4,
            0xa, 0xd, 0x4, 0x3, 0xf, 0x8, 0x1, 0x6, 0x0, 0x7, 0xe, 0x9, 0x5, 0x2, 0xb, 0xc,
            0x7, 0x0, 0x9, 0xe, 0x2, 0x5, 0xc, 0xb, 0xd, 0xa, 0x3, 0x4, 0x8, 0xf, 0x6, 0x1,
            0x9, 0xe, 0x7, 0x0, 0xc, 0xb, 0x2, 0x5, 0x3, 0x4, 0xd, 0xa, 0x6, 0x1, 0x8, 0xf,
            0x4, 0x3, 0xa, 0xd, 0x1, 0x6, 0xf, 0x8, 0xe, 0x9, 0x0, 0x7, 0xb, 0xc, 0x5, 0x2
          };
    
        uint8_t crc4itu_byte(const uint8_t *data)
        {
            uint8_t crc = 0;
            uint8_t length = 5;
    
            while (length--)
                crc = crc4_array[crc ^ *(unsigned char const *)data++)];
            return crc;
        }
      

Links, Quellen