/*************************************************************************** * Copyright (C) 2004 by Johan Maes - ON4QZ * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "rxfunctions.h" #include "dspfunctions.h" #include #include "filterparam.h" #include #include "configdialog.h" #include "vumeter.h" #include "syncproc.h" #include "syncdisplay.h" #include #include "modebase.h" #include "rxmainwindow.h" #include "txmainwindow.h" #include "qdatetime.h" #include "imageview.h" #include "galerymainwindow.h" #include "utils.h" #include "ftp.h" /** \class rxFunctions \verbatim VIS code Vertical Interval Signalling\n start: 30 msec 1200 Hz 7 bits 30msec per bit 1 parity bit 30 msec 1 stopbit 30 msec LSB is sent first \endverbatim */ /*! constructor for the rxfunctions */ rxFunctions::rxFunctions(QObject *parent, const char *name) : rxtxFunctions(parent,name) { state=STARTA; volumeTimer=new QTimer(this); connect(volumeTimer,SIGNAL(timeout()),SLOT(slotUpdateVolume())); volumeTimer->start(500); repeaterToneTimeout=new QTimer(this); connect(repeaterToneTimeout,SIGNAL(timeout()),SLOT(slotResetRepeater())); processTimer=new QTimer(this); connect(processTimer,SIGNAL(timeout()),SLOT(slotProcessLoop())); debugPtr=new debugPlot(QString("Debug Plot")); ftpIntf=new ftpInterface(); busy=FALSE; } rxFunctions::~rxFunctions() { } /*! \fn rxFunctions::process() \brief entry point for rx image processing This functions initialize the process parameters and starts the timer for the process loop. It will return immediately. */ void rxFunctions::process(rxtxState stat) { logfile.add("process called"); dsp->setFilter(F800); dsp->startReceive(); debugPtr->init(); state=stat; processTimer->start(1,TRUE); oldSyncPosition=0; } /*! \fn rxFunctions::calibrate() \brief entry point for rx calibration processing This functions initialize the process parameters and starts the timer for the process loop to execute a calibration. It will return immediately. */ void rxFunctions::calibrate() { dsp->setFilter(F800); dsp->startReceive(); s=FALSE; selectedMode=CALIB; state=DISPLAY; if(!startSelectedMode(rxMW->getImagePtr(),FALSE)) return; processTimer->start(1,TRUE); } /*! \fn rxFunctions::slotProcessLoop() \brief main receive loop This function steps through the different phases of the image reception
  • START
  • VISDETECT
  • HUNT
  • DISPLAY
  • IDLE
It is started through the processTimer (single shot). The processTimer will be rearmed if there is no data available from the dsp. Every routine called from within the slotProcessLoop() and requesting dsp data, should return with the WAITING status. This means that all such routines must be aware of the processing state and position to enable further processing when there is data available. If there is no data available, then we will wait for 1/2 a sample buffer time. */ void rxFunctions::slotProcessLoop() { eIOState result; bool endSync; bool afterVIS; int res; do { if((result=debugPtr->getDemodulatedData(f,s,tempPos))==STOPPED) { return; } if (result==WAITING) { processTimer->start(dsp->getDuration(512),TRUE); // wait for rx ringbuffer to fill return ; } switch (state) { case STARTA: { if(repeaterEnable) { emit statusMessage("Waiting for Repeater tone"); debugPtr->state=stRepTone; syncProcessor.checkRepeaterTone(f,TRUE); nextState(WAITREPTONE); } else { nextState(STARTB); } } break; case WAITREPTONE: { if(syncProcessor.checkRepeaterTone(f,FALSE)) { emit statusMessage("Repeater Sending Ack"); nextState(REPSENDACK); } } break; case REPSENDACK: { txMW->sendCW(repeaterAcknowledge); return; } break; case STARTB: if(repeaterEnable) { repeaterToneTimeout->start(15000,TRUE); repeaterToneDetected=TRUE; } syncProcessor.init(); if (useVIS) { debugPtr->state=stWaitVIS; emit statusMessage("Waiting for VIS code"); nextState(VISDETECT); } else { debugPtr->state=stHUNT; emit statusMessage("Hunting for Sync"); nextState(HUNT); } break; case VISDETECT: { if((!repeaterToneDetected)&&(repeaterEnable)) { nextState(STARTA); break; } if (!useVIS) // check in case we change useVis while already running { nextState(HUNT); debugPtr->state=stHUNT; break; } if(syncProcessor.recordSync(f,s,tempPos,endSync)) { if((visCode=syncProcessor.evaluateVIS(tempPos))!=0) { if((selectedMode=initializeParametersVIS(visCode))!=NOTVALID) { logfile.add("startPos=%u",tempPos); debugPtr->reposition(tempPos); } if(!startSelectedMode(rxMW->getImagePtr(),FALSE)) { debugPtr->state=stSTART; nextState(STARTA); } else { logfile.add("restart position %d)",dsp->getPos()); emit statusMessage(getMode(selectedMode)); connect(rxtxDisplay,SIGNAL(signalDisplaySync(unsigned int)),SLOT(slotUpdateSyncDisplay(unsigned int))); startPosition=tempPos; // debugPtr->init(); } } } } break; case HUNT: debugPtr->state=stHUNT; if((!repeaterToneDetected)&&(repeaterEnable)) { nextState(STARTA); break; } if(syncProcessor.recordSync(f,s,tempPos,endSync)) { unsigned int lineLen; if((lineLen=syncProcessor.evaluateSync(sensitivity,tempPos,afterVIS))!=0) { selectedMode=modeLookup(lineLen,rxClock); if(selectedMode!=NOTVALID) { debugPtr->reposition(tempPos); if(!startSelectedMode(rxMW->getImagePtr(),FALSE)) { nextState(STARTA); } else { startPosition=rxtxDisplay->compensateSyncPosition(selectedMode,afterVIS); logfile.add("compensated startposition %d",dsp->getPos()); emit statusMessage(getMode(selectedMode)); connect(rxtxDisplay,SIGNAL(signalDisplaySync(unsigned int)),SLOT(slotUpdateSyncDisplay(unsigned int))); // debugPtr->init(); } } } } break; case DISPLAY: busy=TRUE; rxtxDisplay->setUse(slantAdjust,dxMode); // do this here to allow dynamic changing of this param res=rxtxDisplay->decodeLine(f,s); if(res==1) // 1 indicates end of image { nextState(IDLE); } else if(res==-1) // -1 indicates restart { nextState(RESTART); } break; case RESTART: { debugPtr->reposition(startPosition+rxtxDisplay->offset); logfile.add("startPosition %d, diff=%d",startPosition,rxtxDisplay->offset); startPosition+=rxtxDisplay->offset; logfile.add("dsp position %d)",dsp->getPos()); rxtxDisplay->init(selectedMode,rxMW->getImagePtr(),FALSE,FALSE); nextState(DISPLAY); } break; case IDLE: syncProcessor.clearSyncArray(); if(rxtxDisplay==NULL) { nextState(STARTA); busy=FALSE; } else { if (rxtxDisplay->getLineCounter() <40) { nextState(STARTA); busy=FALSE; } else { if(autoSave) imageSave(); if (repeaterEnable) { txMW->repeat(&rxMW->getImagePtr()->image,selectedMode); delete rxtxDisplay; rxtxDisplay=NULL; return; } nextState(STARTA); busy=FALSE; } } break; } } while (1); } void rxFunctions::slotStop() { processTimer->stop(); logfile.add("rxfunctions stop called "); state=IDLE; emit statusMessage("Receiver stopped"); busy=FALSE; } void rxFunctions::slotResetRepeater() { repeaterToneDetected=FALSE; } void rxFunctions::setvuMeterFrame(vuMeter *ptr) { vuMeterPtr=ptr; vuMeterPtr->setTotalSteps(20); vuMeterPtr->setProgress(50); } void rxFunctions::setoffsetMeterFrame(vuMeter *ptr) { offsetMeterPtr=ptr; offsetMeterPtr->setTotalSteps(300); offsetMeterPtr->setProgress(50); offsetMeterPtr->UseNeedle(TRUE); } void rxFunctions::setSyncDisplayFrame(syncDisplay *ptr) { syncDisplayFrame=ptr; syncDisplayFrame->show(); } void rxFunctions::slotUpdateVolume() { double volume=dsp->getVolume(); volume=10*(log10(volume*10.)-3); if (volume<0)volume=0; vuMeterPtr->setProgress((int)volume); //logfile.add("volume control %lf",volume); } void rxFunctions::slotUpdateOffset(int ofs,int pos) { offsetMeterPtr->setProgress(ofs-1200+150); syncDisplayFrame->setData(oldSyncPosition); // delay one line, so we don't go beyond the buffer oldSyncPosition=(uint)pos; } void rxFunctions::slotUpdateSyncDisplay(unsigned int pos) { syncDisplayFrame->setData(oldSyncPosition); // delay one line, so we don't go beyond the buffer oldSyncPosition=(uint)pos; } void rxFunctions::imageSave() { QString s,tmp; QTime tim=QTime::currentTime(); QDate dat = QDate::currentDate(); int intdate=dat.year()*10000+dat.month()*100+dat.day(); int inttime=tim.hour()*100+tim.minute(); s.sprintf("%s_%d_%d",getModeShort(selectedMode),intdate,inttime); tmp=rxImagePath+s+"."+defaultImageFormat; rxMW->getImagePtr()->image.save(tmp,defaultImageFormat.upper()); galMW->putRxImage(tmp); if(enableFTP) { if(defaultImageFormat!=ftpDefaultImageFormat) { tmp=rxImagePath+s+"."+ftpDefaultImageFormat; rxMW->getImagePtr()->image.save(tmp,ftpDefaultImageFormat.upper()); ftpIntf->uploadFile(tmp,ftpFilename+'.'+ftpDefaultImageFormat,TRUE); } else { ftpIntf->uploadFile(tmp,ftpFilename+'.'+ftpDefaultImageFormat,FALSE); } } } //#define rxfunctions_debug void localDebug(const char *fmt, ...);