2023-02-25 18:12:34 +01:00
# include <utils/flog.h>
2020-12-22 20:00:51 +01:00
# include <module.h>
2020-11-25 21:52:37 +01:00
# include <gui/gui.h>
# include <signal_path/signal_path.h>
# include <core.h>
# include <gui/style.h>
2022-01-21 20:22:13 +01:00
# include <gui/smgui.h>
2020-11-25 21:52:37 +01:00
# include <iio.h>
2020-11-26 19:25:58 +01:00
# include <ad9361.h>
2024-01-27 21:12:26 +01:00
# include <utils/optionlist.h>
2020-11-25 21:52:37 +01:00
# define CONCAT(a, b) ((std::string(a) + b).c_str())
2021-12-19 22:11:44 +01:00
SDRPP_MOD_INFO {
2020-12-08 04:36:37 +01:00
/* Name: */ " plutosdr_source " ,
/* Description: */ " PlutoSDR source module for SDR++ " ,
/* Author: */ " Ryzerth " ,
/* Version: */ 0 , 1 , 0 ,
/* Max instances */ 1
2020-11-25 21:52:37 +01:00
} ;
2020-11-28 23:24:45 +01:00
ConfigManager config ;
2020-12-08 04:36:37 +01:00
class PlutoSDRSourceModule : public ModuleManager : : Instance {
2020-11-25 21:52:37 +01:00
public :
PlutoSDRSourceModule ( std : : string name ) {
this - > name = name ;
2024-01-27 21:12:26 +01:00
// Load configuration
2021-07-09 14:24:07 -04:00
config . acquire ( ) ;
2020-11-28 23:24:45 +01:00
std : : string _ip = config . conf [ " IP " ] ;
strcpy ( & ip [ 3 ] , _ip . c_str ( ) ) ;
sampleRate = config . conf [ " sampleRate " ] ;
gainMode = config . conf [ " gainMode " ] ;
2021-12-19 22:11:44 +01:00
gain = config . conf [ " gain " ] ;
2021-07-31 21:50:46 +02:00
config . release ( ) ;
2024-01-27 21:12:26 +01:00
// Define valid samplerates
for ( double sr = 1000000.0 ; sr < = 61440000.0 ; sr + = 500000.0 ) {
samplerates . define ( sr , getBandwdithScaled ( sr ) , sr ) ;
}
samplerates . define ( 61440000 , getBandwdithScaled ( 61440000.0 ) , 61440000.0 ) ;
2021-07-31 21:50:46 +02:00
2024-01-27 21:12:26 +01:00
// Set samplerate ID
if ( samplerates . keyExists ( sampleRate ) ) {
srId = samplerates . keyId ( sampleRate ) ;
2021-07-31 21:50:46 +02:00
}
2024-01-27 21:12:26 +01:00
else {
2021-07-31 21:50:46 +02:00
srId = 0 ;
2024-01-27 21:12:26 +01:00
sampleRate = samplerates . value ( srId ) ;
2021-07-31 21:50:46 +02:00
}
2020-11-25 21:52:37 +01:00
2024-01-27 21:29:44 +01:00
// Define gain modes
gainModes . define ( 0 , " Manual " , " manual " ) ;
gainModes . define ( 1 , " Fast Attack " , " fast_attack " ) ;
gainModes . define ( 2 , " Slow Attack " , " slow_attack " ) ;
gainModes . define ( 3 , " Hybrid " , " hybrid " ) ;
2024-01-27 21:12:26 +01:00
// Register source
2020-11-25 21:52:37 +01:00
handler . ctx = this ;
handler . selectHandler = menuSelected ;
handler . deselectHandler = menuDeselected ;
handler . menuHandler = menuHandler ;
handler . startHandler = start ;
handler . stopHandler = stop ;
handler . tuneHandler = tune ;
handler . stream = & stream ;
sigpath : : sourceManager . registerSource ( " PlutoSDR " , & handler ) ;
}
~ PlutoSDRSourceModule ( ) {
2021-07-26 03:11:51 +02:00
stop ( this ) ;
sigpath : : sourceManager . unregisterSource ( " PlutoSDR " ) ;
2020-11-25 21:52:37 +01:00
}
2021-07-26 03:11:51 +02:00
void postInit ( ) { }
2020-12-08 04:36:37 +01:00
void enable ( ) {
enabled = true ;
}
void disable ( ) {
enabled = true ;
}
bool isEnabled ( ) {
return enabled ;
}
2020-11-25 21:52:37 +01:00
private :
2021-07-31 21:50:46 +02:00
std : : string getBandwdithScaled ( double bw ) {
char buf [ 1024 ] ;
if ( bw > = 1000000.0 ) {
sprintf ( buf , " %.1lfMHz " , bw / 1000000.0 ) ;
}
else if ( bw > = 1000.0 ) {
sprintf ( buf , " %.1lfKHz " , bw / 1000.0 ) ;
}
else {
sprintf ( buf , " %.1lfHz " , bw ) ;
}
return std : : string ( buf ) ;
}
2020-11-25 21:52:37 +01:00
static void menuSelected ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
core : : setInputSampleRate ( _this - > sampleRate ) ;
2023-02-25 18:12:34 +01:00
flog : : info ( " PlutoSDRSourceModule '{0}': Menu Select! " , _this - > name ) ;
2020-11-25 21:52:37 +01:00
}
static void menuDeselected ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2023-02-25 18:12:34 +01:00
flog : : info ( " PlutoSDRSourceModule '{0}': Menu Deselect! " , _this - > name ) ;
2020-11-25 21:52:37 +01:00
}
2021-12-19 22:11:44 +01:00
2020-11-25 21:52:37 +01:00
static void start ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2021-07-26 04:16:00 +02:00
if ( _this - > running ) { return ; }
2021-12-19 22:11:44 +01:00
2024-01-27 21:12:26 +01:00
// Open device
2020-11-25 21:54:30 +01:00
_this - > ctx = iio_create_context_from_uri ( _this - > ip ) ;
2020-11-25 21:52:37 +01:00
if ( _this - > ctx = = NULL ) {
2023-02-25 18:12:34 +01:00
flog : : error ( " Could not open pluto " ) ;
2020-11-25 21:52:37 +01:00
return ;
}
2021-12-19 22:11:44 +01:00
_this - > phy = iio_context_find_device ( _this - > ctx , " ad9361-phy " ) ;
2020-11-25 21:52:37 +01:00
if ( _this - > phy = = NULL ) {
2023-02-25 18:12:34 +01:00
flog : : error ( " Could not connect to pluto phy " ) ;
2020-11-25 21:52:37 +01:00
iio_context_destroy ( _this - > ctx ) ;
return ;
}
_this - > dev = iio_context_find_device ( _this - > ctx , " cf-ad9361-lpc " ) ;
if ( _this - > dev = = NULL ) {
2023-02-25 18:12:34 +01:00
flog : : error ( " Could not connect to pluto dev " ) ;
2020-11-25 21:52:37 +01:00
iio_context_destroy ( _this - > ctx ) ;
return ;
}
2024-01-27 21:12:26 +01:00
// Enable RX channel and disable TX
2020-11-26 19:25:58 +01:00
iio_channel_attr_write_bool ( iio_device_find_channel ( _this - > phy , " altvoltage1 " , true ) , " powerdown " , true ) ;
iio_channel_attr_write_bool ( iio_device_find_channel ( _this - > phy , " altvoltage0 " , true ) , " powerdown " , false ) ;
2024-01-27 21:12:26 +01:00
// Configure RX channel
2020-11-26 19:25:58 +01:00
iio_channel_attr_write ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " rf_port_select " , " A_BALANCED " ) ;
2024-01-27 21:29:44 +01:00
iio_channel_attr_write_longlong ( iio_device_find_channel ( _this - > phy , " altvoltage0 " , true ) , " frequency " , round ( _this - > freq ) ) ; // Freq
iio_channel_attr_write_longlong ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " sampling_frequency " , round ( _this - > sampleRate ) ) ; // Sample rate
iio_channel_attr_write ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " gain_control_mode " , _this - > gainModes . value ( _this - > gainMode ) . c_str ( ) ) ; // Gain mode
iio_channel_attr_write_longlong ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " hardwaregain " , round ( _this - > gain ) ) ; // gain
2020-11-26 19:25:58 +01:00
ad9361_set_bb_rate ( _this - > phy , round ( _this - > sampleRate ) ) ;
2021-12-19 22:11:44 +01:00
2024-01-27 21:12:26 +01:00
// Start worker thread
2020-11-25 21:52:37 +01:00
_this - > running = true ;
_this - > workerThread = std : : thread ( worker , _this ) ;
2023-02-25 18:12:34 +01:00
flog : : info ( " PlutoSDRSourceModule '{0}': Start! " , _this - > name ) ;
2020-11-25 21:52:37 +01:00
}
2021-12-19 22:11:44 +01:00
2020-11-25 21:52:37 +01:00
static void stop ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2021-07-26 04:16:00 +02:00
if ( ! _this - > running ) { return ; }
2024-01-27 21:12:26 +01:00
// Stop worker thread
2020-11-25 21:52:37 +01:00
_this - > running = false ;
_this - > stream . stopWriter ( ) ;
_this - > workerThread . join ( ) ;
_this - > stream . clearWriteStop ( ) ;
2024-01-27 21:12:26 +01:00
// Close device
2020-11-25 21:52:37 +01:00
if ( _this - > ctx ! = NULL ) {
iio_context_destroy ( _this - > ctx ) ;
_this - > ctx = NULL ;
}
2023-02-25 18:12:34 +01:00
flog : : info ( " PlutoSDRSourceModule '{0}': Stop! " , _this - > name ) ;
2020-11-25 21:52:37 +01:00
}
2021-12-19 22:11:44 +01:00
2020-11-25 21:52:37 +01:00
static void tune ( double freq , void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2020-11-26 19:25:58 +01:00
_this - > freq = freq ;
2020-11-25 21:52:37 +01:00
if ( _this - > running ) {
2024-01-27 21:12:26 +01:00
// Tune device
2021-02-15 13:18:21 +01:00
iio_channel_attr_write_longlong ( iio_device_find_channel ( _this - > phy , " altvoltage0 " , true ) , " frequency " , round ( freq ) ) ;
2020-11-25 21:52:37 +01:00
}
2023-02-25 18:12:34 +01:00
flog : : info ( " PlutoSDRSourceModule '{0}': Tune: {1}! " , _this - > name , freq ) ;
2020-11-25 21:52:37 +01:00
}
2021-12-19 22:11:44 +01:00
2020-11-25 21:52:37 +01:00
static void menuHandler ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2022-01-21 20:22:13 +01:00
if ( _this - > running ) { SmGui : : BeginDisabled ( ) ; }
SmGui : : LeftLabel ( " IP " ) ;
SmGui : : FillWidth ( ) ;
if ( SmGui : : InputText ( CONCAT ( " ##_pluto_ip_ " , _this - > name ) , & _this - > ip [ 3 ] , 16 ) ) {
2021-07-09 14:24:07 -04:00
config . acquire ( ) ;
2020-11-28 23:24:45 +01:00
config . conf [ " IP " ] = & _this - > ip [ 3 ] ;
config . release ( true ) ;
}
2021-12-19 22:11:44 +01:00
2022-01-21 20:22:13 +01:00
SmGui : : LeftLabel ( " Samplerate " ) ;
SmGui : : FillWidth ( ) ;
2024-01-27 21:12:26 +01:00
if ( SmGui : : Combo ( CONCAT ( " ##_pluto_sr_ " , _this - > name ) , & _this - > srId , _this - > samplerates . txt ) ) {
_this - > sampleRate = _this - > samplerates . value ( _this - > srId ) ;
2021-04-10 15:05:45 +02:00
core : : setInputSampleRate ( _this - > sampleRate ) ;
2021-07-09 14:24:07 -04:00
config . acquire ( ) ;
2021-04-10 15:05:45 +02:00
config . conf [ " sampleRate " ] = _this - > sampleRate ;
config . release ( true ) ;
2020-11-26 19:25:58 +01:00
}
2022-01-21 20:22:13 +01:00
if ( _this - > running ) { SmGui : : EndDisabled ( ) ; }
2020-11-25 21:52:37 +01:00
2022-01-21 20:22:13 +01:00
SmGui : : LeftLabel ( " Gain Mode " ) ;
SmGui : : FillWidth ( ) ;
SmGui : : ForceSync ( ) ;
2024-01-27 21:29:44 +01:00
if ( SmGui : : Combo ( CONCAT ( " ##_gainmode_select_ " , _this - > name ) , & _this - > gainMode , _this - > gainModes . txt ) ) {
2020-11-26 19:25:58 +01:00
if ( _this - > running ) {
2024-01-27 21:29:44 +01:00
iio_channel_attr_write ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " gain_control_mode " , _this - > gainModes . value ( _this - > gainMode ) . c_str ( ) ) ;
2020-11-26 19:25:58 +01:00
}
2021-07-09 14:24:07 -04:00
config . acquire ( ) ;
2020-11-28 23:24:45 +01:00
config . conf [ " gainMode " ] = _this - > gainMode ;
config . release ( true ) ;
2020-11-25 21:52:37 +01:00
}
2022-01-21 20:22:13 +01:00
SmGui : : LeftLabel ( " PGA Gain " ) ;
if ( _this - > gainMode ) { SmGui : : BeginDisabled ( ) ; }
SmGui : : FillWidth ( ) ;
if ( SmGui : : SliderFloat ( CONCAT ( " ##_gain_select_ " , _this - > name ) , & _this - > gain , 0 , 76 ) ) {
2020-11-25 21:52:37 +01:00
if ( _this - > running ) {
2021-12-19 22:11:44 +01:00
iio_channel_attr_write_longlong ( iio_device_find_channel ( _this - > phy , " voltage0 " , false ) , " hardwaregain " , round ( _this - > gain ) ) ;
2020-11-25 21:52:37 +01:00
}
2021-07-09 14:24:07 -04:00
config . acquire ( ) ;
2020-11-28 23:24:45 +01:00
config . conf [ " gain " ] = _this - > gain ;
config . release ( true ) ;
2020-11-25 21:52:37 +01:00
}
2022-01-21 20:22:13 +01:00
if ( _this - > gainMode ) { SmGui : : EndDisabled ( ) ; }
2020-11-25 21:52:37 +01:00
}
static void worker ( void * ctx ) {
PlutoSDRSourceModule * _this = ( PlutoSDRSourceModule * ) ctx ;
2020-12-31 14:26:12 +01:00
int blockSize = _this - > sampleRate / 200.0f ;
2020-11-25 21:52:37 +01:00
2024-01-27 21:12:26 +01:00
// Acquire channels
iio_channel * rx0_i = iio_device_find_channel ( _this - > dev , " voltage0 " , 0 ) ;
iio_channel * rx0_q = iio_device_find_channel ( _this - > dev , " voltage1 " , 0 ) ;
2021-12-19 22:11:44 +01:00
2024-01-27 21:12:26 +01:00
// Start streaming
2020-11-25 21:52:37 +01:00
iio_channel_enable ( rx0_i ) ;
iio_channel_enable ( rx0_q ) ;
2021-12-19 22:11:44 +01:00
2024-01-27 21:12:26 +01:00
// Allocate buffer
iio_buffer * rxbuf = iio_device_create_buffer ( _this - > dev , blockSize , false ) ;
2020-11-25 21:52:37 +01:00
if ( ! rxbuf ) {
2023-02-25 18:12:34 +01:00
flog : : error ( " Could not create RX buffer " ) ;
2020-11-25 21:52:37 +01:00
return ;
}
while ( true ) {
2024-01-27 21:12:26 +01:00
// Read samples
2020-11-25 21:52:37 +01:00
iio_buffer_refill ( rxbuf ) ;
2024-01-27 21:12:26 +01:00
// Get buffer pointer
2020-11-25 21:52:37 +01:00
int16_t * buf = ( int16_t * ) iio_buffer_first ( rxbuf , rx0_i ) ;
2024-01-27 21:12:26 +01:00
// Convert samples to CF32
2021-12-19 22:11:44 +01:00
volk_16i_s32f_convert_32f ( ( float * ) _this - > stream . writeBuf , buf , 32768.0f , blockSize * 2 ) ;
2021-06-30 02:48:36 +02:00
2024-01-27 21:12:26 +01:00
// Send out the samples
2020-12-25 16:58:07 +01:00
if ( ! _this - > stream . swap ( blockSize ) ) { break ; } ;
2020-11-25 21:52:37 +01:00
}
2024-01-27 21:12:26 +01:00
// Stop streaming
iio_channel_disable ( rx0_i ) ;
iio_channel_disable ( rx0_q ) ;
// Free buffer
2020-11-25 21:52:37 +01:00
iio_buffer_destroy ( rxbuf ) ;
}
std : : string name ;
2020-12-08 04:36:37 +01:00
bool enabled = true ;
2020-11-25 21:52:37 +01:00
dsp : : stream < dsp : : complex_t > stream ;
2020-11-26 19:25:58 +01:00
float sampleRate ;
2020-11-25 21:52:37 +01:00
SourceManager : : SourceHandler handler ;
std : : thread workerThread ;
2024-01-27 21:12:26 +01:00
iio_context * ctx = NULL ;
iio_device * phy = NULL ;
iio_device * dev = NULL ;
2020-11-25 21:52:37 +01:00
bool running = false ;
2024-01-27 21:12:26 +01:00
2020-11-26 19:25:58 +01:00
bool ipMode = true ;
2020-11-25 21:52:37 +01:00
double freq ;
2020-11-25 21:54:30 +01:00
char ip [ 1024 ] = " ip:192.168.2.1 " ;
2020-11-25 21:52:37 +01:00
int gainMode = 0 ;
float gain = 0 ;
2021-07-31 21:50:46 +02:00
int srId = 0 ;
2024-01-27 21:12:26 +01:00
OptionList < int , double > samplerates ;
2024-01-27 21:29:44 +01:00
OptionList < int , std : : string > gainModes ;
2020-11-25 21:52:37 +01:00
} ;
MOD_EXPORT void _INIT_ ( ) {
2020-11-28 23:24:45 +01:00
json defConf ;
defConf [ " IP " ] = " 192.168.2.1 " ;
defConf [ " sampleRate " ] = 4000000.0f ;
defConf [ " gainMode " ] = 0 ;
defConf [ " gain " ] = 0.0f ;
2022-02-24 20:49:53 +01:00
config . setPath ( core : : args [ " root " ] . s ( ) + " /plutosdr_source_config.json " ) ;
2020-11-28 23:24:45 +01:00
config . load ( defConf ) ;
config . enableAutoSave ( ) ;
2020-11-25 21:52:37 +01:00
}
2020-12-08 04:36:37 +01:00
MOD_EXPORT ModuleManager : : Instance * _CREATE_INSTANCE_ ( std : : string name ) {
2020-11-25 21:52:37 +01:00
return new PlutoSDRSourceModule ( name ) ;
}
2020-12-08 04:36:37 +01:00
MOD_EXPORT void _DELETE_INSTANCE_ ( ModuleManager : : Instance * instance ) {
2020-11-25 21:52:37 +01:00
delete ( PlutoSDRSourceModule * ) instance ;
}
2020-12-08 04:36:37 +01:00
MOD_EXPORT void _END_ ( ) {
2020-11-28 23:24:45 +01:00
config . disableAutoSave ( ) ;
config . save ( ) ;
2020-11-25 21:52:37 +01:00
}