unsigned short crc16(unsigned char *buf, unsigned long len)
{
    register unsigned char crc_lo, crc_hi, byte;

    crc_lo = 0xFF;
    crc_hi = 0xFF;

    while (len--)
    {
        byte = *(buf++);
        byte ^= crc_hi;

        crc_hi = ( byte & 0x02 ) ? (crc_lo - 0x80) : crc_lo;

        if ( byte & 0x01 )
        crc_hi ^= 0xC0;

        crc_lo = byte;
        crc_lo >>= 1;
        crc_lo ^= byte;
        crc_lo >>= 1;
        byte ^= crc_lo;

        if ( byte & 0x08 )
        --byte;

        if ( byte & 0x40 )
        --byte;

        byte &= 0x01;

        if ( byte )
        crc_lo ^= 0xC0;

        crc_hi ^= byte;
    }

    return (unsigned short)(((unsigned short)crc_hi << 8) | crc_lo);
}
    
