From 30d5b409ebc10965c806310861f0d0e2c0823f96 Mon Sep 17 00:00:00 2001 From: Vladisslav P Date: Fri, 11 Mar 2022 03:12:56 +0300 Subject: [PATCH 1/2] Improve compatibility with intel hubs Disable LPM while streaming to prevent dropouts. --- SDDC_FX3/USBhandler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SDDC_FX3/USBhandler.c b/SDDC_FX3/USBhandler.c index 40a187d1..072a250c 100644 --- a/SDDC_FX3/USBhandler.c +++ b/SDDC_FX3/USBhandler.c @@ -464,6 +464,7 @@ CyFxSlFifoApplnUSBSetupCB ( break; case STARTFX3: + CyU3PUsbLPMDisable(); CyU3PUsbGetEP0Data(wLength, glEp0Buffer, NULL); CyU3PGpifControlSWInput ( CyFalse ); CyU3PDmaMultiChannelReset (&glMultiChHandleSlFifoPtoU); // Reset existing channel @@ -476,6 +477,7 @@ CyFxSlFifoApplnUSBSetupCB ( break; case STOPFX3: + CyU3PUsbLPMEnable(); CyU3PUsbGetEP0Data(wLength, glEp0Buffer, NULL); CyU3PGpifControlSWInput ( CyFalse ); CyU3PThreadSleep(10); From caaa82435b509dce8e42270421b761227c2b473f Mon Sep 17 00:00:00 2001 From: Vladisslav P Date: Tue, 10 May 2022 11:28:32 +0300 Subject: [PATCH 2/2] Make it work under linux with gqrx/gr-osmosdr Requires patched gr-osmosdr (gr3.7 only so far) https://github.com/vladisslav2011/gr-osmosdr/tree/ngrx No correct device listing and sample rates list. Gain selection is still a bit buggy. Fix test segfault. Do not delete fx3Handler as RadioHandlerClass::~RadioHandlerClass() have already taken care of it. Retry opening the USB device after download for 5 times As it may be slow to reenumerate on some platforms. Include the firmware into libsddc binary as a BLOB Make USB HS work at lower sampling rates/tuner at <7MHz BW Implement r82xx bandwidth selection Prevent freeze on close after live device disconnection Allow low sample rates Improve compatibility with intel hubs Restore attenuations after band switch --- Core/RadioHandler.cpp | 54 +++++-- Core/RadioHandler.h | 8 +- Core/arch/linux/FX3handler.cpp | 44 ++++-- Core/arch/linux/FX3handler.h | 2 + Core/arch/linux/streaming.c | 10 +- Core/arch/linux/usb_device.c | 49 ++++--- Core/arch/win32/FX3handler.cpp | 2 +- Core/arch/win32/FX3handler.h | 2 +- Core/config.h | 2 +- Core/conv_r2iq.cpp | 144 +++++++++++++++++++ Core/conv_r2iq.h | 53 +++++++ Core/dsp/ringbuffer.h | 56 ++++---- Core/fft_mt_r2iq.cpp | 22 +-- Core/fft_mt_r2iq.h | 5 +- Core/fft_mt_r2iq_impl.hpp | 4 +- Core/r2iq.h | 17 ++- Core/radio/BBRF103Radio.cpp | 7 +- Core/radio/RX888R2Radio.cpp | 7 +- Interface.h | 3 + SDDC_FX3/StartStopApplication.c | 22 ++- SDDC_FX3/USBhandler.c | 14 +- SDDC_FX3/driver/tuner_r82xx.c | 4 +- SDDC_FX3/makefile | 6 +- SDK/util/elf2img/elf2img.c | 50 +++++-- libsddc/CMakeLists.txt | 6 +- libsddc/libsddc.cpp | 240 +++++++++++++++++++++++++------- libsddc/libsddc.h | 16 ++- libsddc/sddc_stream_test.c | 49 +++++-- libsddc/sddc_vhf_stream_test.c | 23 +-- libsddc/wavewrite.c | 18 +++ unittest/core_test.cpp | 3 - 31 files changed, 747 insertions(+), 195 deletions(-) create mode 100644 Core/conv_r2iq.cpp create mode 100644 Core/conv_r2iq.h diff --git a/Core/RadioHandler.cpp b/Core/RadioHandler.cpp index c3b4423d..5302c399 100644 --- a/Core/RadioHandler.cpp +++ b/Core/RadioHandler.cpp @@ -21,7 +21,7 @@ unsigned long Failures = 0; void RadioHandlerClass::OnDataPacket() { - auto len = outputbuffer.getBlockSize() / 2 / sizeof(float); + auto len = outputbuffer.getBlockSize(); while(run) { @@ -30,12 +30,6 @@ void RadioHandlerClass::OnDataPacket() if (!run) break; - if (fc != 0.0f) - { - std::unique_lock lk(fc_mutex); - shift_limited_unroll_C_sse_inp_c((complexf*)buf, len, stateFineTune); - } - #ifdef _DEBUG //PScope buffer screenshot if (saveADCsamplesflag == true) { @@ -74,11 +68,16 @@ RadioHandlerClass::RadioHandlerClass() : inputbuffer.setBlockSize(transferSamples); stateFineTune = new shift_limited_unroll_C_sse_data_t(); + adcrate = adcnominalfreq; + DbgPrintf("RadioHandlerClass::RadioHandlerClass\n"); } RadioHandlerClass::~RadioHandlerClass() { delete stateFineTune; + delete r2iqCntrl; + delete hardware; + delete fx3; } const char *RadioHandlerClass::getName() @@ -86,15 +85,23 @@ const char *RadioHandlerClass::getName() return hardware->getName(); } -bool RadioHandlerClass::Init(fx3class* Fx3, void (*callback)(void*context, const float*, uint32_t), r2iqControlClass *r2iqCntrl, void *context) +bool RadioHandlerClass::Init(fx3class* Fx3, void (*callback)(void*context, const float*, uint32_t), r2iqControlClass *r2iqCntrlIn, void *context) { uint8_t rdata[4]; this->fx3 = Fx3; this->Callback = callback; this->callbackContext = context; - if (r2iqCntrl == nullptr) + if (r2iqCntrlIn == nullptr) + { r2iqCntrl = new fft_mt_r2iq(); + DbgPrintf("RadioHandlerClass::Init r2iqCntrl created\n"); + } + else + { + r2iqCntrl = r2iqCntrlIn; + DbgPrintf("RadioHandlerClass::Init r2iqCntrl assigned\n"); + } Fx3->GetHardwareInfo((uint32_t*)rdata); @@ -137,15 +144,30 @@ bool RadioHandlerClass::Init(fx3class* Fx3, void (*callback)(void*context, const DbgPrintf("WARNING no SDR connected\n"); break; } - adcrate = adcnominalfreq; hardware->Initialize(adcnominalfreq); - DbgPrintf("%s | firmware %x\n", hardware->getName(), firmware); - this->r2iqCntrl = r2iqCntrl; + DbgPrintf("%s | firmware %x adcrate %u\n", hardware->getName(), firmware, adcrate); r2iqCntrl->Init(hardware->getGain(), &inputbuffer, &outputbuffer); return true; } +int RadioHandlerClass::SetSampleRate(int sr) +{ + adcrate = sr; + if(adcrate < 8000000) + adcrate = 8000000; + if(adcrate > 128000000) + adcrate = 128000000; + + hardware->Initialize(adcrate); + return adcrate; +} + +int RadioHandlerClass::GetSampleRate() +{ + return adcrate; +} + bool RadioHandlerClass::Start(int srate_idx) { Stop(); @@ -169,6 +191,7 @@ bool RadioHandlerClass::Start(int srate_idx) // 0,1,2,3,4 => 32,16,8,4,2 MHz r2iqCntrl->setDecimate(decimate); r2iqCntrl->TurnOn(); + fx3->StartStream(inputbuffer, QUEUE_SIZE); submit_thread = std::thread( @@ -203,8 +226,8 @@ bool RadioHandlerClass::Stop() submit_thread.join(); DbgPrintf("submit_thread join1\n"); - hardware->FX3producerOff(); //FX3 stop the producer } + hardware->FX3producerOff(); //FX3 stop the producer return true; } @@ -247,6 +270,11 @@ int RadioHandlerClass::UpdateIFGain(int idx) return 0; } +int RadioHandlerClass::UpdateTunerBW(int bwHz) +{ + return hardware->UpdateTunerBW(bwHz); +} + int RadioHandlerClass::GetRFAttSteps(const float **steps) { return hardware->getRFSteps(steps); diff --git a/Core/RadioHandler.h b/Core/RadioHandler.h index b44f8151..e50c073e 100644 --- a/Core/RadioHandler.h +++ b/Core/RadioHandler.h @@ -30,7 +30,7 @@ class RadioHandlerClass { public: RadioHandlerClass(); virtual ~RadioHandlerClass(); - bool Init(fx3class* Fx3, void (*callback)(void* context, const float*, uint32_t), r2iqControlClass *r2iqCntrl = nullptr, void* context = nullptr); + bool Init(fx3class* Fx3, void (*callback)(void* context, const float*, uint32_t), r2iqControlClass *r2iqCntrlIn = nullptr, void* context = nullptr); bool Start(int srate_idx); bool Stop(); bool Close(); @@ -41,6 +41,7 @@ class RadioHandlerClass { int GetIFGainSteps(const float **steps); int UpdateIFGain(int attIdx); + int UpdateTunerBW(int bwHz); bool UpdatemodeRF(rf_mode mode); rf_mode GetmodeRF(){return (rf_mode)modeRF;} @@ -52,6 +53,8 @@ class RadioHandlerClass { bool GetRand () {return randout;} uint16_t GetFirmware() { return firmware; } + int SetSampleRate(int sr); + int GetSampleRate(); uint32_t getSampleRate() { return adcrate; } bool UpdateSampleRate(uint32_t samplerate); @@ -145,6 +148,7 @@ class RadioHardware { virtual int getRFSteps(const float** steps ) { return 0; } virtual int getIFSteps(const float** steps ) { return 0; } virtual bool UpdateGainIF(int attIndex) { return false; } + virtual bool UpdateTunerBW(int bwHz) { return false; } bool FX3producerOn() { return Fx3->Control(STARTFX3); } bool FX3producerOff() { return Fx3->Control(STOPFX3); } @@ -170,6 +174,7 @@ class BBRF103Radio : public RadioHardware { uint64_t TuneLo(uint64_t freq) override; bool UpdateattRF(int attIndex) override; bool UpdateGainIF(int attIndex) override; + bool UpdateTunerBW(int bwHz) override; int getRFSteps(const float** steps ) override; int getIFSteps(const float** steps ) override; @@ -203,6 +208,7 @@ class RX888R2Radio : public RadioHardware { uint64_t TuneLo(uint64_t freq) override; bool UpdateattRF(int attIndex) override; bool UpdateGainIF(int attIndex) override; + bool UpdateTunerBW(int bwHz) override; int getRFSteps(const float** steps ) override; int getIFSteps(const float** steps ) override; diff --git a/Core/arch/linux/FX3handler.cpp b/Core/arch/linux/FX3handler.cpp index ca40e5ce..f772a2d9 100644 --- a/Core/arch/linux/FX3handler.cpp +++ b/Core/arch/linux/FX3handler.cpp @@ -2,6 +2,8 @@ #include "FX3handler.h" #include "usb_device.h" +#include +#include fx3class* CreateUsbHandler() { @@ -10,16 +12,20 @@ fx3class* CreateUsbHandler() fx3handler::fx3handler() { + readsize = 0; + fill = 0; } fx3handler::~fx3handler() { + StopStream(); + if(dev) + usb_device_close(dev); } bool fx3handler::Open(uint8_t* fw_data, uint32_t fw_size) { dev = usb_device_open(0, (const char*)fw_data, fw_size); - return dev != nullptr; } @@ -51,8 +57,10 @@ bool fx3handler::GetHardwareInfo(uint32_t* data) void fx3handler::StartStream(ringbuffer& input, int numofblock) { + fprintf(stderr,"fx3handler::StartStream()\n"); inputbuffer = &input; - auto readsize = input.getWriteCount() * sizeof(uint16_t); + readsize = input.getBlockSize() * sizeof(uint16_t); + fill = 0; stream = streaming_open_async(this->dev, readsize, numofblock, PacketRead, this); // Start background thread to poll the events @@ -73,20 +81,40 @@ void fx3handler::StartStream(ringbuffer& input, int numofblock) void fx3handler::StopStream() { + fprintf(stderr,"fx3handler::StopStream()\n"); + if(!run) + return; run = false; poll_thread.join(); - - streaming_stop(stream); - streaming_close(stream); + fprintf(stderr,"fx3handler::StopStream() thread joined\n"); + if(stream) + { + streaming_stop(stream); + fprintf(stderr,"fx3handler::StopStream() streaming_stop\n"); + streaming_close(stream); + fprintf(stderr,"fx3handler::StopStream() streaming_close\n"); + stream = nullptr; + } } void fx3handler::PacketRead(uint32_t data_size, uint8_t *data, void *context) { fx3handler *handler = (fx3handler*)context; - auto *ptr = handler->inputbuffer->getWritePtr(); - memcpy(ptr, data, data_size); - handler->inputbuffer->WriteDone(); + uint32_t written = 0; + while(written < data_size) + { + uint8_t *ptr = (uint8_t *)handler->inputbuffer->getWritePtr(); + int to_copy = std::min(int(data_size - written), handler->readsize - handler->fill); + memcpy(&ptr[handler->fill], &data[written], to_copy); + handler->fill += to_copy; + written += to_copy; + if(handler->fill >= handler->readsize) + { + handler->inputbuffer->WriteDone(); + handler->fill = 0; + } + } } bool fx3handler::ReadDebugTrace(uint8_t* pdata, uint8_t len) diff --git a/Core/arch/linux/FX3handler.h b/Core/arch/linux/FX3handler.h index df2eeae7..c65ab707 100644 --- a/Core/arch/linux/FX3handler.h +++ b/Core/arch/linux/FX3handler.h @@ -38,6 +38,8 @@ class fx3handler : public fx3class streaming_t *stream; ringbuffer *inputbuffer; bool run; + int readsize; + int fill; std::thread poll_thread; }; diff --git a/Core/arch/linux/streaming.c b/Core/arch/linux/streaming.c index 8839b420..adc24cec 100644 --- a/Core/arch/linux/streaming.c +++ b/Core/arch/linux/streaming.c @@ -73,7 +73,7 @@ typedef struct streaming { static const uint32_t DEFAULT_SAMPLE_RATE = 64000000; /* 64Msps */ static const uint32_t DEFAULT_FRAME_SIZE = (2 * 64000000 / 1000); /* ~ 1 ms */ static const uint32_t DEFAULT_NUM_FRAMES = 96; /* we should not exceed 120 ms in total! */ -const unsigned int BULK_XFER_TIMEOUT = 5000; // timeout (in ms) for each bulk transfer +const unsigned int BULK_XFER_TIMEOUT = 500; // timeout (in ms) for each bulk transfer streaming_t *streaming_open_sync(usb_device_t *usb_device) @@ -118,8 +118,9 @@ streaming_t *streaming_open_async(usb_device_t *usb_device, uint32_t frame_size, } /* frame size must be a multiple of max_packet_size * max_burst */ - uint32_t max_xfer_size = usb_device->bulk_in_max_packet_size * - usb_device->bulk_in_max_burst; + uint32_t max_xfer_size = usb_device->bulk_in_max_packet_size; + if(usb_device->bulk_in_max_burst) + max_xfer_size *= usb_device->bulk_in_max_burst; if ( !max_xfer_size ) { fprintf(stderr, "ERROR: maximum transfer size is 0. probably not connected at USB 3 port?!\n"); return ret_val; @@ -253,7 +254,8 @@ int streaming_stop(streaming_t *this) } return 0; } - + if (this->status == STREAMING_STATUS_FAILED) + return 0; this->status = STREAMING_STATUS_CANCELLED; /* cancel all the active transfers */ for (uint32_t i = 0; i < this->num_frames; ++i) { diff --git a/Core/arch/linux/usb_device.c b/Core/arch/linux/usb_device.c index 36b454d1..867bc5f0 100644 --- a/Core/arch/linux/usb_device.c +++ b/Core/arch/linux/usb_device.c @@ -72,9 +72,10 @@ static int n_usb_device_ids = sizeof(usb_device_ids) / sizeof(usb_device_ids[0]) int usb_device_count_devices() { + libusb_context *ctx = 0; int ret_val = -1; - int ret = libusb_init(0); + int ret = libusb_init(&ctx); if (ret < 0) { log_usb_error(ret, __func__, __FILE__, __LINE__); goto FAIL0; @@ -102,7 +103,7 @@ int usb_device_count_devices() ret_val = count; FAIL1: - libusb_exit(0); + libusb_exit(ctx); FAIL0: return ret_val; } @@ -110,6 +111,7 @@ int usb_device_count_devices() int usb_device_get_device_list(struct usb_device_info **usb_device_infos) { + libusb_context *ctx = 0; const int MAX_STRING_BYTES = 256; int ret_val = -1; @@ -119,7 +121,7 @@ int usb_device_get_device_list(struct usb_device_info **usb_device_infos) goto FAIL0; } - int ret = libusb_init(0); + int ret = libusb_init(&ctx); if (ret < 0) { log_usb_error(ret, __func__, __FILE__, __LINE__); goto FAIL0; @@ -206,7 +208,7 @@ int usb_device_get_device_list(struct usb_device_info **usb_device_infos) FAIL2: libusb_free_device_list(list, 1); FAIL1: - libusb_exit(0); + libusb_exit(ctx); FAIL0: return ret_val; } @@ -237,6 +239,7 @@ usb_device_t *usb_device_open(int index, const char* image, { usb_device_t *ret_val = 0; libusb_context *ctx = 0; + int k = 0; int ret = libusb_init(&ctx); if (ret < 0) { @@ -261,23 +264,30 @@ usb_device_t *usb_device_open(int index, const char* image, /* rescan USB to get a new device handle */ libusb_close(dev_handle); - /* wait unitl firmware is ready */ - usleep(500 * 1000L); - needs_firmware = 0; - dev_handle = find_usb_device(index, ctx, &device, &needs_firmware); + + for (k = 0; k < 5; k++) { + /* wait unitl firmware is ready */ + usleep(500 * 1000L); + + dev_handle = find_usb_device(index, ctx, &device, &needs_firmware); + if (dev_handle == 0) { + continue; + } + if (needs_firmware) { + log_error("device is still in boot loader mode", __func__, __FILE__, __LINE__); + goto FAIL2; + } + break; + } if (dev_handle == 0) { goto FAIL1; } - if (needs_firmware) { - log_error("device is still in boot loader mode", __func__, __FILE__, __LINE__); - goto FAIL2; - } } int speed = libusb_get_device_speed(device); - if ( speed == LIBUSB_SPEED_LOW || speed == LIBUSB_SPEED_FULL || speed == LIBUSB_SPEED_HIGH ) { - log_error("USB 3.x SuperSpeed connection failed", __func__, __FILE__, __LINE__); + if ( speed == LIBUSB_SPEED_LOW || speed == LIBUSB_SPEED_FULL) { + log_error("USB 3.x SuperSpeed/HighSpeed connection failed", __func__, __FILE__, __LINE__); goto FAIL2; } @@ -325,12 +335,13 @@ usb_device_t *usb_device_open(int index, const char* image, this->bulk_in_max_burst = bulk_in_max_burst; ret_val = this; + fprintf(stderr,"usb_device_open %p\n",this); return ret_val; FAIL2: libusb_close(dev_handle); FAIL1: - libusb_exit(0); + libusb_exit(ctx); FAIL0: return ret_val; } @@ -338,16 +349,20 @@ usb_device_t *usb_device_open(int index, const char* image, void usb_device_close(usb_device_t *this) { + fprintf(stderr,"usb_device_close %p\n",this); libusb_close(this->dev_handle); + libusb_exit(this->context); free(this); - libusb_exit(0); return; } int usb_device_handle_events(usb_device_t *this) { - return libusb_handle_events_completed(this->context, &this->completed); + struct timeval tv; + tv.tv_sec = 2; + tv.tv_usec = 0; + return libusb_handle_events_timeout_completed(this->context, &tv, &this->completed); } int usb_device_control(usb_device_t *this, uint8_t request, uint16_t value, diff --git a/Core/arch/win32/FX3handler.cpp b/Core/arch/win32/FX3handler.cpp index fefb586a..720fc3af 100644 --- a/Core/arch/win32/FX3handler.cpp +++ b/Core/arch/win32/FX3handler.cpp @@ -82,7 +82,7 @@ bool fx3handler::Enumerate(unsigned char& idx, char* lbuf, uint8_t* fw_data, uin return true; } -bool fx3handler::Open(uint8_t* fw_data, uint32_t fw_size) { +bool fx3handler::Open(const uint8_t* fw_data, uint32_t fw_size) { bool r = false; if (!GetFx3DeviceStreamer()) { diff --git a/Core/arch/win32/FX3handler.h b/Core/arch/win32/FX3handler.h index 8d252b55..faaac507 100644 --- a/Core/arch/win32/FX3handler.h +++ b/Core/arch/win32/FX3handler.h @@ -34,7 +34,7 @@ class fx3handler : public fx3class fx3handler(); virtual ~fx3handler(void); - bool Open(uint8_t* fw_data, uint32_t fw_size); + bool Open(const uint8_t* fw_data, uint32_t fw_size); bool IsOn() { return Fx3IsOn; } bool Control(FX3Command command, uint8_t data); bool Control(FX3Command command, uint32_t data = 0); diff --git a/Core/config.h b/Core/config.h index 5eacba42..27d5ed99 100644 --- a/Core/config.h +++ b/Core/config.h @@ -9,7 +9,7 @@ #include #include -//#define _DEBUG // defined in VS configuration +#define NO_DEBUG // defined in VS configuration #ifdef __cplusplus inline void null_func(const char *format, ...) { } diff --git a/Core/conv_r2iq.cpp b/Core/conv_r2iq.cpp new file mode 100644 index 00000000..6f834cf1 --- /dev/null +++ b/Core/conv_r2iq.cpp @@ -0,0 +1,144 @@ +#include "license.txt" +/* +The ADC input real stream of 16 bit samples (at Fs = 64 Msps in the example) is converted to: +- 32 Msps float Fs/2 complex stream, or +- 16 Msps float Fs/2 complex stream, or +- 8 Msps float Fs/2 complex stream, or +- 4 Msps float Fs/2 complex stream, or +- 2 Msps float Fs/2 complex stream. +The decimation factor is selectable from HDSDR GUI sampling rate selector + +The name r2iq as Real 2 I+Q stream + +*/ + +#include "conv_r2iq.h" +#include "config.h" +#include "RadioHandler.h" + +#include +#include + +#include +#include +#include +#include + + + +conv_r2iq::conv_r2iq() : + r2iqControlClass() +{ + fprintf(stderr,"conv_r2iq created\n"); +} + +conv_r2iq::~conv_r2iq() +{ + if(IsOn()) + TurnOff(); + fprintf(stderr,"conv_r2iq deleted\n"); +} + + +float conv_r2iq::setFreqOffset(float offset) +{ + return 0.0; +} + +void conv_r2iq::TurnOn() +{ + r2iqControlClass::TurnOn(); + this->bufIdx = 0; + + fprintf(stderr,"conv_r2iq::TurnOn()\n"); + r2iq_thread = std::thread( + [this] () + { return this->r2iqThreadf(); }); +} + +void conv_r2iq::TurnOff(void) { + r2iqControlClass::TurnOff(); + + inputbuffer->Stop(); + outputbuffer->Stop(); + r2iq_thread.join(); +} + +void conv_r2iq::Init(float gain, ringbuffer *input, ringbuffer* obuffers) +{ + this->inputbuffer = input; // set to the global exported by main_loop + this->outputbuffer = obuffers; // set to the global exported by main_loop + + (void) gain; + + DbgPrintf((char *) "r2iqCntrl initialization\n"); +} + +#ifdef _WIN32 + // Windows, assumed MSVC + #include + #define cpuid(info, x) __cpuidex(info, x, 0) + #define DETECT_AVX +#elif defined(__x86_64__) + // GCC Intrinsics, x86 only + #include + #define cpuid(info, x) __cpuid_count(x, 0, info[0], info[1], info[2], info[3]) + #define DETECT_AVX +#elif defined(__arm__) + #define DETECT_NEON + #include + #include + static bool detect_neon() + { + unsigned long caps = getauxval(AT_HWCAP); + return (caps & HWCAP_NEON); + } +#else +#error Compiler does not identify an x86 or ARM core.. +#endif + +void * conv_r2iq::r2iqThreadf() +{ + DbgPrintf("Hardware Capability: all SIMD features (AVX, AVX2, AVX512) deactivated\n"); + return r2iqThreadf_def(); +} + +void * conv_r2iq::r2iqThreadf_def() +{ + + while (IsOn()) { + const int16_t *dataADC; // pointer to input data + float *pout; + + { + std::unique_lock lk(mutexR2iqControl); + dataADC = inputbuffer->getReadPtr(); + pout = outputbuffer->getWritePtr(); + + if (!IsOn()) + return 0; + } + + + // @todo: move the following int16_t conversion to (32-bit) float + // directly inside the following loop (for "k < fftPerBuf") + // just before the forward fft "fftwf_execute_dft_r2c" is called + // idea: this should improve cache/memory locality + if (!this->getRand()) // plain samples no ADC rand set + convert_float(dataADC, &pout[bufIdx], transferSamples); + else + convert_float(dataADC, &pout[bufIdx], transferSamples); + + inputbuffer->ReadDone(); + bufIdx += transferSamples * 2; + // decimate in frequency plus tuning + if(bufIdx >= outputbuffer->getBlockSize()) + { +// printf("ibs=%d, obs=%d\n",inputbuffer->getBlockSize(),outputbuffer->getBlockSize()); + outputbuffer->WriteDone(); + bufIdx = 0; + } + } // while(run) +// DbgPrintf((char *) "r2iqThreadf idx %d pthread_exit %u\n",(int)th->t, pthread_self()); + return 0; +} diff --git a/Core/conv_r2iq.h b/Core/conv_r2iq.h new file mode 100644 index 00000000..7be01e8d --- /dev/null +++ b/Core/conv_r2iq.h @@ -0,0 +1,53 @@ +#pragma once + +#include "r2iq.h" +#include "config.h" +#include +#include + +class conv_r2iq : public r2iqControlClass +{ +public: + conv_r2iq(); + virtual ~conv_r2iq(); + + float setFreqOffset(float offset); + + void Init(float gain, ringbuffer* buffers, ringbuffer* obuffers); + void TurnOn() override; + void TurnOff(void) override; + +protected: + + template void convert_float(const int16_t *input, float* output, int size) + { + for(int m = 0; m < size; m++) + { + int16_t val; + if (rand && (input[m] & 1)) + { + val = input[m] ^ (-2); + } + else + { + val = input[m]; + } + output[m*2] = float(val) * (1.0f/32768.0f); + output[m*2+1]=0; + } + } + +private: + ringbuffer* inputbuffer; // pointer to input buffers + ringbuffer* outputbuffer; // pointer to ouput buffers + int bufIdx; // index to next buffer to be processed + + float GainScale; + + void *r2iqThreadf(); // thread function + + void * r2iqThreadf_def(); + std::mutex mutexR2iqControl; + std::thread r2iq_thread; +}; + diff --git a/Core/dsp/ringbuffer.h b/Core/dsp/ringbuffer.h index 97f172ba..5d4e56fc 100644 --- a/Core/dsp/ringbuffer.h +++ b/Core/dsp/ringbuffer.h @@ -5,7 +5,6 @@ #include const int default_count = 64; -const int spin_count = 100; #define ALIGN (8) class ringbufferbase { @@ -16,7 +15,8 @@ class ringbufferbase { write_index(0), emptyCount(0), fullCount(0), - writeCount(0) + writeCount(0), + readCount(0) { } @@ -26,6 +26,8 @@ class ringbufferbase { int getWriteCount() const { return writeCount; } + int getFillCount() const { return writeCount-readCount; } + void ReadDone() { std::unique_lock lk(mutex); @@ -38,6 +40,7 @@ class ringbufferbase { { read_index = (read_index + 1) % max_count; } + readCount++; } void WriteDone() @@ -68,39 +71,33 @@ class ringbufferbase { void WaitUntilNotEmpty() { - // if not empty - for (int i = 0; i < spin_count; i++) - { - if (read_index != write_index) - return; - } - - if (read_index == write_index) + if (read_index != write_index) + return; { std::unique_lock lk(mutex); - - emptyCount++; - nonemptyCV.wait(lk, [this] { - return read_index != write_index; - }); + if (read_index == write_index) + { + emptyCount++; + nonemptyCV.wait(lk, [this] { + return read_index != write_index; + }); + } } } void WaitUntilNotFull() { - for (int i = 0; i < spin_count; i++) - { - if ((write_index + 1) % max_count != read_index) - return; - } - - if ((write_index + 1) % max_count == read_index) + if ((write_index + 1) % max_count != read_index) + return; { std::unique_lock lk(mutex); - fullCount++; - nonfullCV.wait(lk, [this] { - return (write_index + 1) % max_count != read_index; - }); + if ((write_index + 1) % max_count == read_index) + { + fullCount++; + nonfullCV.wait(lk, [this] { + return (write_index + 1) % max_count != read_index; + }); + } } } @@ -108,13 +105,14 @@ class ringbufferbase { volatile int read_index; volatile int write_index; + std::mutex mutex; private: int emptyCount; int fullCount; int writeCount; + int readCount; - std::mutex mutex; std::condition_variable nonemptyCV; std::condition_variable nonfullCV; }; @@ -124,7 +122,8 @@ template class ringbuffer : public ringbufferbase { public: ringbuffer(int count = default_count) : - ringbufferbase(count) + ringbufferbase(count), + block_size(0) { buffers = new TPtr[max_count]; buffers[0] = nullptr; @@ -140,6 +139,7 @@ template class ringbuffer : public ringbufferbase { void setBlockSize(int size) { + std::unique_lock lk(mutex); if (block_size != size) { block_size = size; diff --git a/Core/fft_mt_r2iq.cpp b/Core/fft_mt_r2iq.cpp index 9bcf5803..f913909e 100644 --- a/Core/fft_mt_r2iq.cpp +++ b/Core/fft_mt_r2iq.cpp @@ -23,19 +23,6 @@ The name r2iq as Real 2 I+Q stream #include -r2iqControlClass::r2iqControlClass() -{ - r2iqOn = false; - randADC = false; - sideband = false; - mdecimation = 0; - mratio[0] = 1; // 1,2,4,8,16 - for (int i = 1; i < NDECIDX; i++) - { - mratio[i] = mratio[i - 1] * 2; - } -} - fft_mt_r2iq::fft_mt_r2iq() : r2iqControlClass(), filterHw(nullptr) @@ -109,10 +96,11 @@ float fft_mt_r2iq::setFreqOffset(float offset) } void fft_mt_r2iq::TurnOn() { - this->r2iqOn = true; + r2iqControlClass::TurnOn(); this->bufIdx = 0; this->lastThread = threadArgs[0]; + fprintf(stderr,"fft_mt_r2iq::TurnOn() %d threads\n",processor_count); for (unsigned t = 0; t < processor_count; t++) { r2iq_thread[t] = std::thread( [this] (void* arg) @@ -120,8 +108,8 @@ void fft_mt_r2iq::TurnOn() { } } -void fft_mt_r2iq::TurnOff(void) { - this->r2iqOn = false; +void fft_mt_r2iq::TurnOff() { + r2iqControlClass::TurnOff(); inputbuffer->Stop(); outputbuffer->Stop(); @@ -130,8 +118,6 @@ void fft_mt_r2iq::TurnOff(void) { } } -bool fft_mt_r2iq::IsOn(void) { return(this->r2iqOn); } - void fft_mt_r2iq::Init(float gain, ringbuffer *input, ringbuffer* obuffers) { this->inputbuffer = input; // set to the global exported by main_loop diff --git a/Core/fft_mt_r2iq.h b/Core/fft_mt_r2iq.h index 8aa6f766..a1bcca7a 100644 --- a/Core/fft_mt_r2iq.h +++ b/Core/fft_mt_r2iq.h @@ -22,9 +22,8 @@ class fft_mt_r2iq : public r2iqControlClass float setFreqOffset(float offset); void Init(float gain, ringbuffer* buffers, ringbuffer* obuffers); - void TurnOn(); - void TurnOff(void); - bool IsOn(void); + void TurnOn() override; + void TurnOff() override; protected: diff --git a/Core/fft_mt_r2iq_impl.hpp b/Core/fft_mt_r2iq_impl.hpp index 7d9662b1..dde33677 100644 --- a/Core/fft_mt_r2iq_impl.hpp +++ b/Core/fft_mt_r2iq_impl.hpp @@ -10,7 +10,7 @@ fftwf_complex* pout = nullptr; int decimate_count = 0; - while (r2iqOn) { + while (IsOn()) { const int16_t *dataADC; // pointer to input data const int16_t *endloop; // pointer to end data to be copied to beginning @@ -20,7 +20,7 @@ std::unique_lock lk(mutexR2iqControl); dataADC = inputbuffer->getReadPtr(); - if (!r2iqOn) + if (!IsOn()) return 0; this->bufIdx = (this->bufIdx + 1) % QUEUE_SIZE; diff --git a/Core/r2iq.h b/Core/r2iq.h index 7c5bb87a..253e7408 100644 --- a/Core/r2iq.h +++ b/Core/r2iq.h @@ -15,7 +15,20 @@ struct r2iqThreadArg; class r2iqControlClass { public: - r2iqControlClass(); + r2iqControlClass() + { + r2iqOn = false; + randADC = false; + sideband = false; + mdecimation = 0; + mratio[0] = 1; // 1,2,4,8,16 + for (int i = 1; i < NDECIDX; i++) + { + mratio[i] = mratio[i - 1] * 2; + } + } + + virtual ~r2iqControlClass() {} int getRatio() {return mratio [mdecimation];} @@ -39,10 +52,10 @@ class r2iqControlClass { int mdecimation ; // selected decimation ratio // 64 Msps: 0 => 32Msps, 1=> 16Msps, 2 = 8Msps, 3 = 4Msps, 4 = 2Msps // 128 Msps: 0 => 64Msps, 1 => 32Msps, 2=> 16Msps, 3 = 8Msps, 4 = 4Msps, 5 = 2Msps - bool r2iqOn; // r2iq on flag int mratio [NDECIDX]; // ratio private: + bool r2iqOn; // r2iq on flag bool randADC; // randomized ADC output bool sideband; }; diff --git a/Core/radio/BBRF103Radio.cpp b/Core/radio/BBRF103Radio.cpp index 6fdabbe8..62f0fb43 100644 --- a/Core/radio/BBRF103Radio.cpp +++ b/Core/radio/BBRF103Radio.cpp @@ -142,4 +142,9 @@ bool BBRF103Radio::UpdateGainIF(int attIndex) // this is in VHF mode return Fx3->SetArgument(R82XX_VGA, (uint16_t)attIndex); } -} \ No newline at end of file +} + +bool BBRF103Radio::UpdateTunerBW(int bwHz) +{ + return Fx3->SetArgument(R82XX_BANDWIDTH, bwHz/1000); +} diff --git a/Core/radio/RX888R2Radio.cpp b/Core/radio/RX888R2Radio.cpp index d619626d..f45a8200 100644 --- a/Core/radio/RX888R2Radio.cpp +++ b/Core/radio/RX888R2Radio.cpp @@ -175,4 +175,9 @@ bool RX888R2Radio::UpdateGainIF(int gain_index) // this is in VHF mode return Fx3->SetArgument(R82XX_VGA, (uint16_t)gain_index); } -} \ No newline at end of file +} + +bool RX888R2Radio::UpdateTunerBW(int bwHz) +{ + return Fx3->SetArgument(R82XX_BANDWIDTH, bwHz/1000); +} diff --git a/Interface.h b/Interface.h index db100d0b..f830fb8c 100644 --- a/Interface.h +++ b/Interface.h @@ -130,6 +130,9 @@ enum ArgumentList { // Set R8xx harmonic // value: 0/1 R82XX_HARMONIC = 4, + // Set R8xx bandwidth + //wValue = BW in kHz + R82XX_BANDWIDTH = 5, // Set DAT-31 Att // Value: 0-63 diff --git a/SDDC_FX3/StartStopApplication.c b/SDDC_FX3/StartStopApplication.c index 8cb88f4b..9fa0f068 100644 --- a/SDDC_FX3/StartStopApplication.c +++ b/SDDC_FX3/StartStopApplication.c @@ -95,10 +95,28 @@ void StartApplication ( void ) { CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg)); epCfg.enable = CyTrue; epCfg.epType = CY_U3P_USB_EP_BULK; - epCfg.burstLen = ENDPOINT_BURST_LENGTH; + epCfg.burstLen = (usbSpeed == CY_U3P_SUPER_SPEED ? ENDPOINT_BURST_LENGTH : 1); epCfg.streams = 0; - epCfg.pcktSize = ENDPOINT_BURST_SIZE; epCfg.isoPkts = 1; + /* Determine max packet size based on USB speed */ + switch (usbSpeed) + { + case CY_U3P_FULL_SPEED: + epCfg.pcktSize = 64; + break; + + case CY_U3P_HIGH_SPEED: + epCfg.pcktSize = 512; + break; + + case CY_U3P_SUPER_SPEED: + epCfg.pcktSize = 1024; + break; + + default: + epCfg.pcktSize = 1024; + break; + } glDMACount= 0; /* Consumer endpoint configuration */ diff --git a/SDDC_FX3/USBhandler.c b/SDDC_FX3/USBhandler.c index 072a250c..9d8075ab 100644 --- a/SDDC_FX3/USBhandler.c +++ b/SDDC_FX3/USBhandler.c @@ -66,6 +66,7 @@ extern CyU3PQueue EventAvailable; // Used for threads communications uint32_t Qevent __attribute__ ((aligned (32))); extern char ConsoleInBuffer[32]; // Buffer for user Console Input extern uint32_t ConsoleInIndex; // Index into ConsoleIn buffer +uint32_t bw = 8*1000*1000; /* Trace function */ void @@ -134,9 +135,8 @@ void r820_initialize(uint32_t freq) tuner.cfg = &tuner_config; - uint32_t bw; r82xx_init(&tuner); - r82xx_set_bandwidth(&tuner, 8*1000*1000, 0, &bw, 1); + r82xx_set_bandwidth(&tuner, bw, 0, &bw, 1); return; } @@ -392,6 +392,12 @@ CyFxSlFifoApplnUSBSetupCB ( case R82XX_HARMONIC: // todo break; + case R82XX_BANDWIDTH: + { + bw = wValue*1000; + r82xx_set_bandwidth(&tuner, bw, 0, &bw, 1); + } + break; case DAT31_ATT: switch(HWconfig) { @@ -493,7 +499,7 @@ CyFxSlFifoApplnUSBSetupCB ( CyU3PDeviceReset(CyFalse); break; - case TESTFX3: + case TESTFX3: glEp0Buffer[0] = HWconfig; glEp0Buffer[1] = (uint8_t) (FWconfig >> 8); glEp0Buffer[2] = (uint8_t) FWconfig; @@ -505,7 +511,7 @@ CyFxSlFifoApplnUSBSetupCB ( break; - case READINFODEBUG: + case READINFODEBUG: { if (wValue >0) { diff --git a/SDDC_FX3/driver/tuner_r82xx.c b/SDDC_FX3/driver/tuner_r82xx.c index 0f9544c8..1cdabf0f 100644 --- a/SDDC_FX3/driver/tuner_r82xx.c +++ b/SDDC_FX3/driver/tuner_r82xx.c @@ -2010,9 +2010,9 @@ int r82xx_set_freq64(struct r82xx_priv *priv, uint64_t freq) priv->rf_freq = freq; if ( priv->sideband ^ harm_sideband_xor[priv->tuner_harmonic] ) - lo_freq = freq - priv->int_freq + priv->if_band_center_freq; + lo_freq = freq; else - lo_freq = freq + priv->int_freq + priv->if_band_center_freq; + lo_freq = freq; lo_freqHarm = (nth_harm) ? ( lo_freq / harm ) : lo_freq; diff --git a/SDDC_FX3/makefile b/SDDC_FX3/makefile index 38b09b3e..ecde0da0 100644 --- a/SDDC_FX3/makefile +++ b/SDDC_FX3/makefile @@ -26,7 +26,7 @@ include $(FX3FWROOT)/fw_build/fx3_fw/fx3_build_config.mak MODULE = SDDC_FX3 -all:$(MODULE).img +all:$(MODULE).img $(MODULE).h USER_CFLAGS = -I./radio -I./driver @@ -94,6 +94,7 @@ clean: rm -f ./$(MODULE).$(EXEEXT) rm -f $(ELF2IMG) rm -f ./$(MODULE).img + rm -f ./$(MODULE).h rm -f ./$(MODULE).map rm -f ./*.o rm -Rf ./obj @@ -107,4 +108,7 @@ $(ELF2IMG) : $(FX3FWROOT)/util/elf2img/elf2img.c $(MODULE).img: $(EXES) $(ELF2IMG) $(ELF2IMG) -i $< -o $@ -v +$(MODULE).h: $(EXES) $(ELF2IMG) + $(ELF2IMG) -i $< -o $@ -s -v + #[]# diff --git a/SDK/util/elf2img/elf2img.c b/SDK/util/elf2img/elf2img.c index 7c343b36..0eb68d97 100644 --- a/SDK/util/elf2img/elf2img.c +++ b/SDK/util/elf2img/elf2img.c @@ -91,6 +91,7 @@ int verbose = 0; unsigned int checksum = 0; unsigned int i2cDevSize = 0x4000; /* 64 KB by default. */ int loadIntVectors = 0; +int hfile = 0; int CheckElfHeader ( @@ -144,6 +145,29 @@ CheckElfHeader ( return (0); } +int WriteFile ( + FILE *fpImg, + void *buffer, + int length) +{ + if (hfile) + { + static int bytec = 0; + for (int k = 0; k < length; k++) + { + fprintf(fpImg, "0x%02x,", ((unsigned char *)buffer)[k]); + bytec++; + if ((bytec & 15) == 0) + fprintf(fpImg, "\n"); + } + return length; + } + else + { + return fwrite (buffer, 1, length, fpImg); + } +} + int ProcessProgHeader ( FILE *fpElf, @@ -222,8 +246,8 @@ ProcessProgHeader ( secStart, loadSz, validSz, offset, progHdr->flags); } - fwrite (&loadSz, 4, 1, fpImg); - fwrite (&secStart, 4, 1, fpImg); + WriteFile(fpImg, &loadSz, 4); + WriteFile(fpImg, &secStart, 4); secStart += (loadSz * 4); offset += (loadSz * 4); @@ -245,7 +269,8 @@ ProcessProgHeader ( checksum += buffer[i]; } - actual_wr = fwrite (&buffer, 4, writelen, fpImg); + actual_wr = WriteFile(fpImg, &buffer, 4 * writelen); + actual_wr /= 4; if (actual_wr < actual_rd) actual_rd = actual_wr; @@ -302,7 +327,7 @@ PrintUsageInfo ( { printf ("Usage:\n______\n"); printf ("%s -i -o [-i2cconf ]\n", progName); - printf (" [-imgtype ] [-vectorload ] [-v] [-h]\n"); + printf (" [-imgtype ] [-vectorload ] [-v] [-s] [-h]\n"); printf (" where\n"); printf (" is the input ELF file name with path\n"); printf (" is the output file name with path\n"); @@ -310,6 +335,7 @@ PrintUsageInfo ( printf (" is the image type byte in hexadecimal\n"); printf (" can be set to \"yes\" to force the interrupt vectors to be exported into the image\n"); printf (" -v is used for verbose logs during the conversion process\n"); + printf (" -s is used to produce C include file as an output file\n"); printf (" -h is used to print this help information\n"); } @@ -346,6 +372,8 @@ main ( } if (GetParameter (argc, argv, "-v", 0) == 0) verbose = 1; + if (GetParameter (argc, argv, "-s", 0) == 0) + hfile = 1; if (GetParameter (argc, argv, "-vectorload", &tmp) == 0) { if (strcmp (tmp, "yes") == 0) @@ -384,8 +412,12 @@ main ( if (fpOut == NULL) ERREXIT ("Failed to open output file %s\n", outFilename); + if (hfile) + fprintf(fpOut,"const unsigned char firmware_image[] = {\n"); /* Write the image header to the output file. */ - fprintf (fpOut, "CY%c%c", i2cConf, imgType); + char hdr[5]; + sprintf(&hdr[0],"CY%c%c", i2cConf, imgType); + WriteFile(fpOut,hdr,4); /* Read each program header and process. */ for (i = 0; i < elfHdr.phnum; i++) @@ -404,10 +436,12 @@ main ( entryAddr = elfHdr.entry; /* Write the trailer with the entry section and checksum to the img file. */ - fwrite (&val, 4, 1, fpOut); - fwrite (&entryAddr, 4, 1, fpOut); - fwrite (&checksum, 4, 1, fpOut); + WriteFile(fpOut,&val, 4); + WriteFile(fpOut,&entryAddr, 4); + WriteFile(fpOut,&checksum, 4); + if (hfile) + fprintf(fpOut,"\n};\n"); fclose (fpOut); fclose (fpIn); diff --git a/libsddc/CMakeLists.txt b/libsddc/CMakeLists.txt index 452f90e5..52af9cfc 100644 --- a/libsddc/CMakeLists.txt +++ b/libsddc/CMakeLists.txt @@ -4,12 +4,16 @@ if (MSVC) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) endif (MSVC) -include_directories("." "../Core") +include_directories("." "../Core" "../SDDC_FX3") add_library(sddc SHARED libsddc.cpp + ${CMAKE_SOURCE_DIR}/SDDC_FX3/SDDC_FX3.h ) +add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/SDDC_FX3/SDDC_FX3.h COMMAND make WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/SDDC_FX3) +set_property(TARGET sddc PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_SOURCE_DIR}/SDDC_FX3/SDDC_FX3.h) + if (MSVC) target_link_libraries(sddc PUBLIC Setupapi.lib) else() diff --git a/libsddc/libsddc.cpp b/libsddc/libsddc.cpp index 2509f4ab..8e4d0226 100644 --- a/libsddc/libsddc.cpp +++ b/libsddc/libsddc.cpp @@ -1,7 +1,12 @@ +#include #include "libsddc.h" #include "config.h" #include "r2iq.h" +#include "conv_r2iq.h" #include "RadioHandler.h" +#include "SDDC_FX3.h" + +#define DEBUG 0 struct sddc { @@ -11,6 +16,20 @@ struct sddc int samplerateidx; double freq; + const float *hfRFGains; + int hfRFGainsSize; + const float *vhfRFGains; + int vhfRFGainsSize; + + const float *hfIFGains; + int hfIFGainsSize; + const float *vhfIFGains; + int vhfIFGainsSize; + + float ifAttenuation; + float rfAttenuation; + float bw; + sddc_read_async_cb_t callback; void *callback_context; }; @@ -19,24 +38,11 @@ sddc_t *current_running; static void Callback(void* context, const float* data, uint32_t len) { + struct sddc *s = (struct sddc *) context; + if(s->callback) + s->callback(len, data, s->callback_context); } -class rawdata : public r2iqControlClass { - void Init(float gain, ringbuffer* buffers, ringbuffer* obuffers) override - { - idx = 0; - } - - void TurnOn() override - { - this->r2iqOn = true; - idx = 0; - } - -private: - int idx; -}; - int sddc_get_device_count() { return 1; @@ -74,32 +80,63 @@ sddc_t *sddc_open(int index, const char* imagefile) // open the firmware unsigned char* res_data; uint32_t res_size; + bool openOK = false; - FILE *fp = fopen(imagefile, "rb"); - if (fp == nullptr) + if(imagefile) { - return nullptr; - } - - fseek(fp, 0, SEEK_END); - res_size = ftell(fp); - res_data = (unsigned char*)malloc(res_size); - fseek(fp, 0, SEEK_SET); - if (fread(res_data, 1, res_size, fp) != res_size) - return nullptr; - - bool openOK = fx3->Open(res_data, res_size); + FILE *fp = fopen(imagefile, "rb"); + if (fp == nullptr) + { + return nullptr; + } + + fseek(fp, 0, SEEK_END); + res_size = ftell(fp); + res_data = (unsigned char*)malloc(res_size); + fseek(fp, 0, SEEK_SET); + if (fread(res_data, 1, res_size, fp) != res_size) + return nullptr; + + openOK = fx3->Open(res_data, res_size); + free(res_data); + }else + openOK = fx3->Open(firmware_image, sizeof(firmware_image)); if (!openOK) return nullptr; ret_val->handler = new RadioHandlerClass(); - - if (ret_val->handler->Init(fx3, Callback, new rawdata())) +#if DEBUG + fprintf(stderr,"new RadioHandlerClass()\n"); +#endif + if (ret_val->handler->Init(fx3, Callback, new conv_r2iq(), ret_val)) { ret_val->status = SDDC_STATUS_READY; ret_val->samplerateidx = 0; + ret_val->handler->UpdatemodeRF(VHFMODE); + ret_val->vhfRFGainsSize = ret_val->handler->GetRFAttSteps(&ret_val->vhfRFGains); + ret_val->vhfIFGainsSize = ret_val->handler->GetIFGainSteps(&ret_val->vhfIFGains); + ret_val->handler->UpdatemodeRF(HFMODE); + ret_val->hfRFGainsSize = ret_val->handler->GetRFAttSteps(&ret_val->hfRFGains); + ret_val->hfIFGainsSize = ret_val->handler->GetIFGainSteps(&ret_val->hfIFGains); + +#if DEBUG + fprintf(stderr,"hfRFGainsSize=%d\n",ret_val->hfRFGainsSize); + for(int k=0;khfRFGainsSize;k++) + fprintf(stderr,"hfRFGains[%d]=%f\n",k,ret_val->hfRFGains[k]); + fprintf(stderr,"hfIFGainsSize=%d\n",ret_val->hfIFGainsSize); + for(int k=0;khfIFGainsSize;k++) + fprintf(stderr,"hfIFGains[%d]=%f\n",k,ret_val->hfIFGains[k]); + + fprintf(stderr,"vhfRFGainsSize=%d\n",ret_val->hfIFGainsSize); + for(int k=0;kvhfRFGainsSize;k++) + fprintf(stderr,"vhfRFGains[%d]=%f\n",k,ret_val->vhfRFGains[k]); + fprintf(stderr,"vhfIFGainsSize=%d\n",ret_val->hfIFGainsSize); + for(int k=0;kvhfIFGainsSize;k++) + fprintf(stderr,"vhfIFGains[%d]=%f\n",k,ret_val->vhfIFGains[k]); +#endif } + return ret_val; } @@ -169,10 +206,15 @@ int sddc_set_rf_mode(sddc_t *t, enum RFMode rf_mode) switch (rf_mode) { case VHF_MODE: + if(t->handler->GetmodeRF() == VHFMODE) + break; t->handler->UpdatemodeRF(VHFMODE); break; case HF_MODE: + if(t->handler->GetmodeRF() == HFMODE) + break; t->handler->UpdatemodeRF(HFMODE); + break; default: return -1; } @@ -252,9 +294,9 @@ double sddc_get_hf_attenuation(sddc_t *t) return 0; } -int sddc_set_hf_attenuation(sddc_t *t, double attenuation) +int sddc_set_hf_attenuation(sddc_t *t, float attenuation) { - return 0; + return sddc_set_tuner_rf_attenuation(t,attenuation); } int sddc_get_hf_bias(sddc_t *t) @@ -277,13 +319,39 @@ double sddc_get_tuner_frequency(sddc_t *t) int sddc_set_tuner_frequency(sddc_t *t, double frequency) { + RFMode currentMode = sddc_get_rf_mode(t); + RFMode newMode = currentMode; + if(frequency > 4.57e6) + { + //frequency -= 4.57e6; + newMode = RFMode::VHF_MODE; + } + else + { + newMode = RFMode::HF_MODE; + } + if(currentMode != newMode) + { + sddc_set_rf_mode(t, newMode); + sddc_set_tuner_rf_attenuation(t, t->rfAttenuation); + sddc_set_tuner_if_attenuation(t, t->ifAttenuation); + } t->freq = t->handler->TuneLO((int64_t)frequency); - return 0; } -int sddc_get_tuner_rf_attenuations(sddc_t *t, const double *attenuations[]) +int sddc_get_tuner_rf_attenuations(sddc_t *t, const float **attenuations) { + if(sddc_get_rf_mode(t) == RFMode::VHF_MODE) + { + attenuations = &t->vhfRFGains; + return t->vhfRFGainsSize; + } + if(sddc_get_rf_mode(t) == RFMode::HF_MODE) + { + attenuations = &t->hfRFGains; + return t->hfRFGainsSize; + } return 0; } @@ -292,16 +360,39 @@ double sddc_get_tuner_rf_attenuation(sddc_t *t) return 0; } -int sddc_set_tuner_rf_attenuation(sddc_t *t, double attenuation) +int sddc_set_tuner_rf_attenuation(sddc_t *t, float attenuation) { - //TODO, convert double to index - t->handler->UpdateattRF(5); - return 0; + int k=1; + t->rfAttenuation = attenuation; + if(sddc_get_rf_mode(t) == RFMode::VHF_MODE) + { + for(k=1;kvhfRFGainsSize;k++) + if(t->vhfRFGains[k]>attenuation) + break; + t->handler->UpdateattRF(k - 1); + } + if(sddc_get_rf_mode(t) == RFMode::HF_MODE) + { + for(k=1;khfRFGainsSize;k++) + if(t->hfRFGains[k]>attenuation) + break; + t->handler->UpdateattRF(k - 1); + } + return k - 1; } -int sddc_get_tuner_if_attenuations(sddc_t *t, const double *attenuations[]) +int sddc_get_tuner_if_attenuations(sddc_t *t, const float **attenuations) { - // TODO + if(sddc_get_rf_mode(t) == RFMode::VHF_MODE) + { + attenuations = &t->vhfIFGains; + return t->vhfIFGainsSize; + } + if(sddc_get_rf_mode(t) == RFMode::HF_MODE) + { + attenuations = &t->hfIFGains; + return t->hfIFGainsSize; + } return 0; } @@ -310,11 +401,40 @@ double sddc_get_tuner_if_attenuation(sddc_t *t) return 0; } -int sddc_set_tuner_if_attenuation(sddc_t *t, double attenuation) +int sddc_set_tuner_if_attenuation(sddc_t *t, float attenuation) { - return 0; + int k=1; + t->ifAttenuation = attenuation; + if(sddc_get_rf_mode(t) == RFMode::VHF_MODE) + { + for(k=1;kvhfIFGainsSize;k++) + if(t->vhfIFGains[k]>attenuation) + break; + t->handler->UpdateIFGain(k - 1); + } + if(sddc_get_rf_mode(t) == RFMode::HF_MODE) + { + for(k=1;khfIFGainsSize;k++) + if(t->hfIFGains[k]>attenuation) + break; + t->handler->UpdateIFGain(k - 1); + } + return k - 1; +} + +float sddc_get_tuner_bw(sddc_t *t) +{ + return t->bw; } +int sddc_set_tuner_bw(sddc_t *t, float bw) +{ + if( (int)bw == 0) + bw = 8000000.0; + return t->handler->UpdateTunerBW(t->bw = bw); +} + + int sddc_get_vhf_bias(sddc_t *t) { return t->handler->GetBiasT_VHF(); @@ -328,27 +448,48 @@ int sddc_set_vhf_bias(sddc_t *t, int bias) double sddc_get_sample_rate(sddc_t *t) { - return 0; + return t->handler->GetSampleRate(); + switch(t->samplerateidx) + { + case 0: + return 2000000; + case 1: + return 4000000; + case 2: + return 8000000; + case 3: + return 16000000; + case 4: + return 32000000; + case 5: + return 64000000; + } + return -1; } int sddc_set_sample_rate(sddc_t *t, double sample_rate) { + t->handler->SetSampleRate(sample_rate); + return 4; switch((int64_t)sample_rate) { case 32000000: - t->samplerateidx = 0; + t->samplerateidx = 4; break; case 16000000: - t->samplerateidx = 1; + t->samplerateidx = 3; break; case 8000000: t->samplerateidx = 2; break; case 4000000: - t->samplerateidx = 3; + t->samplerateidx = 1; break; case 2000000: - t->samplerateidx = 4; + t->samplerateidx = 0; + break; + case 1000000: + t->samplerateidx = -1; break; default: return -1; @@ -369,7 +510,8 @@ int sddc_set_async_params(sddc_t *t, uint32_t frame_size, int sddc_start_streaming(sddc_t *t) { current_running = t; - t->handler->Start(t->samplerateidx); +// t->handler->Start(t->samplerateidx); + t->handler->Start(4); return 0; } diff --git a/libsddc/libsddc.h b/libsddc/libsddc.h index 3f2454cb..e059cc80 100644 --- a/libsddc/libsddc.h +++ b/libsddc/libsddc.h @@ -113,7 +113,7 @@ int sddc_set_adc_random(sddc_t *t, int random); /* HF block functions */ double sddc_get_hf_attenuation(sddc_t *t); -int sddc_set_hf_attenuation(sddc_t *t, double attenuation); +int sddc_set_hf_attenuation(sddc_t *t, float attenuation); int sddc_get_hf_bias(sddc_t *t); @@ -125,17 +125,21 @@ double sddc_get_tuner_frequency(sddc_t *t); int sddc_set_tuner_frequency(sddc_t *t, double frequency); -int sddc_get_tuner_rf_attenuations(sddc_t *t, const double *attenuations[]); +int sddc_get_tuner_rf_attenuations(sddc_t *t, const float **attenuations); double sddc_get_tuner_rf_attenuation(sddc_t *t); -int sddc_set_tuner_rf_attenuation(sddc_t *t, double attenuation); +int sddc_set_tuner_rf_attenuation(sddc_t *t, float attenuation); -int sddc_get_tuner_if_attenuations(sddc_t *t, const double *attenuations[]); +int sddc_get_tuner_if_attenuations(sddc_t *t, const float **attenuations); double sddc_get_tuner_if_attenuation(sddc_t *t); -int sddc_set_tuner_if_attenuation(sddc_t *t, double attenuation); +int sddc_set_tuner_if_attenuation(sddc_t *t, float attenuation); + +float sddc_get_tuner_bw(sddc_t *t); + +int sddc_set_tuner_bw(sddc_t *t, float bw); int sddc_get_vhf_bias(sddc_t *t); @@ -143,7 +147,7 @@ int sddc_set_vhf_bias(sddc_t *t, int bias); /* streaming functions */ -typedef void (*sddc_read_async_cb_t)(uint32_t data_size, uint8_t *data, +typedef void (*sddc_read_async_cb_t)(uint32_t data_size, const float* data, void *context); double sddc_get_sample_rate(sddc_t *t); diff --git a/libsddc/sddc_stream_test.c b/libsddc/sddc_stream_test.c index 042edecb..55c099b6 100644 --- a/libsddc/sddc_stream_test.c +++ b/libsddc/sddc_stream_test.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "libsddc.h" #include "wavewrite.h" @@ -93,13 +94,13 @@ clock_gettime(int X, struct timeval* tv) #endif -static void count_bytes_callback(uint32_t data_size, uint8_t *data, +static void count_bytes_callback(uint32_t data_size, const float *data, void *context); static unsigned long long received_samples = 0; static unsigned long long total_samples = 0; static int num_callbacks; -static int16_t *sampleData = 0; +static float *sampleData = 0; static int runtime = 3000; static struct timespec clk_start, clk_end; static int stop_reception = 0; @@ -118,6 +119,10 @@ int main(int argc, char **argv) } char *imagefile = argv[1]; const char *outfilename = 0; + double rf_attenuation = 0;//maximum + double if_attenuation = 35;//maximum + int ret = 0; + double sample_rate = 0.0; sscanf(argv[2], "%lf", &sample_rate); if (3 < argc) @@ -148,6 +153,25 @@ int main(int argc, char **argv) goto DONE; } + if (sddc_set_rf_mode(sddc, HF_MODE) < 0) { + fprintf(stderr, "ERROR - sddc_set_rf_mode() failed\n"); + goto DONE; + } + + ret = sddc_set_tuner_rf_attenuation(sddc, rf_attenuation); + if (ret < 0) { + fprintf(stderr, "ERROR - sddc_set_tuner_rf_attenuation() failed\n"); + goto DONE; + } + fprintf(stderr, "sddc_set_tuner_rf_attenuation(%f)=%d\n",rf_attenuation,ret); + + ret = sddc_set_tuner_if_attenuation(sddc, if_attenuation); + if (ret < 0) { + fprintf(stderr, "ERROR - sddc_set_tuner_if_attenuation() failed\n"); + goto DONE; + } + fprintf(stderr, "sddc_set_tuner_if_attenuation(%f)=%d\n",if_attenuation,ret); + received_samples = 0; num_callbacks = 0; if (sddc_start_streaming(sddc) < 0) { @@ -159,13 +183,17 @@ int main(int argc, char **argv) total_samples = (unsigned long long)(runtime * sample_rate / 1000.0); if (outfilename) - sampleData = (int16_t*)malloc(total_samples * sizeof(int16_t)); + sampleData = malloc(total_samples * sizeof(sampleData[0])); /* todo: move this into a thread */ stop_reception = 0; clock_gettime(CLOCK_REALTIME, &clk_start); while (!stop_reception) + { sddc_handle_events(sddc); + sleep(1); + fprintf(stderr,"\rreceived = %lld ",received_samples); + } fprintf(stderr, "finished. now stop streaming ..\n"); if (sddc_stop_streaming(sddc) < 0) { @@ -174,7 +202,7 @@ int main(int argc, char **argv) } double dur = clk_diff(); - fprintf(stderr, "received=%llu 16-Bit samples in %d callbacks\n", received_samples, num_callbacks); + fprintf(stderr, "received=%llu complex samples in %d callbacks\n", received_samples, num_callbacks); fprintf(stderr, "run for %f sec\n", dur); fprintf(stderr, "approx. samplerate is %f kSamples/sec\n", received_samples / (1000.0*dur) ); @@ -182,7 +210,7 @@ int main(int argc, char **argv) FILE * f = fopen(outfilename, "wb"); if (f) { fprintf(stderr, "saving received real samples to file ..\n"); - waveWriteHeader( (unsigned)(0.5 + sample_rate), 0U /*frequency*/, 16 /*bitsPerSample*/, 1 /*numChannels*/, f); + waveWriteHeader( (unsigned)(0.5 + sample_rate), 0U /*frequency*/, 32 /*bitsPerSample*/, 1 /*numChannels*/, f); for ( unsigned long long off = 0; off + 65536 < received_samples; off += 65536 ) waveWriteSamples(f, sampleData + off, 65536, 0 /*needCleanData*/); waveFinalizeHeader(f); @@ -200,19 +228,22 @@ int main(int argc, char **argv) } static void count_bytes_callback(uint32_t data_size, - uint8_t *data, + const float *data, void *context) { if (stop_reception) return; ++num_callbacks; - unsigned N = data_size / sizeof(int16_t); - if ( received_samples + N < total_samples ) { +// fprintf(stderr, "\rcallback %d ", num_callbacks); + unsigned N = data_size * 2; + if ( received_samples + N < total_samples ) { +// printf("data size = %u\n",data_size); if (sampleData) - memcpy( sampleData+received_samples, data, data_size); + memcpy( sampleData+received_samples, data, data_size * sizeof(float) * 2); received_samples += N; } else { + received_samples += N; clock_gettime(CLOCK_REALTIME, &clk_end); stop_reception = 1; } diff --git a/libsddc/sddc_vhf_stream_test.c b/libsddc/sddc_vhf_stream_test.c index 4b8cda6a..6b25ab80 100644 --- a/libsddc/sddc_vhf_stream_test.c +++ b/libsddc/sddc_vhf_stream_test.c @@ -26,6 +26,7 @@ #include "libsddc.h" #include "wavewrite.h" +#include #if _WIN32 #include @@ -93,13 +94,13 @@ clock_gettime(int X, struct timeval* tv) #endif -static void count_bytes_callback(uint32_t data_size, uint8_t *data, +static void count_bytes_callback(uint32_t data_size, const float *data, void *context); static unsigned long long received_samples = 0; static unsigned long long total_samples = 0; static int num_callbacks; -static int16_t *sampleData = 0; +static float *sampleData = 0; static int runtime = 3000; static struct timespec clk_start, clk_end; static int stop_reception = 0; @@ -120,7 +121,7 @@ int main(int argc, char **argv) const char *outfilename = 0; double sample_rate = 0.0; - double vhf_frequency = 100e6; + double vhf_frequency = 108e6-4.572e6; double vhf_attenuation = 20; /* 20dB attenuation */ sscanf(argv[2], "%lf", &sample_rate); @@ -175,16 +176,20 @@ int main(int argc, char **argv) } fprintf(stderr, "started streaming .. for %d ms ..\n", runtime); - total_samples = (unsigned long long)(runtime * sample_rate / 1000.0); + total_samples = (unsigned long long)(runtime * sample_rate * 2.0 * 2.0 / 1000.0); if (outfilename) - sampleData = (int16_t*)malloc(total_samples * sizeof(int16_t)); + sampleData = malloc(total_samples * sizeof(float)); /* todo: move this into a thread */ stop_reception = 0; clock_gettime(CLOCK_REALTIME, &clk_start); while (!stop_reception) + { sddc_handle_events(sddc); + sleep(1); + fprintf(stderr,"\rreceived = %lld ",received_samples); + } fprintf(stderr, "finished. now stop streaming ..\n"); if (sddc_stop_streaming(sddc) < 0) { @@ -201,7 +206,7 @@ int main(int argc, char **argv) FILE * f = fopen(outfilename, "wb"); if (f) { fprintf(stderr, "saving received real samples to file ..\n"); - waveWriteHeader( (unsigned)(0.5 + sample_rate), 0U /*frequency*/, 16 /*bitsPerSample*/, 1 /*numChannels*/, f); + waveWriteHeader( (unsigned)(0.5 + sample_rate), 0U /*frequency*/, 32 /*bitsPerSample*/, 1 /*numChannels*/, f); for ( unsigned long long off = 0; off + 65536 < received_samples; off += 65536 ) waveWriteSamples(f, sampleData + off, 65536, 0 /*needCleanData*/); waveFinalizeHeader(f); @@ -219,16 +224,16 @@ int main(int argc, char **argv) } static void count_bytes_callback(uint32_t data_size, - uint8_t *data, + const float *data, void *context) { if (stop_reception) return; ++num_callbacks; - unsigned N = data_size / sizeof(int16_t); + unsigned N = data_size; if ( received_samples + N < total_samples ) { if (sampleData) - memcpy( sampleData+received_samples, data, data_size); + memcpy( sampleData+received_samples, data, data_size * sizeof(float)); received_samples += N; } else { diff --git a/libsddc/wavewrite.c b/libsddc/wavewrite.c index 0b3fb145..3660f5a8 100644 --- a/libsddc/wavewrite.c +++ b/libsddc/wavewrite.c @@ -181,6 +181,15 @@ int waveWriteSamples(FILE* f, void * vpData, size_t numSamples, int needCleanD /* TODO: convert back endianness */ } return (nw == numSamples) ? 0 : 1; + case 32: + /* TODO: endian conversion needed */ + nw = fwrite(vpData, sizeof(int32_t), numSamples, f); + waveDataSize += sizeof(int32_t) * numSamples; + if ( needCleanData ) + { + /* TODO: convert back endianness */ + } + return (nw == numSamples) ? 0 : 1; } } @@ -206,6 +215,15 @@ int waveWriteFrames(FILE* f, void * vpData, size_t numFrames, int needCleanDat /* TODO: convert back endianness */ } return (nw == numFrames) ? 0 : 1; + case 32: + /* TODO: endian conversion needed */ + nw = fwrite(vpData, waveHdr.f.nChannels * sizeof(int32_t), numFrames, f); + waveDataSize += waveHdr.f.nChannels * sizeof(int32_t) * numFrames; + if ( needCleanData ) + { + /* TODO: convert back endianness */ + } + return (nw == numFrames) ? 0 : 1; } } diff --git a/unittest/core_test.cpp b/unittest/core_test.cpp index 26b943d5..607d7f75 100644 --- a/unittest/core_test.cpp +++ b/unittest/core_test.cpp @@ -130,7 +130,6 @@ TEST_CASE(CoreFixture, BasicTest) REQUIRE_EQUAL(radio->GetBiasT_VHF(), true); delete radio; - delete usb; } TEST_CASE(CoreFixture, R2IQTest) @@ -157,7 +156,6 @@ TEST_CASE(CoreFixture, R2IQTest) } delete radio; - delete usb; } TEST_CASE(CoreFixture, TuneTest) @@ -180,5 +178,4 @@ TEST_CASE(CoreFixture, TuneTest) delete radio; - delete usb; }