F5OEO-rpitx/src/rpitxv1/rpitx.cpp

364 wiersze
11 KiB
C++

/*<rpitx is a software which use the GPIO of Raspberry Pi to transmit HF>
This version is to allow back compatibility with rpitx v1
Copyright (C) 2015-2018 Evariste COURJAUD F5OEO (evaristec@gmail.com)
Transmitting on HF band is surely not permitted without license (Hamradio for example).
Usage of this software is not the responsability of the author.
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, see <http://www.gnu.org/licenses/>.
Thanks to first test of RF with Pifm by Oliver Mattos and Oskar Weigl
INSPIRED BY THE IMPLEMENTATION OF PIFMDMA by Richard Hirst <richardghirst@gmail.com> December 2012
Helped by a code fragment by PE1NNZ (http://pe1nnz.nl.eu.org/2013/05/direct-ssb-generation-on-pll.html)
*/
#include <unistd.h>
#include "../librpitx/src/librpitx.h"
#include "stdio.h"
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
#include <cstring>
#include <signal.h>
#define PROGRAM_VERSION "2.0"
bool running=true;
void print_usage(void)
{
fprintf(stderr,"Warning : rpitx V2 is only to try to be compatible with version 1\n");
fprintf(stderr,\
"\nrpitx -%s\n\
Usage:\nrpitx [-i File Input][-m ModeInput] [-f frequency output] [-s Samplerate] [-l] [-p ppm] [-h] \n\
-m {IQ(FileInput is a Stereo Wav contains I on left Channel, Q on right channel)}\n\
{IQFLOAT(FileInput is a Raw float interlaced I,Q)}\n\
{RF(FileInput is a (double)Frequency,Time in nanoseconds}\n\
{RFA(FileInput is a (double)Frequency,(int)Time in nanoseconds,(float)Amplitude}\n\
{VFO (constant frequency)}\n\
-i path to File Input \n\
-f float frequency to output on GPIO_4 pin 7 in khz : (130 kHz to 750 MHz),\n\
-l loop mode for file input\n\
-p float frequency correction in parts per million (ppm), positive or negative, for calibration, default 0.\n\
-h help (this help).\n\
\n",\
PROGRAM_VERSION);
} /* end function print_usage */
static void
terminate(int num)
{
running=false;
fprintf(stderr,"Caught signal - Terminating %x\n",num);
}
static void fatal(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
terminate(0);
}
int main(int argc, char* argv[])
{
enum {MODE_RPITX_IQ=0,MODE_RPITX_RF,MODE_RPITX_RFA,MODE_RPITX_IQ_FLOAT,MODE_RPITX_VFO};
int a;
int anyargs = 0;
char Mode = MODE_IQ; // By default
int SampleRate=48000;
float SetFrequency=1e6;//1MHZ
float ppmpll=0.0;
int SetDma=0;
char *FileName=NULL;
FILE *FileInHandle=NULL;
bool loop_mode_flag=false;
bool useStdin;
int Harmonic=1;
while(1)
{
a = getopt(argc, argv, "i:f:m:s:p:hld:w:c:ra:");
if(a == -1)
{
if(anyargs) break;
else a='h'; //print usage and exit
}
anyargs = 1;
switch(a)
{
case 'i': // File name
FileName = optarg;
break;
case 'f': // Frequency
SetFrequency = atof(optarg)*1e3;
break;
case 'm': // Mode (IQ,IQFLOAT,RF,RFA)
if(strcmp("IQ",optarg)==0) Mode=MODE_RPITX_IQ;
if(strcmp("RF",optarg)==0) Mode=MODE_RPITX_RF;
if(strcmp("RFA",optarg)==0) Mode=MODE_RPITX_RFA;
if(strcmp("IQFLOAT",optarg)==0) Mode=MODE_RPITX_IQ_FLOAT;
if(strcmp("VFO",optarg)==0) Mode=MODE_RPITX_VFO;
break;
case 's': // SampleRate (Only needeed in IQ mode)
SampleRate = atoi(optarg);
break;
case 'p': // ppmcorrection
ppmpll = atof(optarg);
break;
case 'h': // help
print_usage();
exit(1);
break;
case 'l': // loop mode
loop_mode_flag = true;
break;
case 'd': // Dma Sample Burst
fprintf(stderr,"Warning : 'd' parameter not used in this version\n");
break;
case 'c': fprintf(stderr,"Warning : 'c' parameter not used in this version\n");
break;
case 'w': // No use pwmfrequency
fprintf(stderr,"Warning : 'w' parameter not used in this version\n");
break;
case 'r': // Randomize PWM frequency
fprintf(stderr,"Warning : 'r' parameter not used in this version\n");
break;
case 'a': // DMA Channel 1-14
fprintf(stderr,"Warning : 'a' parameter not used in this version\n");
break;
case -1:
break;
case '?':
if (isprint(optopt) )
{
fprintf(stderr, "rpitx: unknown option `-%c'.\n", optopt);
}
else
{
fprintf(stderr, "rpitx: unknown option character `\\x%x'.\n", optopt);
}
print_usage();
exit(1);
break;
default:
print_usage();
exit(1);
break;
}/* end switch a */
}/* end while getopt() */
//Open File Input for modes which need it
if((Mode==MODE_RPITX_IQ)||(Mode==MODE_RPITX_IQ_FLOAT)||(Mode==MODE_RPITX_RF)||(Mode==MODE_RPITX_RFA))
{
if(FileName && strcmp(FileName,"-")==0)
{
FileInHandle = stdin;
useStdin = true;
}
else FileInHandle = fopen(FileName ,"rb");
if (FileInHandle ==NULL)
{
fatal("Failed to read Filein %s\n",FileName);
}
}
for (int i = 0; i < 64; i++) {
struct sigaction sa;
std::memset(&sa, 0, sizeof(sa));
sa.sa_handler = terminate;
sigaction(i, &sa, NULL);
}
fprintf(stderr,"Warning : rpitx V2 is only to try to be compatible with version 1\n");
// For IQ
#define IQBURST 4000
iqdmasync *iqsender=NULL;
std::complex<float> CIQBuffer[IQBURST];
int Decimation=1;
// For RF (FM)
//For RFA (AM)
amdmasync *amsender=NULL;
ngfmdmasync *fmsender=NULL;
float AmOrFmBuffer[IQBURST];
int FifoSize=IQBURST*4;
//Init
switch(Mode)
{
case MODE_RPITX_IQ:
case MODE_RPITX_IQ_FLOAT:
{
iqsender=new iqdmasync(SetFrequency,SampleRate,14,FifoSize,MODE_IQ);
iqsender->Setppm(ppmpll);
}
break;
case MODE_RPITX_RFA://Amplitude
{
amsender=new amdmasync(SetFrequency,SampleRate,14,FifoSize);
}
break;
case MODE_RPITX_RF://Frequency
{
fmsender=new ngfmdmasync(SetFrequency,SampleRate,14,FifoSize);
}
}
//resetFile();
//return pitx_run(Mode, SampleRate, SetFrequency, ppmpll, NoUsePwmFrequency, readFile, resetFile, NULL,SetDma);
while(running)
{
switch(Mode)
{
case MODE_RPITX_IQ:
case MODE_RPITX_IQ_FLOAT:
{
int CplxSampleNumber=0;
switch(Mode)
{
case MODE_RPITX_IQ://I16
{
static short IQBuffer[IQBURST*2];
int nbread=fread(IQBuffer,sizeof(short),IQBURST*2,FileInHandle);
if(nbread==0) continue;
if(nbread>0)
{
for(int i=0;i<nbread/2;i++)
{
if(i%Decimation==0)
{
CIQBuffer[CplxSampleNumber++]=std::complex<float>(IQBuffer[i*2]/32768.0,IQBuffer[i*2+1]/32768.0);
}
}
}
else
{
printf("End of file\n");
if(loop_mode_flag&&!useStdin)
fseek ( FileInHandle , 0 , SEEK_SET );
else
running=false;
}
}
break;
case MODE_RPITX_IQ_FLOAT:
{
static float IQBuffer[IQBURST*2];
int nbread=fread(IQBuffer,sizeof(float),IQBURST*2,FileInHandle);
if(nbread==0) continue;
if(nbread>0)
{
for(int i=0;i<nbread/2;i++)
{
if(i%Decimation==0)
{
CIQBuffer[CplxSampleNumber++]=std::complex<float>(IQBuffer[i*2],IQBuffer[i*2+1]);
}
//printf("%f %f\n",(IQBuffer[i*2]-127.5)/128.0,(IQBuffer[i*2+1]-127.5)/128.0);
}
}
else
{
printf("End of file\n");
if(loop_mode_flag&&useStdin)
fseek ( FileInHandle , 0 , SEEK_SET );
else
running=false;
}
}
break;
}
iqsender->SetIQSamples(CIQBuffer,CplxSampleNumber,Harmonic);
}
break;
case MODE_RPITX_RFA://Amplitude
case MODE_RPITX_RF://Frequence
{
typedef struct {
double Frequency;
uint32_t WaitForThisSample;
} samplerf_t;
int SampleNumber=0;
static samplerf_t RfBuffer[IQBURST];
int nbread=fread(RfBuffer,sizeof(samplerf_t),IQBURST,FileInHandle);
if(nbread==0) continue;
if(nbread>0)
{
for(int i=0;i<nbread;i++)
{
AmOrFmBuffer[SampleNumber++]=(float)(RfBuffer[i].Frequency);
}
}
else
{
printf("End of file\n");
if(loop_mode_flag&&useStdin)
fseek ( FileInHandle , 0 , SEEK_SET );
else
running=false;
}
switch(Mode)
{
case MODE_RPITX_RFA:
{
amsender->SetAmSamples(AmOrFmBuffer,SampleNumber);
}
break;
case MODE_RPITX_RF:
{
fmsender->SetFrequencySamples(AmOrFmBuffer,SampleNumber);
}
break;
}
}
break;
case MODE_RPITX_VFO:
{
}
break;
}
}
// This is the end
switch(Mode)
{
case MODE_RPITX_IQ:
case MODE_RPITX_IQ_FLOAT:delete(iqsender);
break;
case MODE_RPITX_RFA:delete(amsender);break;
case MODE_RPITX_RF:delete(fmsender);break;
}
}