2018-03-22 14:51:00 +00:00
# include <unistd.h>
2021-01-13 09:47:38 +00:00
# include <librpitx/librpitx.h>
2018-03-22 14:51:00 +00:00
# include "stdio.h"
# include <cstring>
# include <signal.h>
2018-12-01 00:00:00 +00:00
# include <stdlib.h>
2020-06-07 17:04:10 +00:00
# include <sys/shm.h> //Used for shared memory
2020-06-08 13:31:17 +00:00
// =============================================================================================
// ----- SHARED MEMORY STRUCTURE -----
// All commands sent by a partner program towards sendiq
// Operation tips
// 1-Partner program creates a shared memory block with a given arbitrary token id
// (any integer non-zero integer number).
// 2-sendiq is started with the -m {token} argument, without it no shared memory commands
// are honored.
// 3-Partner program willing to alter the operation of sendiq place the
// appropriate commnand plus optional associated data and/or common_data
// if needed (see table below).
// 4-Partner program set updated=true.
// 5-sendiq checks periodically for condition updated==true.
// 6-if detected updated==true at step -5- the command is evaluated and executed.
// 7-sendiq set updated=false.
// 8-Partner program must refrain to send any command while the condition updated==true is on
//
// Table
// ---------------------------------------------------------------------------
// Command Meaning data common_data
// 1111 Switch to I/Q mode N/A N/A
// 2222 Switch to Freq & A mode N/A N/A
// 3333 Set drive level Drive level {0..7} N/A
// 4444 Change Frequency Frequency in Hz N/A
// ---------------------------------------------------------------------------
//
// Note: with current level if shared memory is enabled the data incoming thru standar input
// or file is expected to be in float format. Other data formats aren't supported together with
// commands, for them sendiq will work but no commands will be honored.
//
// *--- Memory structure
2020-06-07 17:04:10 +00:00
struct shared_memory_struct {
bool updated ;
int command ;
float data ;
char common_data [ 1024 ] ;
} ;
2018-03-22 14:51:00 +00:00
2020-06-07 17:04:10 +00:00
bool running = true ;
bool fdds = false ; //operate as a DDS
2020-06-08 13:31:17 +00:00
float drivedds = 0.1 ; //drive level
2018-03-22 14:51:00 +00:00
2020-06-07 17:04:10 +00:00
# define PROGRAM_VERSION "0.2"
2018-03-22 14:51:00 +00:00
2020-06-07 17:04:10 +00:00
// *----- 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
2018-03-22 14:51:00 +00:00
void print_usage ( void )
{
fprintf ( stderr , \
" \n sendiq -%s \n \
2018-03-30 09:13:12 +00:00
Usage : \ nsendiq [ - i File Input ] [ - s Samplerate ] [ - l ] [ - f Frequency ] [ - h Harmonic number ] \ n \
2018-03-22 14:51:00 +00:00
- i path to File Input \ n \
- s SampleRate 10000 - 250000 \ n \
- f float central frequency Hz ( 50 kHz to 1500 MHz ) , \ n \
2020-06-07 17:04:10 +00:00
- m int shared memory token , \ n \
- d dds mode , \ n \
- p power level ( 0.00 to 7.00 ) , \ n \
2018-03-22 14:51:00 +00:00
- l loop mode for file input \ n \
2018-03-30 09:13:12 +00:00
- h Use harmonic number n \ n \
2018-09-01 13:19:11 +00:00
- t IQ type ( i16 default ) { i16 , u8 , float , double } \ n \
2018-03-30 09:13:12 +00:00
- ? help ( this help ) . \ n \
2018-03-22 14:51:00 +00:00
\ n " , \
PROGRAM_VERSION ) ;
} /* end function print_usage */
static void
terminate ( int num )
{
running = false ;
2020-06-07 17:04:10 +00:00
fprintf ( stderr , " Caught signal - Terminating %x \n " , num ) ;
2018-03-22 14:51:00 +00:00
}
2018-08-06 21:20:02 +00:00
# define MAX_SAMPLERATE 200000
2018-03-22 14:51:00 +00:00
int main ( int argc , char * argv [ ] )
{
int a ;
2018-03-30 09:13:12 +00:00
int anyargs = 1 ;
2018-03-22 14:51:00 +00:00
float SetFrequency = 434e6 ;
float SampleRate = 48000 ;
bool loop_mode_flag = false ;
char * FileName = NULL ;
2018-03-30 09:13:12 +00:00
int Harmonic = 1 ;
2018-09-01 13:19:11 +00:00
enum { typeiq_i16 , typeiq_u8 , typeiq_float , typeiq_double } ;
2018-08-06 09:57:26 +00:00
int InputType = typeiq_i16 ;
2018-08-06 21:20:02 +00:00
int Decimation = 1 ;
2022-02-28 13:53:41 +00:00
char * endptr = NULL ;
2018-03-22 14:51:00 +00:00
while ( 1 )
{
2020-06-07 17:04:10 +00:00
a = getopt ( argc , argv , " i:f:s:m:p:h:ldt: " ) ;
2018-03-22 14:51:00 +00:00
if ( a = = - 1 )
{
if ( anyargs ) break ;
else a = ' h ' ; //print usage and exit
}
anyargs = 1 ;
switch ( a )
{
case ' i ' : // File name
FileName = optarg ;
break ;
2020-06-07 17:04:10 +00:00
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 ;
2018-03-22 14:51:00 +00:00
case ' f ' : // Frequency
2022-02-28 13:53:41 +00:00
SetFrequency = strtof ( optarg , & endptr ) ;
if ( endptr = = optarg | | SetFrequency < = 0.0f | | SetFrequency = = HUGE_VALF ) {
2024-03-11 10:04:33 +00:00
fprintf ( stderr , " tune: not a valid frequency - '%s' " , optarg ) ;
2022-02-28 13:53:41 +00:00
exit ( 1 ) ;
}
break ;
case ' m ' : // Shared memory token
sharedmem_token = atoi ( optarg ) ;
InputType = typeiq_float ; //if using shared memory force float pipe
2020-06-07 17:04:10 +00:00
break ;
2018-03-22 14:51:00 +00:00
case ' s ' : // SampleRate (Only needeed in IQ mode)
SampleRate = atoi ( optarg ) ;
2018-08-06 21:20:02 +00:00
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 ;
2020-06-07 17:04:10 +00:00
}
2018-08-06 21:20:02 +00:00
}
if ( Decimation = = 1 )
2020-06-07 17:04:10 +00:00
{
2018-08-06 21:20:02 +00:00
fprintf ( stderr , " SampleRate too high : >%d sample/s " , 10 * MAX_SAMPLERATE ) ;
exit ( 1 ) ;
2020-06-07 17:04:10 +00:00
}
2018-08-06 21:20:02 +00:00
else
2020-06-07 17:04:10 +00:00
{
2018-08-06 21:20:02 +00:00
fprintf ( stderr , " Warning samplerate too high, decimation by %d will be performed " , Decimation ) ;
2020-06-07 17:04:10 +00:00
}
} ;
2018-03-22 14:51:00 +00:00
break ;
2022-02-28 13:53:41 +00:00
case ' h ' : // Harmonic numebr
2018-03-30 09:13:12 +00:00
Harmonic = atoi ( optarg ) ;
2018-03-22 14:51:00 +00:00
break ;
case ' l ' : // loop mode
loop_mode_flag = true ;
break ;
2018-08-06 09:57:26 +00:00
case ' t ' : // inout type
2018-09-01 12:55:47 +00:00
if ( strcmp ( optarg , " i16 " ) = = 0 ) InputType = typeiq_i16 ;
2018-08-06 09:57:26 +00:00
if ( strcmp ( optarg , " u8 " ) = = 0 ) InputType = typeiq_u8 ;
2018-09-01 12:55:47 +00:00
if ( strcmp ( optarg , " float " ) = = 0 ) InputType = typeiq_float ;
2018-09-01 13:19:11 +00:00
if ( strcmp ( optarg , " double " ) = = 0 ) InputType = typeiq_double ;
2018-08-06 09:57:26 +00:00
break ;
2018-03-22 14:51:00 +00:00
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() */
2018-08-06 21:20:02 +00:00
if ( FileName = = NULL ) { fprintf ( stderr , " Need an input \n " ) ; exit ( 1 ) ; }
2018-03-22 14:51:00 +00:00
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 ;
2018-08-06 21:20:02 +00:00
if ( strcmp ( FileName , " - " ) = = 0 )
iqfile = fopen ( " /dev/stdin " , " rb " ) ;
else
iqfile = fopen ( FileName , " rb " ) ;
2018-03-30 09:13:12 +00:00
if ( iqfile = = NULL )
{
printf ( " input file issue \n " ) ;
exit ( 0 ) ;
}
2018-03-22 14:51:00 +00:00
2018-08-06 21:20:02 +00:00
# define IQBURST 4000
2018-03-22 14:51:00 +00:00
int SR = 48000 ;
2018-08-06 09:57:26 +00:00
int FifoSize = IQBURST * 4 ;
2018-11-01 00:40:20 +00:00
iqdmasync iqtest ( SetFrequency , SampleRate , 14 , FifoSize , MODE_IQ ) ;
2018-06-14 09:37:51 +00:00
iqtest . SetPLLMasterLoop ( 3 , 4 , 0 ) ;
2020-06-07 17:04:10 +00:00
if ( fdds = = true ) { //if instructed to operate as DDS start with carrier, otherwise I/Q mode it is
iqtest . ModeIQ = MODE_FREQ_A ;
}
2018-11-01 18:50:27 +00:00
//iqtest.print_clock_tree();
2018-08-06 09:57:26 +00:00
//iqtest.SetPLLMasterLoop(5,6,0);
2020-06-07 17:04:10 +00:00
//=========================================================================================================
// *------ 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 ;
}
//=========================================================================================================
2018-03-22 14:51:00 +00:00
std : : complex < float > CIQBuffer [ IQBURST ] ;
while ( running )
{
2018-08-06 09:57:26 +00:00
2018-08-06 21:20:02 +00:00
int CplxSampleNumber = 0 ;
2018-08-06 09:57:26 +00:00
switch ( InputType )
2018-03-22 14:51:00 +00:00
{
2018-08-06 09:57:26 +00:00
case typeiq_i16 :
{
static short IQBuffer [ IQBURST * 2 ] ;
int nbread = fread ( IQBuffer , sizeof ( short ) , IQBURST * 2 , iqfile ) ;
2018-08-06 21:20:02 +00:00
if ( nbread > 0 )
2018-08-06 09:57:26 +00:00
{
for ( int i = 0 ; i < nbread / 2 ; i + + )
{
2018-08-06 21:20:02 +00:00
if ( i % Decimation = = 0 )
{
2018-11-01 18:50:27 +00:00
CIQBuffer [ CplxSampleNumber + + ] = std : : complex < float > ( IQBuffer [ i * 2 ] / 32768.0 , IQBuffer [ i * 2 + 1 ] / 32768.0 ) ;
2018-08-06 21:20:02 +00:00
}
2018-08-06 09:57:26 +00:00
}
}
else
{
printf ( " End of file \n " ) ;
if ( loop_mode_flag )
fseek ( iqfile , 0 , SEEK_SET ) ;
else
running = false ;
}
2018-08-06 21:20:02 +00:00
2018-08-06 09:57:26 +00:00
}
break ;
case typeiq_u8 :
{
static unsigned char IQBuffer [ IQBURST * 2 ] ;
int nbread = fread ( IQBuffer , sizeof ( unsigned char ) , IQBURST * 2 , iqfile ) ;
2018-11-06 11:00:14 +00:00
2018-08-06 21:20:02 +00:00
if ( nbread > 0 )
2018-08-06 09:57:26 +00:00
{
for ( int i = 0 ; i < nbread / 2 ; i + + )
{
2018-08-06 21:20:02 +00:00
if ( i % Decimation = = 0 )
{
CIQBuffer [ CplxSampleNumber + + ] = std : : complex < float > ( ( IQBuffer [ i * 2 ] - 127.5 ) / 128.0 , ( IQBuffer [ i * 2 + 1 ] - 127.5 ) / 128.0 ) ;
}
2018-08-06 09:57:26 +00:00
}
}
else
{
printf ( " End of file \n " ) ;
if ( loop_mode_flag )
fseek ( iqfile , 0 , SEEK_SET ) ;
else
running = false ;
}
}
2018-09-01 12:55:47 +00:00
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 + + )
{
2020-06-07 17:04:10 +00:00
// *-----------------------------------------------------[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 ;
2020-06-08 13:31:17 +00:00
printf ( " MODE_IQ selected \n " ) ;
2020-06-07 17:04:10 +00:00
}
if ( sharedmem - > command = = 2222 ) {
iqtest . ModeIQ = MODE_FREQ_A ;
2020-06-08 13:31:17 +00:00
printf ( " MODE_FREQ_A selected \n " ) ;
2020-06-07 17:04:10 +00:00
}
if ( sharedmem - > command = = 3333 ) {
drivedds = sharedmem - > data ;
2020-06-08 13:31:17 +00:00
printf ( " Drive level set (%f) \n " , drivedds ) ;
2020-06-07 17:04:10 +00:00
}
if ( sharedmem - > command = = 4444 ) {
SetFrequency = sharedmem - > data ;
2020-06-08 13:31:17 +00:00
printf ( " Frequency set %f \n " , SetFrequency ) ;
2020-06-07 17:04:10 +00:00
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
}
// *---------------------------------------------------------------------------------------------------------------------------------------------
2018-09-01 12:55:47 +00:00
if ( i % Decimation = = 0 )
2020-06-07 17:04:10 +00:00
{
2018-09-01 12:55:47 +00:00
CIQBuffer [ CplxSampleNumber + + ] = std : : complex < float > ( IQBuffer [ i * 2 ] , IQBuffer [ i * 2 + 1 ] ) ;
2020-06-07 17:04:10 +00:00
}
2018-09-01 12:55:47 +00:00
}
}
else
{
printf ( " End of file \n " ) ;
if ( loop_mode_flag )
fseek ( iqfile , 0 , SEEK_SET ) ;
else
running = false ;
}
}
2018-08-06 09:57:26 +00:00
break ;
2018-09-01 13:19:11 +00:00
case typeiq_double :
{
static double IQBuffer [ IQBURST * 2 ] ;
int nbread = fread ( IQBuffer , sizeof ( double ) , IQBURST * 2 , iqfile ) ;
2018-11-06 11:00:14 +00:00
//if(nbread==0) continue;
2018-09-01 13:19:11 +00:00
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 ;
2018-08-06 09:57:26 +00:00
2018-03-22 14:51:00 +00:00
}
2018-08-06 21:20:02 +00:00
iqtest . SetIQSamples ( CIQBuffer , CplxSampleNumber , Harmonic ) ;
2018-03-22 14:51:00 +00:00
}
2020-06-07 17:04:10 +00:00
2018-03-22 14:51:00 +00:00
iqtest . stop ( ) ;
2020-06-07 17:04:10 +00:00
// *--- 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
2018-03-22 14:51:00 +00:00
}