SLAU131V October 2004 – February 2020
/*****************************************************************************/
/* Reference implementation of a CRC calculation function */
/* gen_crc is the interface function which should be called from the */
/* application. There is also a stand-alone test mode that can be used */
/* if _RUN_MAIN is defined. */
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/* This file does NOT implement a general-purpose CRC function. */
/* Specifically, it does not handle parameterization by initial value, bit */
/* reflection, or final XOR value. This implementation is intended only to */
/* implement the CRC funtions used by the linker for MSP430 CRC tables. The */
/* algorithms used by the linker are selected to match the CRC algorithms in */
/* the PRIME and IEEE 802.15.4-2006 standards. MSP430 crc hardware supports */
/* CRC16_802_15_4 (CRC_CCITT). To understand CRCs in general, especially */
/* what other parameters exist, see: */
/* */
/* "A Painless Guide To CRC Error Detection Algorithms" likely at: */
/* http://www.ross.net/crc/download/crc_v3.txt */
/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */
/* Date : 3 June 1993. */
/* Status : Public domain (C code). */
/*---------------------------------------------------------------------------*/
#include <msp430.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
/*---------------------------------------------------------------------------*/
/* These are the CRC algorithms supported by the linker. MPS430 crc hardware */
/* supports CRC16_802_15_4 (CRC_CCITT). These must match the values in */
/* crc_tbl.h */
/*---------------------------------------------------------------------------*/
#define CRC32_PRIME 0
#define CRC16_802_15_4 1
#define CRC16_ALT 2
#define CRC8_PRIME 3
typedef struct crc_config_t
{
int id;
int degree;
unsigned long poly;
} crc_config_t;
const crc_config_t crc_config[] =
{
{ CRC32_PRIME, 32, 0x04c11db7 },
{ CRC16_802_15_4, 16, 0x1021 },
{ CRC16_ALT, 16, 0x8005 },
{ CRC8_PRIME, 8, 0x07 }
};
unsigned long crc_table[256] = { 0 };
const crc_config_t *find_config(int id) {
size_t i;
for (i = 0; i < sizeof(crc_config) / sizeof(*crc_config); i++)
if (crc_config[i].id == id)
return &crc_config[i];
fprintf(stderr, "invalid config id %d\n", id);
exit(EXIT_FAILURE);
return NULL;
}
/*---------------------------------------------------------------------------*/
/* Table-driven version */
/*---------------------------------------------------------------------------*/
unsigned long generate_mask(int degree)
{
unsigned long half = (1ul << (degree / 2)) - 1;
return half << (degree / 2) | half;
}
void generate_crc_table(const crc_config_t *config)
{
int i, j;
unsigned long bit, crc;
unsigned long high_bit = (1ul << (config->degree - 1));
unsigned long mask = generate_mask(config->degree);
for (i = 0; i < 256; i++)
{
crc = (unsigned long)i << config->degree - 8;
for (j = 0; j < 8; j++)
{
bit = crc & high_bit;
crc <<= 1;
if (bit) crc^= config->poly;
}
crc_table[i] = crc & mask;
}
}
/*****************************************************************************/
/* gen_crc - Return the CRC value for the data using the given CRC algorithm */
/* int id : identifies the CRC algorithm */
/* char *data : the data */
/* size_t len : the size of the data */
/*****************************************************************************/
unsigned long gen_crc(int id, const unsigned char *data, size_t len)
{
/*-----------------------------------------------------------------------*/
/* Note: this is not a general-purpose CRC function. It does not handle */
/* parameterization by initial value, bit reflection, or final XOR */
/* value. This CRC function is specialized to the CRC algorithms in the */
/* linker used for MSP430 CRC tables. */
/*-----------------------------------------------------------------------*/
/* This CRC function is not intended to be optimal; it is written such */
/* that it works and generates the same result on all 8-bit and 16-bit */
/* targets, including MSP430, other TI DSPs, and typical desktops. */
/*-----------------------------------------------------------------------*/
const crc_config_t *config = find_config(id);
unsigned long crc = 0;
unsigned long mask = generate_mask(config->degree);
size_t i;
generate_crc_table(config);
for (i = 0; i < len; i++)
{
unsigned int datum = data[i];
/*--------------------------------------------------------------------*/
/* This loop handles 16-bit chars when we compile on 16-bit machines. */
/*--------------------------------------------------------------------*/
int n;
for (n = 0; n < (CHAR_BIT / 8); n++)
{
unsigned long octet = ((datum >> (8 * n)) & 0xff);
unsigned long term1 = (crc << 8);
int idx = ((crc >> (config->degree - 8)) & 0xff) ^ octet;
crc = term1 ^ crc_table[idx];
}
}
return crc & mask;
}
/*****************************************************************************/
/* main - If requested, compute the CRC of test data using each algorithm. */
/*****************************************************************************/
int main(void)
{
const unsigned char data[] = { 0, 'a', 0, 'b', 0, 'c', 0, 'd' };
/* CRC_8_PRIME: 0x70 */
/* CRC_16_802: 0x1bd3 */
/* CRC_32_PRIME: 0x4beab53b */
const unsigned char *p = (const unsigned char *)data;
unsigned long crc;
crc = gen_crc(CRC32_PRIME, p, sizeof data);
printf("CRC_32_PRIME: %08lx\n", crc);
crc = gen_crc(CRC8_PRIME, p, sizeof data);
printf("CRC_8_PRIME: %02lx\n", crc);
crc = gen_crc(CRC16_802_15_4, p, sizeof data);
printf("CRC16_802_15_4: %04lx\n", crc);
return 0;
}