Well, as the proverb says, "if you want something well done, do it yourself". So that's what I have done
I've coded a dirty PHP script (who needs Python?) which decodes a FSK encoded WAV. Here's the decoded checksum wave file:
LOWER BANK ($8000-$BFFF):
Code:
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
-----------------------------------------------------------------------------------------------
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF, A1EC, 7894, 2D1C, 1ABF,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
UPPER BANK ($C000-$FFFF):
Code:
1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, A1EC, A1EC, A1EC, A1EC,
680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F,
-----------------------------------------------------------------------------------------------
1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF, 1ABF,
C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000, C000,
2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C,
6695, 94AA, FCBD, B9AE, 11F5, 7A9E, 5766, 9FD3, E710, 82B1, 3CCA, C51F, 76B0, 6BD3, 832A, 680F,
2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, 2D1C, A1EC, A1EC, A1EC, A1EC,
680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F, 680F,
If we take each checksum and build a map of those with the same checksum we get:
Code:
0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101,
0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404,
0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101,
0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404,
0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103,
0505, 0606, 0707, 0808, 0909, 0a0a, 0b0b, 0c0c, 0d0d, 0e0e, 0f0f, 1010, 1111, 1212, 1313, 1414,
0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0000, 0200, 0300, 0100,
0514, 0614, 0714, 0814, 0914, 0a14, 0b14, 0c14, 0d14, 0e14, 0f14, 1014, 1114, 1214, 1314, 1414,
-----------------------------------------------------------------------------------------------
0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101,
0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404,
0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101, 0001, 0201, 0301, 0101,
0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404, 0404,
0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103,
0505, 0606, 0707, 0808, 0909, 0a0a, 0b0b, 0c0c, 0d0d, 0e0e, 0f0f, 1010, 1111, 1212, 1313, 1414,
0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0003, 0203, 0303, 0103, 0000, 0200, 0300, 0100,
0514, 0614, 0714, 0814, 0914, 0a14, 0b14, 0c14, 0d14, 0e14, 0f14, 1014, 1114, 1214, 1314, 1414,
First byte is lower bank, second byte is upper bank.
Finally, here's the quick'n'dirty PHP script:
Code:
<?php
function dat_read($f) {
do {
$line = fgets($f);
if ($line === false)
return false;
} while (substr($line, 0, 1) == ";");
return array(
"time" => floatval(substr($line, 0, 16)),
"value" => floatval(substr($line, 17, 16))
);
}
function get_sign($sample) {
$min = 0.3;
if ($sample >= $min)
return 1;
if ($sample <= -$min)
return -1;
return 0;
}
function sign_read($f) {
$t = dat_read($f);
if ($t === false)
return false;
return array(
"time" => $t["time"],
"sign" => get_sign($t["value"])
);
}
function is_transition($old, $new) {
if ($old["sign"] == -1 && $new["sign"] == 1)
return true;
if ($old["sign"] == 1 && $new["sign"] == -1)
return true;
return false;
}
function read_freq($f) {
do {
$a = sign_read($f);
if ($a === false)
return false;
} while ($a["sign"] == 0);
do {
$b = sign_read($f);
if ($b === false)
return false;
} while (!is_transition($a, $b));
do {
$c = sign_read($f);
if ($c === false)
return false;
} while ($c["sign"] == $b["sign"]);
return 1 / ($c["time"] - $a["time"]);
}
function read_bit($f) {
$freqerr = 1000;
$freq = read_freq($f);
if ($freq === false)
return false;
if (abs($freq - 1200) < $freqerr)
return 0;
if (abs($freq - 2400) < $freqerr) {
$freq = read_freq($f);
if ($freq == false)
return false;
if (abs($freq - 2400) < $freqerr)
return 1;
}
return false;
}
function read_byte($f) {
do {
$start = read_bit($f);
if ($start === false)
return false;
} while ($start == 1);
$byte = 0;
for ($i = 0; $i < 8; $i++) {
$bit = read_bit($f);
if ($bit === false)
return false;
$byte = $byte >> 1 | $bit << 7;
}
if (read_bit($f) !== 1)
return false;
return chr($byte);
}
$f = fopen("checksum.dat", "r");
$fout = fopen("checksum.bin", "wb");
while (!feof($f)) {
echo read_byte($f);
}
The .dat file is generated using SOX ("sox input.wav -t dat output.dat").