/*************************************************************************** * 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 "modebase.h" #include "imageview.h" #include "qsstvglobal.h" #include #include "configdialog.h" #include #include #include #include #include "syncproc.h" #include "utils.h" #include "cw.h" static int serialP=0; modeBase::modeBase(QObject *parent, const char *name) : QObject(parent, name) { pixelPositionTable=NULL; greenArray=NULL; blueArray=NULL; redArray=NULL; yArray=NULL; done=FALSE; serialP=0; mbState=SETUPLINE; subLine=0; connect(dsp,SIGNAL(signalTXStopped()),SLOT(slotDeactivatePTT())); } modeBase::~modeBase() { deleteBuffers(); } void modeBase::deleteBuffers() { if(pixelPositionTable) delete [] pixelPositionTable; if(greenArray) delete [] greenArray; if(blueArray) delete [] blueArray; if(redArray) delete [] redArray; if(yArray) delete [] yArray; } /*! \fn modeBase::init(sstvMode imode,imageView *ptr,bool tx,bool initClock) \brief main entry point to display rx images Init all parameters to prepare decoding. If initClock=TRUE, the clocks will be initialized with the standard clock frequencies as defined in the configfile. If initClock=FALSE then the clock is not touched (e.g. in case of a restart the clock will be calculated from the sync processor module(regression). */ void modeBase::init(sstvMode imode,imageView *ptr,bool tx,bool initClock) { logfile.add("modbase init"); // mode=imode; displayPtr=ptr; deleteBuffers(); lineCounter=0; if(tx) { if(initClock) newClock=txClock; syncDuration=activeSSTVParam.synct *newClock; fp=activeSSTVParam.fpt*newClock; bp=activeSSTVParam.bpt*newClock; blank=activeSSTVParam.blankt*newClock; } else { if(initClock) newClock=rxClock; syncDuration=activeSSTVParam.sync *newClock; fp=activeSSTVParam.fp*newClock; bp=activeSSTVParam.bp*newClock; blank=activeSSTVParam.blank*newClock; } pixelCounter=0; sampleCounter=0; setupLineTimeTable(imode,newClock); syncProcessor.restartTrackSync(); pixelPositionTable=new unsigned int[activeSSTVParam.numberOfPixels]; greenArray=new unsigned char[activeSSTVParam.numberOfPixels]; blueArray=new unsigned char[activeSSTVParam.numberOfPixels]; redArray=new unsigned char[activeSSTVParam.numberOfPixels]; yArray=new unsigned char[activeSSTVParam.numberOfPixels]; visibleLineLength=(((float)(lineTimeTable[9]))/10.-fp-bp-2*blank-syncDuration)/3.; logfile.add("fp=%f,bp=%f,blank=%f,sync=%f,linelength=%f, visible=%f",fp,bp,blank,syncDuration,lineTimeTable[9]/10.,visibleLineLength); setSize(); subLine=0; mbState=SETUPLINE; if((imode==S1)||(imode==S2)||(imode==SDX)) { syncProcessor.setOffsetCompensation((int)round(visibleLineLength+blank)); } else { syncProcessor.setOffsetCompensation(0); } } int modeBase::compensateSyncPosition(sstvMode imode,bool afterVIS) { if (((imode==S1) ||(imode==S2)|| (imode==SDX)) && (!afterVIS)) { logfile.add("actual pos=%d",dsp->getPos()); // compensate for startbit position in Scottie mode int newpos=(unsigned int)(1*blank+2*visibleLineLength+syncDuration+fp); logfile.add("newpos after no VIS %d",newpos); debugPtr->rewind(newpos); } else { //always position directly behind the first bp debugPtr->forward((unsigned int)round(bp)); } return dsp->getPos(); } void modeBase::clearImage() { // displayPtr->clearToBottom(0,blue); displayPtr->clearBackground(); } /*! \fn modeBase::decodeLine(float f) \brief main entry point to display rx images \return 1 if end of image, -1 if restart */ int modeBase::decodeLine(float f,bool s) { sample=f; sync=s; int res; syncProcessor.trackSync(f,s,sampleCounter+(int)round(bp),lineCounter); // just continu registering sync/nosync if(mbState==SETUPLINE) { mbState=setupLine(subLine,&buf); if(mbState==ENDOFLINE) { if(showLine()) { mbState=ENDOFIMAGE; return 1; } else { subLine=0; mbState=setupLine(subLine,&buf); } } subLine++; syncStartDetected=FALSE; pixelCounter=0; //logfile.add("subline start at %d",debugPtr->getPos()); } switch (mbState) { case PIXELS: { if(getPixels(buf)) mbState=SETUPLINE; // check for end of subline } break; case SYNC: { res=waitForSync(); if(res==1) { mbState=SETUPLINE; } else if (res==-1) { sampleCounter++; return -1; } } break; case RXWAIT: if(sampleCounter>=marker) { mbState=SETUPLINE; } break; default: sampleCounter++; return 1; } sampleCounter++; return 0; } bool modeBase::showLine() { //logfile.add("showLine %d",lineCounter); combineColors(); displayPtr->showLine(); lineCounter++; if (lineCounter>=activeSSTVParam.numberOfLines) return TRUE; return FALSE; } void modeBase::setSize() { displayPtr->setNewSize(activeSSTVParam.numberOfPixels,activeSSTVParam.numberOfLines); } /*! \fn modeBase::waitForSync() \brief check to sync or resync SyncPosition is the position of the trailing edge of the sync pulse. \ return 1 if syncPosition reached and syncpulse is not active , or sync-end detected before the syncposition is reached. */ int modeBase::waitForSync() { // wait to be in syn if(sampleCounter>=syncPosition) { if(sampleCounter==syncPosition) { emit signalDisplaySync(dsp->getPos()); } if(syncProcessor.evaluateTrackSync(newClock,offset)) { if(mslantAdjust) { logfile.add("adapting"); return -1; } } if(!mdxMode) { if(syncProcessor.isOutOfSync()) { logfile.add("got out of sync"); mbState=ENDOFIMAGE; return 0; } } return 1; } return 0; } /* bool modeBase::waitForSync() { // we can wait for a sync state change // if leading edge then OK // if trailing edge then we were to late if(sampleCounter0) outOfSync--; return FALSE; } else if(syncStartDetected) { logfile.add("leading=%d",syncPosition-sampleCounter); return TRUE; } else { outOfSync++; return FALSE; } } else { if(syncProcessor.inSync()) { // still sync detected return FALSE; } else { logfile.add("latency=%d",sampleCounter-syncPosition); return TRUE; } } } */ bool modeBase::getPixels(unsigned char *pixelArray) { float color; if(sampleCounter>=pixelPositionTable[pixelCounter]) { color=255.*(sample-1500.)/(2300.-1500.); if(color<0) color=0; if (color>255) color=255; pixelArray[pixelCounter]=(unsigned char)color; pixelCounter++; if(pixelCounter>=activeSSTVParam.numberOfPixels) { return TRUE; } if((pixelCounter>(activeSSTVParam.numberOfPixels-6))||(pixelCounter<3)) { // logfile.add("modbase:getPixels sm=%d,sampleCounter=%d,pos=%d",(int)color,sampleCounter,dsp->getPos()); } } return FALSE; // indicate, it's not the end of the line } void modeBase::combineColors() { unsigned int i; unsigned int *pixelArray=displayPtr->getLineAddress(lineCounter); for(i=0;igetLineAddress(line); for (i=0;i255 ? 255 : r); r=(r<0 ? 0 : r); b=(b>255 ? 255 : b); b=(b<0 ? 0 : b); g=(g>255 ? 255 : g); g=(g<0 ? 0 : g); pixelArray[i]=qRgb(r,g,b); } displayPtr->showLine(); } // Transmit functions void modeBase::initTX(QProgressBar *pb) { pbPtr=pb; pbPtr->setProgress(0,activeSSTVParam.numberOfLines-1); sampleCounter=0; headerPhase=0; activatePTT(TRUE); } etxState modeBase::txHeader() { do { switch (headerPhase) { case 0: if(useVOX) { if(sendTone(1900.,1.000*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; } else { if(sendTone(1900.,0.500*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; } break; case 1: if(sendTone(1900.,.300*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; break; case 2: if(sendTone(1200.,.030*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; break; case 3: if(sendTone(1900.,.300*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; break; case 4: if(sendTone(1200.,.030*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase=0; vc=activeSSTVParam.VISCode; logfile.add("ready for vis"); return TXDONE; break; } } while (1); } etxState modeBase::txVisCode() { do { if (headerPhase<8) { if((vc&1)==1) { if(sendTone(1100.,0.03*txClock)==TXWAIT) return TXWAIT; } else { if(sendTone(1300.,0.03*txClock)==TXWAIT) return TXWAIT; } vc>>=1; sampleCounter=0; headerPhase++; } else if(headerPhase==8) { if(sendTone(1200.,0.03*txClock)==TXWAIT) return TXWAIT; //stop sampleCounter=0; headerPhase++; } else { if(sendTone(1500.,bp)==TXWAIT) return TXWAIT; //bp sampleCounter=0; headerPhase++; mbState=SETUPLINE; subLine=0; getLine(); logfile.add("ready for image"); return TXDONE; } } while (1); } etxState modeBase::txLine() { if(mbState==SETUPLINE) { // logfile.add("samplcntr=%d",sampleCounter); mbState=txSetupLine(subLine,&buf); subLine++; pixelCounter=0; savedSampleCounter=sampleCounter; //logfile.add("subline start at %d",debugPtr->getPos()); } switch (mbState) { case PIXELS: { if(sendPixelBuffer(buf)==TXDONE) { // logfile.add("sPixels done"); mbState=SETUPLINE; // check for end of subline } } break; case TXGAP: { if(sendTone(txFreq,savedSampleCounter+txDur)==TXDONE) { // logfile.add("sTXGAP done"); mbState=SETUPLINE; } } break; case ENDOFLINE: { // logfile.add("sEOL"); if(++lineCounter>=activeSSTVParam.numberOfLines) mbState=ENDOFIMAGE; else { getLine(); mbState=SETUPLINE; subLine=0; } pbPtr->setProgress(lineCounter); } break; default: // logfile.add("sEOM scntr=%d",sampleCounter); sampleCounter=0; return TXDONE; } return TXWAIT; } etxState modeBase::txTail() { // logfile.add("sTAIL"); if(sendTone(1200,1*txClock)==TXWAIT) return TXWAIT; return TXDONE; } static float tn; static float dr; void modeBase::initCW(QString cwText) { ::initCW(cwText); headerPhase=0; } etxState modeBase::txCW() { if(!useCW) return TXDONE; if(headerPhase==0) // get symbol { if(!sendTextCW(tn,dr)) return TXDONE; // end of CW headerPhase++; sampleCounter=0; } if(headerPhase==1) { if(sendTone(tn,dr*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase=0; } return TXCONT; } etxState modeBase::txDELAYEDSTOP() { // logfile.add("sDELAYEDSTOP"); dsp->delayedStop(); return TXDONE; } etxState modeBase::txWAITSTOP() { // logfile.add("sWAITSTOP"); if(!done) return TXWAIT; return TXDONE; } etxState modeBase::txSingleTone(float freq,float dur) { if(headerPhase==0) { if(txWait(0.5*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; pbPtr->setTotalSteps((int)dur); } if(headerPhase==1) { if(sendTone(freq,dur)==TXWAIT) { pbPtr->setProgress(sampleCounter); return TXWAIT; } sampleCounter=0; headerPhase++; } if(headerPhase==2) { if(txWait(0.5*txClock)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; } if(headerPhase==3) { dsp->delayedStop(); headerPhase++; } if(headerPhase==4) { pbPtr->reset(); if(!done) return TXWAIT; } return TXDONE; } etxState modeBase::txMultiTone(float freq,float dur, float freqB,float durB) { if(headerPhase==0) { if(sendTone(freq,dur)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase++; } if(headerPhase==1) { if(sendTone(freqB,durB)==TXWAIT) return TXWAIT; sampleCounter=0; headerPhase=0; } return TXDONE; } etxState modeBase::txWait(float dur) { if(sendTone(0,dur)==TXWAIT) return TXWAIT; return TXDONE; } /*! \fn modeBase::sendTone(float freq,float duration) \brief sendtone with frequentie \a freq and duration \a duration Send a tone of frequency \a freq and a duration of \a duration \param freq the frequency of the tone \param duration in samples (i.e time*clock) */ etxState modeBase::sendTone(float freq,float duration) { unsigned int end; end=(unsigned int)(duration+0.5); while(sampleCounternextSample(freq)==WAITING) { return TXWAIT; } sampleCounter++; } return TXDONE; } etxState modeBase::sendPixelBuffer(unsigned char *pixelArray) { float f; do { f=1500.+((float)pixelArray[pixelCounter]*(2300.-1500.)/255.); while(sampleCounter2300) f=2300; if (f<1500) f=1500; if(dsp->nextSample(f)==WAITING) return TXWAIT; sampleCounter++; } pixelCounter++; } while(pixelCountergetLineAddress(lineCounter); if (evenodd) { unsigned int *pixelArrayO=displayPtr->getLineAddress(lineCounter+1); // logfile.add("getline=%d",lineCounter); for (unsigned int i=0;i255 ? 255 : r); redArray[i]=(r<0 ? 0 : r); blueArray[i]=(b>255 ? 255 : b); blueArray[i]=(b<0 ? 0 : b); yArray[i]=(ye>255 ? 255 : ye); yArray[i]=(ye<0 ? 0 : ye); greenArray[i]=(yo>255 ? 255 : yo); greenArray[i]=(yo<0 ? 0 : yo); } } else { // logfile.add("getline=%d",lineCounter); for (unsigned int i=0;i255 ? 255 : r<0 ? 0 : r); blueArray[i]=(b>255 ? 255 : b<0 ? 0 : b); yArray[i]=(ye>255 ? 255 : ye<0 ? 0 : ye); } } } void modeBase::getLineBW() { unsigned int t; unsigned int *pixelArray=displayPtr->getLineAddress(lineCounter); // logfile.add("getline=%d",lineCounter); for (unsigned int i=0;igetLineAddress(lineCounter); logfile.add("getline=%d",lineCounter); for (unsigned int i=0;iConfiguration\n" "make sure that you have read/write permission", QMessageBox::Ok,0 ); return FALSE; } } if(serialP>0) { if(b) { ioctl(serialP,TIOCMGET,&modemlines); modemlines |= TIOCM_DTR; modemlines |= TIOCM_RTS; ioctl(serialP,TIOCMSET,&modemlines); // ioctl(serial,TIOCMBIS,&t); } else { ioctl(serialP,TIOCMGET,&modemlines); modemlines &= ~TIOCM_DTR; modemlines &= ~TIOCM_RTS; ioctl(serialP,TIOCMSET,&modemlines); // ioctl(serial,TIOCMBIC,&t); } } return TRUE; }