HDLC FSK Scrambling

I’ve spent nearly the entire summer working on the comm system for Electra, and now that it (the comm system, not Electra) is nearly complete, I’d like to say something to the HAM community at large: DOCUMENTATION!!! WRITE SOME!!

Specifically, some of the low-level encoding/decoding that is typically handled in hardware on commercial TNC’s could use some clarification. So here it is. To go from the bitstream received by the radio to the original bytestream that was sent, we need to go through 4 levels of decoding.

First, the FSK decoding is handled entirely by our radio chip, a Chipcon CC1000. It is noteworthy that we found a frequency separation of 10 kHz to be most effective, otherwise this layer was more or less straightforward.

Second, the incoming data is NRZI encoded, which is not handled by our radio, and must be done in software. This is fairly straightforward to handle with a couple lines of C:

bit = !(bitIn ^ prevBit);
prevBit = bitIn;

Make sure to declare prevBit as static if this code is in a function that is called once per bit. (Electra is wired such that there is an interrupt on every bit received by the CC1000, and the decoder is part of the interrupt handler)

Third is the descrambling. This is the real kicker. Since FSK operates by sending 0’s and 1’s as lower and higher frequencies respectively, the TNC needs a way to find the center value from which to calculate this deviation. It calculates this by calculating a running average of the high and low frequencies, which is fine, if there aren’t too many 1’s or 0’s in a row, which will skew the average. To avoid this, the TNC scrambles the outgoing data, creating a more “random” data stream. The scrambling algorithm is based on the identity (a^b)^b=a where ‘^‘ represents a bitwise XOR.

On the TX side, a is the unscrambled bit and b=R17^R12 where R17 and R12 are the 17th and 12th bits of a 17-bit shift register. After the bit is scrambled, it is shifted into the least significant bit of the register, and sent to the NRZI encoder. On the RX side, each NRZI decoded bit is again xored by (R17^R12) before being sent to the HDLC decoder. After the bit is descrambled, the scrambled bit is shifted into the register.

Scrambling:

bit = bit ^ ( scramBuff >> 11 ) ^ ( scramBuff >> 16);

scramBuff = (scramBuff << 1) | (bit & 1);

Descrambling:

/* Make room for the new bit */
scramBuff = scramBuff << 1;

/* Add the new bit */
scramBuff |= bit & 1;

/* Descramble the bit */
bit = bit ^ ((scramBuff >> 12)^
(scramBuff >> 17));

Finally, we are ready to decode the HDLC frame itself, which is already well documented.

Leave a Reply

You must be logged in to post a comment.