# Sharp EL-5500III (PC-1403) cassette tape encoding

I have an old audio cassette tape of digital data I converted to .wav and am hacking to recover the original data. I demodulated the 4K/2K FSK modulation with minimodem. Then I get stuck with insufficient understanding of the NRZI bit-stuffing algorithm. Short-cut: does anybody know of sox-like or minimodem-like program that does NRZI decoding through Linux pipes?

Many references explain that bits are stuffed into NRZI data streams after 5 consecutive bits of one polarity. But to be precise, I haven't found a clarification. Does this mean:

1. a bit stuff happens after 5 bits, or
2. a bit stuff happens in order to prevent a run of 6 bits?

By example, if the original data is ...11111001... does it get transmitted as is, or does a bit stuff occur to send the data ...111110001... ? If the bit-stuff is only to cause a transition after 5 bits, then the stuff is not necessary. But the docs say "after 5 bits" which would create unnecessary stuffs if the original data had inherent runs of exactly 5 bits.

Here's the bit stream I'm trying to decode.

root@kali:~# minimodem --rx -R 44100 --mark 4000 --space 2000 --binary-raw 26 -f monoshort8008.wav 500
CARRIER 500 @ 4000.0 Hz
11111111111111111111111111
11111111111111111111111111
11111111111111111110111010
00001111100000100000111110
00001000001111100000100000
11111000001000001111100000
10000011111000001000001111
10000010000011111010101011
11111110100010001011111000
00100000110000010010111000
00101100110101110111111000
10101000110000010101111000
00100000110100010001011000
00100101110101110101011000
10101001110110010101111000
10101000110101110000011011
00100000110101110100011001
00101011110110010100011000
00101011110000010000011010
00100111110000010110011010
11101011110001010100111000
00101011110000010000011001
00100001110000010110011010
11101001110001010100111000
00101011110000010000011011
00100100110000010110011000
11100010110001010100011000
00101011110111110111111011
11101111110000110111011110
NOCARRIER ndata=29 confidence=150.653 ampl=0.126 bps=500.04 (0.0% fast)


Notice the sets of 5 bits near the beginning. Notice also the periodicity of 13 bytes, visible as vertical column runs of 1 or 0 through all the data.

Andy suggested Octave check the frequencies of the modulation. Here is a plot of the data - x axis is an unscaled count of data points. Data was collected at 44,100 Hz. Working the scale factor shows 2KHz and 4KHz, 2msec bit time. Matches Audacity waveform view and Minimodem FSK demodulation.

• i was familiar with the Kansas City Standard, which was 4 cycles of 1200 Hz for a 0 and 8 cycles of 2400 Hz for a 1. i once wrote code for the MC6809 to save and retrieve files using that. But I am not familiar with the protocol with 2 kHz and 4 kHz. i don't see why there is any NRZ issue. that's not how FSK works. Jun 7 '20 at 3:03
• if this is like SDLC, the bit stuffing occurs whenever there is a string of 1 bits, whether it is needed or nor. If the docs say stuff a 0 after 11111, then there should always be a 0 there. If there is six 1 in a row (like 111111) that must be a synchronization preamble. whether the original data is 11111001 or 11111101 the encoder should have always stuffed the zero in after five 1 bits and you should always remove the zero. Jun 7 '20 at 3:08
• can you link to one of these "many references"? might help us! Jun 7 '20 at 7:55
• (I'd frankly just test either hypothesis by making a histogram of the longest consecutive 1-runs in the signal) Jun 7 '20 at 7:55
• Robert, I know I have 500Hz 4KH/2KHz FSK, but then the bit stream is encoded with something I can't get determine. KCS was 8N2 and my data doesn't appear to be any popular async protocol. There is no periodicity at any asynch protocol I'm aware of. Clues point toward synchronous NRZI, but I'm trying to make sure I'm doing the bit stuffing correct. Jun 8 '20 at 1:06

Update:

The source code in the Pocket-Tools software package has all the answers you need:

http://pocket.free.fr/html/soft/pocket-tools_e.html

Although the way the code is written for many different models, makes it hard to read.

Without more context and information about what device may have created this data, there's not much of a question to answer here.

Another way of looking at the bits you have generated is like this:

11111111111111
11111111111111
11111111111111
11111111111111
11111111111111
10 1110 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 0000 10 0000 1111
10 1010 10 1111 1111
10 1000 10 0010 1111
10 0000 10 0000 1
10 0000 10 0101 1
10 0000 10 1100 1
10 1011 10 1111 1
10 0010 10 1000 1
10 0000 10 1011 1
10 0000 10 0000 1
10 1000 10 0010 1
10 0000 10 0101 1
10 1011 10 1010 1
10 0010 10 1001 1
10 1100 10 1011 1
10 0010 10 1000 1
10 1011 10 0000 1
10 1100 10 0000 1
10 1011 10 1000 1
10 0100 10 1011 1
10 1100 10 1000 1
10 0000 10 1011 1
10 0000 10 0000 1
10 1000 10 0111 1
10 0000 10 1100 1
10 1011 10 1011 1
10 0010 10 1001 1
10 0000 10 1011 1
10 0000 10 0000 1
10 0100 10 0001 1
10 0000 10 1100 1
10 1011 10 1001 1
10 0010 10 1001 1
10 0000 10 1011 1
10 0000 10 0000 1
10 1100 10 0100 1
10 0000 10 1100 1
10 0011 10 0010 1
10 0010 10 1000 1
10 0000 10 1011 1
10 1111 10 1111 1
10 1111 10 1111 1
10 0001 10 1110 111
10


There's a lot of repeated framing sequences of $$10$$ (start marker?) and $$1...$$ (end marker?) that don't appear to contain any information of the payload. This sort of run length limited encoding is not uncommon in old tape formats and floppy drives, but there are so many one-off proprietary ones that you really need some device documentation or the code to examine to see how the device was transforming the data.

You can NRZI decode your bits in Octave/MatLab by doing something like:

decoded_bits = (diff(bits) == 0)


or

decoded_bits = (diff(bits) != 0)


But the regularity, in the bits you have, suggests that NRZI decoding is not the correct first step to take with the bits that you have now.

I would also be suspect of the bits minimodem is returning to you. I would do the FSK demod in Octave to make sure that what minimodem is returning isn't bogus. In performing the FM demod in Octave, I'd also verify the mark and space tone frequencies. 4 kHz is an oddly high frequency to use for AFSK on a cassette tape. It implies that the expected cassette recorder isn't low end garbage that was so common in the early 1980's.

• Andy, The audio comes from the CSAVE function of a Sharp EL5500iii calculator/computer. I have come to agree that the periodicity argues against NRZI. The minimodem demodulation matches manually the first 20 bits or so when I use Audacity to zoom in on the waveform. I was unaware of Octave - I will go learn more because I always liked the concise matrix ops of MatLab. Jun 13 '20 at 23:59
• Ok. Write a short program that has 3 statements: 10 print "0123456789"; 20 print "ABCDEFGHIJKLMNOP"; 30 END. And CSAVE that and capture it. The hexadecimal representation of those ASCII characters will hopefully be easy to spot. Jun 14 '20 at 0:29
• @Brian check out the Pocket-tools source code. Jun 14 '20 at 2:58
• @ Andy I'll generate controlled output test cases as soon as I can. In the meantime, I can't find what you mean by "Pocket-tools". Posted Octave output graphs in original posting, above. Jun 14 '20 at 14:18
• I put a link to the pocket tools software in the top of my edited answer. Don't bother generating controlled outputs for me. Jun 14 '20 at 14:39