! CRC Library - see SIBO SDK Vol 3, Page 3-4
! This DYL supplies its own root class - saves an external reference to OLIB
LIBRARY crc
INCLUDE p_std.h
INCLUDE p_object.h
CLASS root {
ADD destroy
PROPERTY
{
P_OBJECT pc ;
}
}
The root class we provide just eliminates the need for an
external references. It could also be subsumed into the crc
class below.
! Abstract base class
CLASS crc root
{
DEFER crc_init ! initializes a CRC object
DEFER crc_calc ! calculate (update) a CRC for a single byte
DEFER crc_calc_len ! calculate (update) a CRC for a stream of bytes
PROPERTY
{
unsigned short crctab[256] ; ! table of values: crctab[n] is just crc_fn(n, polynomial, 0)
}
}
The crc base class is an abstract base class which has just two
purposes:
crc objects. The following member
functions are available:
crc_init; Initialize the crc object -
this just initializes the tables stored within the crc
object.
crc_calc: Calculate the CRC for a single byte.
crc_calc_len: Calculate the CRC for a stream of
contiguous bytes.
! Concrete CCITT CRC - used in X/YMODEM
CLASS ccitt crc
{
REPLACE crc_init
REPLACE crc_calc
REPLACE crc_calc_len
}
The class ccitt inherits from the crc base class
and replaces all methods. The CCITT CRC is the CRC used in the X-MODEM and
Y-MODEM protocols. Psion provides an implementation for this CRC in the PLIB
library, but this DYL also provides it as an example.
! Concrete CRC16 CRC - used in DEX/UCS
CLASS crc16 crc
{
REPLACE crc_init
REPLACE crc_calc
REPLACE crc_calc_len
}
The class crc16 inherits from the crc base class
and replaces all methods. The CRC-16 is used specifically in the DEX
(DEX/UCS) protocol for data interchange used by supermarkets, retailers and
vending machines.
Most of this code is based on Joe Campbell's "C Programmer's Guide to Serial Communications" published by Sam's. I highly recommend this book if you ever want to know anything about serial comms, modems, CRCs, etc. It will earn its keep after just one reference...
You can get it from Amazon.com, which I also highly recommend if you don't want to be tempted by going into a real bookstore.
// CRC generator for inclusion in an EPOC DYL 961105 JCRoux 73733.1014@compuserve.com #include <crc.g> // Code from C Programmer's Guide to Serial Communications, Joe Campbell, Sam's typedef unsigned short USHORT ; #define CRCCCITT 0x1021 // CCITT polynomial (for XMODEM etc.) #define CRC16 0x8005 // CRC16 polynomial #define CRC16_REV 0xA001 // Reverse CRC16 polynomial (for DEX/UCS etc.)The polynomials are bit masks, where the bits in the mask identify which coefficients are used.
#define crcupdate(d, a, t) *(a) = (*(a) << 8) ^ (t)[(*(a) >> 8) ^ (d)] #define crcupdate16(d, a, t) *(a) = ((*(a)>>8) ^ (t)[(*(a) ^ (d)) & 0x00FF])These extremely noxious macros do most of the dirty work in getting the table results.
// "Classical" Hardware bitshift simulation of CRC
USHORT crc_hware(USHORT data, USHORT genpoly, USHORT accum) {
int i ;
data <<= 8 ;
for ( i = 8 ; i > 0 ; i-- ) {
if ( (data ^ accum) & 0x8000 ) {
accum = (accum << 1) ^ genpoly ;
}
else {
accum <<= 1 ;
}
data <<= 1 ;
}
return(accum) ;
}
// "Reverse" Hardware bitshift simulation of CRC
USHORT crc_revhware(USHORT data, USHORT genpoly, USHORT accum) {
int i ;
data <<= 1 ;
for ( i = 8 ; i > 0 ; i-- ) {
data >= 1 ;
if ( (data ^ accum) & 0x0001 ) {
accum = (accum > 1) ^ genpoly ;
}
else {
accum >>= 1 ;
}
}
return(accum) ;
}
The two routines above actually do the CRC calculations and are only used to
build the tables in the crc ojects during initialization.
// Create a table
VOID make_crctbl(USHORT *ptable, USHORT poly, USHORT (*crcfn)(USHORT, USHORT, USHORT)) {
int i ;
for ( i = 0 ; i < 256 ; i++ ) {
ptable[i] = (*crcfn)(i, poly, 0) ;
}
}
The make_crctbl() will be used during initialization and will
call one of the bitshift simulations to calculate the CRCs for each byte in
the table.
#pragma METHOD_CALL
// Initialize the table stored internally
METHOD VOID ccitt_crc_init(PR_CCITT *self) {
// Create the CRC table - DYLs cannot have static data
make_crctbl(self->crc.crctab, CRCCCITT, crc_hware) ;
}
// Calculate the CRC for just one byte
METHOD VOID ccitt_crc_calc(PR_CCITT *self, char *data, USHORT *crc) {
crcupdate(*data, crc, self->crc.crctab) ;
}
// Calculate the CRC for a string of bytes
METHOD VOID ccitt_crc_calc_len(PR_CCITT *self, char *data, USHORT *crc, int len) {
for ( ; len > 0 ; data++, len-- ) {
crcupdate(*data, crc, self->crc.crctab) ;
}
}
The init method implementations simply use the appropriate
polynomials and bitshift simulators to build the tables.
The crc_calc and crc_calc_len implementations use
the macros to perform the necessary bitshifts on the current CRC, the current
data (which gives us the new table entry to be used)
// Initialize the table stored internally
METHOD VOID crc16_crc_init(PR_CRC16 *self) {
// Create the CRC table - DYLs cannot have static data
make_crctbl(self->crc.crctab, CRC16_REV, crc_revhware) ;
}
// Calculate the CRC for just one byte
METHOD VOID crc16_crc_calc(PR_CRC16 *self, char *data, USHORT *crc) {
crcupdate16(*data, crc, self->crc.crctab) ;
}
// Calculate the CRC for a string of bytes
METHOD VOID crc16_crc_calc_len(PR_CRC16 *self, char *data, USHORT *crc, int len) {
for ( ; len > 0 ; data++, len-- ) {
crcupdate16(*data, crc, self->crc.crctab) ;
}
}
Download crc.cat and crc_o.c.
Back to My home page