kopia lustrzana https://github.com/F5OEO/rpitx
383 wiersze
10 KiB
C++
383 wiersze
10 KiB
C++
#include <unistd.h>
|
|
#include "librpitx/src/librpitx.h"
|
|
#include "stdio.h"
|
|
#include <cstring>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <sys/shm.h> //Used for shared memory
|
|
//----- SHARED MEMORY STRUCTURE -----
|
|
struct shared_memory_struct {
|
|
bool updated;
|
|
int command;
|
|
float data;
|
|
char common_data[1024];
|
|
};
|
|
|
|
bool running=true;
|
|
bool fdds=false; //operate as a DDS
|
|
float drivedds=1.0; //drive level
|
|
|
|
#define PROGRAM_VERSION "0.2"
|
|
|
|
// *----- Shared memory Variables
|
|
|
|
void *pshared = (void *)0; //pointer to IPC structure
|
|
struct shared_memory_struct *sharedmem; //Actual shared memory area
|
|
int sharedmem_id; //token is an unique ID for shared memory
|
|
int sharedmem_token=0; //key ID, =0 means no shared memory
|
|
// *----- End of shared memory definitions
|
|
|
|
void print_usage(void)
|
|
{
|
|
|
|
fprintf(stderr,\
|
|
"\nsendiq -%s\n\
|
|
Usage:\nsendiq [-i File Input][-s Samplerate][-l] [-f Frequency] [-h Harmonic number] \n\
|
|
-i path to File Input \n\
|
|
-s SampleRate 10000-250000 \n\
|
|
-f float central frequency Hz(50 kHz to 1500 MHz),\n\
|
|
-m int shared memory token,\n\
|
|
-d dds mode,\n\
|
|
-p power level (0.00 to 7.00),\n\
|
|
-l loop mode for file input\n\
|
|
-h Use harmonic number n\n\
|
|
-t IQ type (i16 default) {i16,u8,float,double}\n\
|
|
-? 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);
|
|
|
|
}
|
|
|
|
#define MAX_SAMPLERATE 200000
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int a;
|
|
int anyargs = 1;
|
|
float SetFrequency=434e6;
|
|
float SampleRate=48000;
|
|
bool loop_mode_flag=false;
|
|
char* FileName=NULL;
|
|
int Harmonic=1;
|
|
enum {typeiq_i16,typeiq_u8,typeiq_float,typeiq_double};
|
|
int InputType=typeiq_i16;
|
|
int Decimation=1;
|
|
|
|
while(1)
|
|
{
|
|
a = getopt(argc, argv, "i:f:s:m:p:h:ldt:");
|
|
|
|
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 'd': // dds mode
|
|
fdds=true;
|
|
break;
|
|
case 'p': // driver level (power)
|
|
drivedds=atof(optarg);
|
|
if (drivedds<0.0) {drivedds=0.0;}
|
|
if (drivedds>7.0) {drivedds=7.0;}
|
|
break;
|
|
case 'f': // Frequency
|
|
SetFrequency = atof(optarg);
|
|
break;
|
|
case 'm': // Shared memory token
|
|
sharedmem_token = atoi(optarg);
|
|
break;
|
|
case 's': // SampleRate (Only needeed in IQ mode)
|
|
SampleRate = atoi(optarg);
|
|
if(SampleRate>MAX_SAMPLERATE)
|
|
{
|
|
for(int i=2;i<12;i++) //Max 10 times samplerate
|
|
{
|
|
if(SampleRate/i<MAX_SAMPLERATE)
|
|
{
|
|
SampleRate=SampleRate/i;
|
|
Decimation=i;
|
|
break;
|
|
}
|
|
}
|
|
if(Decimation==1)
|
|
{
|
|
fprintf(stderr,"SampleRate too high : >%d sample/s",10*MAX_SAMPLERATE);
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr,"Warning samplerate too high, decimation by %d will be performed",Decimation);
|
|
}
|
|
};
|
|
break;
|
|
case 'h': // help
|
|
Harmonic=atoi(optarg);
|
|
break;
|
|
case 'l': // loop mode
|
|
loop_mode_flag = true;
|
|
break;
|
|
case 't': // inout type
|
|
if(strcmp(optarg,"i16")==0) InputType=typeiq_i16;
|
|
if(strcmp(optarg,"u8")==0) InputType=typeiq_u8;
|
|
if(strcmp(optarg,"float")==0) InputType=typeiq_float;
|
|
if(strcmp(optarg,"double")==0) InputType=typeiq_double;
|
|
break;
|
|
case -1:
|
|
break;
|
|
case '?':
|
|
if (isprint(optopt) )
|
|
{
|
|
fprintf(stderr, "sendiq: unknown option `-%c'.\n", optopt);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "sendiq: unknown option character `\\x%x'.\n", optopt);
|
|
}
|
|
print_usage();
|
|
|
|
exit(1);
|
|
break;
|
|
default:
|
|
print_usage();
|
|
exit(1);
|
|
break;
|
|
}/* end switch a */
|
|
}/* end while getopt() */
|
|
|
|
if(FileName==NULL) {fprintf(stderr,"Need an input\n");exit(1);}
|
|
|
|
for (int i = 0; i < 64; i++) {
|
|
struct sigaction sa;
|
|
|
|
std::memset(&sa, 0, sizeof(sa));
|
|
sa.sa_handler = terminate;
|
|
sigaction(i, &sa, NULL);
|
|
}
|
|
|
|
FILE *iqfile=NULL;
|
|
if(strcmp(FileName,"-")==0)
|
|
iqfile=fopen("/dev/stdin","rb");
|
|
else
|
|
iqfile=fopen(FileName ,"rb");
|
|
if (iqfile==NULL)
|
|
{
|
|
printf("input file issue\n");
|
|
exit(0);
|
|
}
|
|
|
|
#define IQBURST 4000
|
|
int SR=48000;
|
|
int FifoSize=IQBURST*4;
|
|
iqdmasync iqtest(SetFrequency,SampleRate,14,FifoSize,MODE_IQ);
|
|
iqtest.SetPLLMasterLoop(3,4,0);
|
|
|
|
if (fdds==true) { //if instructed to operate as DDS start with carrier, otherwise I/Q mode it is
|
|
iqtest.ModeIQ=MODE_FREQ_A;
|
|
}
|
|
|
|
//iqtest.print_clock_tree();
|
|
//iqtest.SetPLLMasterLoop(5,6,0);
|
|
//=========================================================================================================
|
|
// *------ Shared memory definitions if enabled
|
|
//=========================================================================================================
|
|
if (sharedmem_token != 0) {
|
|
sharedmem_id = shmget((key_t)sharedmem_token, sizeof(struct shared_memory_struct), 0666 | IPC_CREAT); //<<<<< SET THE SHARED MEMORY KEY (Shared memory key , Size in bytes, Permission flags)
|
|
if (sharedmem_id == -1) {
|
|
printf("Shared memory shmget() failed\n");
|
|
exit(8);
|
|
}
|
|
|
|
// *----- Make the shared memory accessible to the program
|
|
pshared = shmat(sharedmem_id, (void *)0, 0);
|
|
if (pshared == (void *)-1) {
|
|
printf("Shared memory shmat() failed\n");
|
|
exit(16);
|
|
}
|
|
|
|
// *----- Assign the shared_memory segment
|
|
sharedmem = (struct shared_memory_struct *)pshared;
|
|
|
|
sharedmem->updated=false;
|
|
sharedmem->command=0x00;
|
|
sharedmem->data=0;
|
|
}
|
|
//=========================================================================================================
|
|
|
|
std::complex<float> CIQBuffer[IQBURST];
|
|
while(running)
|
|
{
|
|
|
|
int CplxSampleNumber=0;
|
|
switch(InputType)
|
|
{
|
|
case typeiq_i16:
|
|
{
|
|
static short IQBuffer[IQBURST*2];
|
|
int nbread=fread(IQBuffer,sizeof(short),IQBURST*2,iqfile);
|
|
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)
|
|
fseek ( iqfile , 0 , SEEK_SET );
|
|
else
|
|
running=false;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case typeiq_u8:
|
|
{
|
|
static unsigned char IQBuffer[IQBURST*2];
|
|
int nbread=fread(IQBuffer,sizeof(unsigned char),IQBURST*2,iqfile);
|
|
|
|
if(nbread>0)
|
|
{
|
|
for(int i=0;i<nbread/2;i++)
|
|
{
|
|
if(i%Decimation==0)
|
|
{
|
|
CIQBuffer[CplxSampleNumber++]=std::complex<float>((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)
|
|
fseek ( iqfile , 0 , SEEK_SET );
|
|
else
|
|
running=false;
|
|
}
|
|
}
|
|
break;
|
|
case typeiq_float:
|
|
{
|
|
static float IQBuffer[IQBURST*2];
|
|
int nbread=fread(IQBuffer,sizeof(float),IQBURST*2,iqfile);
|
|
if(nbread>0)
|
|
{
|
|
for(int i=0;i<nbread/2;i++)
|
|
{
|
|
|
|
// *-----------------------------------------------------[Patch to introduce IPC handling]-------------------------------------------------------
|
|
// * this modification operates only when using the float stream for a minimum intervention into the original sendiq
|
|
// * for consistency and transparence it should be propagated to all pipe modes eventually
|
|
// *---------------------------------------------------------------------------------------------------------------------------------------------
|
|
if (sharedmem_token != 0) {
|
|
if (sharedmem->updated==true) {
|
|
if (sharedmem->command == 1111) {
|
|
iqtest.ModeIQ=MODE_IQ;
|
|
}
|
|
if (sharedmem->command == 2222) {
|
|
iqtest.ModeIQ=MODE_FREQ_A;
|
|
}
|
|
|
|
if (sharedmem->command == 3333) {
|
|
drivedds=sharedmem->data;
|
|
}
|
|
if (sharedmem->command == 4444) {
|
|
SetFrequency=sharedmem->data;
|
|
iqtest.clkgpio::disableclk(4);
|
|
iqtest.clkgpio::SetAdvancedPllMode(true);
|
|
iqtest.clkgpio::SetCenterFrequency(SetFrequency,SampleRate);
|
|
iqtest.clkgpio::SetFrequency(0);
|
|
iqtest.clkgpio::enableclk(4);
|
|
}
|
|
sharedmem->updated=false;
|
|
}
|
|
}
|
|
if (iqtest.ModeIQ==MODE_FREQ_A) { //if into Frequency-Amplitude mode then only drive a constant carrier
|
|
IQBuffer[i*2]=10.0; //should be 10 Hz
|
|
IQBuffer[i*2+1]=drivedds; //at the defined drive level
|
|
}
|
|
// *---------------------------------------------------------------------------------------------------------------------------------------------
|
|
if(i%Decimation==0)
|
|
{
|
|
CIQBuffer[CplxSampleNumber++]=std::complex<float>(IQBuffer[i*2],IQBuffer[i*2+1]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("End of file\n");
|
|
if(loop_mode_flag)
|
|
fseek ( iqfile , 0 , SEEK_SET );
|
|
else
|
|
running=false;
|
|
}
|
|
}
|
|
break;
|
|
case typeiq_double:
|
|
{
|
|
static double IQBuffer[IQBURST*2];
|
|
int nbread=fread(IQBuffer,sizeof(double),IQBURST*2,iqfile);
|
|
//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]);
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("End of file\n");
|
|
if(loop_mode_flag)
|
|
fseek ( iqfile , 0 , SEEK_SET );
|
|
else
|
|
running=false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
iqtest.SetIQSamples(CIQBuffer,CplxSampleNumber,Harmonic);
|
|
}
|
|
|
|
|
|
iqtest.stop();
|
|
|
|
// *--- Detach and delete shared memory
|
|
if (sharedmem_token != 0) {
|
|
if (shmdt(pshared) == -1) {
|
|
printf("shmdt failed\n");
|
|
} else {
|
|
if (shmctl(sharedmem_id, IPC_RMID, 0) == -1) {
|
|
printf("shmctl(IPC_RMID) failed\n");
|
|
}
|
|
}
|
|
}
|
|
// *--- end of shared memory detach
|
|
}
|
|
|