separation of soapy objects - two channels, two objects

bug_fixes_integration_tx
David Michaeli 2022-04-20 14:21:32 +03:00
rodzic 0935f22b47
commit a45958561c
9 zmienionych plików z 359 dodań i 417 usunięć

Wyświetl plik

@ -683,10 +683,10 @@ static int caribou_smi_set_driver_streaming_state(caribou_smi_st* dev, int state
//=========================================================================
int caribou_smi_setup_stream(caribou_smi_st* dev,
caribou_smi_stream_type_en type,
caribou_smi_channel_en channel,
caribou_smi_data_callback cb,
void* serviced_context)
caribou_smi_stream_type_en type,
caribou_smi_channel_en channel,
caribou_smi_data_callback cb,
void* serviced_context)
{
int stream_id = CARIBOU_SMI_GET_STREAM_ID(type, channel);
ZF_LOGI("Setting up stream channel (%d) of type (%d)", channel, type);

Wyświetl plik

@ -34,7 +34,9 @@ typedef enum
caribou_smi_stream_end = 0xFF,
} caribou_smi_stream_type_en;
#define CARIBOU_SMI_GET_STREAM_ID(type, ch) ( ((type)<<1) | (ch) )
#define CARIBOU_SMI_GET_STREAM_ID(type, ch) ( ((type)<<1) | (ch) )
#define CARIBOU_SMI_GET_STREAM_TYPE(id) ( (caribou_smi_stream_type_en)(((id)>>1)&0x1) )
#define CARIBOU_SMI_GET_STREAM_CH(id) ( (caribou_smi_channel_en)((id)&0x1) )
typedef enum
{

Wyświetl plik

@ -6,6 +6,7 @@
#include <string.h>
#include <ctype.h>
//============================================================
int caribou_smi_check_modules_loaded(char* mod_name)
{
char line[256] = {0};
@ -29,10 +30,23 @@ int caribou_smi_check_modules_loaded(char* mod_name)
return found;
}
//============================================================
int caribou_smi_insert_smi_modules(void)
{
return 0;
}
//============================================================
int caribou_smi_remove_module(char* module_name)
{
return 0;
}
//============================================================
int caribou_smi_check_modules()
{
int bcm_smi_dev = caribou_smi_check_smi_modules_loaded("bcm2835_smi_dev");
int bcm_smi = caribou_smi_check_smi_modules_loaded("bcm2835_smi");
int bcm_smi_dev = caribou_smi_check_modules_loaded("bcm2835_smi_dev");
int bcm_smi = caribou_smi_check_modules_loaded("bcm2835_smi");
if (bcm_smi_dev == -1 || bcm_smi == -1)
{
@ -47,13 +61,3 @@ int caribou_smi_check_modules()
return 0;
}
int caribou_smi_insert_smi_modules()
{
}
int caribou_smi_remove_module(char* module_name)
{
}

Wyświetl plik

@ -17,24 +17,24 @@ Cariboulite::Cariboulite(const SoapySDR::Kwargs &args)
args.at("channel").c_str());
// Initialize the stream Sample Queues
sample_queue_tx = new SampleQueue(getStreamMTU(NULL)*NUM_BYTES_PER_CPLX_ELEM, NUM_SAMPLEQUEUE_BUFS);
sample_queue_rx = new SampleQueue(getStreamMTU(NULL)*NUM_BYTES_PER_CPLX_ELEM, NUM_SAMPLEQUEUE_BUFS);
sample_queue_tx = new SoapySDR::Stream();
sample_queue_rx = new SoapySDR::Stream();
if (!args.at("channel").compare ("HiF"))
{
sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_2400);
sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_2400);
//sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_2400);
//sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_2400);
cariboulite_radio_init(&radio, &sess.cariboulite_sys, cariboulite_channel_6g);
}
else if (!args.at("channel").compare ("S1G"))
{
sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_900);
sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_900);
//sample_queue_tx->AttachStreamId(0, caribou_smi_stream_type_write, caribou_smi_channel_900);
//sample_queue_rx->AttachStreamId(1, caribou_smi_stream_type_read, caribou_smi_channel_900);
cariboulite_radio_init(&radio, &sess.cariboulite_sys, cariboulite_channel_s1g);
}
else
{
throw std::string("Channel type is not specified correctly");
throw std::runtime_error( "Channel type is not specified correctly" );
}
}
@ -368,23 +368,25 @@ static double convertTxBandwidth(at86rf215_radio_tx_cut_off_en bw_en)
//========================================================
void Cariboulite::setBandwidth( const int direction, const size_t channel, const double bw )
{
int filt = 0;
double setbw = bw;
if (bw == 200000.0f) filt = 4;
else if (bw == 100000.0f) filt = 3;
else if (bw == 50000.0f) filt = 2;
else if (bw == 20000.0f) filt = 1;
if (setbw < 200000) setbw = 200000;
double modem_bw = bw;
if (direction == SOAPY_SDR_RX)
{
cariboulite_radio_set_rx_bandwidth(&radio, convertRxBandwidth(setbw));
sample_queue_rx->dig_filt = filt;
if (modem_bw < (160000*BW_SHIFT_FACT) )
{
modem_bw = 160000*BW_SHIFT_FACT;
if (bw <= 20000.0f) sample_queue_rx->setDigitalFilter(SoapySDR::Stream::DigitalFilter_20KHz);
else if (bw <= 50000.0f) sample_queue_rx->setDigitalFilter(SoapySDR::Stream::DigitalFilter_50KHz);
else if (bw <= 100000.0f) sample_queue_rx->setDigitalFilter(SoapySDR::Stream::DigitalFilter_100KHz);
else sample_queue_rx->setDigitalFilter(SoapySDR::Stream::DigitalFilter_None);
}
else sample_queue_rx->setDigitalFilter(SoapySDR::Stream::DigitalFilter_None);
cariboulite_radio_set_rx_bandwidth(&radio, convertRxBandwidth(modem_bw));
}
else if (direction == SOAPY_SDR_TX)
{
cariboulite_radio_set_tx_bandwidth(&radio, convertTxBandwidth(setbw));
cariboulite_radio_set_tx_bandwidth(&radio, convertTxBandwidth(modem_bw));
}
}
@ -431,11 +433,6 @@ std::vector<double> Cariboulite::listBandwidths( const int direction, const size
options.push_back( 1250000*fact );
options.push_back( 1600000*fact );
options.push_back( 2000000*fact );
//options.push_back( 2500000*fact );
//options.push_back( 3000000*fact );
//options.push_back( 4000000*fact );
//options.push_back( 5000000*fact );
}
else
{

Wyświetl plik

@ -13,63 +13,15 @@
#include <cstring>
#include <algorithm>
#include <atomic>
#include <Iir.h>
//#define ZF_LOG_LEVEL ZF_LOG_ERROR
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#include "datatypes/circular_buffer.h"
#include "CaribouliteSampleQueue.hpp"
#include "cariboulite_setup.h"
#include "cariboulite_radios.h"
#include "cariboulite_radio.h"
enum Cariboulite_Format
{
CARIBOULITE_FORMAT_FLOAT32 = 0,
CARIBOULITE_FORMAT_INT16 = 1,
CARIBOULITE_FORMAT_INT8 = 2,
CARIBOULITE_FORMAT_FLOAT64 = 3,
};
#define NUM_SAMPLEQUEUE_BUFS ( 3 )
#define NUM_BYTES_PER_CPLX_ELEM ( 4 )
#pragma pack(1)
// associated with CS8 - total 2 bytes / element
typedef struct
{
int8_t i; // LSB
int8_t q; // MSB
} sample_complex_int8;
// associated with CS12 - total 3 bytes / element
typedef struct
{
int16_t i :12; // LSB
int16_t q :12; // MSB
} sample_complex_int12;
// associated with CS32 - total 8 bytes / element
typedef struct
{
int32_t i; // LSB
int32_t q; // MSB
} sample_complex_int32;
// associated with CF32 - total 8 bytes / element
typedef struct
{
float i; // LSB
float q; // MSB
} sample_complex_float;
// associated with CF64 - total 16 bytes / element
typedef struct
{
double i; // LSB
double q; // MSB
} sample_complex_double;
#pragma pack()
class SoapyCaribouliteSession
{
@ -83,49 +35,6 @@ public:
static size_t sessionCount;
};
class SampleQueue
{
public:
SampleQueue(int mtu_bytes, int num_buffers);
~SampleQueue();
int AttachStreamId(int id, int dir, int channel);
int Write(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t* meta, long timeout_us);
int Read(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t *meta, long timeout_us);
int ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_float* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_double* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_int8* buffer, size_t num_elements, long timeout_us);
int stream_id;
int stream_dir;
int stream_channel;
int is_cw;
Cariboulite_Format chosen_format;
int dig_filt;
private:
circular_buffer<caribou_smi_sample_complex_int16> *queue;
size_t mtu_size_bytes;
uint8_t *partial_buffer;
int partial_buffer_start;
int partial_buffer_length;
caribou_smi_sample_complex_int16 *interm_native_buffer;
#define FILT_ORDER 6
#define FILT_ORDER1 8
Iir::Butterworth::LowPass<FILT_ORDER> filt20_i;
Iir::Butterworth::LowPass<FILT_ORDER> filt20_q;
Iir::Butterworth::LowPass<FILT_ORDER> filt50_i;
Iir::Butterworth::LowPass<FILT_ORDER> filt50_q;
Iir::Butterworth::LowPass<FILT_ORDER> filt100_i;
Iir::Butterworth::LowPass<FILT_ORDER> filt100_q;
Iir::Butterworth::LowPass<FILT_ORDER> filt200_i;
Iir::Butterworth::LowPass<FILT_ORDER> filt200_q;
Iir::Butterworth::LowPass<FILT_ORDER1> filt2p5M_i;
Iir::Butterworth::LowPass<FILT_ORDER1> filt2p5M_q;
};
/***********************************************************************
* Device interface
**********************************************************************/
@ -234,8 +143,8 @@ public:
public:
cariboulite_radio_state_st radio;
SampleQueue* sample_queue_tx;
SampleQueue* sample_queue_rx;
SoapySDR::Stream* sample_queue_tx;
SoapySDR::Stream* sample_queue_rx;
// Static load time initializations
static SoapyCaribouliteSession sess;

