// // Little demo program showing a scrambler. // #include #include #include // Set up some buffers for our test messages. // #define MAX_MSG 100 unsigned char inmsg[MAX_MSG]; // Original message unsigned char scrmsg[MAX_MSG]; // Scrambled message unsigned char outmsg[MAX_MSG]; // Descrambled message int msglen; // Seed is what gets loaded into the scrambler's shift register. // In DOCSIS, this occurs prior to each burst. Other protocols might // do this at the start of some other type of "frame". // #define SCRAMBLER_SEED (0x0152) // Command codes to make scrambler function do different things. #define SCRAMBLER_OPTION_LOADSEED 1 #define SCRAMBLER_OPTION_GETBIT 2 #define SCRAMBLER_OPTION_ADVANCE 3 unsigned short int scrambler (unsigned short int seed, int option); // Test message.. unsigned char test_msg1[] = "This is a simpl ASCII test message easy to visually verify."; int main () { int i, bitnum, nerrors; int sbit; unsigned char data; // Copy test message into the first buffer msglen = sizeof(test_msg1); for (i = 0; i < sizeof(test_msg1); i++) inmsg[i] = test_msg1[i]; // Display our starting message in HEX printf ("\n***** Dumping the initial message of (%0d) bytes", msglen); for (i = 0; i < msglen; i++) { if ((i % 16) == 0) printf ("\n"); printf ("%02X ", inmsg[i]); } printf ("\n\n"); // Scramble the message scrambler (SCRAMBLER_SEED, SCRAMBLER_OPTION_LOADSEED); for (i = 0; i < msglen; i++) { data = inmsg[i]; for (bitnum = 7; bitnum > 0; bitnum--) { sbit = scrambler (0, SCRAMBLER_OPTION_GETBIT); scrambler (0, SCRAMBLER_OPTION_ADVANCE); data ^= (sbit << bitnum); } scrmsg[i] = data; } // Dump the Scrambled message printf ("\n***** Dumping the scrambled message"); for (i = 0; i < msglen; i++) { if ((i % 16) == 0) printf ("\n"); printf ("%02X ", scrmsg[i]); } printf ("\n\n"); // *** OK. Pretend we've transmitted our bits... Now its time to descramble them back. // Descramble the message (use the same algorithm - its a symetric operation!) scrambler (SCRAMBLER_SEED, SCRAMBLER_OPTION_LOADSEED); for (i = 0; i < msglen; i++) { data = scrmsg[i]; for (bitnum = 7; bitnum > 0; bitnum--) { sbit = scrambler (0, SCRAMBLER_OPTION_GETBIT); scrambler (0, SCRAMBLER_OPTION_ADVANCE); data ^= (sbit << bitnum); } outmsg[i] = data; } // Dump the Descrambled message printf ("\n***** Dumping the descrambled message"); for (i = 0; i < msglen; i++) { if ((i % 16) == 0) printf ("\n"); printf ("%02X ", outmsg[i]); } printf ("\n\n"); // Just for reference, dump the isolated scrambler bits. Use the scrmsg array for this. scrambler (SCRAMBLER_SEED, SCRAMBLER_OPTION_LOADSEED); for (i = 0; i < msglen; i++) { data = 0; for (bitnum = 7; bitnum > 0; bitnum--) { sbit = scrambler (0, SCRAMBLER_OPTION_GETBIT); scrambler (0, SCRAMBLER_OPTION_ADVANCE); data |= (sbit << bitnum); } scrmsg[i] = data; } printf ("\n***** Dumping the scrambler bits"); for (i = 0; i < msglen; i++) { if ((i % 16) == 0) printf ("\n"); printf ("%02X ", scrmsg[i]); } printf ("\n\n"); // I guess we should verify the fimal descrambled message is, in fact, the same as original. nerrors = 0; for (i = 0; i < msglen; i++) { if (inmsg[i] != outmsg[i]) { printf ("\nMismatch!"); nerrors++; } } if (nerrors == 0) { printf ("\nSuccess: received buffer matches original buffer."); } printf ("\nThat's it."); printf ("\n"); } // Here is the actual scrambler. // All it is, is a linear feedback shift register with taps at the MSB and the // next to the MSB. This happens to be the DOCSIS scrambler configuration. // // The scrambler only generates the scrambler bits. The scrambler bit is then // used by the calling function for an XOR with the data. Caller function must do // the final XOR. // // This function happens to break down the operation of the scrambler into // individual steps. This is just for clarity (seemed clearer to me..) but you // could probably easily combine everything into a single call. // unsigned short int scrambler (unsigned short int seed, int option) { static unsigned short int x; // Note this is STATIC! unsigned short int scrambler_bit; // Go ahead and compute the scrambler bit in case we need it. // Taps at bits 14 and 13, which is DOCSIS. XOR the tapped bits // and feed back into X register's LSB. X register is shifted // towards the MSB. // scrambler_bit = ((x >> 14) & 1) ^ ((x >> 13) & 1); if (option == SCRAMBLER_OPTION_LOADSEED) { // Just load the SEED into X register x = seed; return x; } else if (option == SCRAMBLER_OPTION_GETBIT) { return scrambler_bit; } else if (option == SCRAMBLER_OPTION_ADVANCE) { x = (x << 1) + scrambler_bit; return x; } else { printf ("\nSCRAMBLER: Unknown option: %0d", option); return 0; } return 0; } // Another little way to see the scrambler work.. not currently called from main.. // int test_scrambler2 () { int i; unsigned short int x, sbit; printf ("\nScrambler bits with SEED = 0x%04X", 0x0152); printf ("\n-------------------------------", 0x0152); printf ("\nScrambler Bit (to be XORed with data)"); printf ("\n| X Register (15-bits, N=15 to the left, N=1 to the right)"); printf ("\n| |"); printf ("\nV V"); x = scrambler (0x0152, SCRAMBLER_OPTION_LOADSEED); for (i = 0; i < 176; i++) { sbit = scrambler (0, SCRAMBLER_OPTION_GETBIT); printf ("\n%d %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", sbit, (x & (1 << 14)) ? '1' : '0', (x & (1 << 13)) ? '1' : '0', (x & (1 << 12)) ? '1' : '0', (x & (1 << 11)) ? '1' : '0', (x & (1 << 10)) ? '1' : '0', (x & (1 << 9)) ? '1' : '0', (x & (1 << 8)) ? '1' : '0', (x & (1 << 7)) ? '1' : '0', (x & (1 << 6)) ? '1' : '0', (x & (1 << 5)) ? '1' : '0', (x & (1 << 4)) ? '1' : '0', (x & (1 << 3)) ? '1' : '0', (x & (1 << 2)) ? '1' : '0', (x & (1 << 1)) ? '1' : '0', (x & (1 << 0)) ? '1' : '0' ); x = scrambler (0, SCRAMBLER_OPTION_ADVANCE); } printf ("\n"); return 0; }