//------------------------------------------------------------------- // tokencrc.cpp // // This program's output is intended to offer a tutorial on the // steps by which a USB token-packet's 5-bit CRC field could be // calculated by hand, then confirmed by comparison with output // displayed by a USB Protocol Analyzer such as the Beagle 480. // // We hope to clear up various ambiguities in published work on // this topic arising from the USB bitstream order, byte-order, // and the number of bits to retain when representing the CRC-5 // polynomial in binary, as well as the number of bits that get // 'flipped' in the 'leading-zero fix' and 'trailing-zero fix.' // // to compile: $ g++ tokencrc.cpp -o tokencrc // to execute: $ ./tokencrc // // REFERENCE: // "USB Specification, Revision 2.0," (April 2000), page 198. // // programmer: ALLAN CRUSE // written on: 14 JUN 2011 //------------------------------------------------------------------- #include // for printf() #include // for atoi() #include // for strcat() unsigned int bit_reflect( unsigned int parm, int numbits ) { unsigned int temp = 0; for (int i = 0; i < numbits; i++) { temp <<= 1; if ( (parm >> i) & 1 ) temp |= 1; } return temp; } int main( int argc, char **argv ) { if ( argc < 3 ) // fewer than two command-line arguments { fprintf( stderr, "usage: $ %s \n", argv[0] ); exit(1); } int devID = atoi( argv[1] ) & 0x7F; int endpt = atoi( argv[2] ) & 0x0F; printf( "\n\n Developing a USB token-packet's data-bytes for" ); printf( " deviceID=%u, endpoint=%u \n\n", devID, endpt ); unsigned short packet = (endpt << 7)|(devID << 0); printf( "\n packet-bits (lsb-to-msb): " ); for (int i = 0; i < 16; i++) { char bit = (packet >> (15 -i)) & 1; if (( i == 5 )||( i == 9)) printf( "- " ); printf( "%X ", bit ); } printf( "\n" ); unsigned short stream = bit_reflect( packet, 11 ); printf( "\n packet-bits (msb-to-lsb): " ); for (int i = 0; i < 16; i++) { char bit = (packet >> i) & 1; if (( i == 7 )||( i == 11 )) printf( "- " ); printf( "%X ", bit ); } printf( "\n" ); //=========================================================== // Detailed display of the polynomial long-division in GF(2) //=========================================================== printf( "\n\n Now perform the 3-step CRC-5 computation: \n" ); char dividend[ 17 ] = { 0 };; for (int i = 0; i < 16; i++) dividend[i] = (( packet >> i )&1 ) ? '1' : '0'; // the so-called 'leading-zeros fix' printf( "\n STEP 1: complement the five leading bits \n\n" ); printf( " %s \n", dividend ); printf( " xor 11111 \n" ); printf( " ------------------ \n" ); for (int i = 0; i < 5; i++) dividend[i] ^= 1; printf( " %s \n", dividend ); // the long-division of polynomials over the Galois Field GF(2) printf( "\n STEP 2: perform the polynomial long-division \n" ); char poly5[ 7 ] = "100101"; printf( "\n ___________________ \n" ); printf( " %s ) %s \n", poly5, dividend ); char indent[ 60 ] = { 0 }; strcat( indent, " " ); for (int i = 0; i < 11; i++) { printf( "%s", indent ); unsigned int top = dividend[i] & 1; switch ( top ) { case 1: printf( " %s \n", poly5 ); break; case 0: printf( " %s \n", "000000" ); break; } printf( "%s-------- \n", indent ); if ( top ) for (int j = 0; j < 6; j++) dividend[ i+j ] ^= (poly5[ j ] & 1); dividend[i] = ' '; printf( " %s \n", dividend ); strcat( indent, " " ); } // the so-called 'trailing-zeros fix' printf( "\n STEP 3: complement the five remainder-bits \n" ); printf( "\n" ); printf( " %s \n", dividend ); printf( " xor %s \n", "11111" ); printf( "%s------- \n", indent ); for (int j = 0; j < 5; j++) dividend[ 11+j ] ^= 1; printf( " %s \n", dividend ); //======================================================= // convert the residual dividend-string into an integer unsigned int remainder = 0; for (int i = 0; i < 5; i++) { remainder <<= 1; if ( dividend[ 11+i ] & 1 ) remainder |= 1; } // show the final bitstream-reordering and byte-reordering printf( "\n\n Now we merge this CRC with the token-packet's data:\n" ); unsigned int token = packet | (bit_reflect( remainder, 5 ) << 11); printf( "\n packet-bits (lsb-to-msb): " ); for (int i = 0; i < 16; i++) { char bit = (token >> i) & 1; if (( i == 7 )||( i == 11 )) printf( "- " ); printf( "%X ", bit ); } printf( "\n" ); printf( "\n packet-bits (msb-to-lsb): " ); for (int i = 0; i < 16; i++) { char bit = (token >> (15 -i)) & 1; if (( i == 5 )||( i == 9)) printf( "- " ); printf( "%X ", bit ); } printf( "\n\n" ); // show the resulting token-packet's data+CRC in hexadecimal printf( "\n The token-packet's data-bytes " ); printf( "(with 5-bit CRC included): 0x%04X \n", token ); unsigned char *ptr = (unsigned char *)&token; printf( "\n The token-packet data-bytes" ); printf( " in little-endian byte-order: " ); printf( "%02X %02X \n\n", ptr[0], ptr[1] ); }