Wyświetl plik

@ -2,87 +2,124 @@
#include <Iir.h>
#include <byteswap.h>
#define NUM_BYTES_PER_CPLX_ELEM ( sizeof(caribou_smi_sample_complex_int16) )
#define NUM_NATIVE_MTUS_PER_QUEUE ( 10 )
// each MTU = 131072 samples
// Sized 524,288 bytes per MTU = 32.768 milliseconds
// In total, each queue contains ~5 MB = ~320 milliseconds of depth
size_t SoapySDR::Stream::mtu_size_elements = (1024 * 1024 / 2 / NUM_BYTES_PER_CPLX_ELEM );
//=================================================================
SampleQueue::SampleQueue(int mtu_bytes, int num_buffers)
SoapySDR::Stream::Stream()
{
SoapySDR_logf(SOAPY_SDR_INFO, "Creating SampleQueue MTU: %d bytes, NumBuffers: %d", mtu_bytes, num_buffers);
queue = new circular_buffer<caribou_smi_sample_complex_int16>(mtu_bytes / 4 * num_buffers*10);
mtu_size_bytes = mtu_bytes;
stream_id = -1;
stream_dir = -1;
stream_channel = -1;
SoapySDR_logf(SOAPY_SDR_INFO, "Creating SampleQueue MTU: %d I/Q samples (%d bytes), NumBuffers: %d",
mtu_size_elements,
mtu_size_elements * sizeof(caribou_smi_sample_complex_int16),
NUM_NATIVE_MTUS_PER_QUEUE);
partial_buffer = new uint8_t[mtu_size_bytes];
partial_buffer_start = mtu_size_bytes;
partial_buffer_length = 0;
dig_filt = 0;
// create the actual native queue
queue = new circular_buffer<caribou_smi_sample_complex_int16>(
mtu_size_elements * NUM_NATIVE_MTUS_PER_QUEUE);
// a buffer for conversion betwen native and emulated formats
// the maximal size is the 2*(mtu_size in bytes)
interm_native_buffer = new caribou_smi_sample_complex_int16[2*mtu_size_bytes];
is_cw = 0;
format = CARIBOULITE_FORMAT_INT16;
is_cw = 0;
smi_stream_id = -1;
// Init the internal IIR filters
// a buffer for conversion between native and emulated formats
// the maximal size is the twice the MTU
interm_native_buffer = new caribou_smi_sample_complex_int16[2 * mtu_size_elements];
filterType = DigitalFilter_None;
filter_i = NULL;
filter_q = NULL;
filt20_i.setup(4e6, 20e3/2);
filt50_i.setup(4e6, 50e3/2);
filt100_i.setup(4e6, 100e3/2);
filt200_i.setup(4e6, 200e3/2);
filt2p5M_i.setup(4e6, 2.5e6/2);
filt20_q.setup(4e6, 20e3/2);
filt50_q.setup(4e6, 50e3/2);
filt100_q.setup(4e6, 100e3/2);
filt200_q.setup(4e6, 200e3/2);
filt2p5M_q.setup(4e6, 2.5e6/2);
}
//=================================================================
SampleQueue::~SampleQueue()
void SoapySDR::Stream::setDigitalFilter(DigitalFilterType type)
{
stream_id = -1;
stream_dir = -1;
stream_channel = -1;
delete[] partial_buffer;
switch (type)
{
case DigitalFilter_20KHz: filter_i = &filt20_i; filter_q = &filt20_q; break;
case DigitalFilter_50KHz: filter_i = &filt50_i; filter_q = &filt50_q; break;
case DigitalFilter_100KHz: filter_i = &filt100_i; filter_q = &filt100_q; break;
case DigitalFilter_2500KHz: filter_i = &filt2p5M_i; filter_q = &filt2p5M_q; break;
case DigitalFilter_None:
default:
filter_i = NULL;
filter_q = NULL;
break;
}
filterType = type;
}
//=================================================================
SoapySDR::Stream::~Stream()
{
smi_stream_id = -1;
delete[] interm_native_buffer;
filter_i = NULL;
filter_q = NULL;
filterType = DigitalFilter_None;
delete queue;
}
//=================================================================
int SampleQueue::AttachStreamId(int id, int dir, int channel)
int SoapySDR::Stream::getInnerStreamType(void)
{
//printf("SampleQueue::AttachStreamId\n");
if (stream_id != -1)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "Cannot attach stream_id - already attached to %d", stream_id);
return -1;
}
stream_id = id;
stream_dir = dir;
stream_channel = channel;
return 0;
if (smi_stream_id < 0)
{
return SOAPY_SDR_RX;
}
return CARIBOU_SMI_GET_STREAM_TYPE(smi_stream_id) == caribou_smi_stream_type_read ? SOAPY_SDR_RX : SOAPY_SDR_TX;
}
//=================================================================
int SampleQueue::Write(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t* meta, long timeout_us)
int SoapySDR::Stream::setFormat(const std::string &fmt)
{
if (!fmt.compare(SOAPY_SDR_CS16))
format = CARIBOULITE_FORMAT_INT16;
else if (!fmt.compare(SOAPY_SDR_CS8))
format = CARIBOULITE_FORMAT_INT8;
else if (!fmt.compare(SOAPY_SDR_CF32))
format = CARIBOULITE_FORMAT_FLOAT32;
else if (!fmt.compare(SOAPY_SDR_CF64))
format = CARIBOULITE_FORMAT_FLOAT64;
else
{
return -1;
}
return 0;
}
//=================================================================
int SoapySDR::Stream::Write(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t* meta, long timeout_us)
{
return queue->put(buffer, num_samples);
}
//=================================================================
int SampleQueue::Read(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t *meta, long timeout_us)
int SoapySDR::Stream::Read(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t *meta, long timeout_us)
{
return queue->get(buffer, num_samples);
}
//=================================================================
int SampleQueue::ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t num_elements, long timeout_us)
int SoapySDR::Stream::ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t num_elements, long timeout_us)
{
static int once = 100;
static uint16_t last_q = 0;
int res = Read(buffer, num_elements, NULL, timeout_us);
if (res < 0)
{
// todo!!
SoapySDR_logf(SOAPY_SDR_ERROR, "Reading %d elements failed from queue", num_elements);
return res;
}
@ -90,45 +127,12 @@ int SampleQueue::ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t nu
return tot_read_elements;
// digital filters - TBD
if (dig_filt == 0)
if (filterType != DigitalFilter_None && filter_i != NULL && filter_q != NULL)
{
for (int i = 0; i < res; i++)
{
buffer[i].i = (int16_t)filt2p5M_i.filter((float)buffer[i].i);
buffer[i].q = (int16_t)filt2p5M_q.filter((float)buffer[i].q);
}
}
else if (dig_filt == 1)
{
for (int i = 0; i < res; i++)
{
buffer[i].i = (int16_t)filt20_i.filter((float)buffer[i].i);
buffer[i].q = (int16_t)filt20_q.filter((float)buffer[i].q);
}
}
else if (dig_filt == 2)
{
for (int i = 0; i < res; i++)
{
buffer[i].i = (int16_t)filt50_i.filter((float)buffer[i].i);
buffer[i].q = (int16_t)filt50_q.filter((float)buffer[i].q);
}
}
else if (dig_filt == 3)
{
for (int i = 0; i < res; i++)
{
buffer[i].i = (int16_t)filt100_i.filter((float)buffer[i].i);
buffer[i].q = (int16_t)filt100_q.filter((float)buffer[i].q);
}
}
else if (dig_filt == 4)
{
for (int i = 0; i < res; i++)
{
buffer[i].i = (int16_t)filt200_i.filter((float)buffer[i].i);
buffer[i].q = (int16_t)filt200_q.filter((float)buffer[i].q);
buffer[i].i = (int16_t)filter_i->filter((float)buffer[i].i);
buffer[i].q = (int16_t)filter_q->filter((float)buffer[i].q);
}
}
@ -136,123 +140,59 @@ int SampleQueue::ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t nu
}
//=================================================================
int SampleQueue::ReadSamples(sample_complex_float* buffer, size_t num_elements, long timeout_us)
int SoapySDR::Stream::ReadSamples(sample_complex_float* buffer, size_t num_elements, long timeout_us)
{
uint32_t max_native_samples = 2*(mtu_size_bytes / sizeof(caribou_smi_sample_complex_int16));
// do not allow to store more than is possible in the intermediate buffer
if (num_elements > max_native_samples)
{
num_elements = max_native_samples;
}
num_elements = num_elements > mtu_size_elements ? mtu_size_elements : num_elements;
// read out the native data type
int res = ReadSamples(interm_native_buffer, num_elements, timeout_us);
if (res < 0)
{
// todo!!
return res;
}
float max_val = (float)(4095);
float max_val = 4096.0f;
for (int i = 0; i < res; i++)
{
buffer[i].i = (float)interm_native_buffer[i].i / max_val;
buffer[i].q = (float)interm_native_buffer[i].q / max_val;
buffer[i].i = (float)(interm_native_buffer[i].i) / max_val;
buffer[i].q = (float)(interm_native_buffer[i].q) / max_val;
}
double sumI = 0.0;
double sumQ = 0.0;
for (int i = 0; i < res; i++)
{
sumI += buffer[i].i;
sumQ += buffer[i].q;
}
sumI /= (double)res;
sumQ /= (double)res;
for (int i = 0; i < res; i++)
{
buffer[i].i -= sumI;
buffer[i].q -= sumQ;
}
/*double theta1 = 0.0;
double theta2 = 0.0;
double theta3 = 0.0;
for (int i = 0; i < res; i++)
{
int sign_I = (buffer[i].i > 0 ? 1 : -1);
int sign_Q = (buffer[i].q > 0 ? 1 : -1);
theta1 += sign_I * buffer[i].q;
theta2 += sign_I * buffer[i].i;
theta3 += sign_Q * buffer[i].q;
}
theta1 = - theta1 / (double)res;
theta2 /= (double)res;
theta3 /= (double)res;
double c1 = theta1 / theta2;
double c2 = sqrt( (theta3*theta3 - theta1*theta1) / (theta2*theta2) );
for (int i = 0; i < res; i++)
{
float ii = buffer[i].i;
float qq = buffer[i].q;
buffer[i].i = c2 * ii;
buffer[i].q = c1 * ii + qq;
}*/
return res;
}
//=================================================================
int SampleQueue::ReadSamples(sample_complex_double* buffer, size_t num_elements, long timeout_us)
int SoapySDR::Stream::ReadSamples(sample_complex_double* buffer, size_t num_elements, long timeout_us)
{
uint32_t max_native_samples = 2*(mtu_size_bytes / sizeof(caribou_smi_sample_complex_int16));
// do not allow to store more than is possible in the intermediate buffer
if (num_elements > max_native_samples)
{
num_elements = max_native_samples;
}
num_elements = num_elements > mtu_size_elements ? mtu_size_elements : num_elements;
// read out the native data type
int res = ReadSamples(interm_native_buffer, num_elements, timeout_us);
if (res < 0)
{
// todo!!
return res;
}
double max_val = (double)(4095);
double max_val = 4096.0;
for (int i = 0; i < res; i++)
{
buffer[i].i = (double)interm_native_buffer[i].i / max_val;
buffer[i].q = (double)interm_native_buffer[i].q / max_val;
buffer[i].i = (double)(interm_native_buffer[i].i) / max_val;
buffer[i].q = (double)(interm_native_buffer[i].q) / max_val;
}
return res;
}
//=================================================================
int SampleQueue::ReadSamples(sample_complex_int8* buffer, size_t num_elements, long timeout_us)
int SoapySDR::Stream::ReadSamples(sample_complex_int8* buffer, size_t num_elements, long timeout_us)
{
uint32_t max_native_samples = 2*(mtu_size_bytes / sizeof(caribou_smi_sample_complex_int16));
// do not allow to store more than is possible in the intermediate buffer
if (num_elements > max_native_samples)
{
num_elements = max_native_samples;
}
num_elements = num_elements > mtu_size_elements ? mtu_size_elements : num_elements;
// read out the native data type
int res = ReadSamples(interm_native_buffer, num_elements, timeout_us);
if (res < 0)
{
// todo!!
return res;
}
@ -263,4 +203,18 @@ int SampleQueue::ReadSamples(sample_complex_int8* buffer, size_t num_elements, l
}
return res;
}
//=================================================================
int SoapySDR::Stream::ReadSamplesGen(void* buffer, size_t num_elements, long timeout_us)
{
switch (format)
{
case CARIBOULITE_FORMAT_FLOAT32: return ReadSamples((sample_complex_float*)buffer, num_elements, timeout_us); break;
case CARIBOULITE_FORMAT_INT16: return ReadSamples((caribou_smi_sample_complex_int16*)buffer, num_elements, timeout_us); break;
case CARIBOULITE_FORMAT_INT8: return ReadSamples((sample_complex_int8*)buffer, num_elements, timeout_us); break;
case CARIBOULITE_FORMAT_FLOAT64: return ReadSamples((sample_complex_double*)buffer, num_elements, timeout_us); break;
default: return ReadSamples((caribou_smi_sample_complex_int16*)buffer, num_elements, timeout_us); break;
}
return 0;
}

