Надежность контрольной суммы CRC16

habr.png
#include 
#include 
#include 
#include 
#include 
#include 

#define PACKET_LEN    (7)
#define NUM_OF_CYCLES (100000)

static unsigned char reverse_table[16] =
{
  0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
  0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
};

uint8_t reverse_bits(uint8_t byte)
{
  // Reverse the top and bottom nibble then swap them.
  return (reverse_table[byte & 0b1111] << 4) | reverse_table[byte >> 4];
}

uint16_t reverse_word(uint16_t word)
{
  return ((reverse_bits(word & 0xFF) << 8) | reverse_bits(word >> 8));
}

uint16_t crc16_common(uint8_t *data, uint8_t len, uint16_t poly, uint16_t init,
                      uint16_t doXor, bool refIn, bool refOut)
{
  uint8_t y;
  uint16_t crc;

  crc = init;
        while (len--)
  {
    if (refIn)
      crc = ((uint16_t)reverse_bits(*data++) << 8) ^ crc;
    else
            crc = ((uint16_t)*data++ << 8) ^ crc;
    for (y = 0; y < 8; y++)
    {
      if (crc & 0x8000)
        crc = (crc << 1) ^ poly;
      else
        crc = crc << 1;
    }
        }

  if (refOut)
    crc = reverse_word(crc);
  return (crc ^ doXor);
}

uint16_t crc16_ccitt(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x1021, 0xFFFF, 0x0000, false, false);
}

uint16_t crc16_bypass(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x8005, 0x0000, 0x0000, false, false);
}

uint16_t crc16_xmodem(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x1021, 0x0000, 0x0000, false, false);
}

uint16_t crc16_teledisk(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0xA097, 0x0000, 0x0000, false, false);
}

uint16_t crc16_augccitt(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x1021, 0x1d0f, 0x0000, false, false);
}

uint16_t crc16_cdma2000(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0xc867, 0xffff, 0x0000, false, false);
}

uint16_t crc16_dds110(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x8005, 0x800d, 0x0000, false, false);
}

uint16_t crc16_dect(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x0589, 0x0000, 0x0000, false, false);
}

uint16_t crc16_en13757(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x3d65, 0x0000, 0xffff, false, false);
}

uint16_t crc16_t10dif(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x8bb7, 0x0000, 0x0000, false, false);
}

uint16_t crc16_cms(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x8005, 0xFFFF, 0x0000, false, false);
}

uint16_t crc16_modbus(uint8_t *data, uint8_t len)
{
  return crc16_common(data, len, 0x8005, 0xFFFF, 0x0000, true, true);
}

bool compare_buf(uint8_t *buf1, uint8_t *buf2)
{
  uint8_t x;

  for (x = 0; x < PACKET_LEN; x++)
  {
    if (buf1[x] != buf2[x])
      return true;
  }

  return false;
}

bool method_shuffle(uint8_t *buf)
{
  uint8_t i, j;
  uint16_t rnd;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  for (i = 0; i < PACKET_LEN; i++)
  {
    for (j = 0; j < 10; j++)
    {
      rnd = (uint16_t)rand();
      if (rnd % 7 == 0)
        buf[i] ^= (1 << (rnd % 8));
    }
  }

  return compare_buf(buf, copy);
}

bool method_bitshift(uint8_t *buf)
{
  uint8_t x, i, j;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  x = (uint8_t)(rand() % PACKET_LEN) + 1;
  for (j = 0; j < x; j++)
  {
    i = (uint8_t)(rand() % PACKET_LEN);
    if (buf[i] == 0)
      buf[i] = 0x01;
    else
      buf[i] <<= 1;
  }

  return compare_buf(buf, copy);
}

bool method_packetroll(uint8_t *buf)
{
  uint8_t x, i, j;
  uint8_t temp;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  x = (uint8_t)(rand() % (PACKET_LEN - 1)) + 1;
  for (j = 0; j < x; j++)
  {
    temp = buf[0];
    for (i = 0; i < PACKET_LEN - 1; i++)
      buf[i] = buf[i + 1];
    buf[PACKET_LEN - 1] = temp;
  }

  return compare_buf(buf, copy);
}

bool method_shiftright(uint8_t *buf)
{
  uint8_t i;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  for (i = 0; i < PACKET_LEN - 1; i++)
      buf[i + 1] = buf[i];
  buf[0] = 0xff;

  return compare_buf(buf, copy);
}

bool method_shiftleft(uint8_t *buf)
{
  uint8_t i;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  for (i = 0; i < PACKET_LEN - 1; i++)
      buf[i] = buf[i + 1];
  buf[PACKET_LEN - 1] = 0xff;

  return compare_buf(buf, copy);
}

