/*
   CRC calculators by Tim Kientzle, from ``The Working Programmer's
   Guide to Serial Protocols.''

   This file is Copyright (C) 1995 Tim Kientzle.  All rights reserved.

   Redistribution of this code in source or binary forms is permitted
   under the following conditions:
   1. The above attribution, copyright notice, this list of conditions,
      and the disclaimer below must be preserved intact in all source
      copies of this code.
   2. The name of Tim Kientzle may not be used to advertise or
      promote programs using this code without prior written
      permission.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED.  IN NO EVENT SHALL TIM KIENTZLE OR THE
CORIOLIS GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED, ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Please note that the above conditions are unique to this file.  Other
source files from ``The Working Programmer's Guide to Serial
Protocols'' are subject to the terms and conditions indicated in those
files.

*/

/* Original simple CRC calculator */
short 
BitwiseCrc16 (int bit, short crc)
{
  long longcrc = crc;

  longcrc = (longcrc << 1) ^ bit;
  if (longcrc & 0x10000)
    longcrc ^= 0x11021;

  return (longcrc & 0xFFFF);
}

/* Slightly improved... */
short 
BitwiseCrc16 (int bit, short crc)
{
  if (crc & 0x8000)
    crc = (crc << 1) ^ 0x1021 ^ bit;
  else
    crc = (crc << 1) ^ bit;

  return (crc);
}

/* Basic, table-driven CRC16 calculator */
static short Crc16Table[256];

void 
InitCrc16 ()
{
  short i, j, crc;

  for (i = 0; i < 256; i++)
    {
      crc = (i << 8);
      for (j = 0; j < 8; j++)
	crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0);
      Crc16Table[i] = crc & 0xFFFF;
    }
}

short 
Crc16 (int ch, short crc)
{
  crc = Crc16Table[((crc >> 8) & 255)] ^ (crc << 8) ^ ch;
  return crc & 0xFFFF;
}

/* As above, except implicitly accumulates two zero bytes */

short 
XYZModemCrc16 (int ch, short crc)
{
  crc = Crc16Table[((crc >> 8) ^ ch) & 255] ^ (crc << 8);
  return crc & 0xFFFF;
}


/* CRC-16 as computed by Kermit */

static short Crc16Table[256];

void 
InitCrc16 ()
{
  int i, j, crc;

  for (i = 0; i < 256; i++)
    {
      crc = i;
      for (j = 0; j < 8; j++)
	crc = (crc >> 1) ^ ((crc & 1) ? 0x8408 : 0);
      Crc16Table[i] = crc & 0xFFFF;
    }
}

short 
KermitCrc16 (int ch, short crc)
{
  crc = Crc16Table[(crc ^ ch) & 255)] ^ (crc >> 8);
  return crc & 0xFFFF;
}


/* Standard 12-bit CRC */

static short Crc12Table[256];

void InitCrc12 ()
{
  int i, j, crc;

  for (i = 0; i < 256; i++)
    {
      crc = (i << 4);
      for (j = 0; j < 8; j++)
	crc = (crc << 1) ^ ((crc & 0x800) ? 0x80F : 0);
      Crc12Table[i] = crc & 0xFFF;
    }
}

short Crc12 (int ch, short crc)
{
  crc = Crc16Table[((crc >> 4) ^ ch) & 255] ^ (crc << 8);
  return crc & 0xFFF;
}

/* 32-bit CRC, similar to one used by ZModem */
static long Crc32Table[256];

InitCrc32 ()
{
  int i, j;
  long crc;

  for (i = 0; i < 256; i++)
    {
      crc = (i << 24);
      for (j = 0; j < 8; j++)
	crc = (crc << 1) ^ ((crc & 0x80000000L) ? 0x04c11db7L : 0);
      Crc32Table[i] = crc;
    }
}

long Crc32 (int ch, long crc)
{
  crc = Crc32Table[((crc >> 24) ^ ch) & 255] ^ (crc << 8);
  return crc & 0xFFFFFFFF;
}