Wyświetl plik

@ -0,0 +1,125 @@
#pragma once
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Logger.h>
#include <SoapySDR/Types.h>
#include <SoapySDR/Formats.hpp>
#include <stdexcept>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <string>
#include <cstring>
#include <algorithm>
#include <atomic>
#include <Iir.h>
//#define ZF_LOG_LEVEL ZF_LOG_ERROR
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#include "datatypes/circular_buffer.h"
#include "cariboulite_setup.h"
#include "cariboulite_radios.h"
#include "cariboulite_radio.h"
#define DIG_FILT_ORDER 6
#pragma pack(1)
// associated with CS8 - total 2 bytes / element
typedef struct
{
int8_t i; // LSB
int8_t q; // MSB
} sample_complex_int8;
// associated with CS12 - total 3 bytes / element
typedef struct
{
int16_t i :12; // LSB
int16_t q :12; // MSB
} sample_complex_int12;
// associated with CS32 - total 8 bytes / element
typedef struct
{
int32_t i; // LSB
int32_t q; // MSB
} sample_complex_int32;
// associated with CF32 - total 8 bytes / element
typedef struct
{
float i; // LSB
float q; // MSB
} sample_complex_float;
// associated with CF64 - total 16 bytes / element
typedef struct
{
double i; // LSB
double q; // MSB
} sample_complex_double;
#pragma pack()
// The forward declared Stream Class
class SoapySDR::Stream
{
public:
enum CaribouliteFormat
{
CARIBOULITE_FORMAT_FLOAT32 = 0,
CARIBOULITE_FORMAT_INT16 = 1,
CARIBOULITE_FORMAT_INT8 = 2,
CARIBOULITE_FORMAT_FLOAT64 = 3,
};
CaribouliteFormat format;
enum DigitalFilterType
{
DigitalFilter_None = 0,
DigitalFilter_20KHz,
DigitalFilter_50KHz,
DigitalFilter_100KHz,
DigitalFilter_200KHz,
DigitalFilter_2500KHz,
};
public:
Stream();
~Stream();
int Write(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t* meta, long timeout_us);
int Read(caribou_smi_sample_complex_int16 *buffer, size_t num_samples, uint8_t *meta, long timeout_us);
int ReadSamples(caribou_smi_sample_complex_int16* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_float* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_double* buffer, size_t num_elements, long timeout_us);
int ReadSamples(sample_complex_int8* buffer, size_t num_elements, long timeout_us);
int ReadSamplesGen(void* buffer, size_t num_elements, long timeout_us);
int getInnerStreamType(void);
void setDigitalFilter(DigitalFilterType type);
int setFormat(const std::string &fmt);
int smi_stream_id;
int is_cw;
private: // Internal data
circular_buffer<caribou_smi_sample_complex_int16> *queue;
caribou_smi_sample_complex_int16 *interm_native_buffer;
DigitalFilterType filterType;
Iir::Butterworth::LowPass<DIG_FILT_ORDER>* filter_i;
Iir::Butterworth::LowPass<DIG_FILT_ORDER>* filter_q;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt20_i;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt20_q;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt50_i;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt50_q;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt100_i;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt100_q;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt2p5M_i;
Iir::Butterworth::LowPass<DIG_FILT_ORDER> filt2p5M_q;
public:
static size_t mtu_size_elements;
static size_t getMTUSizeElements(void) {return mtu_size_elements;}
};

