File:  [ELWIX - Embedded LightWeight unIX -] / libaitcrc / src / aitcrc.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Wed Jan 20 00:04:45 2010 UTC (14 years, 5 months ago) by misho
Branches: MAIN
CVS tags: crc1_2, HEAD, CRC1_1
version 1.1

/*************************************************************************
* (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
*  by Michael Pounov <misho@openbsd-bg.org>
*
* $Author: misho $
* $Id: aitcrc.c,v 1.2 2010/01/20 00:04:45 misho Exp $
*
*************************************************************************/
#include "global.h"


static int crc_Errno;
static char crc_Error[MAX_STR + 1];

// Adler module
const u_long crc_modAdler = 0xFFF1L;

// All known library CRC types ...
const crcPoly_t crc_Poly[] = {
	{ 1, (u_long) 0x1, "CRC-1-Parity" }, 
	{ 4, (u_long) 0x3, "CRC-4-ITU" }, 
	{ 5, (u_long) 0x15, "CRC-5-ITU" }, 
	{ 6, (u_long) 0x3, "CRC-6-ITU" }, 
	{ 7, (u_long) 0x9, "CRC-7-MMC" }, 
	{ 8, (u_long) 0x8D, "CRC-8-CCITT" }, 
	{ 10, (u_long) 0x233, "CRC-10" }, 
	{ 11, (u_long) 0x385, "CRC-11-FlexRay" }, 
	{ 12, (u_long) 0x80F, "CRC-12-Telco" }, 
	{ 15, (u_long) 0x4599, "CRC-15-CAN" }, 
	{ 16, (u_long) 0x8005, "CRC-16-IBM" }, 
	{ 24, (u_long) 0x864CFB, "CRC-24-Radix64" }, 
	{ 30, (u_long) 0x2030B9C7, "CRC-30-CDMA" }, 
	{ 32, (u_long) 0x04C11DB7, "CRC-32-802.3" }
};

// ----------------------------------------------------------

//
// Error maintenance functions ...
//

// crc_GetErrno() Get error code of last operation
inline int crc_GetErrno()
{
	return crc_Errno;
}

// crc_GetError() Get error text of last operation
inline const char *crc_GetError()
{
	return crc_Error;
}

// crcSetErr() Set error to variables for internal use!!!
inline void crcSetErr(int eno, char *estr, ...)
{
	va_list lst;

	crc_Errno = eno;
	memset(crc_Error, 0, MAX_STR + 1);
	va_start(lst, estr);
	vsnprintf(crc_Error, MAX_STR + 1, estr, lst);
	va_end(lst);
}

// ----------------------------------------------------------

/*
 * crcReflect() Reflect all bits of number 
 * @crcNum = Number for reflection
 * @crcBits = Number width bits 
 * return: -1 error, !=-1 reflecting number
 */
inline u_long crcReflect(u_long crcNum, u_char crcBits)
{
	register u_long i, j, rev;

	for (i = (u_long) 1 << (crcBits - 1), j = 1, rev ^= rev; i; i >>= 1, j <<= 1)
		if (crcNum & i)
			rev |= j;

	crc_Errno ^= crc_Errno;
	return rev;
}

/*
 * crcCalc() Generic CRC calculation function for many sub variants of CRC algorithms
 * @psBuf = Data for calculation
 * @bufLen = Length of data
 * @crcBits = CRC algorithm bits (1, 4, 5, 6, 7, 8, 10, 11, 12, 15, 16, 24, 30, 32)
 * @RevOpts = Options for computation (REVOPTS_REVERTBYTE, REVOPTS_REVERTCRC)
 * @initCRC = Initial CRC value
 * @xorCRC = Last xor CRC value
 * return: -1 error, !=-1 CRC checksum
 */
