1 #include "sstvrx.h"
2 #include "appglobal.h"
3 #include "configparams.h"
4 #include "dispatcher.h"
5 #include "filterparam.h"
6 #include "filters.h"
7 #include "modes/modebase.h"
8 
9 
10 #ifndef QT_NO_DEBUG
11 #include "arraydumper.h"
12 #include "scope/scopeview.h"
13 #include "scope/scopeoffset.h"
14 #endif
15 
16 QString defaultImageFormat;
17 int minCompletion;
18 
19 #define DECAY 0.9956
20 
21 #ifdef DISABLENARROW
22   #pragma message "NARROW DETECTION DISABLED"
23 #endif
24 
25 const QString stateStr[sstvRx::END+1]=
26 {
27   "Hunting",
28   "Processing",
29   "WaitForSync",
30   "SlantAdjust",
31   "Restart",
32   "Sync Lost",
33   "Wait",
34   "End"
35 };
36 
37 
sstvRx(QObject * parent)38 sstvRx::sstvRx(QObject *parent) : QObject(parent),syncNarrowProc(true),syncWideProc(false)
39 {
40   syncFilterPtr=NULL;
41   videoFilterPtr=NULL;
42   syncProcPtr=NULL;
43 #ifndef QT_NO_DEBUG
44   scopeViewerData=new scopeView("Data Scope");
45   scopeViewerSyncNarrow=new scopeView("Sync Scope Narrow");
46   scopeViewerSyncWide=new scopeView("Sync Scope Wide");
47 #endif
48 }
49 
init()50 void sstvRx::init()
51 {
52   setFilters(); // setup sstvRx Filters
53   resetParams(true);
54 #ifndef QT_NO_DEBUG
55   scopeViewerData->setAlternativeScaleMultiplier(SUBSAMPLINGFACTOR/rxClock);
56   scopeViewerData->setCurveName("RX VOL",SCDATA1);
57   scopeViewerData->setCurveName("TEST",SCDATA2);
58   scopeViewerData->setCurveName("STATE",SCDATA3);
59   scopeViewerData->setCurveName("DEMOD",SCDATA4);
60   scopeViewerData->setAxisTitles("Samples","int","State");
61   scopeViewerSyncNarrow->setAlternativeScaleMultiplier(SUBSAMPLINGFACTOR/rxClock);
62   scopeViewerSyncWide->setAlternativeScaleMultiplier(SUBSAMPLINGFACTOR/rxClock);
63 #endif
64 }
resetParams(bool bufferReset)65 void sstvRx::resetParams(bool bufferReset)
66 {
67   SSTVState=HUNTING;
68   bufferCounter=0;
69   if(bufferReset)
70     {
71       addToLog("reset Buffers",LOGRXMAIN);
72       agcVolume=0;
73       bufferVideoDemod.reset();
74       bufferSync1200Vol.reset();
75       bufferSync1900Vol.reset();
76       bufferInputVol.reset();
77       syncNarrowProc.reset();
78       syncWideProc.reset();
79     }
80   else
81     {
82       syncNarrowProc.init();
83       syncWideProc.init();
84     }
85 }
86 
~sstvRx()87 sstvRx::~sstvRx()
88 {
89   if(videoFilterPtr!=NULL) delete videoFilterPtr;
90   if(syncFilterPtr !=NULL) delete syncFilterPtr;
91 }
92 
setFilters()93 void sstvRx::setFilters()
94 {
95   if(videoFilterPtr==NULL)
96     videoFilterPtr=new videoFilter(RXSTRIPE);
97   else
98     videoFilterPtr->init();
99   if(syncFilterPtr==NULL) syncFilterPtr=new syncFilter(RXSTRIPE);
100   else syncFilterPtr->init();
101 }
102 
103 
104 //void sstvRx::run(DSPFLOAT *dataPtr, unsigned int *inputVolumePtr)
run(DSPFLOAT * dataPtr,DSPFLOAT * volumePtr)105 void sstvRx::run(DSPFLOAT *dataPtr,DSPFLOAT *volumePtr)
106 {
107   bufferCounter++;
108   if(videoFilterPtr==NULL)
109     {
110       errorOut() << "videoFltr NULL";
111       return;
112     }
113   // run AGC
114 //  for(i=0;i<RXSTRIPE;i++)
115 //    {
116 //      DSPFLOAT tmp=sqrt(dataPtr[i]*dataPtr[i]);
117 //      if(tmp>agcVolume) agcVolume=tmp;
118 //      else agcVolume*=DECAY;
119 //      if(agcVolume<1000) agcVolume=1000;  //maximum gain is 8
120 //      dataPtr[i]=dataPtr[i]*8000/agcVolume;
121 //    }
122   videoFilterPtr->process(dataPtr);
123   bufferVideoDemod.putNoCheck(videoFilterPtr->demodPtr,RXSTRIPE);
124   syncFilterPtr->process(dataPtr);
125   bufferSync1200Vol.putNoCheck(syncFilterPtr->detect1200Ptr,RXSTRIPE);
126 #ifndef DISABLENARROW
127   bufferSync1900Vol.putNoCheck(syncFilterPtr->detect1900Ptr,RXSTRIPE);
128 #endif
129   bufferInputVol.putNoCheck(volumePtr ,RXSTRIPE);
130 
131   while (bufferVideoDemod.count())
132     {
133       syncWideProc.freqPtr=bufferVideoDemod.readPointer();
134       syncNarrowProc.freqPtr=bufferVideoDemod.readPointer();
135       syncWideProc.syncVolumePtr =bufferSync1200Vol.readPointer();
136       syncNarrowProc.syncVolumePtr =bufferSync1900Vol.readPointer();
137       syncWideProc.inputVolumePtr=bufferInputVol.readPointer();
138       syncNarrowProc.inputVolumePtr=bufferInputVol.readPointer();
139 
140       displaySyncEvent* ce;
141       if(syncProcPtr)
142         {
143           ce = new displaySyncEvent(syncProcPtr->syncQuality);
144         }
145       else
146         {
147           ce = new displaySyncEvent(0);
148         }
149       QApplication::postEvent(dispatcherPtr, ce);
150 #ifndef QT_NO_DEBUG
151       scopeViewerData->addData(SCDATA1,bufferInputVol.readPointer(),syncWideProc.sampleCounter,RXSTRIPE);
152       scopeViewerData->addData(SCDATA2,dataPtr,syncWideProc.sampleCounter,RXSTRIPE);
153       scopeViewerData->addData(SCDATA4,bufferVideoDemod.readPointer(),syncWideProc.sampleCounter,RXSTRIPE);
154 #endif
155 
156       process();
157     }
158   //  addToLog(QString("After process readIndex:=%1 sampleCounter:=%2").arg(bufferVideoDemod.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
159 }
160 
advanceBuffers()161 void sstvRx::advanceBuffers()
162 {
163   syncWideProc.sampleCounter+=RXSTRIPE;
164   syncNarrowProc.sampleCounter+=RXSTRIPE;
165   bufferVideoDemod.skip(RXSTRIPE);
166   bufferSync1200Vol.skip(RXSTRIPE);
167   bufferSync1900Vol.skip(RXSTRIPE);
168   bufferInputVol.skip(RXSTRIPE);
169 }
170 
rewindBuffers(uint rlen)171 void sstvRx::rewindBuffers(uint rlen)
172 {
173   syncWideProc.sampleCounter-=rlen;
174   syncNarrowProc.sampleCounter-=rlen;
175   bufferVideoDemod.rewind(rlen);
176   bufferSync1200Vol.rewind(rlen);
177   bufferSync1900Vol.rewind(rlen);
178   bufferInputVol.rewind(rlen);
179 }
180 
181 
182 
183 
process()184 void sstvRx::process()
185 {
186 //  unsigned int ri;
187   quint32 block;
188   quint32 syncPosition;
189   quint32 sampleCounterLatch;
190   quint32 diff;
191 
192   syncProcessor::esyncProcessState syncStateWide;
193   syncProcessor::esyncProcessState syncStateNarrow;
194   syncProcessor::esyncProcessState syncState;
195   rxSSTVStatusEvent *stce;
196 
197   syncWideProc.process();
198 
199   syncStateWide=syncWideProc.getSyncState(syncPosition);
200 
201   if(syncStateWide!=syncProcessor::MODEDETECT)
202     {
203       usingWide=true;
204       syncNarrowProc.setSyncDetectionEnabled(false);
205       syncProcPtr=&syncWideProc;
206      }
207   else
208     {
209       syncNarrowProc.process();
210       syncStateNarrow=syncNarrowProc.getSyncState(syncPosition);
211       if(syncStateNarrow!=syncProcessor::MODEDETECT)
212         {
213           usingWide=false;
214           syncWideProc.setSyncDetectionEnabled(false);
215           syncProcPtr=&syncNarrowProc;
216         }
217       else
218         {
219           syncProcPtr=NULL;
220           syncState=syncProcessor::MODEDETECT;
221           if(SSTVState!=HUNTING)
222             {
223               switchState(HUNTING);
224             }
225         }
226      }
227   if(syncProcPtr)
228     {
229       syncState=syncProcPtr->getSyncState(syncPosition);
230     }
231 
232 
233   if((syncProcPtr!=0) && (syncProcPtr->getSyncState(syncPosition)==syncProcessor::SYNCLOST))
234     {
235       switchState(SYNCLOST);
236     }
237   switch (SSTVState)
238     {
239     case HUNTING:
240       if(syncProcPtr==NULL)
241         {
242           stce= new rxSSTVStatusEvent(QString("No sync"));
243           QApplication::postEvent( dispatcherPtr, stce );  // Qt will delete it when done
244           advanceBuffers();
245           break; // no sync
246         }
247       stce= new rxSSTVStatusEvent(QString("Receiving ")+getSSTVModeNameLong(syncProcPtr->getMode()));
248       lastUsedModeStr=getSSTVModeNameShort(syncProcPtr->getMode());
249       QApplication::postEvent( dispatcherPtr, stce );  // Qt will delete it when done
250       // fallthrough for first processing
251       switchState(SLANTADJUST); // for logging
252       // clear the call received via fskID
253       emit (resetCall());
254 
255     case SLANTADJUST:
256       sampleCounterLatch=syncProcPtr->sampleCounter; //remember where we've got
257 //      ri=bufferVideoDemod.getReadIndex();
258 //      addToLog(QString("rxFunctions: sampleCounterLatch= %1,readIndex=%2").arg(sampleCounterLatch).arg(ri),LOGRXFUNC);
259       block=(syncPosition)/RXSTRIPE;
260       bufferVideoDemod.rewind(syncProcPtr->sampleCounter-block*RXSTRIPE);
261 //      ri=bufferVideoDemod.getReadIndex();
262       //      addToLog(QString("sc_rewind: block=%1,new readIndex= %2").arg(block).arg(ri),LOGRXFUNC);
263       syncProcPtr->sampleCounter=block*RXSTRIPE;
264       syncProcPtr->currentModePtr->setRxSampleCounter(syncProcPtr->sampleCounter);
265       syncProcPtr->currentModePtr->redrawFast(true);
266       if(syncProcPtr->currentModePtr->process(bufferVideoDemod.readPointer(),syncPosition-syncProcPtr->sampleCounter,true,syncProcPtr->sampleCounter)!=modeBase::MBRUNNING)
267         {
268           switchState(END);
269           break;
270         }
271 
272 
273       //    scopeViewerData->addData(SCDATA2,bufferVideoDemod.readPointer(),syncProcPtr->sampleCounter,RXSTRIPE);
274       //      addToLog(QString("slant scope add demodIdx=%1; syncProcPtr->sampleCounter=%2").arg(bufferVideoDemod.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
275 #ifndef QT_NO_DEBUG
276       scopeViewerData->addData(SCDATA3,syncProcPtr->currentModePtr->debugStatePtr,syncProcPtr->sampleCounter,RXSTRIPE);
277 #endif
278       addToLog(QString("rxFunctions: currentMode pos:=%1, syncProcPtr->sampleCounter %2").arg(syncPosition-syncProcPtr->sampleCounter).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
279       //      addToLog(QString("after Current mode set: %1,syncProcPtr->sampleCounter: %2").arg(rxHoldingBuffer.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
280       while(syncProcPtr->sampleCounter<sampleCounterLatch)
281         {
282           bufferVideoDemod.skip(RXSTRIPE);
283           syncProcPtr->sampleCounter+=RXSTRIPE;
284           //          addToLog(QString("loop readIndex: %1,syncProcPtr->sampleCounter: %2").arg(rxHoldingBuffer.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
285           syncProcPtr->currentModePtr->process(bufferVideoDemod.readPointer(),0,false,syncProcPtr->sampleCounter);
286           //      scopeViewerData->addData(SCDATA2,bufferVideoDemod.readPointer(),syncProcPtr->sampleCounter,RXSTRIPE);
287 #ifndef QT_NO_DEBUG
288           scopeViewerData->addData(SCDATA3,syncProcPtr->currentModePtr->debugStatePtr,syncProcPtr->sampleCounter,RXSTRIPE);
289 #endif
290         }
291       addToLog(QString("end loop readIndex: %1,syncProcPtr->sampleCounter: %2").arg(bufferVideoDemod.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
292       syncProcPtr->currentModePtr->redrawFast(false);
293       syncProcPtr->recalculateMatchArray();
294       switchState(PROCESSING);
295       advanceBuffers();
296       break;
297     case PROCESSING:
298       if(syncState!=syncProcessor::INSYNC)
299         {
300           switchState(END);
301         }
302       else if(syncProcPtr->retraceFlag)
303         {
304           addToLog(QString("retrace detected"),LOGRXFUNC);
305           saveImage();
306           rewindBuffers(8*RXSTRIPE);
307           syncProcPtr->resetRetraceFlag();
308           resetParams(false);
309           break;
310         }
311       else
312         {
313           if(syncProcPtr->currentModePtr->process(bufferVideoDemod.readPointer(),0,false,syncProcPtr->sampleCounter)!=modeBase::MBRUNNING)
314             {
315               switchState(END);
316             }
317         }
318 
319       if(syncProcPtr->hasNewClock())
320         {
321           syncProcPtr->currentModePtr->init(syncProcPtr->getNewClock());
322           switchState(SLANTADJUST);
323         }
324 #ifndef QT_NO_DEBUG
325       scopeViewerData->addData(SCDATA3,syncProcPtr->currentModePtr->debugStatePtr,syncProcPtr->sampleCounter,RXSTRIPE);
326 #endif
327       advanceBuffers();
328       if(syncProcPtr->tempOutOfSync)
329         {
330           bufferIdx=bufferVideoDemod.getReadIndex();
331           switchState(WAITFORSYNC);
332         }
333       break;
334     case WAITFORSYNC:
335       {
336 
337         if(!(syncState==syncProcessor::INSYNC))
338           {
339             switchState(END);
340           }
341         else if(syncProcPtr->retraceFlag)
342           {
343             addToLog(QString("retrace detected"),LOGRXFUNC);
344             saveImage();
345             //          addToLog(QString("before rewind readIndex:=%1 sampleCounter:=%2").arg(bufferVideoDemod.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
346             rewindBuffers(8*RXSTRIPE);
347             syncProcPtr->resetRetraceFlag();
348             resetParams(false);
349             //          addToLog(QString("after resetParms readIndex:=%1 sampleCounter:=%2").arg(bufferVideoDemod.getReadIndex()).arg(syncProcPtr->sampleCounter),LOGRXFUNC);
350             break;
351           }
352 
353         else
354           {
355             currentIdx=bufferVideoDemod.getReadIndex();
356             if(!syncProcPtr->tempOutOfSync)
357               {
358                 bufferVideoDemod.setReadIndex(bufferIdx);
359                 while(bufferVideoDemod.getReadIndex()!=currentIdx)
360                   {
361                     if(syncProcPtr->currentModePtr->process(bufferVideoDemod.readPointer(),0,false,syncProcPtr->sampleCounter)==modeBase::MBENDOFIMAGE)
362                       {
363                         switchState(END);
364                       }
365                     bufferVideoDemod.skip(RXSTRIPE);
366                   }
367                 if(syncProcPtr->currentModePtr->process(bufferVideoDemod.readPointer(),0,false,syncProcPtr->sampleCounter)==modeBase::MBENDOFIMAGE)
368                   {
369                     switchState(END);
370                   }
371                 else
372                   {
373                     switchState(PROCESSING);
374                   }
375               }
376           }
377         advanceBuffers();
378         break;
379       }
380     case RESTART:
381       resetParams(true);
382       break;
383     case SYNCLOST:
384       saveImage();
385       diff=(syncProcPtr->sampleCounter-syncProcPtr->lastValidSyncCounter)/RXSTRIPE;
386       addToLog(QString("rewind after synclost %1").arg(diff),LOGRXFUNC);
387       rewindBuffers(diff*RXSTRIPE);
388       syncProcPtr->resetRetraceFlag();
389       resetParams(true);
390       break;
391     case WAIT:
392       break;
393     case END:
394       saveImage();
395       resetParams(false); // will set state to HUNTING
396       advanceBuffers();
397       break;
398     }
399 }
400 
saveImage()401 void sstvRx::saveImage()
402 {
403   bool done=false;
404   addToLog("saveImage",LOGRXFUNC);
405   endImageSSTVRXEvent *endce;
406   if(syncProcPtr->currentModePtr->receivedLines()<(syncProcPtr->currentModePtr->imageLines()*minCompletion)/100)
407     {
408       endce = new endImageSSTVRXEvent(NOTVALID); //indicate there  is no valid image
409     }
410   else
411     {
412 //      endce = new endImageSSTVRXEvent(getSSTVModeNameShort(syncProcPtr->getMode()));
413       endce = new endImageSSTVRXEvent(syncProcPtr->getMode());
414     }
415   endce->waitFor(&done);
416   QApplication::postEvent(dispatcherPtr, endce);
417   while(!done) { usleep(100);}
418 }
419 
420 
switchState(eSSTVState newState)421 void sstvRx::switchState(eSSTVState  newState)
422 {
423   addToLog(QString("%1 to %2").arg(stateStr[SSTVState]).arg(stateStr[newState]),LOGRXFUNC);
424   SSTVState=newState;
425 }
426 
eraseImage()427 void sstvRx::eraseImage()
428 {
429   switchState(RESTART);
430   while(SSTVState!=HUNTING)
431     {
432       QApplication::processEvents();
433     }
434 }
435 
436 
437 #ifndef QT_NO_DEBUG
setOffset(unsigned int offset,bool ask)438 unsigned int sstvRx::setOffset(unsigned int offset,bool ask)
439 {
440   unsigned int xOffset=0;
441   if(ask)
442     {
443       scopeOffset so;
444       so.setOffset(offset);
445       if(so.exec()==QDialog::Accepted)
446         {
447           xOffset=so.getOffset()*1000;
448         }
449     }
450   else
451     {
452       xOffset=offset*1000;
453     }
454   syncNarrowProc.clear();
455   syncWideProc.clear();
456   scopeViewerData->clear();
457   syncNarrowProc.setOffset(xOffset);
458   syncWideProc.setOffset(xOffset);
459   scopeViewerData->setOffset(xOffset);
460 
461 
462   return xOffset/1000;
463 }
464 #endif
465 
466