Wyświetl plik

@ -77,28 +77,25 @@ Type Cariboulite::readSensor(const int direction, const size_t channel, const st
if (key == "RSSI")
{
float rssi = 0.0f;
cariboulite_get_rssi((cariboulite_radios_st*)&radios,(cariboulite_channel_en)channel, &rssi);
cariboulite_radio_get_rssi((cariboulite_radio_state_st*)&radio, &rssi);
return rssi;
}
if (key == "ENERGY")
{
float energy = 0.0f;
cariboulite_get_energy_det((cariboulite_radios_st*)&radios,(cariboulite_channel_en)channel, &energy);
cariboulite_radio_get_energy_det((cariboulite_radio_state_st*)&radio, &energy);
return energy;
}
}
cariboulite_radio_state_st* rad = (cariboulite_radio_state_st* )
((channel == cariboulite_channel_s1g) ? &radios.radio_sub1g : &radios.radio_6g);
if (key == "PLL_LOCK_MODEM")
{
return rad->modem_pll_locked;
return radio.modem_pll_locked;
}
if (channel == cariboulite_channel_6g && key == "PLL_LOCK_MIXER")
{
return rad->lo_pll_locked;
return radio.lo_pll_locked;
}
return 0;
}
}

Wyświetl plik

@ -2,36 +2,41 @@
#include "cariboulite_config/cariboulite_config_default.h"
//=================================================================
static void caribou_stream_data_event( void *ctx,
void *service_context,
caribou_smi_stream_type_en type,
caribou_smi_channel_en ch,
size_t sample_count,
caribou_smi_sample_complex_int16 *cmplx_vec,
caribou_smi_sample_meta *meta_vec,
size_t buffers_capacity_samples)
void caribou_stream_data_event( void *ctx,
void *service_context,
caribou_smi_stream_type_en type,
caribou_smi_channel_en ch,
size_t sample_count,
caribou_smi_sample_complex_int16 *cmplx_vec,
caribou_smi_sample_meta *meta_vec,
size_t buffers_capacity_samples)
{
cariboulite_st* sys = (cariboulite_st*)ctx;
Cariboulite *obj = (Cariboulite*)service_context;
//cariboulite_st* sys = (cariboulite_st*)ctx;
Cariboulite *soapy_obj = (Cariboulite*)service_context;
int dir = (type == caribou_smi_stream_type_read) ? SOAPY_SDR_RX : SOAPY_SDR_TX;
int channel = (ch == caribou_smi_channel_900) ? cariboulite_channel_s1g : cariboulite_channel_6g;
// Basic sanity checking
cariboulite_channel_en ch_type = ch == caribou_smi_channel_900 ? cariboulite_channel_s1g : cariboulite_channel_6g;
if (soapy_obj->radio.type != ch_type)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "caribou_stream_data_event: reaceived wrong CH <=> service_context pair");
return;
}
switch(type)
{
//-------------------------------------------------------
case caribou_smi_stream_type_read:
{
int sample_queue_index = CARIBOU_SMI_GET_STREAM_ID(type, ch);
obj->sample_queues[sample_queue_index]->Write(cmplx_vec, sample_count, 0, 10000L);
// SMI read samples from Caribou and these samples are written into the Soapy buffer
soapy_obj->sample_queue_rx->Write(cmplx_vec, sample_count, 0, 10000L);
}
break;
//-------------------------------------------------------
case caribou_smi_stream_type_write:
{
int sample_queue_index = CARIBOU_SMI_GET_STREAM_ID(dir, channel);
printf("Wrote to sample_queue_index %d\n", sample_queue_index);
// SMI requests to get (read) samples from Soapy and write them to Caribou
soapy_obj->sample_queue_tx->Read(cmplx_vec, sample_count, 0, 10000L);
}
break;
@ -66,7 +71,6 @@ static void caribou_stream_data_event( void *ctx,
*/
std::vector<std::string> Cariboulite::getStreamFormats(const int direction, const size_t channel) const
{
//printf("getStreamFormats\n");
std::vector<std::string> formats;
formats.push_back(SOAPY_SDR_CS16);
formats.push_back(SOAPY_SDR_CS8);
@ -87,7 +91,6 @@ std::vector<std::string> Cariboulite::getStreamFormats(const int direction, cons
*/
std::string Cariboulite::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
{
//printf("getNativeStreamFormat\n");
fullScale = (double)((1<<12)-1);
return SOAPY_SDR_CS16;
}
@ -101,7 +104,6 @@ std::string Cariboulite::getNativeStreamFormat(const int direction, const size_t
*/
SoapySDR::ArgInfoList Cariboulite::getStreamArgsInfo(const int direction, const size_t channel) const
{
//printf("getStreamArgsInfo start\n");
SoapySDR::ArgInfoList streamArgs;
return streamArgs;
}
@ -161,71 +163,50 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction,
const std::vector<size_t> &channels,
const SoapySDR::Kwargs &args)
{
int cw = (args.count("CW") != 0) ? std::atoi(args.at("CW").c_str()) : 0;
SoapySDR_logf(SOAPY_SDR_INFO, "setupStream: dir= %s, format= %s, is_cw= %d, ch= %d",
direction == SOAPY_SDR_TX?"TX":"RX", format.c_str(), cw,
channels.size()?channels[0]:0);
std::vector<size_t> channels_internal = channels;
// is it a CW TX channel
int cw = (args.count("CW") != 0) ? std::atoi(args.at("CW").c_str()) : 0;
if (direction == SOAPY_SDR_RX && cw)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "setupStream: CW channel can only be used with TX channel");
return NULL;
}
// default channel - sub1GHz
if ( channels_internal.size() == 0 )
{
channels_internal.push_back(cariboulite_channel_s1g);
}
SoapySDR_logf(SOAPY_SDR_INFO, "setupStream: dir= %s, format= %s, is_cw= %d",
direction == SOAPY_SDR_TX ? "TX" : "RX",
format.c_str(), cw);
// currently we take only the first channel
size_t ch = channels_internal[0];
// calculate the stream_id
caribou_smi_stream_type_en type = (direction == SOAPY_SDR_RX) ? caribou_smi_stream_type_read : caribou_smi_stream_type_write;
caribou_smi_channel_en channel = (ch == cariboulite_channel_s1g) ? caribou_smi_channel_900 : caribou_smi_channel_2400;
int stream_id = CARIBOU_SMI_GET_STREAM_ID(type, channel);
sample_queues[stream_id]->is_cw = cw;
// Setup the SampleQueue's format
if (format == SOAPY_SDR_CS16)
{
sample_queues[stream_id]->chosen_format = CARIBOULITE_FORMAT_INT16;
}
else if (format == SOAPY_SDR_CS8)
{
sample_queues[stream_id]->chosen_format = CARIBOULITE_FORMAT_INT8;
}
else if (format == SOAPY_SDR_CF32)
{
sample_queues[stream_id]->chosen_format = CARIBOULITE_FORMAT_FLOAT32;
}
else if (format == SOAPY_SDR_CF64)
{
sample_queues[stream_id]->chosen_format = CARIBOULITE_FORMAT_FLOAT64;
}
else
{
SoapySDR_logf(SOAPY_SDR_ERROR, "the specified format %s is not supported", format.c_str());
// configure the queue
SoapySDR::Stream* queue = direction == SOAPY_SDR_RX ? sample_queue_rx : sample_queue_tx;
queue->smi_stream_id = -1; // by default, the smi stream is not configured (e.g. with CS / BB-FSK...)
queue->is_cw = cw;
if (queue->setFormat(format) != 0)
{
SoapySDR_logf(SOAPY_SDR_ERROR, "the specified format %s is not supported", format.c_str());
throw std::runtime_error( "setupStream invalid format " + format );
}
}
// create the stream (only for non CW streams)
if (sample_queues[stream_id]->is_cw)
// configure the radio channel to CW if needed
cariboulite_radio_set_cw_outputs(&radio, false, queue->is_cw);
// configure the smi stream and attach it to the queue
if (!cw)
{
cariboulite_set_cw_outputs(&radios, (cariboulite_channel_en)ch, false, true);
}
else
{
cariboulite_set_cw_outputs(&radios, (cariboulite_channel_en)ch, false, false);
stream_id = caribou_smi_setup_stream(&sess.cariboulite_sys.smi,
type, channel,
caribou_stream_data_event,
this);
if (stream_id < 0)
// find out the SMI channel info
caribou_smi_stream_type_en type = direction == SOAPY_SDR_RX ? caribou_smi_stream_type_read : caribou_smi_stream_type_write;
caribou_smi_channel_en channel = radio.type == cariboulite_channel_s1g ? caribou_smi_channel_900 : caribou_smi_channel_2400;
queue->smi_stream_id = caribou_smi_setup_stream(&sess.cariboulite_sys.smi,
type,
channel,
caribou_stream_data_event,
this);
if (queue->smi_stream_id < 0)
{
throw std::runtime_error( "setupStream caribou_smi_setup_stream failed" );
}
}
//SoapySDR_logf(SOAPY_SDR_INFO, "finished setup stream, stream_id = %d, CW=%d", stream_id, cw);
return (SoapySDR::Stream *)((void*)(stream_id));
// Queue inherits Stream class
return queue;
}
//========================================================
@ -236,10 +217,18 @@ SoapySDR::Stream *Cariboulite::setupStream(const int direction,
*/
void Cariboulite::closeStream(SoapySDR::Stream *stream)
{
if (stream == NULL) return;
int stream_id = (intptr_t)stream;
// if it is a CW stream, disable the output
if (stream->is_cw)
{
cariboulite_radio_set_cw_outputs(&radio, false, false);
}
caribou_smi_destroy_stream(&sess.cariboulite_sys.smi, stream_id);
// check if this is a valid SMI stream
if (stream->smi_stream_id != -1)
{
caribou_smi_destroy_stream(&sess.cariboulite_sys.smi, stream->smi_stream_id);
stream->smi_stream_id = -1;
}
}
//========================================================
@ -254,7 +243,7 @@ void Cariboulite::closeStream(SoapySDR::Stream *stream)
*/
size_t Cariboulite::getStreamMTU(SoapySDR::Stream *stream) const
{
return 1024 * 1024 / 2 / 4;
return stream->getMTUSizeElements();
}
//========================================================
@ -280,17 +269,11 @@ int Cariboulite::activateStream(SoapySDR::Stream *stream,
const long long timeNs,
const size_t numElems)
{
//printf("activateStream\n");
//SoapySDR_logf(SOAPY_SDR_INFO, "activateStream");
int stream_id = (intptr_t)stream;
cariboulite_radio_activate_channel(&radio, true);
cariboulite_activate_channel(&radios,
(cariboulite_channel_en)sample_queues[stream_id]->stream_channel,
true);
if ((cariboulite_channel_en)sample_queues[stream_id]->is_cw == 0)
if (!stream->is_cw)
{
caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 1);
caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, stream->smi_stream_id, 1);
}
return 0;
}
@ -312,18 +295,13 @@ int Cariboulite::activateStream(SoapySDR::Stream *stream,
*/
int Cariboulite::deactivateStream(SoapySDR::Stream *stream, const int flags, const long long timeNs)
{
//SoapySDR_logf(SOAPY_SDR_INFO, "deactivateStream");
int stream_id = (intptr_t)stream;
if ((cariboulite_channel_en)sample_queues[stream_id]->is_cw == 0)
if (!stream->is_cw)
{
caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, (intptr_t)stream, 0);
sleep(1);
caribou_smi_run_pause_stream (&sess.cariboulite_sys.smi, stream->smi_stream_id, 0);
sleep(1);
}
cariboulite_activate_channel(&radios,
(cariboulite_channel_en)sample_queues[stream_id]->stream_channel,
false);
cariboulite_radio_activate_channel(&radio, false);
return 0;
}
@ -356,35 +334,11 @@ int Cariboulite::readStream(
long long &timeNs,
const long timeoutUs)
{
//printf("readStream\n");
int stream_id = (intptr_t)stream;
if (sample_queues[stream_id]->stream_dir != SOAPY_SDR_RX)
// Verify that it is an RX stream
if (stream->getInnerStreamType() != SOAPY_SDR_RX)
{
// wrong sample queue => wrong stream_id
return SOAPY_SDR_NOT_SUPPORTED;
}
uint32_t metadata = 0;
int res = 0;
switch(sample_queues[stream_id]->chosen_format)
{
case CARIBOULITE_FORMAT_FLOAT32:
{
res = sample_queues[stream_id]->ReadSamples((sample_complex_float*)buffs[0], numElems, timeoutUs);
}
break;
case CARIBOULITE_FORMAT_INT16:
res = sample_queues[stream_id]->ReadSamples((caribou_smi_sample_complex_int16*)buffs[0], numElems, timeoutUs);
break;
case CARIBOULITE_FORMAT_INT8:
res = sample_queues[stream_id]->ReadSamples((sample_complex_int8*)buffs[0], numElems, timeoutUs);
break;
case CARIBOULITE_FORMAT_FLOAT64:
res = sample_queues[stream_id]->ReadSamples((sample_complex_double*)buffs[0], numElems, timeoutUs);
break;
default: return -1; break;
}
return res;
return stream->ReadSamplesGen((void*)buffs[0], numElems, timeoutUs);
}