inline u_long crcCalc(u_char * __restrict psBuf, u_int bufLen, u_char crcBits, u_char RevOpts, u_long initCRC, u_long xorCRC)
{
	const u_long bits = sizeof(long) * 8 - crcBits;
	u_long poly, crchibit, crc;
	register u_long i, j, b, ch;

	if (!psBuf) {
		crc_Errno = 1;
		strlcpy(crc_Error, "crcCalc(): Invalid parameters!", MAX_STR + 1);
		return -1;
	}

	switch (crcBits) {
		case 1:
			poly = crc_Poly[0].poly_num;
			break;
		case 4:
			poly = crc_Poly[1].poly_num;
			break;
		case 5:
			poly = crc_Poly[2].poly_num;
			break;
		case 6:
			poly = crc_Poly[3].poly_num;
			break;
		case 7:
			poly = crc_Poly[4].poly_num;
			break;
		case 8:
			poly = crc_Poly[5].poly_num;
			break;
		case 10:
			poly = crc_Poly[6].poly_num;
			break;
		case 11:
			poly = crc_Poly[7].poly_num;
			break;
		case 12:
			poly = crc_Poly[8].poly_num;
			break;
		case 15:
			poly = crc_Poly[9].poly_num;
			break;
		case 16:
			poly = crc_Poly[10].poly_num;
			break;
		case 24:
			poly = crc_Poly[11].poly_num;
			break;
		case 30:
			poly = crc_Poly[12].poly_num;
			break;
		case 32:
			poly = crc_Poly[13].poly_num;
			break;
		default:
			crc_Errno = 2;
			strlcpy(crc_Error, "crcCalc(): Unsupported CRC method!!!", MAX_STR + 1);
			return -1;
	}
	poly <<= bits;

	crchibit = (u_long) 1 << (crcBits - 1);
	crchibit <<= bits;
	crc = initCRC << bits;

	for (i = 0; i < bufLen; i++) {
		ch = (u_long) *psBuf++;
		if (RevOpts & REVOPTS_REVERTBYTE)
			ch = crcReflect(ch, 8);

		for (j = 0x80; j; j >>= 1) {
			b = crc & crchibit;
			crc <<= 1;

			if (ch & j)
				b ^= crchibit;
			if (b)
				crc ^= poly;
		}
	}

	if (RevOpts & REVOPTS_REVERTCRC)
		crc = crcReflect(crc, sizeof(long) * 8);
	crc ^= xorCRC << bits;
	crc &= (((crchibit - 1) << 1) | 1);
	if (!(RevOpts & REVOPTS_REVERTCRC))
		crc >>= bits;

	crc_Errno ^= crc_Errno;
	return crc;
}

// ----------------------------------------------------------

/*
 * crcIP() Checksum in IP communication
 * @nBuf = Data for calculation
 * @bufLen = Length of data
 * return: -1 error, !=-1 Checksum
 */
inline u_short crcIP(u_short * __restrict nBuf, int bufLen)
{
	register u_long sum;

	if (!nBuf) {
		crc_Errno = 1;
		strlcpy(crc_Error, "crcIP(): Invalid parameters!", MAX_STR + 1);
		return -1;
	}

	for (sum = 0; bufLen; bufLen--)
		sum += *nBuf++;

	sum = (sum >> 16) + (sum & 0xFFFF);
	sum += sum >> 16;

	crc_Errno ^= crc_Errno;
	return (u_short) ~sum;
}

/*
 * crcFletcher() Fletcher-16 Checksum computing
 * @nBuf = Data for calculation
 * @bufLen = Length of data
 * return: -1 error, !=-1 Checksum
 */
inline u_long crcFletcher(u_short * __restrict nBuf, int bufLen)
{
	register u_long s1, s2, clen;

	if (!nBuf) {
		crc_Errno = 1;
		strlcpy(crc_Error, "crcFletcher(): Invalid parameters!", MAX_STR + 1);
		return -1;
	}

	s1 = s2 = 0xFFFF;
	while (bufLen) {
		clen = bufLen > MAX_FLETCHER_DIGEST ? MAX_FLETCHER_DIGEST : bufLen;
		bufLen -= clen;

		do {
			s1 += (u_long) *nBuf++;
			s2 += s1;
		} while (--clen);

		s1 = (s1 >> 16) + (s1 & 0xFFFF);
		s2 = (s2 >> 16) + (s2 & 0xFFFF);
	}

	crc_Errno ^= crc_Errno;
	return (s2 << 16) | s1;
}

/*
 * crcAdler() crcAdler-32 Checksum computing
 * @psBuf = Data for calculation
 * @bufLen = Length of data
 * return: -1 error, !=-1 Checksum
 */
inline u_long crcAdler(u_char * __restrict psBuf, int bufLen)
{
	register u_long s1, s2, clen;

	if (!psBuf) {
		crc_Errno = 1;
		strlcpy(crc_Error, "crcAdler(): Invalid parameters!", MAX_STR + 1);
		return -1;
	}

	s1 = 1L;
	s2 ^= s2;
	while (bufLen) {
		clen = bufLen > MAX_ADLER_DIGEST ? MAX_ADLER_DIGEST : bufLen;
		bufLen -= clen;

		do {
			s1 += (u_long) *psBuf++;
			s2 += s1;
		} while (--clen);

		s1 %= crc_modAdler;
		s2 %= crc_modAdler;
	}

	crc_Errno ^= crc_Errno;
	return (s2 << 16) | s1;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>