/* * mt63rx.cc -- The MT63ASC receiver in C++ for LINUX, * written to be compatible with the * MT63ASC.ASM modem for the EVM56K/DSPCARD4. * * Copyright (C) 1999-2004 Pawel Jalocha, SP9VRC * * This file is part of MT63. * * MT63 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. * * MT63 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 MT63; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // Date: 11-NOV-1999 #include #include #include #include #include #ifdef __FreeBSD__ #include #endif #include "dsp.h" #include "mt63.h" #include "sound.h" #include "term.h" #include "stdinr.h" // ============================================================================ char DevName[32]=""; // the name of the sound device char UseDevice=0; int ReqRate=8000; // we request 8000 Hz sampling float DevRate=0; // the device gives us a possibly different rate float UserRate=0.0; // user provided rate (overrides the DevRate) int ReadFromFile=0; // read real audio or playback from a file char *PlaybackFile=NULL; // file to read audio from in playback mode int SaveToFile=0; // save audio to a file char *SaveFile=NULL; // file to save audio /* int SendTextFile=0; // send text from a file char *TextFile=NULL; */ int Bandwidth=1000; // 500, 1000 or 2000 Hz bandwidth int Interleave=0; // short/long interleave int IntegLen=32; // integration period for sync./data tracking int UseTerm=1; // use terminal or output to STDOUT // ============================================================================ SoundDevice RxDev; // sound device to read audio RateConvBL RateConv; // rate converter to adjust the sampling rate int UseRateConv=1; #define BuffLen 512 s16 InpBuff[BuffLen]; // Signed 16-bit audio input buffer float_buff InpFloat; LevelMonitor InpLevel; MT63rx Rx; SplitTerm RxTerm; // ============================================================================ /* this code is to debug the spectra waterfall support void SpectraDisplay(float *SpectraPower, int Len) { int i; printf("[SpectraDisplay] Len=%d\n",Len); for(i=0; i99) Conf=99; SNR=Rx.FEC_SNR(); if(SNR>99.9) SNR=99.9; sprintf(StatusLine,"Inp:%5.3f/%04.1f%% %s:%02d%%/%+05.2f/%4.2f/%4.2f FEC:%4.1f/%+2d %+6.1fHz ", InpLevel.RMS, 100.0*InpLevel.OutOfRange, Rx.SYNC_LockStatus() ? "Lock" : "Seek",Conf, Rx.SYNC_FreqOffset(),Rx.SYNC_FreqDevRMS(),Rx.SYNC_TimeOffset(), SNR,Rx.FEC_CarrOffset(), Rx.TotalFreqOffset()); RxTerm.RxStatLow(StatusLine); } int main(int argc, char *argv[]) { int err,arg,InpLen,i; char code; float ValueF; int ValueI; int stop,key; int OutFileNo=0; int wr; printf("\n\ Multitone MT63 modem for Linux - receiver, (c) 1999 Pawel Jalocha\n\ Made to be compatible with the MT63ASC for the EVM56K/DSPCARD4\n\ \n"); if(argc<=1) { printf("\ Usage: mt63rx \n\ the options:\n\ -d the output dsp device number or name [default = none]\n\ -d => /dev/dsp, -d1 => /dev/dsp1, etc.\n\ or: -d/dev/dsp, -d/dev/dsp1, etc.\n\ -s save audio to a file\n\ -p playback audio from a file\n\ -r request given sampling rate from device [8000 Hz]\n\ -R the true sampling rate (if you know it already)\n\ -B select bandwidth: 500, 1000 or 2000 Hz [1000Hz]\n\ -i use the double interleave [default = single]\n\ -I set the sync. integration period [32 symbols]\n\ Examples:\n\ mt63rx -d0 => read audio from /dev/dsp0, decode with single interleave\n\ mt63rx -d0 -i -I32 => decode with double interleave and longer integration\n\ mt63rx -pmsg.raw => decode the audio file in the raw signed 16-bit format\n\ mt63rx -pmsg.raw -R8010 => decode from msg.raw, the sampling rate was 8010 Hz\n\ mt63rx -d0 -slog.raw -i => decode audio from /dev/dsp0 with double interleave\n\ but save it to log.raw for later playback\n\ "); goto Error; } for(err=0,arg=1; arg %s\n", DevName,strerror(errno)); goto Error; } } if(SaveToFile) { #ifdef __MSDOS__ OutFileNo=open(SaveFile,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IREAD|S_IWRITE); #else OutFileNo=open(SaveFile,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE); #endif if(OutFileNo<0) { printf("Can't open file %s to save audio, errno => %s\n", SaveFile,strerror(errno)); goto Error; } printf("We will save the audio to %s for later playback\n",SaveFile); } else OutFileNo=0; DevRate=RxDev.Rate; printf("Requested rate = %d Hz, device reported rate = %1.0f Hz\n", ReqRate,DevRate); if(UserRate>0.0) { printf("You say the true device rate is %4.2f Hz.\n",UserRate); DevRate=UserRate; } UseRateConv=(DevRate!=8000.0); InpLevel.Preset(10.0,0.75); if(UseRateConv) { err=RateConv.Preset(16,(float**)NULL,64); if(err) { printf("Can't preset the rate converter - not enough RAM ?!\n"); goto Error; } err=RateConv.ComputeShape(0.0,0.75*M_PI,WindowBlackman2); if(err) { printf("Can't compute the shape for the rate converter - not enough RAM ?!\n"); goto Error; } RateConv.SetOutVsInp(8000.0/DevRate); } printf("Modem bandwidth is %d Hz with %s interleave\n", Bandwidth,Interleave ? "DOUBLE (64)" : "SINGLE (32)"); printf("The time/frequency synchronizer integrates over %d symbols\n",IntegLen); // err=Rx.Preset(Bandwidth,Interleave,IntegLen,SpectraDisplay); err=Rx.Preset(Bandwidth,Interleave,IntegLen); if(err) { printf("Can't preset the MT63 receiver - not enough RAM ?\n"); goto Error; } /* InpFloat.EnsureSpace(BuffLen); for(i=0; i %s\n", DevName,strerror(errno)); break; } // the following applies when we read audio in non-blocking mode #ifdef __linux__ if(InpLen==0) { usleep(50000); continue; } #endif #ifdef __MSDOS__ if(InpLen==0) continue; #endif if(OutFileNo>0) { wr=write(OutFileNo,InpBuff,2*InpLen); if(wr!=(2*InpLen)) { printf("Error while writing data to %s\n",SaveFile); break; } } ConvS16toFloat(InpBuff,&InpFloat,InpLen); InpLevel.Process(&InpFloat); if(UseRateConv) { RateConv.ProcessLinI(&InpFloat); Rx.Process(&RateConv.Output); } else Rx.Process(&InpFloat); if(UseTerm) { for(i=0; i=' ')||(code==0x08)||(code==0x09)) printf("%c",code); else if(code=='\r') printf("\n"); else if(code!='\0') printf("<%02X>",code); fflush(stdout); } } } Stop: if(UseTerm) RxTerm.Close(); printf("\nClosing audio device ...\n"); RxDev.Close(); if(OutFileNo>0) close(OutFileNo); printf("Stopped OK.\n"); printf("%ld samples read = %3.1f sec\n", RxDev.TotalRead,RxDev.TotalRead/DevRate); return 0; Error: RxDev.Close(); if(OutFileNo>0) close(OutFileNo); return 1; }