windytan / slowrx

A decoder for Slow-Scanning Television (SSTV).
ISC License
94 stars 10 forks source link

Freeze on "Receiving FSK ID..." #10

Open LightningStalker opened 3 years ago

LightningStalker commented 3 years ago

After running for a few days, slowrx will suddenly freeze saying "Receiving FSK ID...". The time elapsed before freeezing appears to be highly variable. It doesn't freeze completely but the receiving and decoding images freezes up and the program must be restarted.

windytan commented 3 years ago

Hi, thanks a lot for the report. Sounds like a deadlock, could be a little bug in the thread synchronization code. Slowrx hasn't been in development for many years and I kind of dread going back into the C code :), so at this point I can only suggest alternative software. I wonder if QSSTV is still state-of-the art?

LightningStalker commented 3 years ago

QSSTV development has slowed. QSSTV gets a lot of false positives resulting in static images. It also misses many images even when signal conditions are good enough to decode them. Most of the images it does decode end up getting cut off at the top or bottom. At least it has TX capability when it works. Aside from the odd freezing and sometimes some horizontal rolling and maybe lack of support of all the protocols QSSTV supports, I have found slowrx to be much better at receiving.

windytan commented 3 years ago

Glad to hear it's still useful! I'll see if I could reproduce the hang.

sjlongland commented 2 months ago

I managed to reproduce a hang reliably if the FSK ID synchronisation fails.

In my fork, I'm re-working the mathematics used to handle other sample rates (since not that many modern sound cards natively support 44.1kHz, 48kHz or harmonics thereof are more common).

The fsk.c has a while (true) loop, in which we break if the TestPtr variable exceeds 200, if the AsciiByte is observed to contain a byte less than 0x0d, or if BytePtr exceeds 9.

Something like the following will probably fix it (this was taken from my branch in #12):

commit 300c5e8058db3638eb5878d580202caae0380ccd
Author: Stuart Longland <me@vk4msl.com>
Date:   Fri Jul 12 12:14:08 2024 +1000

    fsk: Give up after 5 seconds

    If FSK sync never happens, we can be stuck trying to sync to a FSK ID
    that never synchronises, it's an infinite loop.

    Make the infinite loop finite!

diff --git a/fsk.c b/fsk.c
index 0cb07b0..38a1e05 100644
--- a/fsk.c
+++ b/fsk.c
@@ -25,6 +25,12 @@
  */
 #define FSK_5M5S_SAMPLES (FSK_11MS_SAMPLES/2)

+/*
+ * Set a limit of 5 seconds for a FSK.  That allows for ~227 bits of FSK
+ * data or approximately 34 characters for an ID.  That should be plenty!
+ */
+#define FSK_TIMEOUT     PCM_MS_FRAMES(5000)
+
 /* 
  * Decode FSK ID
  *
@@ -40,6 +46,8 @@ void GetFSK (char* const dest, uint8_t dest_sz) {
   double     HiPow,LoPow,Hann[FSK_11MS_SAMPLES];
   _Bool      InSync = false;

+  uint32_t   remain = FSK_TIMEOUT;
+
   // Bit-reversion lookup table
   static const uint8_t BitRev[] = {
     0x00, 0x20, 0x10, 0x30,   0x08, 0x28, 0x18, 0x38,
@@ -58,13 +66,21 @@ void GetFSK (char* const dest, uint8_t dest_sz) {
     Hann[i] = 0.5 * (1 - cos( 2 * M_PI * i / ((double)(FSK_11MS_SAMPLES-1)) ) );
   }

-  while ( true ) {
+  while ( remain > 0 ) {
+    // Figure out how much data to read?  If not in sync, use 5.5ms steps.
+    uint32_t read_sz = (InSync ? FSK_11MS_SAMPLES: FSK_5M5S_SAMPLES);

     // Read data from DSP: half the number of samples if not in sync.
-    readPcm(InSync ? FSK_11MS_SAMPLES: FSK_5M5S_SAMPLES);
+    readPcm(read_sz);
+
+    if (remain > read_sz) {
+      remain -= read_sz;
+    } else {
+      remain = 0;
+    }

     if (pcm.WindowPtr < (int32_t)FSK_5M5S_SAMPLES) {
-      pcm.WindowPtr += (InSync ? FSK_11MS_SAMPLES: FSK_5M5S_SAMPLES);
+      pcm.WindowPtr += read_sz;
       continue;
     }

@@ -73,7 +89,7 @@ void GetFSK (char* const dest, uint8_t dest_sz) {
       fft.in[i] = pcm.Buffer[pcm.WindowPtr+i- FSK_5M5S_SAMPLES] * Hann[i];
     }

-    pcm.WindowPtr += (InSync ? FSK_11MS_SAMPLES : FSK_5M5S_SAMPLES);
+    pcm.WindowPtr += read_sz;

     // FFT of last 22 ms
     fftw_execute(fft.Plan2048);
@@ -124,7 +140,6 @@ void GetFSK (char* const dest, uint8_t dest_sz) {
         BytePtr ++;
       }
     }
-
   }

   if (BytePtr < dest_sz) {

PCM_MS_FRAMES(5000) is a macro that computes the number of frames from the sample rate, which I exposed in the pcm object; but in the main-line source code, you could substitute with 5*44100.