bool method_zero(uint8_t *buf)
{
  uint8_t x, i, j;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  x = (uint8_t)(rand() % PACKET_LEN) + 1;
  for (j = 0; j < x; j++)
  {
    i = (uint8_t)(rand() % PACKET_LEN);
    if (buf[i] != 0x00)
      buf[i] = 0x00;
    else
      buf[i] = 0xFF;
  }

  return compare_buf(buf, copy);
}

bool method_one(uint8_t *buf)
{
  uint8_t x, i, j;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  x = (uint8_t)(rand() % PACKET_LEN) + 1;
  for (j = 0; j < x; j++)
  {
    i = (uint8_t)(rand() % PACKET_LEN);
    if (buf[i] != 0xFF)
      buf[i] = 0xFF;
    else
      buf[i] = 0x00;
  }

  return compare_buf(buf, copy);
}

bool method_injection(uint8_t *buf)
{
  uint8_t x, i;
  uint8_t copy[PACKET_LEN];

  memcpy(copy, buf, PACKET_LEN);

  x = (uint8_t)(rand() % PACKET_LEN);
  for (i = PACKET_LEN - 1; i > x; i--)
  {
    buf[i] = buf[i - 1];
  }
  buf[x] = (uint8_t)rand();

  return compare_buf(buf, copy);
}

bool method_single(uint8_t *buf)
{
  uint8_t x;

  x = (uint8_t)(rand() % (PACKET_LEN * 8));
  buf[(uint8_t)(x / 8)] ^= (1 << (x % 8));

  return true;
}

typedef struct
{
  uint16_t crc1;
  uint16_t crc2;
  uint32_t errors;
  uint16_t (*fn)(uint8_t *data, uint8_t len);
  char name[32];
} tCRC;

typedef struct
{
  bool (*fn)(uint8_t *buf);
  char name[32];
} tMethod;

static tMethod methods[] =
{
  {method_shuffle, "Shuffle"},
  {method_bitshift, "Bit shift"},
  {method_packetroll, "Roll packet"},
  {method_shiftright, "Right shift"},
  {method_shiftleft, "Left shift"},
  {method_zero, "Fill zeros"},
  {method_one, "Fill ones"},
  {method_injection, "Byte injection"},
  {method_single, "Single bit"}
};

static tCRC crcs[] =
{
  {0, 0, 0, crc16_cms, "CMS"},
  {0, 0, 0, crc16_ccitt, "CCITT"},
  {0, 0, 0, crc16_augccitt, "AUG-CCITT"},
  {0, 0, 0, crc16_bypass, "BYPASS"},
  {0, 0, 0, crc16_cdma2000, "CDMA2000"},
  {0, 0, 0, crc16_dds110, "DDS-110"},
  {0, 0, 0, crc16_dect, "DECT-X"},
  {0, 0, 0, crc16_en13757, "EN-13757"},
  {0, 0, 0, crc16_modbus, "Modbus"},
  {0, 0, 0, crc16_t10dif, "T10-DIF"},
  {0, 0, 0, crc16_teledisk, "TELEDISK"},
  {0, 0, 0, crc16_xmodem, "XMODEM"}
};

int main(int argc, char * argv[])
{
  uint32_t num_of_cycle;
  uint32_t num_of_sums;
  uint8_t packet[PACKET_LEN];
  uint8_t i;
  uint8_t m;
  //uint8_t buf[8] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};

  srand(time(NULL));

  printf("------------------------- CRC16 comparison -------------------------\n");

  num_of_sums = sizeof(crcs) / sizeof(tCRC);
  for (m = 0; m < sizeof(methods) / sizeof(tMethod); m++)
  {
    printf("\r%s:\n", methods[m].name);

    for (i = 0; i < num_of_sums; i++)
    {
      crcs[i].errors = 0;
    }
    for (num_of_cycle = 0; num_of_cycle < NUM_OF_CYCLES; num_of_cycle++)
    {
      for (i = 0; i < PACKET_LEN; i++)
        packet[i] = (uint8_t)rand();

      for (i = 0; i < num_of_sums; i++)
        crcs[i].crc1 = crcs[i].fn(packet, PACKET_LEN);

      if (!methods[m].fn(packet))
        continue;

      for (i = 0; i < num_of_sums; i++)
      {
        crcs[i].crc2 = crcs[i].fn(packet, PACKET_LEN);
        if (crcs[i].crc1 == crcs[i].crc2)
          crcs[i].errors++;
      }
      if (num_of_cycle % 1000 == 0)
        printf("\r%.2f%%", (float)num_of_cycle / NUM_OF_CYCLES * 100);
    }

    for (i = 0; i < num_of_sums; i++)
      printf("\r  %20s: %10d\n", crcs[i].name, crcs[i].errors);
  }

  return 0;
}


© Habrahabr.ru