removed broken SDDC source

pull/814/head
AlexandreRouma 2022-07-09 15:54:39 +02:00
rodzic dbedc0d352
commit d3e9ebef72
68 zmienionych plików z 0 dodań i 14347 usunięć

Wyświetl plik

@ -1,45 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(sddc_source)
if (MSVC)
# What the fuck?
file(GLOB SRC "src/*.cpp" "src/*.c" "src/libsddc/libsddc/*.c" "src/libsddc/libsddc/*.cpp" "src/libsddc/Core/*.c" "src/libsddc/Core/*.cpp" "src/libsddc/Core/radio/*.cpp" "src/libsddc/Core/pffft/*.c" "src/libsddc/Core/pffft/*.cpp" "src/libsddc/Core/arch/win32/*.c" "src/libsddc/Core/arch/win32/*.cpp" "src/libsddc/Core/arch/win32/CyAPI/*.cpp")
else (MSVC)
file(GLOB SRC "src/*.cpp" "src/*.c" "src/libsddc/libsddc/*.c" "src/libsddc/libsddc/*.cpp" "src/libsddc/Core/*.c" "src/libsddc/Core/*.cpp" "src/libsddc/Core/radio/*.cpp" "src/libsddc/Core/pffft/*.c" "src/libsddc/Core/pffft/*.cpp" "src/libsddc/Core/arch/linux/*.c" "src/libsddc/Core/arch/linux/*.cpp")
endif ()
add_library(sddc_source SHARED ${SRC})
target_link_libraries(sddc_source PRIVATE sdrpp_core)
set_target_properties(sddc_source PROPERTIES PREFIX "")
target_include_directories(sddc_source PRIVATE "src/" "src/libsddc/" "src/libsddc/Core/" "src/libsddc/Core/pffft/" "src/libsddc/libsddc/")
if (MSVC)
target_compile_options(sddc_source PRIVATE /O2 /Ob2 /std:c++17 /EHsc)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_compile_options(sddc_source PRIVATE -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup)
else ()
target_compile_options(sddc_source PRIVATE -O3 -std=c++17)
endif ()
if (MSVC)
# Lib path
target_link_directories(sddc_source PRIVATE "C:/Program Files/PothosSDR/lib/")
# Misc headers
target_include_directories(sddc_source PRIVATE "C:/Program Files/PothosSDR/include/libusb-1.0/")
target_link_libraries(sddc_source PRIVATE libusb-1.0)
target_link_libraries(sddc_source PRIVATE Setupapi.lib)
else (MSVC)
find_package(PkgConfig)
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
target_include_directories(sddc_source PRIVATE ${LIBUSB_INCLUDE_DIRS})
target_link_directories(sddc_source PRIVATE ${LIBUSB_LIBRARY_DIRS})
target_link_libraries(sddc_source PRIVATE ${LIBUSB_LIBRARIES})
endif ()
# Install directives
install(TARGETS sddc_source DESTINATION lib/sdrpp/plugins)

Wyświetl plik

@ -1,78 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(SDDC VERSION 1.0.1)
include(CTest)
### build options
# default build type: Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif(NOT CMAKE_BUILD_TYPE)
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE} " - Version: " ${VERSION} " / " ${LIBVER})
# allow disabling optimizations - for debug reasons
option(USE_SIMD_OPTIMIZATIONS "enable SIMD optimizations" ON)
# allow enabling address sanitizer - for debug reasons
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
option(USE_DEBUG_ASAN "use GCC's address sanitizer?" OFF)
endif()
if (USE_DEBUG_ASAN)
set(ASANLIB "asan")
else()
set(ASANLIB "")
endif()
if (MSVC)
set(CMAKE_CXX_FLAGS "-O2 /std:c++17 /EHsc /W3")
get_filename_component(SDKPATH ${CMAKE_LINKER} DIRECTORY)
find_program(LIBEXE lib HINTS ${SDKPATH} REQUIRED)
# External Project FFTW on Windows
if(${CMAKE_EXE_LINKER_FLAGS} MATCHES "X86")
SET(FFTW_URL "ftp://ftp.fftw.org/pub/fftw/fftw-3.3.5-dll32.zip")
SET(ARCH x86)
SET(HASH 29882a43033c9393479a4df52a2e9120589c06a2b724155b1a682747fa3e57d4)
else()
SET(FFTW_URL "ftp://ftp.fftw.org/pub/fftw/fftw-3.3.5-dll64.zip")
SET(ARCH x64)
SET(HASH cfd88dc0e8d7001115ea79e069a2c695d52c8947f5b4f3b7ac54a192756f439f)
endif()
include(ExternalProject)
ExternalProject_Add(
LIBFFTW
URL ${FFTW_URL}
URL_HASH SHA256=${HASH}
BUILD_IN_SOURCE TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ${LIBEXE} /def:./libfftw3f-3.def /MACHINE:${ARCH} /OUT:./fftw3f-3.lib
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(LIBFFTW SOURCE_DIR)
SET(LIBFFTW_INCLUDE_DIRS ${SOURCE_DIR})
SET(LIBFFTW_LIBRARY_DIRS ${SOURCE_DIR})
SET(LIBFFTW_LIBRARIES fftw3f-3)
add_subdirectory(ExtIO_sddc)
else()
if (USE_DEBUG_ASAN)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address")
set(CMAKE_CXX_FLAGS "-O0 -std=c++17 -Wall -Werror")
else()
set(CMAKE_CXX_FLAGS "-O3 -std=c++17 -Wall -Werror")
endif(USE_DEBUG_ASAN)
#add_compile_options(-Wall -Wextra -pedantic)
include(FindPkgConfig)
pkg_check_modules(LIBUSB REQUIRED libusb-1.0)
pkg_check_modules(LIBFFTW REQUIRED fftw3f)
endif (MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
add_subdirectory(Core)
add_subdirectory(libsddc)
add_subdirectory(unittest)

Wyświetl plik

@ -1,35 +0,0 @@
cmake_minimum_required(VERSION 3.13)
if (MSVC)
file(GLOB ARCH_SRC "arch/win32/*.cpp" "arch/win32/CyAPI/*.cpp")
else()
file(GLOB ARCH_SRC "arch/linux/*.c" "arch/linux/*.cpp")
endif (MSVC)
file(GLOB SRC "*.cpp" "radio/*.cpp" "pffft/*.cpp" ${ARCH_SRC})
include_directories("." "CyAPI/" "pffft/")
if (MSVC)
set_source_files_properties(fft_mt_r2iq_avx.cpp PROPERTIES COMPILE_FLAGS /arch:AVX)
set_source_files_properties(fft_mt_r2iq_avx2.cpp PROPERTIES COMPILE_FLAGS /arch:AVX2)
set_source_files_properties(fft_mt_r2iq_avx512.cpp PROPERTIES COMPILE_FLAGS /arch:AVX512)
else()
set_source_files_properties(fft_mt_r2iq_avx.cpp PROPERTIES COMPILE_FLAGS -mavx)
set_source_files_properties(fft_mt_r2iq_avx2.cpp PROPERTIES COMPILE_FLAGS -mavx2)
set_source_files_properties(fft_mt_r2iq_avx512.cpp PROPERTIES COMPILE_FLAGS -mavx512f)
include_directories(${LIBUSB_INCLUDE_DIRS})
endif (MSVC)
include_directories(${LIBFFTW_INCLUDE_DIRS})
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
add_library(SDDC_CORE STATIC ${SRC})
set_target_properties(SDDC_CORE PROPERTIES POSITION_INDEPENDENT_CODE True)
target_compile_definitions(SDDC_CORE PUBLIC _CRT_SECURE_NO_WARNINGS)
if (NOT USE_SIMD_OPTIMIZATIONS)
target_compile_definitions(SDDC_CORE PRIVATE NO_SIMD_OPTIM)
endif()

Wyświetl plik

@ -1,37 +0,0 @@
#ifndef FX3CLASS_H
#define FX3CLASS_H
//
// FX3handler.cpp
// 2020 10 12 Oscar Steila ik1xpv
// loading arm code.img from resource by Howard Su and Hayati Ayguen
// This module was previous named:openFX3.cpp
// MIT License Copyright (c) 2016 Booya Corp.
// booyasdr@gmail.com, http://booyasdr.sf.net
// modified 2017 11 30 ik1xpv@gmail.com, http://www.steila.com/blog
//
#include <stdint.h>
#include <functional>
#include "../Interface.h"
#include "dsp/ringbuffer.h"
class fx3class
{
public:
virtual ~fx3class(void) {}
virtual bool Open(uint8_t* fw_data, uint32_t fw_size) = 0;
virtual bool Control(FX3Command command, uint8_t data = 0) = 0;
virtual bool Control(FX3Command command, uint32_t data) = 0;
virtual bool Control(FX3Command command, uint64_t data) = 0;
virtual bool SetArgument(uint16_t index, uint16_t value) = 0;
virtual bool GetHardwareInfo(uint32_t* data) = 0;
virtual bool ReadDebugTrace(uint8_t* pdata, uint8_t len) = 0;
virtual void StartStream(ringbuffer<int16_t>& input, int numofblock) = 0;
virtual void StopStream() = 0;
};
extern "C" fx3class* CreateUsbHandler();
#endif // FX3CLASS_H

Wyświetl plik

@ -1,35 +0,0 @@
#include "PScope_uti.h"
#include "license.txt"
int PScopeShot(const char * filename, const char * title2, const char * title1, short * data, float samplerate, unsigned int numsamples )
{
FILE *fp;
fp = fopen(filename, "w+");
fputs("Version,115\n", fp);
fprintf(fp, "Retainers,0,1,%d,1024,0,%f,1,1\n",numsamples,samplerate );
fputs("Placement,44,0,1,-1,-1,-1,-1,88,40,1116,879", fp);
fputs("WindMgr,7,2,0\n", fp);
fputs("Page,0,2\n", fp);
fputs("Col,3,1\n", fp);
fputs("Row,2,1\n", fp);
fputs("Row,3,146\n", fp);
fputs("Row,1,319\n", fp);
fputs("Col,2,1063\n", fp);
fputs("Row,4,1\n", fp);
fputs("Row,0,319\n", fp);
fputs("Page,1,2\n", fp);
fputs("Col,1,1\n", fp);
fputs("Row,1,1\n", fp);
fputs("Col,2,425\n", fp);
fputs("Row,4,1\n", fp);
fputs("Row,0,319\n", fp);
fprintf(fp,"DemoID,%s,%s,0\n", title1, title2 );
fprintf(fp,"RawData,1,%d,16,-32768,32767,%f,-3.276800e+04,3.276800e+04\n", numsamples,samplerate);
for (unsigned int n = 0; n < numsamples; n++ )
{
fprintf(fp, "%d\n", data[n]);
}
fputs("end\n", fp);
return fclose(fp);
}

Wyświetl plik

@ -1,9 +0,0 @@
#ifndef _PSCOPE_
#define _PSCOPE_
#include "license.txt"
#include <stdio.h>
#include <stdlib.h>
int PScopeShot(const char * filename, const char * title1, const char * title2, short * data, float samplerate, unsigned int numsamples );
#endif // _PSCOPE_

Wyświetl plik

@ -1,440 +0,0 @@
#include "license.txt"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "pf_mixer.h"
#include "RadioHandler.h"
#include "sddc_config.h"
#include "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "PScope_uti.h"
#include "../Interface.h"
#include <chrono>
using namespace std::chrono;
// transfer variables
unsigned long Failures = 0;
void RadioHandlerClass::OnDataPacket()
{
auto len = outputbuffer.getBlockSize() / 2 / sizeof(float);
while(run)
{
auto buf = outputbuffer.getReadPtr();
if (!run)
break;
if (fc != 0.0f)
{
std::unique_lock<std::mutex> lk(fc_mutex);
shift_limited_unroll_C_sse_inp_c((complexf*)buf, len, stateFineTune);
}
#ifdef _DEBUG //PScope buffer screenshot
if (saveADCsamplesflag == true)
{
saveADCsamplesflag = false; // do it once
unsigned int numsamples = transferSize / sizeof(int16_t);
float samplerate = (float) getSampleRate();
PScopeShot("ADCrealsamples.adc", "ExtIO_sddc.dll",
"ADCrealsamples.adc input real ADC 16 bit samples",
(short*)buf, samplerate, numsamples);
}
#endif
Callback(buf, len);
outputbuffer.ReadDone();
SamplesXIF += len;
}
}
RadioHandlerClass::RadioHandlerClass() :
DbgPrintFX3(nullptr),
GetConsoleIn(nullptr),
run(false),
pga(false),
dither(false),
randout(false),
biasT_HF(false),
biasT_VHF(false),
firmware(0),
modeRF(NOMODE),
adcrate(DEFAULT_ADC_FREQ),
fc(0.0f),
hardware(new DummyRadio(nullptr))
{
inputbuffer.setBlockSize(transferSamples);
stateFineTune = new shift_limited_unroll_C_sse_data_t();
}
RadioHandlerClass::~RadioHandlerClass()
{
delete stateFineTune;
}
const char *RadioHandlerClass::getName()
{
return hardware->getName();
}
bool RadioHandlerClass::Init(fx3class* Fx3, void (*callback)(const float*, uint32_t), r2iqControlClass *r2iqCntrl)
{
uint8_t rdata[4];
this->fx3 = Fx3;
this->Callback = callback;
if (r2iqCntrl == nullptr)
r2iqCntrl = new fft_mt_r2iq();
Fx3->GetHardwareInfo((uint32_t*)rdata);
radio = (RadioModel)rdata[0];
firmware = (rdata[1] << 8) + rdata[2];
delete hardware; // delete dummy instance
switch (radio)
{
case HF103:
hardware = new HF103Radio(Fx3);
break;
case BBRF103:
hardware = new BBRF103Radio(Fx3);
break;
case RX888:
hardware = new RX888Radio(Fx3);
break;
case RX888r2:
hardware = new RX888R2Radio(Fx3);
break;
case RX888r3:
hardware = new RX888R3Radio(Fx3);
break;
case RX999:
hardware = new RX999Radio(Fx3);
break;
case RXLUCY:
hardware = new RXLucyRadio(Fx3);
break;
default:
hardware = new DummyRadio(Fx3);
DbgPrintf("WARNING no SDR connected\n");
break;
}
adcrate = adcnominalfreq;
hardware->Initialize(adcnominalfreq);
DbgPrintf("%s | firmware %x\n", hardware->getName(), firmware);
this->r2iqCntrl = r2iqCntrl;
r2iqCntrl->Init(hardware->getGain(), &inputbuffer, &outputbuffer);
return true;
}
bool RadioHandlerClass::Start(int srate_idx)
{
Stop();
DbgPrintf("RadioHandlerClass::Start\n");
int decimate = 4 - srate_idx; // 5 IF bands
if (adcnominalfreq > N2_BANDSWITCH)
decimate = 5 - srate_idx; // 6 IF bands
if (decimate < 0)
{
decimate = 0;
DbgPrintf("WARNING decimate mismatch at srate_idx = %d\n", srate_idx);
}
run = true;
count = 0;
hardware->FX3producerOn(); // FX3 start the producer
outputbuffer.setBlockSize(EXT_BLOCKLEN * 2 * sizeof(float));
// 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(
[this]() {
this->OnDataPacket();
});
show_stats_thread = std::thread([this](void*) {
this->CaculateStats();
}, nullptr);
return true;
}
bool RadioHandlerClass::Stop()
{
std::unique_lock<std::mutex> lk(stop_mutex);
DbgPrintf("RadioHandlerClass::Stop %d\n", run);
if (run)
{
run = false; // now waits for threads
r2iqCntrl->TurnOff();
fx3->StopStream();
run = false; // now waits for threads
show_stats_thread.join(); //first to be joined
DbgPrintf("show_stats_thread join2\n");
submit_thread.join();
DbgPrintf("submit_thread join1\n");
hardware->FX3producerOff(); //FX3 stop the producer
}
return true;
}
bool RadioHandlerClass::Close()
{
delete hardware;
hardware = nullptr;
return true;
}
bool RadioHandlerClass::UpdateSampleRate(uint32_t samplefreq)
{
hardware->Initialize(samplefreq);
this->adcrate = samplefreq;
return 0;
}
// attenuator RF used in HF
int RadioHandlerClass::UpdateattRF(int att)
{
if (hardware->UpdateattRF(att))
{
return att;
}
return 0;
}
// attenuator RF used in HF
int RadioHandlerClass::UpdateIFGain(int idx)
{
if (hardware->UpdateGainIF(idx))
{
return idx;
}
return 0;
}
int RadioHandlerClass::GetRFAttSteps(const float **steps)
{
return hardware->getRFSteps(steps);
}
int RadioHandlerClass::GetIFGainSteps(const float **steps)
{
return hardware->getIFSteps(steps);
}
bool RadioHandlerClass::UpdatemodeRF(rf_mode mode)
{
if (modeRF != mode){
modeRF = mode;
DbgPrintf("Switch to mode: %d\n", modeRF);
hardware->UpdatemodeRF(mode);
if (mode == VHFMODE)
r2iqCntrl->setSideband(true);
else
r2iqCntrl->setSideband(false);
}
return true;
}
rf_mode RadioHandlerClass::PrepareLo(uint64_t lo)
{
return hardware->PrepareLo(lo);
}
uint64_t RadioHandlerClass::TuneLO(uint64_t wishedFreq)
{
uint64_t actLo;
actLo = hardware->TuneLo(wishedFreq);
// we need shift the samples
int64_t offset = wishedFreq - actLo;
DbgPrintf("Offset freq %" PRIi64 "\n", offset);
float fc = r2iqCntrl->setFreqOffset(offset / (getSampleRate() / 2.0f));
if (GetmodeRF() == VHFMODE)
fc = -fc; // sign change with sideband used
if (this->fc != fc)
{
std::unique_lock<std::mutex> lk(fc_mutex);
*stateFineTune = shift_limited_unroll_C_sse_init(fc, 0.0F);
this->fc = fc;
}
return wishedFreq;
}
bool RadioHandlerClass::UptDither(bool b)
{
dither = b;
if (dither)
hardware->FX3SetGPIO(DITH);
else
hardware->FX3UnsetGPIO(DITH);
return dither;
}
bool RadioHandlerClass::UptPga(bool b)
{
pga = b;
if (pga)
hardware->FX3SetGPIO(PGA_EN);
else
hardware->FX3UnsetGPIO(PGA_EN);
return pga;
}
bool RadioHandlerClass::UptRand(bool b)
{
randout = b;
if (randout)
hardware->FX3SetGPIO(RANDO);
else
hardware->FX3UnsetGPIO(RANDO);
r2iqCntrl->updateRand(randout);
return randout;
}
void RadioHandlerClass::CaculateStats()
{
high_resolution_clock::time_point EndingTime;
float kbRead = 0;
float kSReadIF = 0;
kbRead = 0; // zeros the kilobytes counter
kSReadIF = 0;
BytesXferred = 0;
SamplesXIF = 0;
uint8_t debdata[MAXLEN_D_USB];
memset(debdata, 0, MAXLEN_D_USB);
auto StartingTime = high_resolution_clock::now();
while (run) {
kbRead = float(BytesXferred) / 1000.0f;
kSReadIF = float(SamplesXIF) / 1000.0f;
EndingTime = high_resolution_clock::now();
duration<float,std::ratio<1,1>> timeElapsed(EndingTime-StartingTime);
mBps = (float)kbRead / timeElapsed.count() / 1000 / sizeof(int16_t);
mSpsIF = (float)kSReadIF / timeElapsed.count() / 1000;
BytesXferred = 0;
SamplesXIF = 0;
StartingTime = high_resolution_clock::now();
#ifdef _DEBUG
int nt = 10;
while (nt-- > 0)
{
std::this_thread::sleep_for(0.05s);
debdata[0] = 0; //clean buffer
if (GetConsoleIn != nullptr)
{
GetConsoleIn((char *)debdata, MAXLEN_D_USB);
if (debdata[0] !=0)
DbgPrintf("%s", (char*)debdata);
}
if (hardware->ReadDebugTrace(debdata, MAXLEN_D_USB) == true) // there are message from FX3 ?
{
int len = strlen((char*)debdata);
if (len > MAXLEN_D_USB - 1) len = MAXLEN_D_USB - 1;
debdata[len] = 0;
if ((len > 0)&&(DbgPrintFX3 != nullptr))
{
DbgPrintFX3("%s", (char*)debdata);
memset(debdata, 0, sizeof(debdata));
}
}
}
#else
std::this_thread::sleep_for(0.5s);
#endif
}
return;
}
void RadioHandlerClass::UpdBiasT_HF(bool flag)
{
biasT_HF = flag;
if (biasT_HF)
hardware->FX3SetGPIO(BIAS_HF);
else
hardware->FX3UnsetGPIO(BIAS_HF);
}
void RadioHandlerClass::UpdBiasT_VHF(bool flag)
{
biasT_VHF = flag;
if (biasT_VHF)
hardware->FX3SetGPIO(BIAS_VHF);
else
hardware->FX3UnsetGPIO(BIAS_VHF);
}
void RadioHandlerClass::uptLed(int led, bool on)
{
int pin;
switch(led)
{
case 0:
pin = LED_YELLOW;
break;
case 1:
pin = LED_RED;
break;
case 2:
pin = LED_BLUE;
break;
default:
return;
}
if (on)
hardware->FX3SetGPIO(pin);
else
hardware->FX3UnsetGPIO(pin);
}

Wyświetl plik

@ -1,341 +0,0 @@
#ifndef RADIOHANDLER_H
#define RADIOHANDLER_H
#include "license.txt"
#include "sddc_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "FX3Class.h"
#include "dsp/ringbuffer.h"
class RadioHardware;
class r2iqControlClass;
enum {
RESULT_OK,
RESULT_BIG_STEP,
RESULT_TOO_HIGH,
RESULT_TOO_LOW,
RESULT_NOT_POSSIBLE
};
struct shift_limited_unroll_C_sse_data_s;
typedef struct shift_limited_unroll_C_sse_data_s shift_limited_unroll_C_sse_data_t;
class RadioHandlerClass {
public:
RadioHandlerClass();
virtual ~RadioHandlerClass();
bool Init(fx3class* Fx3, void (*callback)(const float*, uint32_t), r2iqControlClass *r2iqCntrl = nullptr);
bool Start(int srate_idx);
bool Stop();
bool Close();
bool IsReady(){return true;}
int GetRFAttSteps(const float **steps);
int UpdateattRF(int attIdx);
int GetIFGainSteps(const float **steps);
int UpdateIFGain(int attIdx);
bool UpdatemodeRF(rf_mode mode);
rf_mode GetmodeRF(){return (rf_mode)modeRF;}
bool UptDither (bool b);
bool GetDither () {return dither;}
bool UptPga(bool b);
bool GetPga() { return pga;}
bool UptRand (bool b);
bool GetRand () {return randout;}
uint16_t GetFirmware() { return firmware; }
uint32_t getSampleRate() { return adcrate; }
bool UpdateSampleRate(uint32_t samplerate);
float getBps() const { return mBps; }
float getSpsIF() const {return mSpsIF; }
const char* getName();
RadioModel getModel() { return radio; }
bool GetBiasT_HF() { return biasT_HF; }
void UpdBiasT_HF(bool flag);
bool GetBiasT_VHF() { return biasT_VHF; }
void UpdBiasT_VHF(bool flag);
uint64_t TuneLO(uint64_t lo);
rf_mode PrepareLo(uint64_t lo);
void uptLed(int led, bool on);
void EnableDebug(void (*dbgprintFX3)(const char* fmt, ...), bool (*getconsolein)(char* buf, int maxlen))
{
this->DbgPrintFX3 = dbgprintFX3;
this->GetConsoleIn = getconsolein;
};
bool ReadDebugTrace(uint8_t* pdata, uint8_t len) { return fx3->ReadDebugTrace(pdata, len); }
private:
void AdcSamplesProcess();
void AbortXferLoop(int qidx);
void CaculateStats();
void OnDataPacket();
r2iqControlClass* r2iqCntrl;
void (*Callback)(const float *data, uint32_t length);
void (*DbgPrintFX3)(const char* fmt, ...);
bool (*GetConsoleIn)(char* buf, int maxlen);
bool run;
unsigned long count; // absolute index
bool pga;
bool dither;
bool randout;
bool biasT_HF;
bool biasT_VHF;
uint16_t firmware;
rf_mode modeRF;
RadioModel radio;
// transfer variables
ringbuffer<int16_t> inputbuffer;
ringbuffer<float> outputbuffer;
// threads
std::thread show_stats_thread;
std::thread submit_thread;
// stats
unsigned long BytesXferred;
unsigned long SamplesXIF;
float mBps;
float mSpsIF;
fx3class *fx3;
uint32_t adcrate;
std::mutex fc_mutex;
std::mutex stop_mutex;
float fc;
RadioHardware* hardware;
shift_limited_unroll_C_sse_data_t* stateFineTune;
};
extern unsigned long Failures;
class RadioHardware {
public:
RadioHardware(fx3class* fx3) : Fx3(fx3), gpios(0) {}
virtual ~RadioHardware();
virtual const char* getName() = 0;
virtual rf_mode PrepareLo(uint64_t freq) = 0;
virtual float getGain() { return BBRF103_GAINFACTOR; }
virtual void Initialize(uint32_t samplefreq) = 0;
virtual bool UpdatemodeRF(rf_mode mode) = 0;
virtual bool UpdateattRF(int attIndex) = 0;
virtual uint64_t TuneLo(uint64_t freq) = 0;
virtual int getRFSteps(const float** steps ) { return 0; }
virtual int getIFSteps(const float** steps ) { return 0; }
virtual bool UpdateGainIF(int attIndex) { return false; }
bool FX3producerOn() { return Fx3->Control(STARTFX3); }
bool FX3producerOff() { return Fx3->Control(STOPFX3); }
bool ReadDebugTrace(uint8_t* pdata, uint8_t len) { return Fx3->ReadDebugTrace(pdata, len); }
bool FX3SetGPIO(uint32_t mask);
bool FX3UnsetGPIO(uint32_t mask);
protected:
fx3class* Fx3;
uint32_t gpios;
};
class BBRF103Radio : public RadioHardware {
public:
BBRF103Radio(fx3class* fx3);
const char* getName() override { return "BBRF103"; }
float getGain() override { return BBRF103_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override;
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override;
bool UpdateattRF(int attIndex) override;
bool UpdateGainIF(int attIndex) override;
int getRFSteps(const float** steps ) override;
int getIFSteps(const float** steps ) override;
private:
static const int step_size = 29;
static const float steps[step_size];
static const float hfsteps[3];
static const int if_step_size = 16;
static const float if_steps[if_step_size];
uint32_t SampleRate;
};
class RX888Radio : public BBRF103Radio {
public:
RX888Radio(fx3class* fx3) : BBRF103Radio(fx3) {}
const char* getName() override { return "RX888"; }
float getGain() override { return RX888_GAINFACTOR; }
};
class RX888R2Radio : public RadioHardware {
public:
RX888R2Radio(fx3class* fx3);
const char* getName() override { return "RX888 mkII"; }
float getGain() override { return RX888mk2_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override;
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override;
bool UpdateattRF(int attIndex) override;
bool UpdateGainIF(int attIndex) override;
int getRFSteps(const float** steps ) override;
int getIFSteps(const float** steps ) override;
private:
static const int hf_rf_step_size = 64;
static const int hf_if_step_size = 127;
static const int vhf_if_step_size = 16;
static const int vhf_rf_step_size = 29;
float hf_rf_steps[hf_rf_step_size];
float hf_if_steps[hf_if_step_size];
static const float vhf_rf_steps[vhf_rf_step_size];
static const float vhf_if_steps[vhf_if_step_size];
uint32_t SampleRate;
};
class RX888R3Radio : public RadioHardware {
public:
RX888R3Radio(fx3class* fx3);
const char* getName() override { return "RX888 mkIII"; }
float getGain() override { return RX888mk2_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override;
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override;
bool UpdateattRF(int attIndex) override;
bool UpdateGainIF(int attIndex) override;
int getRFSteps(const float** steps ) override;
int getIFSteps(const float** steps ) override;
private:
static const int hf_rf_step_size = 64;
static const int hf_if_step_size = 127;
static const int vhf_if_step_size = 16;
static const int vhf_rf_step_size = 29;
float hf_rf_steps[hf_rf_step_size];
float hf_if_steps[hf_if_step_size];
static const float vhf_rf_steps[vhf_rf_step_size];
static const float vhf_if_steps[vhf_if_step_size];
uint32_t SampleRate;
};
class RX999Radio : public RadioHardware {
public:
RX999Radio(fx3class* fx3);
const char* getName() override { return "RX999"; }
float getGain() override { return RX888_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override;
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override;
bool UpdateattRF(int attIndex) override;
bool UpdateGainIF(int attIndex) override;
int getRFSteps(const float** steps ) override;
int getIFSteps(const float** steps ) override;
private:
static const int if_step_size = 127;
float if_steps[if_step_size];
uint32_t SampleRate;
};
class HF103Radio : public RadioHardware {
public:
HF103Radio(fx3class* fx3);
const char* getName() override { return "HF103"; }
float getGain() override { return HF103_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override {};
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override { return 0; }
bool UpdateattRF(int attIndex) override;
int getRFSteps(const float** steps ) override;
private:
static const int step_size = 64;
float steps[step_size];
};
class RXLucyRadio : public RadioHardware {
public:
RXLucyRadio(fx3class* fx3);
const char* getName() override { return "Lucy"; }
float getGain() override { return HF103_GAINFACTOR; }
rf_mode PrepareLo(uint64_t freq) override;
void Initialize(uint32_t samplefreq) override;
bool UpdatemodeRF(rf_mode mode) override;
uint64_t TuneLo(uint64_t freq) override ;
bool UpdateattRF(int attIndex) override;
bool UpdateGainIF(int attIndex) override;
int getRFSteps(const float** steps) override;
int getIFSteps(const float** steps) override;
private:
static const int step_size = 16;
float steps[step_size];
static const int if_step_size = 64;
float if_steps[if_step_size];
uint32_t SampleRate;
};
class DummyRadio : public RadioHardware {
public:
DummyRadio(fx3class* fx3) : RadioHardware(fx3) {}
const char* getName() override { return "Dummy"; }
rf_mode PrepareLo(uint64_t freq) override
{ return HFMODE;}
void Initialize(uint32_t samplefreq) override {}
bool UpdatemodeRF(rf_mode mode) override { return true; }
bool UpdateattRF(int attIndex) override { return true; }
uint64_t TuneLo(uint64_t freq) override {
if (freq < 64000000 /2)
return 0;
else
return freq;
}
};
#endif

Wyświetl plik

@ -1,95 +0,0 @@
#include <string.h>
#include "FX3handler.h"
#include "usb_device.h"
fx3class* CreateUsbHandler()
{
return new fx3handler();
}
fx3handler::fx3handler()
{
}
fx3handler::~fx3handler()
{
}
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;
}
bool fx3handler::Control(FX3Command command, uint8_t data)
{
return usb_device_control(this->dev, command, 0, 0, (uint8_t *) &data, sizeof(data), 0) == 0;
}
bool fx3handler::Control(FX3Command command, uint32_t data)
{
return usb_device_control(this->dev, command, 0, 0, (uint8_t *) &data, sizeof(data), 0) == 0;
}
bool fx3handler::Control(FX3Command command, uint64_t data)
{
return usb_device_control(this->dev, command, 0, 0, (uint8_t *) &data, sizeof(data), 0) == 0;
}
bool fx3handler::SetArgument(uint16_t index, uint16_t value)
{
uint8_t data = 0;
return usb_device_control(this->dev, SETARGFX3, value, index, (uint8_t *) &data, sizeof(data), 0) == 0;
}
bool fx3handler::GetHardwareInfo(uint32_t* data)
{
return usb_device_control(this->dev, TESTFX3, 0, 0, (uint8_t *) data, sizeof(*data), 1) == 0;
}
void fx3handler::StartStream(ringbuffer<int16_t>& input, int numofblock)
{
inputbuffer = &input;
auto readsize = input.getWriteCount() * sizeof(uint16_t);
stream = streaming_open_async(this->dev, readsize, numofblock, PacketRead, this);
// Start background thread to poll the events
run = true;
poll_thread = std::thread(
[this]() {
while(run)
{
usb_device_handle_events(this->dev);
}
});
if (stream)
{
streaming_start(stream);
}
}
void fx3handler::StopStream()
{
run = false;
poll_thread.join();
streaming_stop(stream);
streaming_close(stream);
}
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();
}
bool fx3handler::ReadDebugTrace(uint8_t* pdata, uint8_t len)
{
return true;
}

Wyświetl plik

@ -1,44 +0,0 @@
#ifndef FX3HANDLER_H
#define FX3HANDLER_H
#include "sddc_config.h"
#define VENDOR_ID (0x04B4)
#define STREAMER_ID (0x00F1)
#define BOOTLOADER_ID (0x00F3)
#include "FX3Class.h"
#include "usb_device.h"
#include "streaming.h"
#include "dsp/ringbuffer.h"
class fx3handler : public fx3class
{
public:
fx3handler();
virtual ~fx3handler(void);
bool Open(uint8_t* fw_data, uint32_t fw_size) override;
bool Control(FX3Command command, uint8_t data) override;
bool Control(FX3Command command, uint32_t data) override;
bool Control(FX3Command command, uint64_t data) override;
bool SetArgument(uint16_t index, uint16_t value) override;
bool GetHardwareInfo(uint32_t* data) override;
bool ReadDebugTrace(uint8_t* pdata, uint8_t len);
void StartStream(ringbuffer<int16_t>& input, int numofblock);
void StopStream();
private:
bool ReadUsb(uint8_t command, uint16_t value, uint16_t index, uint8_t *data, size_t size);
bool WriteUsb(uint8_t command, uint16_t value, uint16_t index, uint8_t *data, size_t size);
static void PacketRead(uint32_t data_size, uint8_t *data, void *context);
usb_device_t *dev;
streaming_t *stream;
ringbuffer<int16_t> *inputbuffer;
bool run;
std::thread poll_thread;
};
#endif // FX3HANDLER_H

Wyświetl plik

@ -1,815 +0,0 @@
/*
* Copyright © 2001 Stephen Williams (steve@icarus.com)
* Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net)
* Copyright © 2012 Pete Batard (pete@akeo.ie)
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include "libusb.h"
#include "ezusb.h"
//extern void logerror(const char *format, ...)
// __attribute__ ((format(printf, 1, 2)));
//
void logerror(const char *format, ...)
__attribute__ ((format (__printf__, 1, 2)));
void logerror(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
/*
* This file contains functions for uploading firmware into Cypress
* EZ-USB microcontrollers. These chips use control endpoint 0 and vendor
* specific commands to support writing into the on-chip SRAM. They also
* support writing into the CPUCS register, which is how we reset the
* processor after loading firmware (including the reset vector).
*
* These Cypress devices are 8-bit 8051 based microcontrollers with
* special support for USB I/O. They come in several packages, and
* some can be set up with external memory when device costs allow.
* Note that the design was originally by AnchorChips, so you may find
* references to that vendor (which was later merged into Cypress).
* The Cypress FX parts are largely compatible with the Anchorhip ones.
*/
int verbose = 1;
/*
* return true if [addr,addr+len] includes external RAM
* for Anchorchips EZ-USB or Cypress EZ-USB FX
*/
static bool fx_is_external(uint32_t addr, size_t len)
{
/* with 8KB RAM, 0x0000-0x1b3f can be written
* we can't tell if it's a 4KB device here
*/
if (addr <= 0x1b3f)
return ((addr + len) > 0x1b40);
/* there may be more RAM; unclear if we can write it.
* some bulk buffers may be unused, 0x1b3f-0x1f3f
* firmware can set ISODISAB for 2KB at 0x2000-0x27ff
*/
return true;
}
/*
* return true if [addr,addr+len] includes external RAM
* for Cypress EZ-USB FX2
*/
static bool fx2_is_external(uint32_t addr, size_t len)
{
/* 1st 8KB for data/code, 0x0000-0x1fff */
if (addr <= 0x1fff)
return ((addr + len) > 0x2000);
/* and 512 for data, 0xe000-0xe1ff */
else if (addr >= 0xe000 && addr <= 0xe1ff)
return ((addr + len) > 0xe200);
/* otherwise, it's certainly external */
else
return true;
}
/*
* return true if [addr,addr+len] includes external RAM
* for Cypress EZ-USB FX2LP
*/
static bool fx2lp_is_external(uint32_t addr, size_t len)
{
/* 1st 16KB for data/code, 0x0000-0x3fff */
if (addr <= 0x3fff)
return ((addr + len) > 0x4000);
/* and 512 for data, 0xe000-0xe1ff */
else if (addr >= 0xe000 && addr <= 0xe1ff)
return ((addr + len) > 0xe200);
/* otherwise, it's certainly external */
else
return true;
}
/*****************************************************************************/
/*
* These are the requests (bRequest) that the bootstrap loader is expected
* to recognize. The codes are reserved by Cypress, and these values match
* what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses.
* Cypress' "a3load" is nice because it supports both FX and FX2, although
* it doesn't have the EEPROM support (subset of "Vend_Ax").
*/
#define RW_INTERNAL 0xA0 /* hardware implements this one */
#define RW_MEMORY 0xA3
/*
* Issues the specified vendor-specific write request.
*/
static int ezusb_write(libusb_device_handle *device, const char *label,
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
{
int status;
if (verbose > 1)
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
opcode, addr & 0xFFFF, addr >> 16,
(unsigned char*)data, (uint16_t)len, 1000);
if (status != (signed)len) {
if (status < 0)
logerror("%s: %s\n", label, libusb_error_name(status));
else
logerror("%s ==> %d\n", label, status);
}
return (status < 0) ? -EIO : 0;
}
/*
* Issues the specified vendor-specific read request.
*/
static int ezusb_read(libusb_device_handle *device, const char *label,
uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
{
int status;
if (verbose > 1)
logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
opcode, addr & 0xFFFF, addr >> 16,
(unsigned char*)data, (uint16_t)len, 1000);
if (status != (signed)len) {
if (status < 0)
logerror("%s: %s\n", label, libusb_error_name(status));
else
logerror("%s ==> %d\n", label, status);
}
return (status < 0) ? -EIO : 0;
}
/*
* Modifies the CPUCS register to stop or reset the CPU.
* Returns false on error.
*/
static bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun)
{
int status;
uint8_t data = doRun ? 0x00 : 0x01;
if (verbose)
logerror("%s\n", data ? "stop CPU" : "reset CPU");
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
&data, 1, 1000);
if ((status != 1) &&
/* We may get an I/O error from libusb as the device disappears */
((!doRun) || (status != LIBUSB_ERROR_IO)))
{
const char *mesg = "can't modify CPUCS";
if (status < 0)
logerror("%s: %s\n", mesg, libusb_error_name(status));
else
logerror("%s\n", mesg);
return false;
} else
return true;
}
/*
* Send an FX3 jumpt to address command
* Returns false on error.
*/
static bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr)
{
int status;
if (verbose)
logerror("transfer execution to Program Entry at 0x%08x\n", addr);
status = libusb_control_transfer(device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
RW_INTERNAL, addr & 0xFFFF, addr >> 16,
NULL, 0, 1000);
/* We may get an I/O error from libusb as the device disappears */
if ((status != 0) && (status != LIBUSB_ERROR_IO))
{
const char *mesg = "failed to send jump command";
if (status < 0)
logerror("%s: %s\n", mesg, libusb_error_name(status));
else
logerror("%s\n", mesg);
return false;
} else
return true;
}
/*****************************************************************************/
/*
* Parse an Intel HEX image file and invoke the poke() function on the
* various segments to implement policies such as writing to RAM (with
* a one or two stage loader setup, depending on the firmware) or to
* EEPROM (two stages required).
*
* image - the hex image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_ihex(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len),
int (*poke) (void *context, uint32_t addr, bool external,
const unsigned char *data, size_t len))
{
unsigned char data[1023];
uint32_t data_addr = 0;
size_t data_len = 0;
int rc;
int first_line = 1;
bool external = false;
/* Read the input file as an IHEX file, and report the memory segments
* as we go. Each line holds a max of 16 bytes, but uploading is
* faster (and EEPROM space smaller) if we merge those lines into larger
* chunks. Most hex files keep memory segments together, which makes
* such merging all but free. (But it may still be worth sorting the
* hex files to make up for undesirable behavior from tools.)
*
* Note that EEPROM segments max out at 1023 bytes; the upload protocol
* allows segments of up to 64 KBytes (more than a loader could handle).
*/
for (;;) {
char buf[512], *cp;
char tmp, type;
size_t len;
unsigned idx, off;
cp = fgets(buf, sizeof(buf), image);
if (cp == NULL) {
logerror("EOF without EOF record!\n");
break;
}
/* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
if (buf[0] == '#')
continue;
if (buf[0] != ':') {
logerror("not an ihex record: %s", buf);
return -2;
}
/* ignore any newline */
cp = strchr(buf, '\n');
if (cp)
*cp = 0;
if (verbose >= 3)
logerror("** LINE: %s\n", buf);
/* Read the length field (up to 16 bytes) */
tmp = buf[3];
buf[3] = 0;
len = strtoul(buf+1, NULL, 16);
buf[3] = tmp;
/* Read the target offset (address up to 64KB) */
tmp = buf[7];
buf[7] = 0;
off = (unsigned int)strtoul(buf+3, NULL, 16);
buf[7] = tmp;
/* Initialize data_addr */
if (first_line) {
data_addr = off;
first_line = 0;
}
/* Read the record type */
tmp = buf[9];
buf[9] = 0;
type = (char)strtoul(buf+7, NULL, 16);
buf[9] = tmp;
/* If this is an EOF record, then make it so. */
if (type == 1) {
if (verbose >= 2)
logerror("EOF on hexfile\n");
break;
}
if (type != 0) {
logerror("unsupported record type: %u\n", type);
return -3;
}
if ((len * 2) + 11 > strlen(buf)) {
logerror("record too short?\n");
return -4;
}
/* FIXME check for _physically_ contiguous not just virtually
* e.g. on FX2 0x1f00-0x2100 includes both on-chip and external
* memory so it's not really contiguous */
/* flush the saved data if it's not contiguous,
* or when we've buffered as much as we can.
*/
if (data_len != 0
&& (off != (data_addr + data_len)
/* || !merge */
|| (data_len + len) > sizeof(data))) {
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
data_addr = off;
data_len = 0;
}
/* append to saved data, flush later */
for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
tmp = cp[2];
cp[2] = 0;
data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16);
cp[2] = tmp;
}
data_len += len;
}
/* flush any data remaining */
if (data_len != 0) {
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
}
return 0;
}
/*
* Parse a binary image file and write it as is to the target.
* Applies to Cypress BIX images for RAM or Cypress IIC images
* for EEPROM.
*
* image - the BIX image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_bin(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context,
uint32_t addr, bool external, const unsigned char *data, size_t len))
{
unsigned char data[4096];
uint32_t data_addr = 0;
size_t data_len = 0;
int rc;
bool external = false;
for (;;) {
data_len = fread(data, 1, 4096, image);
if (data_len == 0)
break;
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
data_addr += (uint32_t)data_len;
}
return feof(image)?0:-1;
}
/*
* Parse a Cypress IIC image file and invoke the poke() function on the
* various segments for writing to RAM
*
* image - the IIC image file
* context - for use by poke()
* is_external - if non-null, used to check which segments go into
* external memory (writable only by software loader)
* poke - called with each memory segment; errors indicated
* by returning negative values.
*
* Caller is responsible for halting CPU as needed, such as when
* overwriting a second stage loader.
*/
static int parse_iic(FILE *image, void *context,
bool (*is_external)(uint32_t addr, size_t len),
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
{
unsigned char data[4096];
uint32_t data_addr = 0;
size_t data_len = 0, read_len;
uint8_t block_header[4];
int rc;
bool external = false;
long file_size, initial_pos;
initial_pos = ftell(image);
if (initial_pos < 0)
return -1;
if (fseek(image, 0L, SEEK_END) != 0)
return -1;
file_size = ftell(image);
if (fseek(image, initial_pos, SEEK_SET) != 0)
return -1;
for (;;) {
/* Ignore the trailing reset IIC data (5 bytes) */
if (ftell(image) >= (file_size - 5))
break;
if (fread(&block_header, 1, sizeof(block_header), image) != 4) {
logerror("unable to read IIC block header\n");
return -1;
}
data_len = (block_header[0] << 8) + block_header[1];
data_addr = (block_header[2] << 8) + block_header[3];
if (data_len > sizeof(data)) {
/* If this is ever reported as an error, switch to using malloc/realloc */
logerror("IIC data block too small - please report this error to libusb.info\n");
return -1;
}
read_len = fread(data, 1, data_len, image);
if (read_len != data_len) {
logerror("read error\n");
return -1;
}
if (is_external)
external = is_external(data_addr, data_len);
rc = poke(context, data_addr, external, data, data_len);
if (rc < 0)
return -1;
}
return 0;
}
/* the parse call will be selected according to the image type */
static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
= { parse_ihex, parse_iic, parse_bin };
/*****************************************************************************/
/*
* For writing to RAM using a first (hardware) or second (software)
* stage loader and 0xA0 or 0xA3 vendor requests
*/
typedef enum {
_undef = 0,
internal_only, /* hardware first-stage loader */
skip_internal, /* first phase, second-stage loader */
skip_external /* second phase, second-stage loader */
} ram_mode;
struct ram_poke_context {
libusb_device_handle *device;
ram_mode mode;
size_t total, count;
};
#define RETRY_LIMIT 5
static int ram_poke(void *context, uint32_t addr, bool external,
const unsigned char *data, size_t len)
{
struct ram_poke_context *ctx = (struct ram_poke_context*)context;
int rc;
unsigned retry = 0;
switch (ctx->mode) {
case internal_only: /* CPU should be stopped */
if (external) {
logerror("can't write %u bytes external memory at 0x%08x\n",
(unsigned)len, addr);
return -EINVAL;
}
break;
case skip_internal: /* CPU must be running */
if (!external) {
if (verbose >= 2) {
logerror("SKIP on-chip RAM, %u bytes at 0x%08x\n",
(unsigned)len, addr);
}
return 0;
}
break;
case skip_external: /* CPU should be stopped */
if (external) {
if (verbose >= 2) {
logerror("SKIP external RAM, %u bytes at 0x%08x\n",
(unsigned)len, addr);
}
return 0;
}
break;
case _undef:
default:
logerror("bug\n");
return -EDOM;
}
ctx->total += len;
ctx->count++;
/* Retry this till we get a real error. Control messages are not
* NAKed (just dropped) so time out means is a real problem.
*/
while ((rc = ezusb_write(ctx->device,
external ? "write external" : "write on-chip",
external ? RW_MEMORY : RW_INTERNAL,
addr, data, len)) < 0
&& retry < RETRY_LIMIT) {
if (rc != LIBUSB_ERROR_TIMEOUT)
break;
retry += 1;
}
return rc;
}
/*
* Load a Cypress Image file into target RAM.
* See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info.
*/
int fx3_load_ram(libusb_device_handle *device, const char *image)
{
uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength;
uint32_t* dImageBuf;
const unsigned char *bBuf, *hBuf;
unsigned char blBuf[4], rBuf[4096];
int ret = 0;
int offset = 0;
hBuf = image;
offset += 4;
// check "CY" signature byte and format
if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) {
logerror("image doesn't have a CYpress signature\n");
ret = -3;
goto exit;
}
// Check bImageType
switch(hBuf[3]) {
case 0xB0:
if (verbose)
logerror("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable");
break;
case 0xB1:
logerror("security binary image is not currently supported\n");
ret = -3;
goto exit;
case 0xB2:
logerror("VID:PID image is not currently supported\n");
ret = -3;
goto exit;
default:
logerror("invalid image type 0x%02X\n", hBuf[3]);
ret = -3;
goto exit;
}
// Read the bootloader version
if (verbose) {
if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) {
logerror("Could not read bootloader version\n");
ret = -8;
goto exit;
}
logerror("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]);
}
dCheckSum = 0;
if (verbose)
logerror("writing image...\n");
while (1) {
dLength = *(uint32_t*)(image+offset); offset += sizeof(uint32_t);
dAddress = *(uint32_t*)(image+offset); offset += sizeof(uint32_t);
if (dLength == 0)
break; // done
// read sections
dImageBuf = (uint32_t*)(image+offset); offset += sizeof(uint32_t) * dLength;
for (i = 0; i < dLength; i++)
dCheckSum += dImageBuf[i];
dLength <<= 2; // convert to Byte length
bBuf = (unsigned char*) dImageBuf;
while (dLength > 0) {
dLen = 4096; // 4K max
if (dLen > dLength)
dLen = dLength;
if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) ||
(ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) {
logerror("R/W error\n");
ret = -5;
goto exit;
}
// Verify data: rBuf with bBuf
for (i = 0; i < dLen; i++) {
if (rBuf[i] != bBuf[i]) {
logerror("verify error");
ret = -6;
goto exit;
}
}
dLength -= dLen;
bBuf += dLen;
dAddress += dLen;
}
}
// read pre-computed checksum data
dExpectedCheckSum = *(uint32_t*)(image + offset); offset += sizeof(uint32_t);
if (dCheckSum != dExpectedCheckSum) {
logerror("checksum error\n");
ret = -7;
goto exit;
}
// transfer execution to Program Entry
if (!ezusb_fx3_jump(device, dAddress)) {
ret = -6;
}
exit:
return ret;
}
/*
* Load a firmware file into target RAM. device is the open libusb
* device, and the path is the name of the source file. Open the file,
* parse the bytes, and write them in one or two phases.
*
* If stage == 0, this uses the first stage loader, built into EZ-USB
* hardware but limited to writing on-chip memory or CPUCS. Everything
* is written during one stage, unless there's an error such as the image
* holding data that needs to be written to external memory.
*
* Otherwise, things are written in two stages. First the external
* memory is written, expecting a second stage loader to have already
* been loaded. Then file is re-parsed and on-chip memory is written.
*/
int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage)
{
FILE *image;
uint32_t cpucs_addr;
bool (*is_external)(uint32_t off, size_t len);
struct ram_poke_context ctx;
int status;
uint8_t iic_header[8] = { 0 };
int ret = 0;
if (fx_type == FX_TYPE_FX3)
return fx3_load_ram(device, path);
image = fopen(path, "rb");
if (image == NULL) {
logerror("%s: unable to open for input.\n", path);
return -2;
} else if (verbose > 1)
logerror("open firmware image %s for RAM upload\n", path);
if (img_type == IMG_TYPE_IIC) {
if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header))
|| (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2))
|| ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2))
|| ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) {
logerror("IIC image does not contain executable code - cannot load to RAM.\n");
ret = -1;
goto exit;
}
}
/* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
switch(fx_type) {
case FX_TYPE_FX2LP:
cpucs_addr = 0xe600;
is_external = fx2lp_is_external;
break;
case FX_TYPE_FX2:
cpucs_addr = 0xe600;
is_external = fx2_is_external;
break;
default:
cpucs_addr = 0x7f92;
is_external = fx_is_external;
break;
}
/* use only first stage loader? */
if (stage == 0) {
ctx.mode = internal_only;
/* if required, halt the CPU while we overwrite its code/data */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
{
ret = -1;
goto exit;
}
/* 2nd stage, first part? loader was already uploaded */
} else {
ctx.mode = skip_internal;
/* let CPU run; overwrite the 2nd stage loader later */
if (verbose)
logerror("2nd stage: write external memory\n");
}
/* scan the image, first (maybe only) time */
ctx.device = device;
ctx.total = ctx.count = 0;
status = parse[img_type](image, &ctx, is_external, ram_poke);
if (status < 0) {
logerror("unable to upload %s\n", path);
ret = status;
goto exit;
}
/* second part of 2nd stage: rescan */
// TODO: what should we do for non HEX images there?
if (stage) {
ctx.mode = skip_external;
/* if needed, halt the CPU while we overwrite the 1st stage loader */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
{
ret = -1;
goto exit;
}
/* at least write the interrupt vectors (at 0x0000) for reset! */
rewind(image);
if (verbose)
logerror("2nd stage: write on-chip memory\n");
status = parse_ihex(image, &ctx, is_external, ram_poke);
if (status < 0) {
logerror("unable to completely upload %s\n", path);
ret = status;
goto exit;
}
}
if (verbose && (ctx.count != 0)) {
logerror("... WROTE: %d bytes, %d segments, avg %d\n",
(int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count));
}
/* if required, reset the CPU so it runs what we just uploaded */
if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true))
ret = -1;
exit:
fclose(image);
return ret;
}

Wyświetl plik

@ -1,114 +0,0 @@
#ifndef ezusb_H
#define ezusb_H
/*
* Copyright © 2001 Stephen Williams (steve@icarus.com)
* Copyright © 2002 David Brownell (dbrownell@users.sourceforge.net)
* Copyright © 2013 Federico Manzan (f.manzan@gmail.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if defined(_MSC_VER)
#define __attribute__(x)
#if defined(_PREFAST_)
#pragma warning(disable:28193)
#endif
#endif
#include <stdbool.h>
#define FX_TYPE_UNDEFINED -1
#define FX_TYPE_AN21 0 /* Original AnchorChips parts */
#define FX_TYPE_FX1 1 /* Updated Cypress versions */
#define FX_TYPE_FX2 2 /* USB 2.0 versions */
#define FX_TYPE_FX2LP 3 /* Updated FX2 */
#define FX_TYPE_FX3 4 /* USB 3.0 versions */
#define FX_TYPE_MAX 5
#define FX_TYPE_NAMES { "an21", "fx", "fx2", "fx2lp", "fx3" }
#define IMG_TYPE_UNDEFINED -1
#define IMG_TYPE_HEX 0 /* Intel HEX */
#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */
#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */
#define IMG_TYPE_IMG 3 /* Cypress IMG format */
#define IMG_TYPE_MAX 4
#define IMG_TYPE_NAMES { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" }
#ifdef __cplusplus
extern "C" {
#endif
/*
* Automatically identified devices (VID, PID, type, designation).
* TODO: Could use some validation. Also where's the FX2?
*/
typedef struct {
uint16_t vid;
uint16_t pid;
int type;
const char* designation;
} fx_known_device;
#define FX_KNOWN_DEVICES { \
{ 0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)" },\
{ 0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)" },\
{ 0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)" },\
{ 0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)" },\
{ 0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)" },\
{ 0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)" },\
{ 0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)" },\
{ 0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)" },\
{ 0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)" },\
{ 0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1" },\
{ 0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)" }, \
{ 0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3" },\
}
/*
* This function uploads the firmware from the given file into RAM.
* Stage == 0 means this is a single stage load (or the first of
* two stages). Otherwise it's the second of two stages; the
* caller having preloaded the second stage loader.
*
* The target processor is reset at the end of this upload.
*/
extern int ezusb_load_ram(libusb_device_handle *device,
const char *path, int fx_type, int img_type, int stage);
extern int fx3_load_ram(libusb_device_handle *device, const char *image);
/*
* This function uploads the firmware from the given file into EEPROM.
* This uses the right CPUCS address to terminate the EEPROM load with
* a reset command where FX parts behave differently than FX2 ones.
* The configuration byte is as provided here (zero for an21xx parts)
* and the EEPROM type is set so that the microcontroller will boot
* from it.
*
* The caller must have preloaded a second stage loader that knows
* how to respond to the EEPROM write request.
*/
extern int ezusb_load_eeprom(libusb_device_handle *device,
const char *path, int fx_type, int img_type, int config);
/* Verbosity level (default 1). Can be increased or decreased with options v/q */
extern int verbose;
#ifdef __cplusplus
}
#endif
#endif

Wyświetl plik

@ -1,47 +0,0 @@
/*
* logging.c - logging functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <stdio.h>
#include <libusb.h>
#include "logging.h"
void log_error(const char *error_message, const char *function,
const char *file, int line) {
fprintf(stderr, "ERROR - %s in %s at %s:%d\n", error_message, function,
file, line);
return;
}
void log_usb_error(int usb_error_code, const char *function, const char *file,
int line) {
fprintf(stderr, "ERROR - USB error %s in %s at %s:%d\n",
libusb_error_name(usb_error_code), function, file, line);
return;
}
void log_usb_warning(int usb_error_code, const char *function, const char *file,
int line) {
fprintf(stderr, "WARNING - USB warning %s in %s at %s:%d\n",
libusb_error_name(usb_error_code), function, file, line);
return;
}

Wyświetl plik

@ -1,43 +0,0 @@
/*
* logging.h - logging functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __LOGGING_H
#define __LOGGING_H
#include <libusb.h>
#ifdef __cplusplus
extern "C" {
#endif
void log_error(const char *error_message, const char *function,
const char *file, int line);
void log_usb_error(int usb_error_code, const char *function, const char *file,
int line);
void log_usb_warning(int usb_error_code, const char *function, const char *file,
int line);
#ifdef __cplusplus
}
#endif
#endif /* __LOGGING_H */

Wyświetl plik

@ -1,387 +0,0 @@
/*
* streaming.c - streaming functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/* References:
* - librtlsdr.c: https://github.com/librtlsdr/librtlsdr/blob/development/src/librtlsdr.c
* - Ettus Research UHD libusb1_zero_copy.cpp: https://github.com/EttusResearch/uhd/blob/master/host/lib/transport/libusb1_zero_copy.cpp
*/
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdatomic.h>
#include "streaming.h"
#include "usb_device.h"
#include "usb_device_internals.h"
#include "logging.h"
typedef struct streaming streaming_t;
/* internal functions */
static void streaming_read_async_callback(struct libusb_transfer *transfer);
enum StreamingStatus {
STREAMING_STATUS_OFF,
STREAMING_STATUS_READY,
STREAMING_STATUS_STREAMING,
STREAMING_STATUS_CANCELLED,
STREAMING_STATUS_FAILED = 0xff
};
typedef struct streaming {
enum StreamingStatus status;
int random;
usb_device_t *usb_device;
uint32_t sample_rate;
uint32_t frame_size;
uint32_t num_frames;
sddc_read_async_cb_t callback;
void *callback_context;
uint8_t **frames;
struct libusb_transfer **transfers;
atomic_int active_transfers;
} streaming_t;
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
streaming_t *streaming_open_sync(usb_device_t *usb_device)
{
streaming_t *ret_val = 0;
/* we must have a bulk in device to transfer data from */
if (usb_device->bulk_in_endpoint_address == 0) {
log_error("no USB bulk in endpoint found", __func__, __FILE__, __LINE__);
return ret_val;
}
/* we are good here - create and initialize the streaming */
streaming_t *this = (streaming_t *) malloc(sizeof(streaming_t));
this->status = STREAMING_STATUS_READY;
this->random = 0;
this->usb_device = usb_device;
this->sample_rate = DEFAULT_SAMPLE_RATE;
this->frame_size = 0;
this->num_frames = 0;
this->callback = 0;
this->callback_context = 0;
this->frames = 0;
this->transfers = 0;
atomic_init(&this->active_transfers, 0);
ret_val = this;
return ret_val;
}
streaming_t *streaming_open_async(usb_device_t *usb_device, uint32_t frame_size,
uint32_t num_frames, sddc_read_async_cb_t callback,
void *callback_context)
{
streaming_t *ret_val = 0;
/* we must have a bulk in device to transfer data from */
if (usb_device->bulk_in_endpoint_address == 0) {
log_error("no USB bulk in endpoint found", __func__, __FILE__, __LINE__);
return ret_val;
}
/* 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;
if ( !max_xfer_size ) {
fprintf(stderr, "ERROR: maximum transfer size is 0. probably not connected at USB 3 port?!\n");
return ret_val;
}
num_frames = num_frames > 0 ? num_frames : DEFAULT_NUM_FRAMES;
frame_size = frame_size > 0 ? frame_size : DEFAULT_FRAME_SIZE;
frame_size = max_xfer_size * ((frame_size +max_xfer_size -1) / max_xfer_size); // round up
int iso_packets_per_frame = frame_size / usb_device->bulk_in_max_packet_size;
fprintf(stderr, "frame_size = %u, iso_packets_per_frame = %d\n", (unsigned)frame_size, iso_packets_per_frame);
if (frame_size % max_xfer_size != 0) {
fprintf(stderr, "frame size must be a multiple of %d\n", max_xfer_size);
return ret_val;
}
/* allocate frames for zerocopy USB bulk transfers */
uint8_t **frames = (uint8_t **) malloc(num_frames * sizeof(uint8_t *));
for (uint32_t i = 0; i < num_frames; ++i) {
frames[i] = libusb_dev_mem_alloc(usb_device->dev_handle, frame_size);
if (frames[i] == 0) {
log_error("libusb_dev_mem_alloc() failed", __func__, __FILE__, __LINE__);
for (uint32_t j = 0; j < i; j++) {
libusb_dev_mem_free(usb_device->dev_handle, frames[j], frame_size);
}
return ret_val;
}
}
/* we are good here - create and initialize the streaming */
streaming_t *this = (streaming_t *) malloc(sizeof(streaming_t));
this->status = STREAMING_STATUS_READY;
this->random = 0;
this->usb_device = usb_device;
this->sample_rate = DEFAULT_SAMPLE_RATE;
this->frame_size = frame_size > 0 ? frame_size : DEFAULT_FRAME_SIZE;
this->num_frames = num_frames > 0 ? num_frames : DEFAULT_NUM_FRAMES;
this->callback = callback;
this->callback_context = callback_context;
this->frames = frames;
/* populate the required libusb_transfer fields */
struct libusb_transfer **transfers = (struct libusb_transfer **) malloc(num_frames * sizeof(struct libusb_transfer *));
for (uint32_t i = 0; i < num_frames; ++i) {
transfers[i] = libusb_alloc_transfer(0); // iso_packets_per_frame ?
libusb_fill_bulk_transfer(transfers[i], usb_device->dev_handle,
usb_device->bulk_in_endpoint_address,
frames[i], frame_size, streaming_read_async_callback,
this, BULK_XFER_TIMEOUT);
}
this->transfers = transfers;
atomic_init(&this->active_transfers, 0);
ret_val = this;
return ret_val;
}
void streaming_close(streaming_t *this)
{
if (this->transfers) {
for (uint32_t i = 0; i < this->num_frames; ++i) {
libusb_free_transfer(this->transfers[i]);
}
free(this->transfers);
}
if (this->frames != 0) {
for (uint32_t i = 0; i < this->num_frames; ++i) {
libusb_dev_mem_free(this->usb_device->dev_handle, this->frames[i],
this->frame_size);
}
free(this->frames);
}
free(this);
return;
}
int streaming_set_sample_rate(streaming_t *this, uint32_t sample_rate)
{
/* no checks yet */
this->sample_rate = sample_rate;
return 0;
}
int streaming_set_random(streaming_t *this, int random)
{
this->random = random;
return 0;
}
int streaming_start(streaming_t *this)
{
if (this->status != STREAMING_STATUS_READY) {
fprintf(stderr, "ERROR - streaming_start() called with streaming status not READY: %d\n", this->status);
return -1;
}
/* if there is no callback, then streaming is synchronous - nothing to do */
if (this->callback == 0) {
this->status = STREAMING_STATUS_STREAMING;
return 0;
}
/* submit all the transfers */
atomic_init(&this->active_transfers, 0);
for (uint32_t i = 0; i < this->num_frames; ++i) {
int ret = libusb_submit_transfer(this->transfers[i]);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
this->status = STREAMING_STATUS_FAILED;
return -1;
}
atomic_fetch_add(&this->active_transfers, 1);
}
this->status = STREAMING_STATUS_STREAMING;
return 0;
}
int streaming_stop(streaming_t *this)
{
/* if there is no callback, then streaming is synchronous - nothing to do */
if (this->callback == 0) {
if (this->status == STREAMING_STATUS_STREAMING) {
this->status = STREAMING_STATUS_READY;
}
return 0;
}
this->status = STREAMING_STATUS_CANCELLED;
/* cancel all the active transfers */
for (uint32_t i = 0; i < this->num_frames; ++i) {
int ret = libusb_cancel_transfer(this->transfers[i]);
if (ret < 0) {
if (ret == LIBUSB_ERROR_NOT_FOUND) {
continue;
}
log_usb_error(ret, __func__, __FILE__, __LINE__);
this->status = STREAMING_STATUS_FAILED;
}
}
/* flush all the events */
struct timeval noblock = { 0, 0 };
int ret = libusb_handle_events_timeout_completed(this->usb_device->context, &noblock, 0);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
this->status = STREAMING_STATUS_FAILED;
}
return 0;
}
int streaming_reset_status(streaming_t *this)
{
switch (this->status) {
case STREAMING_STATUS_READY:
/* nothing to do here */
return 0;
case STREAMING_STATUS_CANCELLED:
case STREAMING_STATUS_FAILED:
if (this->active_transfers > 0) {
fprintf(stderr, "ERROR - streaming_reset_status() called with %d transfers still active\n",
this->active_transfers);
return -1;
}
break;
default:
fprintf(stderr, "ERROR - streaming_reset_status() called with invalid status: %d\n",
this->status);
return -1;
}
/* we are good here; reset the status */
this->status = STREAMING_STATUS_READY;
return 0;
}
int streaming_read_sync(streaming_t *this, uint8_t *data, int length, int *transferred)
{
int ret = libusb_bulk_transfer(this->usb_device->dev_handle,
this->usb_device->bulk_in_endpoint_address,
data, length, transferred, BULK_XFER_TIMEOUT);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
/* remove ADC randomization */
if (this->random) {
uint16_t *samples = (uint16_t *) data;
int n = *transferred / 2;
for (int i = 0; i < n; ++i) {
if (samples[i] & 1) {
samples[i] ^= 0xfffe;
}
}
}
return 0;
}
/* internal functions */
static void LIBUSB_CALL streaming_read_async_callback(struct libusb_transfer *transfer)
{
streaming_t *this = (streaming_t *) transfer->user_data;
int ret;
switch (transfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
/* success!!! */
if (this->status == STREAMING_STATUS_STREAMING) {
/* remove ADC randomization */
if (this->random) {
uint16_t *samples = (uint16_t *) transfer->buffer;
int n = transfer->actual_length / 2;
for (int i = 0; i < n; ++i) {
if (samples[i] & 1) {
samples[i] ^= 0xfffe;
}
}
}
this->callback(transfer->actual_length, transfer->buffer,
this->callback_context);
ret = libusb_submit_transfer(transfer);
if (ret == 0) {
return;
}
log_usb_error(ret, __func__, __FILE__, __LINE__);
}
break;
case LIBUSB_TRANSFER_CANCELLED:
/* librtlsdr does also ignore LIBUSB_TRANSFER_CANCELLED */
return;
case LIBUSB_TRANSFER_ERROR:
case LIBUSB_TRANSFER_TIMED_OUT:
case LIBUSB_TRANSFER_STALL:
case LIBUSB_TRANSFER_NO_DEVICE:
case LIBUSB_TRANSFER_OVERFLOW:
log_usb_error(transfer->status, __func__, __FILE__, __LINE__);
break;
}
this->status = STREAMING_STATUS_FAILED;
atomic_fetch_sub(&this->active_transfers, 1);
fprintf(stderr, "Cancelling\n");
/* cancel all the active transfers */
for (uint32_t i = 0; i < this->num_frames; ++i) {
int ret = libusb_cancel_transfer(transfer);
if (ret < 0) {
if (ret == LIBUSB_ERROR_NOT_FOUND) {
continue;
}
log_usb_error(ret, __func__, __FILE__, __LINE__);
}
}
return;
}

Wyświetl plik

@ -1,63 +0,0 @@
/*
* streaming.h - streaming functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __STREAMING_H
#define __STREAMING_H
#include "usb_device.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct streaming streaming_t;
typedef void (*sddc_read_async_cb_t)(uint32_t data_size, uint8_t *data,
void *context);
streaming_t *streaming_open_sync(usb_device_t *usb_device);
streaming_t *streaming_open_async(usb_device_t *usb_device, uint32_t frame_size,
uint32_t num_frames,
sddc_read_async_cb_t callback,
void *callback_context);
void streaming_close(streaming_t *that);
int streaming_set_sample_rate(streaming_t *that, uint32_t sample_rate);
int streaming_set_random(streaming_t *that, int random);
int streaming_start(streaming_t *that);
int streaming_stop(streaming_t *that);
int streaming_reset_status(streaming_t *that);
int streaming_read_sync(streaming_t *that, uint8_t *data, int length,
int *transferred);
#ifdef __cplusplus
}
#endif
#endif /* __STREAMING_H */

Wyświetl plik

@ -1,574 +0,0 @@
/*
* usb_device.c - Basic USB and USB control functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
/* References:
* - FX3 SDK for Linux Platforms (https://www.cypress.com/documentation/software-and-drivers/ez-usb-fx3-software-development-kit)
* example: cyusb_linux_1.0.5/src/download_fx3.cpp
*/
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libusb.h>
#include "usb_device.h"
#include "usb_device_internals.h"
#include "ezusb.h"
#include "logging.h"
typedef struct usb_device usb_device_t;
/* internal functions */
static libusb_device_handle *find_usb_device(int index, libusb_context *ctx,
libusb_device **device, int *needs_firmware);
static int load_image(libusb_device_handle *dev_handle,
const char *image, uint32_t size);
static int validate_image(const uint8_t *image, const size_t size);
static int transfer_image(const uint8_t *image,
libusb_device_handle *dev_handle);
static int list_endpoints(struct libusb_endpoint_descriptor endpoints[],
struct libusb_ss_endpoint_companion_descriptor ss_endpoints[],
libusb_device *device);
struct usb_device_id {
uint16_t vid;
uint16_t pid;
int needs_firmware;
};
static struct usb_device_id usb_device_ids[] = {
{ 0x04b4, 0x00f3, 1 }, /* Cypress / FX3 Boot-loader */
{ 0x04b4, 0x00f1, 0 } /* Cypress / FX3 Streamer Example */
};
static int n_usb_device_ids = sizeof(usb_device_ids) / sizeof(usb_device_ids[0]);
int usb_device_count_devices()
{
int ret_val = -1;
int ret = libusb_init(0);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL0;
}
libusb_device **list = 0;
ssize_t nusbdevices = libusb_get_device_list(0, &list);
if (nusbdevices < 0) {
log_usb_error(nusbdevices, __func__, __FILE__, __LINE__);
goto FAIL1;
}
int count = 0;
for (ssize_t i = 0; i < nusbdevices; ++i) {
libusb_device *dev = list[i];
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(dev, &desc);
for (int i = 0; i < n_usb_device_ids; ++i) {
if (desc.idVendor == usb_device_ids[i].vid &&
desc.idProduct == usb_device_ids[i].pid) {
count++;
}
}
}
libusb_free_device_list(list, 1);
ret_val = count;
FAIL1:
libusb_exit(0);
FAIL0:
return ret_val;
}
int usb_device_get_device_list(struct usb_device_info **usb_device_infos)
{
const int MAX_STRING_BYTES = 256;
int ret_val = -1;
if (usb_device_infos == 0) {
log_error("argument usb_device_infos is a null pointer", __func__, __FILE__, __LINE__);
goto FAIL0;
}
int ret = libusb_init(0);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL0;
}
libusb_device **list = 0;
ssize_t nusbdevices = libusb_get_device_list(0, &list);
if (nusbdevices < 0) {
log_usb_error(nusbdevices, __func__, __FILE__, __LINE__);
goto FAIL1;
}
struct usb_device_info *device_infos = (struct usb_device_info *) malloc((nusbdevices + 1) * sizeof(struct usb_device_info));
int count = 0;
for (ssize_t j = 0; j < nusbdevices; ++j) {
libusb_device *device = list[j];
struct libusb_device_descriptor desc;
ret = libusb_get_device_descriptor(device, &desc);
for (int i = 0; i < n_usb_device_ids; ++i) {
if (!(desc.idVendor == usb_device_ids[i].vid &&
desc.idProduct == usb_device_ids[i].pid)) {
continue;
}
libusb_device_handle *dev_handle = 0;
ret = libusb_open(device, &dev_handle);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL2;
}
device_infos[count].manufacturer = (unsigned char *) malloc(MAX_STRING_BYTES);
device_infos[count].manufacturer[0] = '\0';
if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iManufacturer,
device_infos[count].manufacturer, MAX_STRING_BYTES);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL3;
}
device_infos[count].manufacturer = (unsigned char *) realloc(device_infos[count].manufacturer, ret);
}
device_infos[count].product = (unsigned char *) malloc(MAX_STRING_BYTES);
device_infos[count].product[0] = '\0';
if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iProduct,
device_infos[count].product, MAX_STRING_BYTES);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL3;
}
device_infos[count].product = (unsigned char *) realloc(device_infos[count].product, ret);
}
device_infos[count].serial_number = (unsigned char *) malloc(MAX_STRING_BYTES);
device_infos[count].serial_number[0] = '\0';
if (desc.iSerialNumber) {
ret = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber,
device_infos[count].serial_number, MAX_STRING_BYTES);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL3;
}
device_infos[count].serial_number = (unsigned char *) realloc(device_infos[count].serial_number, ret);
}
ret = 0;
FAIL3:
libusb_close(dev_handle);
if (ret < 0) {
goto FAIL2;
}
count++;
}
}
device_infos[count].manufacturer = 0;
device_infos[count].product = 0;
device_infos[count].serial_number = 0;
*usb_device_infos = device_infos;
ret_val = count;
FAIL2:
libusb_free_device_list(list, 1);
FAIL1:
libusb_exit(0);
FAIL0:
return ret_val;
}
int usb_device_free_device_list(struct usb_device_info *usb_device_infos)
{
for (struct usb_device_info *udi = usb_device_infos;
udi->manufacturer || udi->product || udi->serial_number;
++udi) {
if (udi->manufacturer) {
free(udi->manufacturer);
}
if (udi->product) {
free(udi->product);
}
if (udi->serial_number) {
free(udi->serial_number);
}
}
free(usb_device_infos);
return 0;
}
usb_device_t *usb_device_open(int index, const char* image,
uint32_t size)
{
usb_device_t *ret_val = 0;
libusb_context *ctx = 0;
int ret = libusb_init(&ctx);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL0;
}
libusb_device *device;
int needs_firmware = 0;
libusb_device_handle *dev_handle = find_usb_device(index, ctx, &device, &needs_firmware);
if (dev_handle == 0) {
goto FAIL1;
}
if (needs_firmware) {
ret = load_image(dev_handle, image, size);
if (ret != 0) {
log_error("load_image() failed", __func__, __FILE__, __LINE__);
goto FAIL2;
}
/* 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);
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__);
goto FAIL2;
}
/* list endpoints */
struct libusb_endpoint_descriptor endpoints[MAX_ENDPOINTS];
struct libusb_ss_endpoint_companion_descriptor ss_endpoints[MAX_ENDPOINTS];
ret = list_endpoints(endpoints, ss_endpoints, device);
if (ret < 0) {
log_error("list_endpoints() failed", __func__, __FILE__, __LINE__);
goto FAIL2;
}
int nendpoints = ret;
uint8_t bulk_in_endpoint_address = 0;
uint16_t bulk_in_max_packet_size = 0;
uint8_t bulk_in_max_burst = 0;
for (int i = 0; i < nendpoints; ++i) {
if ((endpoints[i].bmAttributes & 0x03) == LIBUSB_TRANSFER_TYPE_BULK &&
(endpoints[i].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
bulk_in_endpoint_address = endpoints[i].bEndpointAddress;
bulk_in_max_packet_size = endpoints[i].wMaxPacketSize;
bulk_in_max_burst = ss_endpoints[i].bLength == 0 ? 0 :
ss_endpoints[i].bMaxBurst;
break;
}
}
if (bulk_in_endpoint_address == 0) {
fprintf(stderr, "ERROR - bulk in endpoint not found\n");
goto FAIL2;
}
/* we are good here - create and initialize the usb_device */
usb_device_t *this = (usb_device_t *) malloc(sizeof(usb_device_t));
this->dev = device;
this->dev_handle = dev_handle;
this->context = ctx;
this->completed = 0;
this->nendpoints = nendpoints;
memset(this->endpoints, 0, sizeof(this->endpoints));
for (int i = 0; i < nendpoints; ++i) {
this->endpoints[i] = endpoints[i];
this->ss_endpoints[i] = ss_endpoints[i];
}
this->bulk_in_endpoint_address = bulk_in_endpoint_address;
this->bulk_in_max_packet_size = bulk_in_max_packet_size;
this->bulk_in_max_burst = bulk_in_max_burst;
ret_val = this;
return ret_val;
FAIL2:
libusb_close(dev_handle);
FAIL1:
libusb_exit(0);
FAIL0:
return ret_val;
}
void usb_device_close(usb_device_t *this)
{
libusb_close(this->dev_handle);
free(this);
libusb_exit(0);
return;
}
int usb_device_handle_events(usb_device_t *this)
{
return libusb_handle_events_completed(this->context, &this->completed);
}
int usb_device_control(usb_device_t *this, uint8_t request, uint16_t value,
uint16_t index, uint8_t *data, uint16_t length, int read) {
const uint8_t bmWriteRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
const uint8_t bmReadRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
const unsigned int timeout = 5000; // timeout (in ms) for each command
int ret;
if (!read) {
ret = libusb_control_transfer(this->dev_handle, bmWriteRequestType,
request, value, index, data, length,
timeout);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
}
else
{
ret = libusb_control_transfer(this->dev_handle, bmReadRequestType,
request, value, index, data, length,
timeout);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
}
return 0;
}
/* internal functions */
static libusb_device_handle *find_usb_device(int index, libusb_context *ctx,
libusb_device **device, int *needs_firmware)
{
libusb_device_handle *ret_val = 0;
*device = 0;
*needs_firmware = 0;
libusb_device **list = 0;
ssize_t nusbdevices = libusb_get_device_list(ctx, &list);
if (nusbdevices < 0) {
log_usb_error(nusbdevices, __func__, __FILE__, __LINE__);
goto FAIL0;
}
int count = 0;
for (ssize_t j = 0; j < nusbdevices; ++j) {
libusb_device *dev = list[j];
struct libusb_device_descriptor desc;
libusb_get_device_descriptor(dev, &desc);
for (int i = 0; i < n_usb_device_ids; ++i) {
if (desc.idVendor == usb_device_ids[i].vid &&
desc.idProduct == usb_device_ids[i].pid) {
if (count == index) {
*device = dev;
*needs_firmware = usb_device_ids[i].needs_firmware;
}
count++;
}
}
}
if (*device == 0) {
fprintf(stderr, "ERROR - usb_device@%d not found\n", index);
goto FAIL1;
}
libusb_device_handle *dev_handle = 0;
int ret = libusb_open(*device, &dev_handle);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAIL1;
}
libusb_free_device_list(list, 1);
ret = libusb_kernel_driver_active(dev_handle, 0);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAILA;
}
if (ret == 1) {
fprintf(stderr, "ERROR - device busy\n");
goto FAILA;
}
ret = libusb_claim_interface(dev_handle, 0);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
goto FAILA;
}
ret_val = dev_handle;
return ret_val;
FAILA:
libusb_close(dev_handle);
return ret_val;
FAIL1:
libusb_free_device_list(list, 1);
FAIL0:
return ret_val;
}
int load_image(libusb_device_handle *dev_handle, const char *image, uint32_t image_size)
{
int ret_val = -1;
const int fx_type = FX_TYPE_FX3;
const int img_type = IMG_TYPE_IMG;
const int stage = 0;
verbose = 1;
ret_val = fx3_load_ram(dev_handle, image);
return ret_val;
}
static int transfer_image(const uint8_t *image,
libusb_device_handle *dev_handle)
{
const uint8_t bmRequestType = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE;
const uint8_t bRequest = 0xa0; // vendor command
const unsigned int timeout = 5000; // timeout (in ms) for each command
const size_t max_write_size = 2 * 1024; // max write size in bytes
// skip first word with 'CY' magic
uint32_t *current = (uint32_t *) image + 1;
while (1) {
uint32_t loadSz = *current++;
if (loadSz == 0) {
break;
}
uint32_t address = *current++;
unsigned char *data = (unsigned char *) current;
for (size_t nleft = loadSz * 4; nleft > 0; ) {
uint16_t wLength = nleft > max_write_size ? max_write_size : nleft;
int ret = libusb_control_transfer(dev_handle, bmRequestType, bRequest,
address & 0xffff, address >> 16,
data, wLength, timeout);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
if (!(ret == wLength)) {
fprintf(stderr, "ERROR - libusb_control_transfer() returned less bytes than expected - actual=%hu expected=%hu\n", ret, wLength);
return -1;
}
data += wLength;
nleft -= wLength;
}
current += loadSz;
}
uint32_t entryAddr = *current++;
uint32_t checksum __attribute__((unused)) = *current++;
sleep(1);
int ret = libusb_control_transfer(dev_handle, bmRequestType, bRequest,
entryAddr & 0xffff, entryAddr >> 16,
0, 0, timeout);
if (ret < 0) {
log_usb_warning(ret, __func__, __FILE__, __LINE__);
}
return 0;
}
static int list_endpoints(struct libusb_endpoint_descriptor endpoints[],
struct libusb_ss_endpoint_companion_descriptor ss_endpoints[],
libusb_device *device)
{
struct libusb_config_descriptor *config;
int ret = libusb_get_active_config_descriptor(device, &config);
if (ret < 0) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
int count = 0;
/* loop through the interfaces */
for (int intf = 0; intf < config->bNumInterfaces; ++intf) {
const struct libusb_interface *interface = &config->interface[intf];
for (int setng = 0; setng < interface->num_altsetting; ++setng) {
const struct libusb_interface_descriptor *setting = &interface->altsetting[setng];
for (int endp = 0; endp < setting->bNumEndpoints; ++endp) {
const struct libusb_endpoint_descriptor *endpoint = &setting->endpoint[endp];
if (count == MAX_ENDPOINTS) {
fprintf(stderr, "WARNING - found too many USB endpoints; returning only the first %d\n", MAX_ENDPOINTS);
return count;
}
endpoints[count] = *endpoint;
struct libusb_ss_endpoint_companion_descriptor *endpoint_ss_companion;
ret = libusb_get_ss_endpoint_companion_descriptor(0, endpoint,
&endpoint_ss_companion);
if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
log_usb_error(ret, __func__, __FILE__, __LINE__);
return -1;
}
if (ret == 0) {
ss_endpoints[count] = *endpoint_ss_companion;
} else {
ss_endpoints[count].bLength = 0;
}
libusb_free_ss_endpoint_companion_descriptor(endpoint_ss_companion);
count++;
}
}
}
return count;
}

Wyświetl plik

@ -1,60 +0,0 @@
/*
* usb_device.h - Basic USB and USB control functions
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __USB_DEVICE_H
#define __USB_DEVICE_H
#include <libusb.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct usb_device usb_device_t;
struct usb_device_info {
unsigned char *manufacturer;
unsigned char *product;
unsigned char *serial_number;
};
int usb_device_count_devices();
int usb_device_get_device_list(struct usb_device_info **usb_device_infos);
int usb_device_free_device_list(struct usb_device_info *usb_device_infos);
usb_device_t *usb_device_open(int index, const char* image,
uint32_t size);
int usb_device_handle_events(usb_device_t *t);
void usb_device_close(usb_device_t *t);
int usb_device_control(usb_device_t *t, uint8_t request, uint16_t value,
uint16_t index, uint8_t *data, uint16_t length, int read);
#ifdef __cplusplus
}
#endif
#endif /* __USB_DEVICE_H */

Wyświetl plik

@ -1,52 +0,0 @@
/*
* usb_device_internals.h - internal USB structures to be shared between
* usb_device and usb_streaming
*
* Copyright (C) 2020 by Franco Venturi
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __USB_DEVICE_INTERNALS_H
#define __USB_DEVICE_INTERNALS_H
#include "usb_device.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct usb_device {
libusb_device *dev;
libusb_device_handle *dev_handle;
libusb_context *context;
int completed;
int nendpoints;
#define MAX_ENDPOINTS (16)
struct libusb_endpoint_descriptor endpoints[MAX_ENDPOINTS];
struct libusb_ss_endpoint_companion_descriptor ss_endpoints[MAX_ENDPOINTS];
uint8_t bulk_in_endpoint_address;
uint16_t bulk_in_max_packet_size;
uint8_t bulk_in_max_burst;
} usb_device_t;
typedef struct usb_device usb_device_t;
#ifdef __cplusplus
}
#endif
#endif /* __USB_DEVICE_INTERNALS_H */

Wyświetl plik

@ -1,602 +0,0 @@
/*
## Cypress CyAPI C++ library header file (CyAPI.h)
## =======================================================
##
## Copyright Cypress Semiconductor Corporation, 2009-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.rtf
##
## where <install> is the Cypress software
## install root directory path.
##
## =======================================================
*/
#ifndef CyUSBH
#define CyUSBH
#include "cyusb30_def.h"
/* Data straucture for the Vendor request and data */
typedef struct vendorCmdData
{
UCHAR *buf; /* Pointer to the data */
UCHAR opCode; /* Vendor request code */
UINT addr; /* Read/Write address */
long size; /* Size of the read/write */
bool isRead; /* Read or write */
} vendorCmdData ;
#ifndef __USB200_H__
#define __USB200_H__
#pragma pack(push,1)
typedef struct _USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
typedef struct _USB_ENDPOINT_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bEndpointAddress;
UCHAR bmAttributes;
USHORT wMaxPacketSize;
UCHAR bInterval;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
typedef struct _USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
typedef struct _USB_INTERFACE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bInterfaceNumber;
UCHAR bAlternateSetting;
UCHAR bNumEndpoints;
UCHAR bInterfaceClass;
UCHAR bInterfaceSubClass;
UCHAR bInterfaceProtocol;
UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
typedef struct _USB_STRING_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
typedef struct _USB_COMMON_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
} USB_COMMON_DESCRIPTOR, *PUSB_COMMON_DESCRIPTOR;
#pragma pack(pop)
#endif
/*******************************************************************************/
class CCyIsoPktInfo {
public:
LONG Status;
LONG Length;
};
/*******************************************************************************/
/* {AE18AA60-7F6A-11d4-97DD-00010229B959} */
static GUID CYUSBDRV_GUID = {0xae18aa60, 0x7f6a, 0x11d4, {0x97, 0xdd, 0x0, 0x1, 0x2, 0x29, 0xb9, 0x59}};
typedef enum {TGT_DEVICE, TGT_INTFC, TGT_ENDPT, TGT_OTHER } CTL_XFER_TGT_TYPE;
typedef enum {REQ_STD, REQ_CLASS, REQ_VENDOR } CTL_XFER_REQ_TYPE;
typedef enum {DIR_TO_DEVICE, DIR_FROM_DEVICE } CTL_XFER_DIR_TYPE;
typedef enum {XMODE_BUFFERED, XMODE_DIRECT } XFER_MODE_TYPE;
const int MAX_ENDPTS = 32;
const int MAX_INTERFACES = 255;
const int USB_STRING_MAXLEN = 256;
#define BUFSIZE_UPORT 2048 //4096 - CDT 130492
typedef enum { RAM = 1, I2CE2PROM, SPIFLASH } FX3_FWDWNLOAD_MEDIA_TYPE ;
typedef enum { SUCCESS = 0, FAILED, INVALID_MEDIA_TYPE, INVALID_FWSIGNATURE, DEVICE_CREATE_FAILED, INCORRECT_IMAGE_LENGTH, INVALID_FILE, SPILASH_ERASE_FAILED, CORRUPT_FIRMWARE_IMAGE_FILE,I2CE2PROM_UNKNOWN_I2C_SIZE } FX3_FWDWNLOAD_ERROR_CODE;
#define CYWB_BL_4_BYTES_COPY(destination,source) {memcpy((void *)(destination), (void *)(source), 4);}
/********************************************************************************
*
* The CCyEndPoint ABSTRACT Class
*
********************************************************************************/
class CCyUSBEndPoint
{
protected:
bool WaitForIO(OVERLAPPED *ovLapStatus);
virtual PUCHAR BeginDirectXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov);
virtual PUCHAR BeginBufferedXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov);
public:
CCyUSBEndPoint(void);
CCyUSBEndPoint(CCyUSBEndPoint& ept);
CCyUSBEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor);
CCyUSBEndPoint(HANDLE hDev, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor);
HANDLE hDevice;
/* The fields of an EndPoint Descriptor */
UCHAR DscLen;
UCHAR DscType;
UCHAR Address;
UCHAR Attributes;
USHORT MaxPktSize;
USHORT PktsPerFrame;
UCHAR Interval;
/* This are the fields for Super speed endpoint */
UCHAR ssdscLen;
UCHAR ssdscType;
UCHAR ssmaxburst; /* Maximum number of packets endpoint can send in one burst */
UCHAR ssbmAttribute; /* store endpoint attribute like for bulk it will be number of streams */
USHORT ssbytesperinterval;
/* Other fields */
ULONG TimeOut;
ULONG UsbdStatus;
ULONG NtStatus;
DWORD bytesWritten;
DWORD LastError;
bool bIn;
XFER_MODE_TYPE XferMode;
bool XferData(PUCHAR buf, LONG &len, CCyIsoPktInfo* pktInfos = NULL);
bool XferData(PUCHAR buf, LONG &bufLen, CCyIsoPktInfo* pktInfos, bool pktMode);
virtual PUCHAR BeginDataXfer(PUCHAR buf, LONG len, OVERLAPPED *ov) = 0;
virtual bool FinishDataXfer(PUCHAR buf, LONG &len, OVERLAPPED *ov, PUCHAR pXmitBuf, CCyIsoPktInfo* pktInfos = NULL);
bool WaitForXfer(OVERLAPPED *ov, ULONG tOut);
ULONG GetXferSize(void);
void SetXferSize(ULONG xfer);
bool Reset(void);
bool Abort(void);
};
/********************************************************************************
*
* The Control Endpoint Class
*
********************************************************************************/
class CCyControlEndPoint : public CCyUSBEndPoint
{
public:
CCyControlEndPoint(void);
CCyControlEndPoint(CCyControlEndPoint& ept);
CCyControlEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor);
CTL_XFER_TGT_TYPE Target;
CTL_XFER_REQ_TYPE ReqType;
CTL_XFER_DIR_TYPE Direction;
UCHAR ReqCode;
WORD Value;
WORD Index;
bool Read(PUCHAR buf, LONG &len);
bool Write(PUCHAR buf, LONG &len);
PUCHAR BeginDataXfer(PUCHAR buf, LONG len, OVERLAPPED *ov);
};
/********************************************************************************
*
* The Isoc Endpoint Class
*
********************************************************************************/
class CCyIsocEndPoint : public CCyUSBEndPoint
{
protected:
virtual PUCHAR BeginDirectXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov);
virtual PUCHAR BeginBufferedXfer(PUCHAR buf, LONG bufLen, OVERLAPPED *ov);
public:
CCyIsocEndPoint(void);
CCyIsocEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor);
CCyIsocEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor);
PUCHAR BeginDataXfer(PUCHAR buf, LONG len, OVERLAPPED *ov);
CCyIsoPktInfo* CreatePktInfos(LONG bufLen, int &packets);
};
/********************************************************************************
*
* The Bulk Endpoint Class
*
********************************************************************************/
class CCyBulkEndPoint : public CCyUSBEndPoint
{
public:
CCyBulkEndPoint(void);
CCyBulkEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor);
CCyBulkEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor);
PUCHAR BeginDataXfer(PUCHAR buf, LONG len, OVERLAPPED *ov);
};
/********************************************************************************
*
* The Interrupt Endpoint Class
*
********************************************************************************/
class CCyInterruptEndPoint : public CCyUSBEndPoint
{
public:
CCyInterruptEndPoint(void);
CCyInterruptEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor);
CCyInterruptEndPoint(HANDLE h, PUSB_ENDPOINT_DESCRIPTOR pEndPtDescriptor,USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR* SSEndPtDescriptor);
PUCHAR BeginDataXfer(PUCHAR buf, LONG len, OVERLAPPED *ov);
};
/********************************************************************************
*
* The Interface Class
*
********************************************************************************/
class CCyUSBInterface
{
public:
CCyUSBEndPoint *EndPoints[MAX_ENDPTS]; /* Holds pointers to all the interface's endpoints,
plus a pointer to the Control endpoint zero */
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bInterfaceNumber;
UCHAR bAlternateSetting;
UCHAR bNumEndpoints; /* Not counting the control endpoint */
UCHAR bInterfaceClass;
UCHAR bInterfaceSubClass;
UCHAR bInterfaceProtocol;
UCHAR iInterface;
UCHAR bAltSettings;
USHORT wTotalLength; /* Needed in case Intfc has additional (non-endpt) descriptors */
CCyUSBInterface(HANDLE handle, PUSB_INTERFACE_DESCRIPTOR pIntfcDescriptor,UCHAR usb30Dummy);
CCyUSBInterface(HANDLE h, PUSB_INTERFACE_DESCRIPTOR pIntfcDescriptor);
CCyUSBInterface(CCyUSBInterface& ifc); /* Copy Constructor */
~CCyUSBInterface(void);
};
/********************************************************************************
*
* The Config Class
*
********************************************************************************/
class CCyUSBConfig
{
public:
CCyUSBInterface *Interfaces[MAX_INTERFACES];
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
UCHAR AltInterfaces;
CCyUSBConfig(void);
CCyUSBConfig(CCyUSBConfig& cfg); /* Copy Constructor */
CCyUSBConfig(HANDLE h, PUSB_CONFIGURATION_DESCRIPTOR pConfigDescr);
CCyUSBConfig(HANDLE h, PUSB_CONFIGURATION_DESCRIPTOR pConfigDescr,UCHAR usb30Dummy);
~CCyUSBConfig(void);
};
/********************************************************************************
*
* The Bos USB20 Extesnion Class
*
********************************************************************************/
class CCyBosUSB20Extesnion
{
public:
UCHAR bLength; /* Descriptor length */
UCHAR bDescriptorType; /* Descriptor Type */
UCHAR bDevCapabilityType; /* Device capability type */
UINT bmAttribute; /* Bitmap encoding for supprted feature and Link power managment supprted if set */
CCyBosUSB20Extesnion(void);
CCyBosUSB20Extesnion(HANDLE h,PUSB_BOS_USB20_DEVICE_EXTENSION BosUsb20ExtDesc);
};
/********************************************************************************
*
* The Bos SuperSpeed Capability Class
*
********************************************************************************/
class CCyBosSuperSpeedCapability
{
public:
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bDevCapabilityType;
UCHAR bmAttribute;
USHORT SpeedsSuported;
UCHAR bFunctionalitySupporte;
UCHAR bU1DevExitLat;
USHORT bU2DevExitLat;
CCyBosSuperSpeedCapability(void);
CCyBosSuperSpeedCapability(HANDLE h,PUSB_BOS_SS_DEVICE_CAPABILITY pUSB_SuperSpeedUsb);
};
/********************************************************************************
*
* The Bos Container ID Class
*
********************************************************************************/
class CCyBosContainerID
{
public:
UCHAR bLength; /* Descriptor length */
UCHAR bDescriptorType; /* Descriptor Type */
UCHAR bDevCapabilityType; /* Device capability type */
UCHAR bReserved; /* no use */
UCHAR ContainerID[USB_BOS_CAPABILITY_TYPE_CONTAINER_ID_SIZE]; /* UUID */
CCyBosContainerID(void);
CCyBosContainerID(HANDLE h,PUSB_BOS_CONTAINER_ID pContainerID);
};
/********************************************************************************
*
* The USB BOS Class
*
********************************************************************************/
class CCyUSBBOS
{
public:
CCyBosContainerID *pContainer_ID;
CCyBosUSB20Extesnion *pUSB20_DeviceExt;
CCyBosSuperSpeedCapability *pSS_DeviceCap;
UCHAR bLength; /* Descriptor length */
UCHAR bDescriptorType; /* Descriptor Type */
USHORT wTotalLength; /* Total length of descriptor ( icluding device capabilty */
UCHAR bNumDeviceCaps; /* Number of device capability descriptors in BOS */
CCyUSBBOS(void);
CCyUSBBOS(HANDLE h,PUSB_BOS_DESCRIPTOR pBosDescrData);
~CCyUSBBOS();
};
/*********************************************************************************
*
* The USB Device Class - This is the main class that contains members of all the
* other classes.
*
* To use the library, create an instance of this Class and call it's Open method.
*
*********************************************************************************/
class CCyUSBDevice
{
/* The public members are accessible (i.e. corruptible) by the user of the library
* Algorithms of the class don't rely on any public members. Instead, they use the
* private members of the class for their calculations. */
public:
CCyUSBDevice(HANDLE hnd = NULL, GUID guid = CYUSBDRV_GUID, BOOL bOpen = true);
~CCyUSBDevice(void);
CCyUSBEndPoint **EndPoints; /* Shortcut to USBCfgs[CfgNum]->Interfaces[IntfcIndex]->Endpoints */
CCyUSBEndPoint *EndPointOf(UCHAR addr);
CCyUSBBOS *UsbBos;
CCyIsocEndPoint *IsocInEndPt;
CCyIsocEndPoint *IsocOutEndPt;
CCyBulkEndPoint *BulkInEndPt;
CCyBulkEndPoint *BulkOutEndPt;
CCyControlEndPoint *ControlEndPt;
CCyInterruptEndPoint *InterruptInEndPt;
CCyInterruptEndPoint *InterruptOutEndPt;
USHORT StrLangID;
ULONG LastError;
ULONG UsbdStatus;
ULONG NtStatus;
ULONG DriverVersion;
ULONG USBDIVersion;
char DeviceName[USB_STRING_MAXLEN];
char FriendlyName[USB_STRING_MAXLEN];
wchar_t Manufacturer[USB_STRING_MAXLEN];
wchar_t Product[USB_STRING_MAXLEN];
wchar_t SerialNumber[USB_STRING_MAXLEN];
CHAR DevPath[USB_STRING_MAXLEN];
USHORT BcdUSB;
USHORT VendorID;
USHORT ProductID;
UCHAR USBAddress;
UCHAR DevClass;
UCHAR DevSubClass;
UCHAR DevProtocol;
INT MaxPacketSize;
USHORT BcdDevice;
UCHAR ConfigValue;
UCHAR ConfigAttrib;
UCHAR MaxPower;
UCHAR IntfcClass;
UCHAR IntfcSubClass;
UCHAR IntfcProtocol;
bool bHighSpeed;
bool bSuperSpeed;
DWORD BytesXfered;
UCHAR DeviceCount(void);
UCHAR ConfigCount(void);
UCHAR IntfcCount(void);
UCHAR AltIntfcCount(void);
UCHAR EndPointCount(void);
void SetConfig(UCHAR cfg);
UCHAR Config(void) { return CfgNum; } /* Normally 0 */
UCHAR Interface(void) { return IntfcNum; } /* Usually 0 */
/* No SetInterface method since only 1 intfc per device (per Windows) */
UCHAR AltIntfc(void);
bool SetAltIntfc(UCHAR alt);
GUID DriverGUID(void) { return DrvGuid; }
HANDLE DeviceHandle(void) { return hDevice; }
void UsbdStatusString(ULONG stat, PCHAR s);
bool CreateHandle(UCHAR dev);
void DestroyHandle();
bool Open(UCHAR dev);
void Close(void);
bool Reset(void);
bool ReConnect(void);
bool Suspend(void);
bool Resume(void);
bool IsOpen(void) { return (hDevice != INVALID_HANDLE_VALUE); }
UCHAR PowerState(void);
bool GetBosDescriptor(PUSB_BOS_DESCRIPTOR descr);
bool GetBosUSB20DeviceExtensionDescriptor(PUSB_BOS_USB20_DEVICE_EXTENSION descr);
bool GetBosContainedIDDescriptor(PUSB_BOS_CONTAINER_ID descr);
bool GetBosSSCapabilityDescriptor(PUSB_BOS_SS_DEVICE_CAPABILITY descr);
void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR descr);
void GetConfigDescriptor(PUSB_CONFIGURATION_DESCRIPTOR descr);
void GetIntfcDescriptor(PUSB_INTERFACE_DESCRIPTOR descr);
CCyUSBConfig GetUSBConfig(int index);
private:
USB_DEVICE_DESCRIPTOR USBDeviceDescriptor;
PUSB_CONFIGURATION_DESCRIPTOR USBConfigDescriptors[2];
PUSB_BOS_DESCRIPTOR pUsbBosDescriptor;
CCyUSBConfig *USBCfgs[2];
HANDLE hWnd;
HANDLE hDevice;
HANDLE hDevNotification;
HANDLE hHndNotification;
GUID DrvGuid;
UCHAR Devices;
UCHAR Interfaces;
UCHAR AltInterfaces;
UCHAR Configs;
UCHAR DevNum;
UCHAR CfgNum;
UCHAR IntfcNum; /* The current selected interface's bInterfaceNumber */
UCHAR IntfcIndex; /* The entry in the Config's interfaces table matching to IntfcNum and AltSetting */
bool GetInternalBosDescriptor();
void GetDevDescriptor(void);
void GetCfgDescriptor(int descIndex);
void GetString(wchar_t *s, UCHAR sIndex);
void SetStringDescrLanguage(void);
void SetAltIntfcParams(UCHAR alt);
bool IoControl(ULONG cmd, PUCHAR buf, ULONG len);
void SetEndPointPtrs(void);
void GetDeviceName(void);
void GetFriendlyName(void);
void GetDriverVer(void);
void GetUSBDIVer(void);
void GetSpeed(void);
void GetUSBAddress(void);
//void CloseEndPtHandles(void);
bool RegisterForPnpEvents(HANDLE h);
};
/********************************************************************************
*
* The FX3 Device Class
*
********************************************************************************/
class CCyFX3Device: public CCyUSBDevice
{
public:
CCyFX3Device(void);
~CCyFX3Device(void);
bool IsBootLoaderRunning();
FX3_FWDWNLOAD_ERROR_CODE DownloadFw(char *fileName, FX3_FWDWNLOAD_MEDIA_TYPE enMediaType);
FX3_FWDWNLOAD_ERROR_CODE DownloadFwToRam(const UCHAR *buffer_p, UINT fw_size, UCHAR opCode = 0xA0);
private:
bool Ep0VendorCommand(vendorCmdData cmdData);
bool SetProgramEntry(UCHAR opCode,UINT start_addr);
bool DownloadBufferToDevice(UINT start_addr, USHORT count, UCHAR *data_buf, UCHAR opCode);
bool UploadBufferFromDevice(UINT start_addr, USHORT count, UCHAR *data_buf, UCHAR opCode);
FX3_FWDWNLOAD_ERROR_CODE DownloadUserIMGtoI2CE2PROM(PUCHAR buffer_p, UINT fw_size, UCHAR opCode);
FX3_FWDWNLOAD_ERROR_CODE DownloadUserIMGtoSPIFLASH(PUCHAR buffer_p, UINT fw_size, UCHAR opCode);
FX3_FWDWNLOAD_ERROR_CODE EraseSectorOfSPIFlash(UINT SectorNumber, UCHAR opCode);
bool WriteToSPIFlash(PUCHAR Buf, UINT buflen, UINT ByteAddress, UCHAR opCode);
};
/********************************************************************************/
#endif

Wyświetl plik

@ -1,90 +0,0 @@
/*
## Cypress CyAPI C++ library USB3.0 defination header file (CyUSB30_def.h)
## =======================================================
##
## Copyright Cypress Semiconductor Corporation, 2009-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.rtf
##
## where <install> is the Cypress software
## install root directory path.
##
## =======================================================
*/
#ifndef _CYUSB30_H
#define _CYUSB30_H
//#pragma pack(1)
#pragma pack(push, 1)
// USB3.0 specific constant defination
#define BCDUSBJJMASK 0xFF00 //(0xJJMN JJ - Major version,M Minor version, N sub-minor vesion)
#define USB30MAJORVER 0x0300
#define USB20MAJORVER 0x0200
#define USB_BOS_DESCRIPTOR_TYPE 0x0F
#define USB_DEVICE_CAPABILITY 0x10
#define USB_SUPERSPEED_ENDPOINT_COMPANION 0x30
#define USB_BOS_CAPABILITY_TYPE_Wireless_USB 0x01
#define USB_BOS_CAPABILITY_TYPE_USB20_EXT 0x02
#define USB_BOS_CAPABILITY_TYPE_SUPERSPEED_USB 0x03
#define USB_BOS_CAPABILITY_TYPE_CONTAINER_ID 0x04
#define USB_BOS_CAPABILITY_TYPE_CONTAINER_ID_SIZE 0x10
#define USB_BOS_DEVICE_CAPABILITY_TYPE_INDEX 0x2
//constant defination
typedef struct _USB_BOS_DESCRIPTOR
{
UCHAR bLength;/* Descriptor length*/
UCHAR bDescriptorType;/* Descriptor Type */
USHORT wTotalLength;/* Total length of descriptor ( icluding device capability*/
UCHAR bNumDeviceCaps;/* Number of device capability descriptors in BOS */
}USB_BOS_DESCRIPTOR,*PUSB_BOS_DESCRIPTOR;
typedef struct _USB_BOS_USB20_DEVICE_EXTENSION
{
UCHAR bLength;/* Descriptor length*/
UCHAR bDescriptorType;/* Descriptor Type */
UCHAR bDevCapabilityType;/* Device capability type*/
UINT bmAttribute;// Bitmap encoding for supprted feature and Link power managment supprted if set
}USB_BOS_USB20_DEVICE_EXTENSION,*PUSB_BOS_USB20_DEVICE_EXTENSION;
typedef struct _USB_BOS_SS_DEVICE_CAPABILITY
{
UCHAR bLength;/* Descriptor length*/
UCHAR bDescriptorType;/* Descriptor Type */
UCHAR bDevCapabilityType;/* Device capability type*/
UCHAR bmAttribute;// Bitmap encoding for supprted feature and Link power managment supprted if set
USHORT wSpeedsSuported;//low speed supported if set,full speed supported if set,high speed supported if set,super speed supported if set,15:4 nt used
UCHAR bFunctionalitySupporte;
UCHAR bU1DevExitLat;//U1 device exit latency
USHORT bU2DevExitLat;//U2 device exit latency
}USB_BOS_SS_DEVICE_CAPABILITY,*PUSB_BOS_SS_DEVICE_CAPABILITY;
typedef struct _USB_BOS_CONTAINER_ID
{
UCHAR bLength;/* Descriptor length*/
UCHAR bDescriptorType;/* Descriptor Type */
UCHAR bDevCapabilityType;/* Device capability type*/
UCHAR bReserved; // no use
UCHAR ContainerID[USB_BOS_CAPABILITY_TYPE_CONTAINER_ID_SIZE];/* UUID */
}USB_BOS_CONTAINER_ID,*PUSB_BOS_CONTAINER_ID;
typedef struct _USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR
{
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bMaxBurst;
UCHAR bmAttributes;
USHORT bBytesPerInterval;
}USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR,*PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR;
#pragma pack(pop)
#endif /*_CYUSB30_H*/

Wyświetl plik

@ -1,46 +0,0 @@
// Note: see usbdi.h in the DDK for the USBD_STATUS source definitions
typedef LONG USBD_STATUS;
#define USBD_STATUS(Status) ((ULONG)(Status) & 0x0FFFFFFFL)
#define USBD_STATE(Status) ((ULONG)(Status) & 0xF0000000L)
// HC status codes (Note: both error and stall bit are set)
#define USBD_STATUS_SUCCESS ((USBD_STATUS)0x00000000L)
#define USBD_STATUS_PENDING ((USBD_STATUS)0x40000000L)
#define USBD_STATUS_HALTED ((USBD_STATUS)0xC0000000L)
#define USBD_STATUS_ERROR ((USBD_STATUS)0x80000000L)
#define USBD_STATUS_CRC ((USBD_STATUS)0xC0000001L)
#define USBD_STATUS_BTSTUFF ((USBD_STATUS)0xC0000002L)
#define USBD_STATUS_DATA_TOGGLE_MISMATCH ((USBD_STATUS)0xC0000003L)
#define USBD_STATUS_STALL_PID ((USBD_STATUS)0xC0000004L)
#define USBD_STATUS_DEV_NOT_RESPONDING ((USBD_STATUS)0xC0000005L)
#define USBD_STATUS_PID_CHECK_FAILURE ((USBD_STATUS)0xC0000006L)
#define USBD_STATUS_UNEXPECTED_PID ((USBD_STATUS)0xC0000007L)
#define USBD_STATUS_DATA_OVERRUN ((USBD_STATUS)0xC0000008L)
#define USBD_STATUS_DATA_UNDERRUN ((USBD_STATUS)0xC0000009L)
#define USBD_STATUS_RESERVED1 ((USBD_STATUS)0xC000000AL)
#define USBD_STATUS_RESERVED2 ((USBD_STATUS)0xC000000BL)
#define USBD_STATUS_BUFFER_OVERRUN ((USBD_STATUS)0xC000000CL)
#define USBD_STATUS_BUFFER_UNDERRUN ((USBD_STATUS)0xC000000DL)
#define USBD_STATUS_NOT_ACCESSED ((USBD_STATUS)0xC000000FL)
#define USBD_STATUS_FIFO ((USBD_STATUS)0xC0000010L)
#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
#define USBD_STATUS_NO_MEMORY ((USBD_STATUS)0x80000100L)
#define USBD_STATUS_INVALID_URB_FUNCTION ((USBD_STATUS)0x80000200L)
#define USBD_STATUS_INVALID_PARAMETER ((USBD_STATUS)0x80000300L)
#define USBD_STATUS_ERROR_BUSY ((USBD_STATUS)0x80000400L)
#define USBD_STATUS_REQUEST_FAILED ((USBD_STATUS)0x80000500L)
#define USBD_STATUS_INVALID_PIPE_HANDLE ((USBD_STATUS)0x80000600L)
#define USBD_STATUS_NO_BANDWIDTH ((USBD_STATUS)0x80000700L)
#define USBD_STATUS_INTERNAL_HC_ERROR ((USBD_STATUS)0x80000800L)
#define USBD_STATUS_ERROR_SHORT_TRANSFER ((USBD_STATUS)0x80000900L)
#define USBD_STATUS_BAD_START_FRAME ((USBD_STATUS)0xC0000A00L)
#define USBD_STATUS_ISOCH_REQUEST_FAILED ((USBD_STATUS)0xC0000B00L)
#define USBD_STATUS_FRAME_CONTROL_OWNED ((USBD_STATUS)0xC0000C00L)
#define USBD_STATUS_FRAME_CONTROL_NOT_OWNED ((USBD_STATUS)0xC0000D00L)
#define USBD_STATUS_CANCELED ((USBD_STATUS)0x00010000L)
#define USBD_STATUS_CANCELING ((USBD_STATUS)0x00020000L)

Wyświetl plik

@ -1,26 +0,0 @@
/*
## Cypress CyAPI C++ library version number header file (VersionNo.h)
## =======================================================
##
## Copyright Cypress Semiconductor Corporation, 2009-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.rtf
##
## where <install> is the Cypress software
## install root directory path.
##
## =======================================================
*/
#define FILEVER 1,2,1,0
#define PRODUCTVER 1,2,1,0
#define STRFILEVER "1, 2, 1, 0"
#define STRPRODUCTVER "1, 2, 1, 0"
#define STRFILEVER_ASSENBLY "1.2.1.0"

Wyświetl plik

@ -1,213 +0,0 @@
/*
## Cypress CyAPI C++ library IOCTL defination header file (cyioctl.h)
## =======================================================
##
## Copyright Cypress Semiconductor Corporation, 2009-2012,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.rtf
##
## where <install> is the Cypress software
## install root directory path.
##
## =======================================================
*/
#ifndef __IOCTL_H__
#define __IOCTL_H__
#ifndef DRIVER
#ifndef CTL_CODE
#include "devioctl.h"
#endif
#ifndef BM_REQUEST_TYPE
#include "usb200.h"
#endif
#include <PSHPACK1.H>
#define DIR_HOST_TO_DEVICE 0
#define DIR_DEVICE_TO_HOST 1
#define DEVICE_SPEED_UNKNOWN 0x00000000
#define DEVICE_SPEED_LOW_FULL 0x00000001
#define DEVICE_SPEED_HIGH 0x00000002
#define DEVICE_SPEED_SUPER 0x00000004
typedef struct _WORD_SPLIT {
UCHAR lowByte;
UCHAR hiByte;
} WORD_SPLIT, *PWORD_SPLIT;
typedef struct _BM_REQ_TYPE {
UCHAR Recipient:2;
UCHAR Reserved:3;
UCHAR Type:2;
UCHAR Direction:1;
} BM_REQ_TYPE, *PBM_REQ_TYPE;
typedef struct _SETUP_PACKET {
union {
BM_REQ_TYPE bmReqType;
UCHAR bmRequest;
};
UCHAR bRequest;
union {
WORD_SPLIT wVal;
USHORT wValue;
};
union {
WORD_SPLIT wIndx;
USHORT wIndex;
};
union {
WORD_SPLIT wLen;
USHORT wLength;
};
ULONG ulTimeOut;
} SETUP_PACKET, *PSETUP_PACKET;
#define USB_ISO_ID 0x4945
#define USB_ISO_CMD_ASAP 0x8000
#define USB_ISO_CMD_CURRENT_FRAME 0x8001
#define USB_ISO_CMD_SET_FRAME 0x8002
typedef struct _ISO_ADV_PARAMS {
USHORT isoId;
USHORT isoCmd;
ULONG ulParam1;
ULONG ulParam2;
} ISO_ADV_PARAMS, *PISO_ADV_PARAMS;
typedef struct _ISO_PACKET_INFO {
ULONG Status;
ULONG Length;
} ISO_PACKET_INFO, *PISO_PACKET_INFO;
typedef struct _SINGLE_TRANSFER {
union {
SETUP_PACKET SetupPacket;
ISO_ADV_PARAMS IsoParams;
};
UCHAR reserved;
UCHAR ucEndpointAddress;
ULONG NtStatus;
ULONG UsbdStatus;
ULONG IsoPacketOffset;
ULONG IsoPacketLength;
ULONG BufferOffset;
ULONG BufferLength;
} SINGLE_TRANSFER, *PSINGLE_TRANSFER;
#endif // #ifndef DRIVER
typedef struct _SET_TRANSFER_SIZE_INFO {
UCHAR EndpointAddress;
ULONG TransferSize;
} SET_TRANSFER_SIZE_INFO, *PSET_TRANSFER_SIZE_INFO;
//
// Macro to extract function out of the device io control code
//
#ifdef WIN_98_DDK
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
#endif
#define FUNCTION_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0x00003FFC)) >> 2)
#define ACCESS_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0x000C0000)) >> 14)
//#define METHOD_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0x00000003)))
#define IOCTL_ADAPT_INDEX 0x0000
// Get the driver version
#define IOCTL_ADAPT_GET_DRIVER_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get the current USBDI version
#define IOCTL_ADAPT_GET_USBDI_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get the current device alt interface settings from driver
#define IOCTL_ADAPT_GET_ALT_INTERFACE_SETTING CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+2, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Set the device interface and alt interface setting
#define IOCTL_ADAPT_SELECT_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+3, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get device address from driver
#define IOCTL_ADAPT_GET_ADDRESS CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+4, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get number of endpoints for current interface and alt interface setting from driver
#define IOCTL_ADAPT_GET_NUMBER_ENDPOINTS CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+5, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get the current device power state
#define IOCTL_ADAPT_GET_DEVICE_POWER_STATE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+6, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Set the device power state
#define IOCTL_ADAPT_SET_DEVICE_POWER_STATE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+7, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Send a raw packet to endpoint 0
#define IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+8, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Send/receive data to/from nonep0
#define IOCTL_ADAPT_SEND_NON_EP0_TRANSFER CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+9, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Simulate a disconnect/reconnect
#define IOCTL_ADAPT_CYCLE_PORT CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+10, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Reset the pipe
#define IOCTL_ADAPT_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+11, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Reset the device
#define IOCTL_ADAPT_RESET_PARENT_PORT CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+12, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get the current transfer size of an endpoint (in number of bytes)
#define IOCTL_ADAPT_GET_TRANSFER_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+13, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Set the transfer size of an endpoint (in number of bytes)
#define IOCTL_ADAPT_SET_TRANSFER_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+14, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Return the name of the device
#define IOCTL_ADAPT_GET_DEVICE_NAME CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+15, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Return the "Friendly Name" of the device
#define IOCTL_ADAPT_GET_FRIENDLY_NAME CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+16, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Abort all outstanding transfers on the pipe
#define IOCTL_ADAPT_ABORT_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+17, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Send/receive data to/from nonep0 w/ direct buffer acccess (no buffering)
#define IOCTL_ADAPT_SEND_NON_EP0_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+18, METHOD_NEITHER, FILE_ANY_ACCESS)
// Return device speed
#define IOCTL_ADAPT_GET_DEVICE_SPEED CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+19, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Get the current USB frame number
#define IOCTL_ADAPT_GET_CURRENT_FRAME CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_ADAPT_INDEX+20, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define NUMBER_OF_ADAPT_IOCTLS 21 // Last IOCTL_ADAPT_INDEX + 1
#include <POPPACK.H>
#endif // __IOCTL_H__

Wyświetl plik

@ -1,184 +0,0 @@
/*****************************************************************************
* *
* OpenNI 1.x Alpha *
* Copyright (C) 2012 PrimeSense Ltd. *
* *
* This file is part of OpenNI. *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*****************************************************************************/
/*++ BUILD Version: 0004 // Increment this if a change has global effects
Copyright (c) 1992-1999 Microsoft Corporation
Module Name:
devioctl.h
Abstract:
This module contains
Revision History:
--*/
// begin_winioctl
#ifndef _DEVIOCTL_
#define _DEVIOCTL_
// begin_ntddk begin_wdm begin_nthal begin_ntifs
//
// Define the various device type values. Note that values used by Microsoft
// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
// by customers.
//
#define DEVICE_TYPE ULONG
#define FILE_DEVICE_BEEP 0x00000001
#define FILE_DEVICE_CD_ROM 0x00000002
#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
#define FILE_DEVICE_CONTROLLER 0x00000004
#define FILE_DEVICE_DATALINK 0x00000005
#define FILE_DEVICE_DFS 0x00000006
#define FILE_DEVICE_DISK 0x00000007
#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
#define FILE_DEVICE_FILE_SYSTEM 0x00000009
#define FILE_DEVICE_INPORT_PORT 0x0000000a
#define FILE_DEVICE_KEYBOARD 0x0000000b
#define FILE_DEVICE_MAILSLOT 0x0000000c
#define FILE_DEVICE_MIDI_IN 0x0000000d
#define FILE_DEVICE_MIDI_OUT 0x0000000e
#define FILE_DEVICE_MOUSE 0x0000000f
#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
#define FILE_DEVICE_NAMED_PIPE 0x00000011
#define FILE_DEVICE_NETWORK 0x00000012
#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
#define FILE_DEVICE_NULL 0x00000015
#define FILE_DEVICE_PARALLEL_PORT 0x00000016
#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
#define FILE_DEVICE_PRINTER 0x00000018
#define FILE_DEVICE_SCANNER 0x00000019
#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
#define FILE_DEVICE_SERIAL_PORT 0x0000001b
#define FILE_DEVICE_SCREEN 0x0000001c
#define FILE_DEVICE_SOUND 0x0000001d
#define FILE_DEVICE_STREAMS 0x0000001e
#define FILE_DEVICE_TAPE 0x0000001f
#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
#define FILE_DEVICE_TRANSPORT 0x00000021
#define FILE_DEVICE_UNKNOWN 0x00000022
#define FILE_DEVICE_VIDEO 0x00000023
#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
#define FILE_DEVICE_WAVE_IN 0x00000025
#define FILE_DEVICE_WAVE_OUT 0x00000026
#define FILE_DEVICE_8042_PORT 0x00000027
#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
#define FILE_DEVICE_BATTERY 0x00000029
#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
#define FILE_DEVICE_MODEM 0x0000002b
#define FILE_DEVICE_VDM 0x0000002c
#define FILE_DEVICE_MASS_STORAGE 0x0000002d
#define FILE_DEVICE_SMB 0x0000002e
#define FILE_DEVICE_KS 0x0000002f
#define FILE_DEVICE_CHANGER 0x00000030
#define FILE_DEVICE_SMARTCARD 0x00000031
#define FILE_DEVICE_ACPI 0x00000032
#define FILE_DEVICE_DVD 0x00000033
#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034
#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035
#define FILE_DEVICE_DFS_VOLUME 0x00000036
#define FILE_DEVICE_SERENUM 0x00000037
#define FILE_DEVICE_TERMSRV 0x00000038
#define FILE_DEVICE_KSEC 0x00000039
#define FILE_DEVICE_FIPS 0x0000003A
#define FILE_DEVICE_INFINIBAND 0x0000003B
#define FILE_DEVICE_VMBUS 0x0000003E
#define FILE_DEVICE_CRYPT_PROVIDER 0x0000003F
#define FILE_DEVICE_WPD 0x00000040
#define FILE_DEVICE_BLUETOOTH 0x00000041
#define FILE_DEVICE_MT_COMPOSITE 0x00000042
#define FILE_DEVICE_MT_TRANSPORT 0x00000043
#define FILE_DEVICE_BIOMETRIC 0x00000044
#define FILE_DEVICE_PMI 0x00000045
//
// Macro definition for defining IOCTL and FSCTL function control codes. Note
// that function codes 0-2047 are reserved for Microsoft Corporation, and
// 2048-4095 are reserved for customers.
//
#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
//
// Macro to extract device type out of the device io control code
//
#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16)
//
// Macro to extract buffering method out of the device io control code
//
#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3))
//
// Define the method codes for how buffers are passed for I/O and FS controls
//
#define METHOD_BUFFERED 0
#define METHOD_IN_DIRECT 1
#define METHOD_OUT_DIRECT 2
#define METHOD_NEITHER 3
//
// Define some easier to comprehend aliases:
// METHOD_DIRECT_TO_HARDWARE (writes, aka METHOD_IN_DIRECT)
// METHOD_DIRECT_FROM_HARDWARE (reads, aka METHOD_OUT_DIRECT)
//
#define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
#define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
//
// Define the access check value for any access
//
//
// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in
// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these
// constants *MUST* always be in sync.
//
//
// FILE_SPECIAL_ACCESS is checked by the NT I/O system the same as FILE_ANY_ACCESS.
// The file systems, however, may add additional access checks for I/O and FS controls
// that use this value.
//
#define FILE_ANY_ACCESS 0
#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe
#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe
// end_ntddk end_wdm end_nthal end_ntifs
#endif // _DEVIOCTL_
// end_winioctl

Wyświetl plik

@ -1,270 +0,0 @@
#ifndef __USB100_H__
#define __USB100_H__
#include <PSHPACK1.H>
//bmRequest.Dir
#define BMREQUEST_HOST_TO_DEVICE 0
#define BMREQUEST_DEVICE_TO_HOST 1
//bmRequest.Type
#define BMREQUEST_STANDARD 0
#define BMREQUEST_CLASS 1
#define BMREQUEST_VENDOR 2
//bmRequest.Recipient
#define BMREQUEST_TO_DEVICE 0
#define BMREQUEST_TO_INTERFACE 1
#define BMREQUEST_TO_ENDPOINT 2
#define BMREQUEST_TO_OTHER 3
#define MAXIMUM_USB_STRING_LENGTH 255
// values for the bits returned by the USB GET_STATUS command
#define USB_GETSTATUS_SELF_POWERED 0x01
#define USB_GETSTATUS_REMOTE_WAKEUP_ENABLED 0x02
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
// descriptor types defined by DWG documents
#define USB_RESERVED_DESCRIPTOR_TYPE 0x06
#define USB_CONFIG_POWER_DESCRIPTOR_TYPE 0x07
#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 0x08
#define USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(d, i) ((USHORT)((USHORT)d<<8 | i))
//
// Values for bmAttributes field of an
// endpoint descriptor
//
#define USB_ENDPOINT_TYPE_MASK 0x03
#define USB_ENDPOINT_TYPE_CONTROL 0x00
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
#define USB_ENDPOINT_TYPE_BULK 0x02
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
//
// definitions for bits in the bmAttributes field of a
// configuration descriptor.
//
#define USB_CONFIG_POWERED_MASK 0xc0
#define USB_CONFIG_BUS_POWERED 0x80
#define USB_CONFIG_SELF_POWERED 0x40
#define USB_CONFIG_REMOTE_WAKEUP 0x20
//
// Endpoint direction bit, stored in address
//
#define USB_ENDPOINT_DIRECTION_MASK 0x80
// test direction bit in the bEndpointAddress field of
// an endpoint descriptor.
#define USB_ENDPOINT_DIRECTION_OUT(addr) (!((addr) & USB_ENDPOINT_DIRECTION_MASK))
#define USB_ENDPOINT_DIRECTION_IN(addr) ((addr) & USB_ENDPOINT_DIRECTION_MASK)
//
// USB defined request codes
// see chapter 9 of the USB 1.0 specifcation for
// more information.
//
// These are the correct values based on the USB 1.0
// specification
#define USB_REQUEST_GET_STATUS 0x00
#define USB_REQUEST_CLEAR_FEATURE 0x01
#define USB_REQUEST_SET_FEATURE 0x03
#define USB_REQUEST_SET_ADDRESS 0x05
#define USB_REQUEST_GET_DESCRIPTOR 0x06
#define USB_REQUEST_SET_DESCRIPTOR 0x07
#define USB_REQUEST_GET_CONFIGURATION 0x08
#define USB_REQUEST_SET_CONFIGURATION 0x09
#define USB_REQUEST_GET_INTERFACE 0x0A
#define USB_REQUEST_SET_INTERFACE 0x0B
#define USB_REQUEST_SYNC_FRAME 0x0C
//
// defined USB device classes
//
#define USB_DEVICE_CLASS_RESERVED 0x00
#define USB_DEVICE_CLASS_AUDIO 0x01
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
#define USB_DEVICE_CLASS_MONITOR 0x04
#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05
#define USB_DEVICE_CLASS_POWER 0x06
#define USB_DEVICE_CLASS_PRINTER 0x07
#define USB_DEVICE_CLASS_STORAGE 0x08
#define USB_DEVICE_CLASS_HUB 0x09
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
//
// USB Core defined Feature selectors
//
#define USB_FEATURE_ENDPOINT_STALL 0x0000
#define USB_FEATURE_REMOTE_WAKEUP 0x0001
//
// USB DWG defined Feature selectors
//
#define USB_FEATURE_INTERFACE_POWER_D0 0x0002
#define USB_FEATURE_INTERFACE_POWER_D1 0x0003
#define USB_FEATURE_INTERFACE_POWER_D2 0x0004
#define USB_FEATURE_INTERFACE_POWER_D3 0x0005
typedef struct _USB_DEVICE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
USHORT idVendor;
USHORT idProduct;
USHORT bcdDevice;
UCHAR iManufacturer;
UCHAR iProduct;
UCHAR iSerialNumber;
UCHAR bNumConfigurations;
} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
typedef struct _USB_ENDPOINT_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bEndpointAddress;
UCHAR bmAttributes;
USHORT wMaxPacketSize;
UCHAR bInterval;
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
typedef struct _USB_CONFIGURATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT wTotalLength;
UCHAR bNumInterfaces;
UCHAR bConfigurationValue;
UCHAR iConfiguration;
UCHAR bmAttributes;
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
typedef struct _USB_INTERFACE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bInterfaceNumber;
UCHAR bAlternateSetting;
UCHAR bNumEndpoints;
UCHAR bInterfaceClass;
UCHAR bInterfaceSubClass;
UCHAR bInterfaceProtocol;
UCHAR iInterface;
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
typedef struct _USB_STRING_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
typedef struct _USB_COMMON_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
} USB_COMMON_DESCRIPTOR, *PUSB_COMMON_DESCRIPTOR;
//
// Standard USB HUB definitions
//
// See Chapter 11 USB core specification
//
typedef struct _USB_HUB_DESCRIPTOR {
UCHAR bDescriptorLength; // Length of this descriptor
UCHAR bDescriptorType; // Hub configuration type
UCHAR bNumberOfPorts; // number of ports on this hub
USHORT wHubCharacteristics; // Hub Charateristics
UCHAR bPowerOnToPowerGood; // port power on till power good in 2ms
UCHAR bHubControlCurrent; // max current in mA
//
// room for 255 ports power control and removable bitmask
UCHAR bRemoveAndPowerMask[64];
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
//
// Structures defined by various DWG feature documents
//
//
// See DWG USB Feature Specification: Interface Power Management
//
#define USB_SUPPORT_D0_COMMAND 0x01
#define USB_SUPPORT_D1_COMMAND 0x02
#define USB_SUPPORT_D2_COMMAND 0x04
#define USB_SUPPORT_D3_COMMAND 0x08
#define USB_SUPPORT_D1_WAKEUP 0x10
#define USB_SUPPORT_D2_WAKEUP 0x20
typedef struct _USB_CONFIGURATION_POWER_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR SelfPowerConsumedD0[3];
UCHAR bPowerSummaryId;
UCHAR bBusPowerSavingD1;
UCHAR bSelfPowerSavingD1;
UCHAR bBusPowerSavingD2;
UCHAR bSelfPowerSavingD2;
UCHAR bBusPowerSavingD3;
UCHAR bSelfPowerSavingD3;
USHORT TransitionTimeFromD1;
USHORT TransitionTimeFromD2;
USHORT TransitionTimeFromD3;
} USB_CONFIGURATION_POWER_DESCRIPTOR, *PUSB_CONFIGURATION_POWER_DESCRIPTOR;
typedef struct _USB_INTERFACE_POWER_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bmCapabilitiesFlags;
UCHAR bBusPowerSavingD1;
UCHAR bSelfPowerSavingD1;
UCHAR bBusPowerSavingD2;
UCHAR bSelfPowerSavingD2;
UCHAR bBusPowerSavingD3;
UCHAR bSelfPowerSavingD3;
USHORT TransitionTimeFromD1;
USHORT TransitionTimeFromD2;
USHORT TransitionTimeFromD3;
} USB_INTERFACE_POWER_DESCRIPTOR, *PUSB_INTERFACE_POWER_DESCRIPTOR;
#include <POPPACK.H>
#endif /* __USB100_H__ */

Wyświetl plik

@ -1,111 +0,0 @@
#ifndef __USB200_H__
#define __USB200_H__
#include "usb100.h"
#include <PSHPACK1.H>
typedef enum _USB_DEVICE_SPEED {
UsbLowSpeed = 0,
UsbFullSpeed,
UsbHighSpeed
} USB_DEVICE_SPEED;
typedef enum _USB_DEVICE_TYPE {
Usb11Device = 0,
Usb20Device
} USB_DEVICE_TYPE;
// standard definiions for the port status
// word of the HUB port register
#define USB_PORT_STATUS_CONNECT 0x0001
#define USB_PORT_STATUS_ENABLE 0x0002
#define USB_PORT_STATUS_SUSPEND 0x0004
#define USB_PORT_STATUS_OVER_CURRENT 0x0008
#define USB_PORT_STATUS_RESET 0x0010
#define USB_PORT_STATUS_POWER 0x0100
#define USB_PORT_STATUS_LOW_SPEED 0x0200
#define USB_PORT_STATUS_HIGH_SPEED 0x0400
typedef union _BM_REQUEST_TYPE {
struct _BM {
UCHAR Recipient:2;
UCHAR Reserved:3;
UCHAR Type:2;
UCHAR Dir:1;
};
UCHAR B;
} BM_REQUEST_TYPE, *PBM_REQUEST_TYPE;
typedef struct _USB_DEFAULT_PIPE_SETUP_PACKET {
BM_REQUEST_TYPE bmRequestType;
UCHAR bRequest;
union _wValue {
struct {
UCHAR LowByte;
UCHAR HiByte;
};
USHORT W;
} wValue;
union _wIndex {
struct {
UCHAR LowByte;
UCHAR HiByte;
};
USHORT W;
} wIndex;
USHORT wLength;
} USB_DEFAULT_PIPE_SETUP_PACKET, *PUSB_DEFAULT_PIPE_SETUP_PACKET;
// setup packet is eight bytes -- defined by spec
C_ASSERT(sizeof(USB_DEFAULT_PIPE_SETUP_PACKET) == 8);
#define USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE 0x06
typedef struct _USB_DEVICE_QUALIFIER_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
USHORT bcdUSB;
UCHAR bDeviceClass;
UCHAR bDeviceSubClass;
UCHAR bDeviceProtocol;
UCHAR bMaxPacketSize0;
UCHAR bNumConfigurations;
UCHAR bReserved;
} USB_DEVICE_QUALIFIER_DESCRIPTOR, *PUSB_DEVICE_QUALIFIER_DESCRIPTOR;
typedef union _USB_HIGH_SPEED_MAXPACKET {
struct _MP {
USHORT MaxPacket:11; /* 0..10 */
USHORT HSmux:2; /* 11..12 */
USHORT Reserved:3; /* 13..15 */
};
USHORT us;
} USB_HIGH_SPEED_MAXPACKET, *PUSB_HIGH_SPEED_MAXPACKET;
#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE 0x0B
typedef struct _USB_INTERFACE_ASSOCIATION_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
UCHAR bFirstInterface;
UCHAR bInterfaceCount;
UCHAR bFunctionClass;
UCHAR bFunctionSubClass;
UCHAR bFunctionProtocol;
UCHAR iFunction;
} USB_INTERFACE_ASSOCIATION_DESCRIPTOR, *PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR;
#include <POPPACK.H>
#endif // __USB200_H__

Wyświetl plik

@ -1,456 +0,0 @@
//
// FX3handler.cpp
// 2020 10 12 Oscar Steila ik1xpv
// loading arm code.img from resource by Howard Su and Hayati Ayguen
// This module was previous named:
// openFX3.cpp MIT License Copyright (c) 2016 Booya Corp.
// booyasdr@gmail.com, http://booyasdr.sf.net
// modified 2017 11 30 ik1xpv@gmail.com, http://www.steila.com/blog
//
#include <windows.h>
#include "FX3handler.h"
#include "./CyAPI/CyAPI.h"
#include "./CyAPI/cyioctl.h"
#define RES_BIN_FIRMWARE 2000
fx3class* CreateUsbHandler()
{
return new fx3handler();
}
fx3handler::fx3handler():
fx3dev (nullptr),
Fx3IsOn (false)
{
}
fx3handler::~fx3handler() // reset USB device and exit
{
DbgPrintf("\r\n~fx3handler\r\n");
Close();
}
bool fx3handler::GetFx3Device() {
bool r = false;
if (fx3dev == nullptr) return r; // no device
int n = fx3dev->DeviceCount();
if (n == 0) return r; // no one
// Walk through all devices looking for VENDOR_ID/STREAMER_ID
for (int i = 0; i <= n; i++) {
fx3dev->Open(i); // go down the list of devices to find our device
if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == STREAMER_ID))
{
r = true;
break;
}
if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == BOOTLOADER_ID))
{
r = true;
break;
}
}
if (r == false)
fx3dev->Close();
return r;
}
bool fx3handler::GetFx3DeviceStreamer(void) { // open class
bool r = false;
if (fx3dev == NULL) return r;
int n = fx3dev->DeviceCount();
// Walk through all devices looking for VENDOR_ID/STREAMER_ID
if (n == 0) return r;
// go down the list of devices to find STREAMER_ID device
for (int i = 0; i <= n; i++) {
fx3dev->Open(i);
if ((fx3dev->VendorID == VENDOR_ID) && (fx3dev->ProductID == STREAMER_ID))
{
r = true;
break;
}
}
if (r == false)
fx3dev->Close();
return r;
}
bool fx3handler::Open(uint8_t* fw_data, uint32_t fw_size) {
bool r = false;
fx3dev = new CCyFX3Device; // instantiate the device
if (fx3dev == nullptr) return r; // return if failed
int n = fx3dev->DeviceCount();
if (n == 0) return r; // return if no devices connected
if (!GetFx3Device()) return r; // NO FX3 device connected
#ifdef _DEBUG
if (!fx3dev->IsBootLoaderRunning()) { // if not bootloader device
Control(RESETFX3); // reset the fx3 firmware via CyU3PDeviceReset(false)
DbgPrintf("DEBUG - Reset Firmware\n");
Sleep(300);
fx3dev->Close(); // close class
delete fx3dev; // destroy class
Sleep(300);
fx3dev = new CCyFX3Device; // create class
GetFx3Device(); // open class
}
#endif
FX3_FWDWNLOAD_ERROR_CODE dlf = SUCCESS;
if (fx3dev->IsBootLoaderRunning())
{
dlf = fx3dev->DownloadFwToRam(fw_data, fw_size);
Sleep(500); // wait for download to finish
}
if (dlf != 0)
{
DbgPrintf("MISSING/OLD FIRMWARE\n");
return false;
}
int x = 0;
int maxretry = 30;
CCyFX3Device* expdev = nullptr;
while (x++ < maxretry) // wait new firmware setup
{
bool r = false;
expdev = new CCyFX3Device; // instantiate the device
if (expdev != NULL)
int n = expdev->DeviceCount();
if (n > 0)
{
expdev->Open(0);
// go down the list of devices to find our device
for (int i = 1; i <= n; i++)
{
if ((expdev->VendorID == VENDOR_ID) && (expdev->ProductID == STREAMER_ID))
{
x = maxretry; //got it exit
}
}
}
expdev->Close(); // close class
delete expdev; // destroy class
}
GetFx3DeviceStreamer(); // open class with new ram firmware
if (!fx3dev->IsOpen()) {
DbgPrintf("Failed to open device\n");
return r;
}
EndPt = fx3dev->BulkInEndPt;
if (!EndPt) {
DbgPrintf("No Bulk In end point\n");
return r; // init failed
}
long pktSize = EndPt->MaxPktSize;
EndPt->SetXferSize(transferSize);
long ppx = transferSize / pktSize;
DbgPrintf("buffer transferSize = %d. packet size = %ld. packets per transfer = %ld\n"
, transferSize, pktSize, ppx);
uint8_t data[4];
GetHardwareInfo((uint32_t*)&data);
if (data[1] != FIRMWARE_VER_MAJOR ||
data[2] != FIRMWARE_VER_MINOR)
{
DbgPrintf("Firmware version mismatch %d.%d != %d.%d (actual)\n", FIRMWARE_VER_MAJOR, FIRMWARE_VER_MINOR, data[1], data[2]);
Control(RESETFX3);
return false;
}
Fx3IsOn = true;
return Fx3IsOn; // init success
}
using namespace std;
bool fx3handler::Control(FX3Command command, UINT8 data) { // firmware control BBRF
long lgt = 1;
fx3dev->ControlEndPt->ReqCode = command;
fx3dev->ControlEndPt->Value = (USHORT)0;
fx3dev->ControlEndPt->Index = (USHORT)0;
bool r = fx3dev->ControlEndPt->Write(&data, lgt);
DbgPrintf("FX3FWControl %x .%x %x\n", r, command, data);
if (r == false)
{
Close();
}
return r;
}
bool fx3handler::Control(FX3Command command, UINT32 data) { // firmware control BBRF
long lgt = 4;
fx3dev->ControlEndPt->ReqCode = command;
fx3dev->ControlEndPt->Value = (USHORT)0;
fx3dev->ControlEndPt->Index = (USHORT)0;
bool r = fx3dev->ControlEndPt->Write((PUCHAR)&data, lgt);
DbgPrintf("FX3FWControl %x .%x %x\n", r, command, data);
if (r == false)
{
Close();
}
return r;
}
bool fx3handler::Control(FX3Command command, UINT64 data) { // firmware control BBRF
long lgt = 8;
fx3dev->ControlEndPt->ReqCode = command;
fx3dev->ControlEndPt->Value = (USHORT)0;
fx3dev->ControlEndPt->Index = (USHORT)0;
bool r = fx3dev->ControlEndPt->Write((PUCHAR)&data, lgt);
DbgPrintf("FX3FWControl %x .%x %llx\n", r, command, data);
if (r == false)
{
Close();
}
return r;
}
bool fx3handler::SetArgument(UINT16 index, UINT16 value) { // firmware control BBRF
long lgt = 1;
uint8_t data = 0;
fx3dev->ControlEndPt->ReqCode = SETARGFX3;
fx3dev->ControlEndPt->Value = (USHORT)value;
fx3dev->ControlEndPt->Index = (USHORT)index;
bool r = fx3dev->ControlEndPt->Write((PUCHAR)&data, lgt);
DbgPrintf("SetArgument %x .%x (%x, %x)\n", r, SETARGFX3, index, value);
if (r == false)
{
Close();
}
return r;
}
bool fx3handler::GetHardwareInfo(UINT32* data) { // firmware control BBRF
long lgt = 4;
fx3dev->ControlEndPt->ReqCode = TESTFX3;
#ifdef _DEBUG
fx3dev->ControlEndPt->Value = (USHORT) 1;
#else
fx3dev->ControlEndPt->Value = (USHORT) 0;
#endif
fx3dev->ControlEndPt->Index = (USHORT)0;
bool r = fx3dev->ControlEndPt->Read((PUCHAR)data, lgt);
DbgPrintf("GetHardwareInfo %x .%x %x\n", r, TESTFX3, *data);
if (r == false)
{
Close();
}
return r;
}
bool fx3handler::ReadDebugTrace(uint8_t* pdata, uint8_t len)
{
long lgt = len;
bool r;
fx3dev->ControlEndPt->ReqCode = READINFODEBUG;
fx3dev->ControlEndPt->Value = (USHORT) pdata[0]; // upstream char
r = fx3dev->ControlEndPt->Read((PUCHAR)pdata, lgt);
return r;
}
bool fx3handler::SendI2cbytes(UINT8 i2caddr, UINT8 regaddr, PUINT8 pdata, UINT8 len)
{
bool r = false;
LONG lgt = len;
fx3dev->ControlEndPt->ReqCode = I2CWFX3;
fx3dev->ControlEndPt->Value = (USHORT)i2caddr;
fx3dev->ControlEndPt->Index = (USHORT)regaddr;
Sleep(10);
r = fx3dev->ControlEndPt->Write(pdata, lgt);
if (r == false)
DbgPrintf("\nfx3FWSendI2cbytes 0x%02x regaddr 0x%02x 1data 0x%02x len 0x%02x \n",
i2caddr, regaddr, *pdata, len);
return r;
}
bool fx3handler::ReadI2cbytes(UINT8 i2caddr, UINT8 regaddr, PUINT8 pdata, UINT8 len)
{
bool r = false;
LONG lgt = len;
WORD saveValue, saveIndex;
saveValue = fx3dev->ControlEndPt->Value;
saveIndex = fx3dev->ControlEndPt->Index;
fx3dev->ControlEndPt->ReqCode = I2CRFX3;
fx3dev->ControlEndPt->Value = (USHORT)i2caddr;
fx3dev->ControlEndPt->Index = (USHORT)regaddr;
r = fx3dev->ControlEndPt->Read(pdata, lgt);
if (r == false)
printf("fx3FWReadI2cbytes %x : %02x %02x %02x %02x : %02x\n", r, I2CRFX3, i2caddr, regaddr, len, *pdata);
fx3dev->ControlEndPt->Value = saveValue;
fx3dev->ControlEndPt->Index = saveIndex;
return r;
}
bool fx3handler::Close() {
fx3dev->Close(); // close class
delete fx3dev; // destroy class
Fx3IsOn = false;
return true;
}
#define BLOCK_TIMEOUT (80) // block 65.536 ms timeout is 80
struct ReadContext
{
PUCHAR context;
OVERLAPPED overlap;
SINGLE_TRANSFER transfer;
uint8_t* buffer;
long size;
};
bool fx3handler::BeginDataXfer(UINT8 *buffer, long transferSize, void** context)
{
ReadContext *readContext = (ReadContext *)(*context);
if (!EndPt)
return false;
if (*context == nullptr)
{
// first time call, allocate the context structure
readContext = new ReadContext;
*context = readContext;
memset(&readContext->overlap, 0, sizeof(readContext->overlap));
readContext->overlap.hEvent = CreateEvent(NULL, false, false, NULL);
}
readContext->buffer = buffer;
readContext->size = transferSize;
readContext->context = EndPt->BeginDataXfer(readContext->buffer, transferSize, &readContext->overlap);
if (EndPt->NtStatus || EndPt->UsbdStatus) {// BeginDataXfer failed
DbgPrintf((char*)"Xfer request rejected. 1 STATUS = %ld %ld\n", EndPt->NtStatus, EndPt->UsbdStatus);
return false;
}
return true;
}
bool fx3handler::FinishDataXfer(void** context)
{
ReadContext *readContext = (ReadContext *)(*context);
if (!readContext)
{
return nullptr;
}
if (!EndPt->WaitForXfer(&readContext->overlap, BLOCK_TIMEOUT)) { // block on transfer
DbgPrintf("WaitForXfer timeout. NTSTATUS = 0x%08X\n", EndPt->NtStatus);
EndPt->Abort(); // abort if timeout
return false;
}
auto requested_size = readContext->size;
if (!EndPt->FinishDataXfer(readContext->buffer, readContext->size, &readContext->overlap, readContext->context)) {
DbgPrintf("FinishDataXfer Failed. NTSTATUS = 0x%08X\n", EndPt->NtStatus);
return false;
}
if (readContext->size < requested_size)
DbgPrintf("only read %ld but requested %ld\n", readContext->size, requested_size);
return true;
}
void fx3handler::CleanupDataXfer(void** context)
{
ReadContext *readContext = (ReadContext *)(*context);
CloseHandle(readContext->overlap.hEvent);
delete (readContext);
}
#define USB_READ_CONCURRENT 4
void fx3handler::AdcSamplesProcess()
{
DbgPrintf("AdcSamplesProc thread runs\n");
int buf_idx; // queue index
int read_idx;
void* contexts[USB_READ_CONCURRENT];
memset(contexts, 0, sizeof(contexts));
// Queue-up the first batch of transfer requests
for (int n = 0; n < USB_READ_CONCURRENT; n++) {
auto ptr = inputbuffer->peekWritePtr(n);
if (!BeginDataXfer((uint8_t*)ptr, transferSize, &contexts[n])) {
DbgPrintf("Xfer request rejected.\n");
return;
}
}
read_idx = 0; // context cycle index
buf_idx = 0; // buffer cycle index
// The infinite xfer loop.
while (run) {
if (!FinishDataXfer(&contexts[read_idx])) {
break;
}
inputbuffer->WriteDone();
// Re-submit this queue element to keep the queue full
auto ptr = inputbuffer->peekWritePtr(USB_READ_CONCURRENT - 1);
if (!BeginDataXfer((uint8_t*)ptr, transferSize, &contexts[read_idx])) { // BeginDataXfer failed
DbgPrintf("Xfer request rejected.\n");
break;
}
buf_idx = (buf_idx + 1) % QUEUE_SIZE;
read_idx = (read_idx + 1) % USB_READ_CONCURRENT;
} // End of the infinite loop
for (int n = 0; n < USB_READ_CONCURRENT; n++) {
CleanupDataXfer(&contexts[n]);
}
DbgPrintf("AdcSamplesProc thread_exit\n");
return; // void *
}
void fx3handler::StartStream(ringbuffer<int16_t>& input, int numofblock)
{
// Allocate the context and buffers
inputbuffer = &input;
// create the thread
this->numofblock = numofblock;
run = true;
adc_samples_thread = new std::thread(
[this]() {
this->AdcSamplesProcess();
}
);
}
void fx3handler::StopStream()
{
// set the flag
run = false;
adc_samples_thread->join();
// force exit the thread
inputbuffer = nullptr;
delete adc_samples_thread;
}

Wyświetl plik

@ -1,73 +0,0 @@
#ifndef FX3HANDLER_H
#define FX3HANDLER_H
//
// FX3handler.cpp
// 2020 10 12 Oscar Steila ik1xpv
// loading arm code.img from resource by Howard Su and Hayati Ayguen
// This module was previous named:openFX3.cpp
// MIT License Copyright (c) 2016 Booya Corp.
// booyasdr@gmail.com, http://booyasdr.sf.net
// modified 2017 11 30 ik1xpv@gmail.com, http://www.steila.com/blog
//
#include <sys/stat.h>
#include <iostream>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include "sddc_config.h"
#include "dsp/ringbuffer.h"
#define VENDOR_ID (0x04B4)
#define STREAMER_ID (0x00F1)
#define BOOTLOADER_ID (0x00F3)
#include "FX3Class.h"
class CCyFX3Device;
class CCyUSBEndPoint;
class fx3handler : public fx3class
{
public:
fx3handler();
virtual ~fx3handler(void);
bool Open(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);
bool Control(FX3Command command, uint64_t data);
bool SetArgument(uint16_t index, uint16_t value);
bool GetHardwareInfo(uint32_t* data);
bool ReadDebugTrace(uint8_t* pdata, uint8_t len);
void StartStream(ringbuffer<int16_t>& input, int numofblock);
void StopStream();
private:
bool SendI2cbytes(uint8_t i2caddr, uint8_t regaddr, uint8_t* pdata, uint8_t len);
bool ReadI2cbytes(uint8_t i2caddr, uint8_t regaddr, uint8_t* pdata, uint8_t len);
bool BeginDataXfer(uint8_t *buffer, long transferSize, void** context);
bool FinishDataXfer(void** context);
void CleanupDataXfer(void** context);
CCyFX3Device* fx3dev;
CCyUSBEndPoint* EndPt;
std::thread *adc_samples_thread;
bool GetFx3Device();
bool GetFx3DeviceStreamer();
bool Fx3IsOn;
bool Close(void);
void AdcSamplesProcess();
ringbuffer<int16_t> *inputbuffer;
int numofblock;
bool run;
};
#endif // FX3HANDLER_H

Wyświetl plik

@ -1,191 +0,0 @@
#pragma once
#include <thread>
#include <mutex>
#include <condition_variable>
const int default_count = 64;
const int spin_count = 100;
#define ALIGN (8)
class ringbufferbase {
public:
ringbufferbase(int count) :
max_count(count),
read_index(0),
write_index(0),
emptyCount(0),
fullCount(0),
writeCount(0)
{
}
int getFullCount() const { return fullCount; }
int getEmptyCount() const { return emptyCount; }
int getWriteCount() const { return writeCount; }
void ReadDone()
{
std::unique_lock<std::mutex> lk(mutex);
if ((write_index + 1) % max_count == read_index)
{
read_index = (read_index + 1) % max_count;
nonfullCV.notify_all();
}
else
{
read_index = (read_index + 1) % max_count;
}
}
void WriteDone()
{
std::unique_lock<std::mutex> lk(mutex);
if (read_index == write_index)
{
write_index = (write_index + 1) % max_count;
nonemptyCV.notify_all();
}
else
{
write_index = (write_index + 1) % max_count;
}
writeCount++;
}
void Stop()
{
std::unique_lock<std::mutex> lk(mutex);
read_index = 0;
write_index = max_count / 2;
nonfullCV.notify_all();
nonemptyCV.notify_all();
}
protected:
void WaitUntilNotEmpty()
{
// if not empty
for (int i = 0; i < spin_count; i++)
{
if (read_index != write_index)
return;
}
if (read_index == write_index)
{
std::unique_lock<std::mutex> lk(mutex);
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)
{
std::unique_lock<std::mutex> lk(mutex);
fullCount++;
nonfullCV.wait(lk, [this] {
return (write_index + 1) % max_count != read_index;
});
}
}
int max_count;
volatile int read_index;
volatile int write_index;
private:
int emptyCount;
int fullCount;
int writeCount;
std::mutex mutex;
std::condition_variable nonemptyCV;
std::condition_variable nonfullCV;
};
template<typename T> class ringbuffer : public ringbufferbase {
typedef T* TPtr;
public:
ringbuffer(int count = default_count) :
ringbufferbase(count)
{
buffers = new TPtr[max_count];
buffers[0] = nullptr;
}
~ringbuffer()
{
if (buffers[0])
delete[] buffers[0];
delete[] buffers;
}
void setBlockSize(int size)
{
if (block_size != size)
{
block_size = size;
if (buffers[0])
delete[] buffers[0];
int aligned_block_size = (block_size + ALIGN - 1) & (~(ALIGN - 1));
auto data = new T[max_count * aligned_block_size];
for (int i = 0; i < max_count; ++i)
{
buffers[i] = &data[i * aligned_block_size];
}
}
}
T* peekWritePtr(int offset)
{
return buffers[(write_index + max_count + offset) % max_count];
}
T* peekReadPtr(int offset)
{
return buffers[(read_index + max_count + offset) % max_count];
}
T* getWritePtr()
{
// if there is still space
WaitUntilNotFull();
return buffers[(write_index) % max_count];
}
const T* getReadPtr()
{
WaitUntilNotEmpty();
return buffers[read_index];
}
int getBlockSize() const { return block_size; }
private:
int block_size;
TPtr* buffers;
};

Wyświetl plik

@ -1,263 +0,0 @@
#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 "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "fftw3.h"
#include "RadioHandler.h"
#include "fir.h"
#include <assert.h>
#include <utility>
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)
{
mtunebin = halfFft / 4;
mfftdim[0] = halfFft;
for (int i = 1; i < NDECIDX; i++)
{
mfftdim[i] = mfftdim[i - 1] / 2;
}
GainScale = 0.0f;
#ifndef NDEBUG
int mratio = 1; // 1,2,4,8,16,..
const float Astop = 120.0f;
const float relPass = 0.85f; // 85% of Nyquist should be usable
const float relStop = 1.1f; // 'some' alias back into transition band is OK
printf("\n***************************************************************************\n");
printf("Filter tap estimation, Astop = %.1f dB, relPass = %.2f, relStop = %.2f\n", Astop, relPass, relStop);
for (int d = 0; d < NDECIDX; d++)
{
float Bw = 64.0f / mratio;
int ntaps = KaiserWindow(0, Astop, relPass * Bw / 128.0f, relStop * Bw / 128.0f, nullptr);
printf("decimation %2d: KaiserWindow(Astop = %.1f dB, Fpass = %.3f,Fstop = %.3f, Bw %.3f @ %f ) => %d taps\n",
d, Astop, relPass * Bw, relStop * Bw, Bw, 128.0f, ntaps);
mratio = mratio * 2;
}
printf("***************************************************************************\n");
#endif
}
fft_mt_r2iq::~fft_mt_r2iq()
{
if (filterHw == nullptr)
return;
fftwf_export_wisdom_to_filename("wisdom");
for (int d = 0; d < NDECIDX; d++)
{
fftwf_free(filterHw[d]); // 4096
}
fftwf_free(filterHw);
fftwf_destroy_plan(plan_t2f_r2c);
for (int d = 0; d < NDECIDX; d++)
{
fftwf_destroy_plan(plans_f2t_c2c[d]);
}
for (unsigned t = 0; t < processor_count; t++) {
auto th = threadArgs[t];
fftwf_free(th->ADCinTime);
fftwf_free(th->ADCinFreq);
fftwf_free(th->inFreqTmp);
delete threadArgs[t];
}
}
float fft_mt_r2iq::setFreqOffset(float offset)
{
// align to 1/4 of halfft
this->mtunebin = int(offset * halfFft / 4) * 4; // mtunebin step 4 bin ?
float delta = ((float)this->mtunebin / halfFft) - offset;
float ret = delta * getRatio(); // ret increases with higher decimation
DbgPrintf("offset %f mtunebin %d delta %f (%f)\n", offset, this->mtunebin, delta, ret);
return ret;
}
void fft_mt_r2iq::TurnOn() {
this->r2iqOn = true;
this->bufIdx = 0;
this->lastThread = threadArgs[0];
for (unsigned t = 0; t < processor_count; t++) {
r2iq_thread[t] = std::thread(
[this] (void* arg)
{ return this->r2iqThreadf((r2iqThreadArg*)arg); }, (void*)threadArgs[t]);
}
}
void fft_mt_r2iq::TurnOff(void) {
this->r2iqOn = false;
inputbuffer->Stop();
outputbuffer->Stop();
for (unsigned t = 0; t < processor_count; t++) {
r2iq_thread[t].join();
}
}
bool fft_mt_r2iq::IsOn(void) { return(this->r2iqOn); }
void fft_mt_r2iq::Init(float gain, ringbuffer<int16_t> *input, ringbuffer<float>* obuffers)
{
this->inputbuffer = input; // set to the global exported by main_loop
this->outputbuffer = obuffers; // set to the global exported by main_loop
this->GainScale = gain;
fftwf_import_wisdom_from_filename("wisdom");
// Get the processor count
processor_count = std::thread::hardware_concurrency() - 1;
if (processor_count == 0)
processor_count = 1;
if (processor_count > N_MAX_R2IQ_THREADS)
processor_count = N_MAX_R2IQ_THREADS;
{
fftwf_plan filterplan_t2f_c2c; // time to frequency fft
DbgPrintf((char *) "r2iqCntrl initialization\n");
// DbgPrintf((char *) "RandTable generated\n");
// filters
fftwf_complex *pfilterht; // time filter ht
pfilterht = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*halfFft); // halfFft
filterHw = (fftwf_complex**)fftwf_malloc(sizeof(fftwf_complex*)*NDECIDX);
for (int d = 0; d < NDECIDX; d++)
{
filterHw[d] = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*halfFft); // halfFft
}
filterplan_t2f_c2c = fftwf_plan_dft_1d(halfFft, pfilterht, filterHw[0], FFTW_FORWARD, FFTW_MEASURE);
float *pht = new float[halfFft / 4 + 1];
const float Astop = 120.0f;
const float relPass = 0.85f; // 85% of Nyquist should be usable
const float relStop = 1.1f; // 'some' alias back into transition band is OK
for (int d = 0; d < NDECIDX; d++) // @todo when increasing NDECIDX
{
// @todo: have dynamic bandpass filter size - depending on decimation
// to allow same stopband-attenuation for all decimations
float Bw = 64.0f / mratio[d];
// Bw *= 0.8f; // easily visualize Kaiser filter's response
KaiserWindow(halfFft / 4 + 1, Astop, relPass * Bw / 128.0f, relStop * Bw / 128.0f, pht);
float gainadj = gain * 2048.0f / (float)FFTN_R_ADC; // reference is FFTN_R_ADC == 2048
for (int t = 0; t < halfFft; t++)
{
pfilterht[t][0] = pfilterht[t][1]= 0.0F;
}
for (int t = 0; t < (halfFft/4+1); t++)
{
pfilterht[halfFft-1-t][0] = gainadj * pht[t];
}
fftwf_execute_dft(filterplan_t2f_c2c, pfilterht, filterHw[d]);
}
delete[] pht;
fftwf_destroy_plan(filterplan_t2f_c2c);
fftwf_free(pfilterht);
for (unsigned t = 0; t < processor_count; t++) {
r2iqThreadArg *th = new r2iqThreadArg();
threadArgs[t] = th;
th->ADCinTime = (float*)fftwf_malloc(sizeof(float) * (halfFft + transferSize / 2)); // 2048
th->ADCinFreq = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*(halfFft + 1)); // 1024+1
th->inFreqTmp = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex)*(halfFft)); // 1024
}
plan_t2f_r2c = fftwf_plan_dft_r2c_1d(2 * halfFft, threadArgs[0]->ADCinTime, threadArgs[0]->ADCinFreq, FFTW_MEASURE);
for (int d = 0; d < NDECIDX; d++)
{
plans_f2t_c2c[d] = fftwf_plan_dft_1d(mfftdim[d], threadArgs[0]->inFreqTmp, threadArgs[0]->inFreqTmp, FFTW_BACKWARD, FFTW_MEASURE);
}
}
}
#ifdef _WIN32
// Windows
#include <intrin.h>
#define cpuid(info, x) __cpuidex(info, x, 0)
#else
// GCC Intrinsics
#include <cpuid.h>
#define cpuid(info, x) __cpuid_count(x, 0, info[0], info[1], info[2], info[3])
#endif
void * fft_mt_r2iq::r2iqThreadf(r2iqThreadArg *th)
{
#ifdef NO_SIMD_OPTIM
DbgPrintf("Hardware Capability: all SIMD features (AVX, AVX2, AVX512) deactivated\n");
return r2iqThreadf_def(th);
#else
int info[4];
bool HW_AVX = false;
bool HW_AVX2 = false;
bool HW_AVX512F = false;
cpuid(info, 0);
int nIds = info[0];
if (nIds >= 0x00000001){
cpuid(info,0x00000001);
HW_AVX = (info[2] & ((int)1 << 28)) != 0;
}
if (nIds >= 0x00000007){
cpuid(info,0x00000007);
HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
HW_AVX512F = (info[1] & ((int)1 << 16)) != 0;
}
DbgPrintf("Hardware Capability: AVX:%d AVX2:%d AVX512:%d\n", HW_AVX, HW_AVX2, HW_AVX512F);
if (HW_AVX512F)
return r2iqThreadf_avx512(th);
else if (HW_AVX2)
return r2iqThreadf_avx2(th);
else if (HW_AVX)
return r2iqThreadf_avx(th);
else
return r2iqThreadf_def(th);
#endif
}

Wyświetl plik

@ -1,127 +0,0 @@
#pragma once
#include "r2iq.h"
#include "fftw3.h"
#include "sddc_config.h"
#include <algorithm>
#include <string.h>
// use up to this many threads
#define N_MAX_R2IQ_THREADS 1
#define PRINT_INPUT_RANGE 0
static const int halfFft = FFTN_R_ADC / 2; // half the size of the first fft at ADC 64Msps real rate (2048)
static const int fftPerBuf = transferSize / sizeof(short) / (3 * halfFft / 2) + 1; // number of ffts per buffer with 256|768 overlap
class fft_mt_r2iq : public r2iqControlClass
{
public:
fft_mt_r2iq();
virtual ~fft_mt_r2iq();
float setFreqOffset(float offset);
void Init(float gain, ringbuffer<int16_t>* buffers, ringbuffer<float>* obuffers);
void TurnOn();
void TurnOff(void);
bool IsOn(void);
protected:
template<bool rand> 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] = float(val);
}
}
void shift_freq(fftwf_complex* dest, const fftwf_complex* source1, const fftwf_complex* source2, int start, int end)
{
for (int m = start; m < end; m++)
{
// besides circular shift, do complex multiplication with the lowpass filter's spectrum
dest[m][0] = source1[m][0] * source2[m][0] - source1[m][1] * source2[m][1];
dest[m][1] = source1[m][1] * source2[m][0] + source1[m][0] * source2[m][1];
}
}
template<bool flip> void copy(fftwf_complex* dest, const fftwf_complex* source, int count)
{
if (flip)
{
for (int i = 0; i < count; i++)
{
dest[i][0] = source[i][0];
dest[i][1] = -source[i][1];
}
}
else
{
for (int i = 0; i < count; i++)
{
dest[i][0] = source[i][0];
dest[i][1] = source[i][1];
}
}
}
private:
ringbuffer<int16_t>* inputbuffer; // pointer to input buffers
ringbuffer<float>* outputbuffer; // pointer to ouput buffers
int bufIdx; // index to next buffer to be processed
r2iqThreadArg* lastThread;
float GainScale;
int mfftdim [NDECIDX]; // FFT N dimensions: mfftdim[k] = halfFft / 2^k
int mtunebin;
void *r2iqThreadf(r2iqThreadArg *th); // thread function
void * r2iqThreadf_def(r2iqThreadArg *th);
void * r2iqThreadf_avx(r2iqThreadArg *th);
void * r2iqThreadf_avx2(r2iqThreadArg *th);
void * r2iqThreadf_avx512(r2iqThreadArg *th);
fftwf_complex **filterHw; // Hw complex to each decimation ratio
fftwf_plan plan_t2f_r2c; // fftw plan buffers Freq to Time complex to complex per decimation ratio
fftwf_plan *plan_f2t_c2c; // fftw plan buffers Time to Freq real to complex per buffer
fftwf_plan plans_f2t_c2c[NDECIDX];
uint32_t processor_count;
r2iqThreadArg* threadArgs[N_MAX_R2IQ_THREADS];
std::mutex mutexR2iqControl; // r2iq control lock
std::thread r2iq_thread[N_MAX_R2IQ_THREADS]; // thread pointers
};
// assure, that ADC is not oversteered?
struct r2iqThreadArg {
r2iqThreadArg()
{
#if PRINT_INPUT_RANGE
MinMaxBlockCount = 0;
MinValue = 0;
MaxValue = 0;
#endif
}
float *ADCinTime; // point to each threads input buffers [nftt][n]
fftwf_complex *ADCinFreq; // buffers in frequency
fftwf_complex *inFreqTmp; // tmp decimation output buffers (after tune shift)
#if PRINT_INPUT_RANGE
int MinMaxBlockCount;
int16_t MinValue;
int16_t MaxValue;
#endif
};

Wyświetl plik

@ -1,9 +0,0 @@
#include "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "fftw3.h"
#include "RadioHandler.h"
void * fft_mt_r2iq::r2iqThreadf_avx(r2iqThreadArg *th)
{
#include "fft_mt_r2iq_impl.hpp"
}

Wyświetl plik

@ -1,9 +0,0 @@
#include "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "fftw3.h"
#include "RadioHandler.h"
void * fft_mt_r2iq::r2iqThreadf_avx2(r2iqThreadArg *th)
{
#include "fft_mt_r2iq_impl.hpp"
}

Wyświetl plik

@ -1,9 +0,0 @@
#include "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "fftw3.h"
#include "RadioHandler.h"
void * fft_mt_r2iq::r2iqThreadf_avx512(r2iqThreadArg *th)
{
#include "fft_mt_r2iq_impl.hpp"
}

Wyświetl plik

@ -1,9 +0,0 @@
#include "fft_mt_r2iq.h"
#include "sddc_config.h"
#include "fftw3.h"
#include "RadioHandler.h"
void * fft_mt_r2iq::r2iqThreadf_def(r2iqThreadArg *th)
{
#include "fft_mt_r2iq_impl.hpp"
}

Wyświetl plik

@ -1,171 +0,0 @@
{
const int decimate = this->mdecimation;
const int mfft = this->mfftdim[decimate]; // = halfFft / 2^mdecimation
const fftwf_complex* filter = filterHw[decimate];
const bool lsb = this->getSideband();
const auto filter2 = &filter[halfFft - mfft / 2];
plan_f2t_c2c = &plans_f2t_c2c[decimate];
fftwf_complex* pout = nullptr;
int decimate_count = 0;
while (r2iqOn) {
const int16_t *dataADC; // pointer to input data
const int16_t *endloop; // pointer to end data to be copied to beginning
const int _mtunebin = this->mtunebin; // Update LO tune is possible during run
{
std::unique_lock<std::mutex> lk(mutexR2iqControl);
dataADC = inputbuffer->getReadPtr();
if (!r2iqOn)
return 0;
this->bufIdx = (this->bufIdx + 1) % QUEUE_SIZE;
endloop = inputbuffer->peekReadPtr(-1) + transferSamples - halfFft;
}
auto inloop = th->ADCinTime;
// @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 PRINT_INPUT_RANGE
std::pair<int16_t, int16_t> blockMinMax = std::make_pair<int16_t, int16_t>(0, 0);
#endif
if (!this->getRand()) // plain samples no ADC rand set
{
convert_float<false>(endloop, inloop, halfFft);
#if PRINT_INPUT_RANGE
auto minmax = std::minmax_element(dataADC, dataADC + transferSamples);
blockMinMax.first = *minmax.first;
blockMinMax.second = *minmax.second;
#endif
convert_float<false>(dataADC, inloop + halfFft, transferSamples);
}
else
{
convert_float<true>(endloop, inloop, halfFft);
convert_float<true>(dataADC, inloop + halfFft, transferSamples);
}
#if PRINT_INPUT_RANGE
th->MinValue = std::min(blockMinMax.first, th->MinValue);
th->MaxValue = std::max(blockMinMax.second, th->MaxValue);
++th->MinMaxBlockCount;
if (th->MinMaxBlockCount * processor_count / 3 >= DEFAULT_TRANSFERS_PER_SEC )
{
float minBits = (th->MinValue < 0) ? (log10f((float)(-th->MinValue)) / log10f(2.0f)) : -1.0f;
float maxBits = (th->MaxValue > 0) ? (log10f((float)(th->MaxValue)) / log10f(2.0f)) : -1.0f;
printf("r2iq: min = %d (%.1f bits) %.2f%%, max = %d (%.1f bits) %.2f%%\n",
(int)th->MinValue, minBits, th->MinValue *-100.0f / 32768.0f,
(int)th->MaxValue, maxBits, th->MaxValue * 100.0f / 32768.0f);
th->MinValue = 0;
th->MaxValue = 0;
th->MinMaxBlockCount = 0;
}
#endif
dataADC = nullptr;
inputbuffer->ReadDone();
// decimate in frequency plus tuning
if (decimate_count == 0)
pout = (fftwf_complex*)outputbuffer->getWritePtr();
decimate_count = (decimate_count + 1) & ((1 << decimate) - 1);
// Calculate the parameters for the first half
const auto count = std::min(mfft/2, halfFft - _mtunebin);
const auto source = &th->ADCinFreq[_mtunebin];
// Calculate the parameters for the second half
const auto start = std::max(0, mfft / 2 - _mtunebin);
const auto source2 = &th->ADCinFreq[_mtunebin - mfft / 2];
const auto dest = &th->inFreqTmp[mfft / 2];
for (int k = 0; k < fftPerBuf; k++)
{
// core of fast convolution including filter and decimation
// main part is 'overlap-scrap' (IMHO better name for 'overlap-save'), see
// https://en.wikipedia.org/wiki/Overlap%E2%80%93save_method
{
// FFT first stage: time to frequency, real to complex
// 'full' transformation size: 2 * halfFft
fftwf_execute_dft_r2c(plan_t2f_r2c, th->ADCinTime + (3 * halfFft / 2) * k, th->ADCinFreq);
// result now in th->ADCinFreq[]
// circular shift (mixing in full bins) and low/bandpass filtering (complex multiplication)
{
// circular shift tune fs/2 first half array into th->inFreqTmp[]
shift_freq(th->inFreqTmp, source, filter, 0, count);
if (mfft / 2 != count)
memset(th->inFreqTmp[count], 0, sizeof(float) * 2 * (mfft / 2 - count));
// circular shift tune fs/2 second half array
shift_freq(dest, source2, filter2, start, mfft/2);
if (start != 0)
memset(th->inFreqTmp[mfft / 2], 0, sizeof(float) * 2 * start);
}
// result now in th->inFreqTmp[]
// 'shorter' inverse FFT transform (decimation); frequency (back) to COMPLEX time domain
// transform size: mfft = mfftdim[k] = halfFft / 2^k with k = mdecimation
fftwf_execute_dft(*plan_f2t_c2c, th->inFreqTmp, th->inFreqTmp); // c2c decimation
// result now in th->inFreqTmp[]
}
// postprocessing
// @todo: is it possible to ..
// 1)
// let inverse FFT produce/save it's result directly
// in "this->obuffers[modx] + offset" (pout)
// ( obuffers[] would need to have additional space ..;
// need to move 'scrap' of 'ovelap-scrap'? )
// at least FFTW would allow so,
// see http://www.fftw.org/fftw3_doc/New_002darray-Execute-Functions.html
// attention: multithreading!
// 2)
// could mirroring (lower sideband) get calculated together
// with fine mixer - modifying the mixer frequency? (fs - fc)/fs
// (this would reduce one memory pass)
if (lsb) // lower sideband
{
// mirror just by negating the imaginary Q of complex I/Q
if (k == 0)
{
copy<true>(pout, &th->inFreqTmp[mfft / 4], mfft/2);
}
else
{
copy<true>(pout + mfft / 2 + (3 * mfft / 4) * (k - 1), &th->inFreqTmp[0], (3 * mfft / 4));
}
}
else // upper sideband
{
if (k == 0)
{
copy<false>(pout, &th->inFreqTmp[mfft / 4], mfft/2);
}
else
{
copy<false>(pout + mfft / 2 + (3 * mfft / 4) * (k - 1), &th->inFreqTmp[0], (3 * mfft / 4));
}
}
// result now in this->obuffers[]
}
if (decimate_count == 0) {
outputbuffer->WriteDone();
pout = nullptr;
}
else
{
pout += mfft / 2 + (3 * mfft / 4) * (fftPerBuf - 1);
}
} // while(run)
// DbgPrintf((char *) "r2iqThreadf idx %d pthread_exit %u\n",(int)th->t, pthread_self());
return 0;
}

Wyświetl plik

@ -1,105 +0,0 @@
#include "fir.h"
#include <math.h>
#define K_PI 3.141592653f
#define K_2PI (2*K_PI)
static float Izero(float x)
{
float x2 = x / 2.0f;
float sum = 1.0f;
float ds = 1.0f;
float di = 1.0f;
float errorlimit = 1e-9f;
float tmp;
do
{
tmp = x2 / di;
tmp *= tmp;
ds *= tmp;
sum += ds;
di += 1.0;
} while (ds >= errorlimit * sum);
//qDebug()<<"x="<<x<<" I0="<<sum;
return(sum);
}
////////////////////////////////////////////////////////////////////
// Create a FIR Low Pass filter
// num_taps if > 0, forces filter design to be this number of taps
// if < 0, limits filter design to be max negative number of taps
// Astop = Stopband Atenuation in dB (ie 40dB is 40dB stopband attenuation)
// normFpass = Lowpass passband frequency - relative to samplerate
// normFstop = Lowpass stopband frequency - relative to samplerate
// Coef = pointer to array, where to put the resulting (real) coefficients
// might be nullptr, to estimate the number of coefficients
// return the used/estimated number of coefficients
//
// -------------
// |
// |
// |
// |
// Astop ---------------
// Fpass Fstop
//
////////////////////////////////////////////////////////////////////
int KaiserWindow(int num_taps, float Astop, float normFpass, float normFstop, float *Coef)
{
int n;
float Beta;
float Scale = 1.0f; //+106dB over 1.0 to have high level in wavosaur spectrum analisys out. otherwise set to 1.0
// float Astop = 100.0f; // we want high attenuation 100 dB
//create normalized frequency parameters
float normFcut = (normFstop + normFpass) / 2.0f; //low pass filter 6dB cutoff
//calculate Kaiser-Bessel window shape factor, Beta, from stopband attenuation
if (Astop < 20.96f)
Beta = 0.0f;
else if (Astop >= 50.0f)
Beta = .1102f * (Astop - 8.71f);
else
Beta = .5842f * powf((Astop - 20.96f), 0.4f) + .07886f * (Astop - 20.96f);
/* I used this way but beta is Beta way is better
float Alpha = 3.5;
Beta = K_PI * Alpha;
*/
// now estimate number of filter taps required based on filter specs
int m_NumTaps = (Astop - 8.0) / (2.285*K_2PI*(normFstop - normFpass) ) + 1;
// clamp range of filter taps
if (num_taps < 0 && m_NumTaps > -num_taps)
m_NumTaps = -num_taps;
if (m_NumTaps < 3)
m_NumTaps = 3;
// early exit, if the user only wanted to estimate the number of taps
if (num_taps <= 0 && !Coef)
return m_NumTaps;
if (num_taps > 0)
m_NumTaps = num_taps;
float fCenter = .5f * (float)(m_NumTaps - 1);
float izb = Izero(Beta); //precalculate denominator since is same for all points
for (n = 0; n < m_NumTaps; n++)
{
float x = (float)n - fCenter;
float c;
// create ideal Sinc() LP filter with normFcut
if ((float)n == fCenter) //deal with odd size filter singularity where sin(0)/0==1
c = 2.0f * normFcut;
else
c = (float)sinf(K_2PI * x * normFcut) / (K_PI * x);
//calculate Kaiser window and multiply to get coefficient
x = ((float)n - ((float)m_NumTaps - 1.0f) / 2.0f) / (((float)m_NumTaps - 1.0f) / 2.0f);
Coef[n] = Scale * c * Izero(Beta * sqrtf(1 - (x * x))) / izb;
}
return m_NumTaps;
}

Wyświetl plik

@ -1,3 +0,0 @@
#pragma once
int KaiserWindow(int num_taps, float Astop, float normFpass, float normFstop, float * Coef);

Wyświetl plik

@ -1,28 +0,0 @@
#ifndef LICENSE_H_
#define LICENSE_H_
/*
The MIT License (MIT)
Copyright (c) 2017-2020 Oscar Steila ik1xpv<at>gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.The MIT License (MIT)
The MIT License (MIT)
*/
#endif // LICENSE_H_

Wyświetl plik

@ -1,38 +0,0 @@
Copyright (c) 2020 Dario Mambro ( dario.mambro@gmail.com )
Copyright (c) 2019 Hayati Ayguen ( h_ayguen@web.de )
Copyright (c) 2013 Julien Pommier ( pommier@modartt.com )
Copyright (c) 2004 the University Corporation for Atmospheric
Research ("UCAR"). All rights reserved. Developed by NCAR's
Computational and Information Systems Laboratory, UCAR,
www.cisl.ucar.edu.
Redistribution and use of the Software in source and binary forms,
with or without modification, is permitted provided that the
following conditions are met:
- Neither the names of NCAR's Computational and Information Systems
Laboratory, the University Corporation for Atmospheric Research,
nor the names of its sponsors or contributors may be used to
endorse or promote products derived from this Software without
specific prior written permission.
- Redistributions of source code must retain the above copyright
notices, this list of conditions, and the disclaimer below.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer below in the
documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.

Wyświetl plik

@ -1,733 +0,0 @@
/*
Copyright (c) 2020 Hayati Ayguen ( h_ayguen@web.de )
bench for mixer algorithm/implementations
*/
#include "pf_mixer.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
//#define HAVE_SYS_TIMES
#ifdef HAVE_SYS_TIMES
# include <sys/times.h>
# include <unistd.h>
#endif
#define BENCH_REF_TRIG_FUNC 1
#define BENCH_OUT_OF_PLACE_ALGOS 0
#define BENCH_INPLACE_ALGOS 1
#define SAVE_BY_DEFAULT 1
#define SAVE_LIMIT_MSPS 16
#if 1
#define BENCH_FILE_SHIFT_MATH_CC "A_shift_math_cc.bin"
#define BENCH_FILE_ADD_FAST_CC "C_shift_addfast_cc.bin"
#define BENCH_FILE_ADD_FAST_INP_C "C_shift_addfast_inp_c.bin"
#define BENCH_FILE_UNROLL_INP_C "D_shift_unroll_inp_c.bin"
#define BENCH_FILE_LTD_UNROLL_INP_C "E_shift_limited_unroll_inp_c.bin"
#define BENCH_FILE_LTD_UNROLL_A_SSE_INP_C "F_shift_limited_unroll_A_sse_inp_c.bin"
#define BENCH_FILE_LTD_UNROLL_B_SSE_INP_C "G_shift_limited_unroll_B_sse_inp_c.bin"
#define BENCH_FILE_LTD_UNROLL_C_SSE_INP_C "H_shift_limited_unroll_C_sse_inp_c.bin"
#define BENCH_FILE_REC_OSC_CC ""
#define BENCH_FILE_REC_OSC_INP_C "I_shift_recursive_osc_inp_c.bin"
#define BENCH_FILE_REC_OSC_SSE_INP_C "J_shift_recursive_osc_sse_inp_c.bin"
#else
#define BENCH_FILE_SHIFT_MATH_CC ""
#define BENCH_FILE_ADD_FAST_CC ""
#define BENCH_FILE_ADD_FAST_INP_C ""
#define BENCH_FILE_UNROLL_INP_C ""
#define BENCH_FILE_LTD_UNROLL_INP_C ""
#define BENCH_FILE_LTD_UNROLL_A_SSE_INP_C ""
#define BENCH_FILE_LTD_UNROLL_B_SSE_INP_C ""
#define BENCH_FILE_LTD_UNROLL_C_SSE_INP_C ""
#define BENCH_FILE_REC_OSC_CC ""
#define BENCH_FILE_REC_OSC_INP_C ""
#define BENCH_FILE_REC_OSC_SSE_INP_C ""
#endif
#if defined(HAVE_SYS_TIMES)
static double ttclk = 0.;
static double uclock_sec(int find_start)
{
struct tms t0, t;
if (ttclk == 0.)
{
ttclk = sysconf(_SC_CLK_TCK);
fprintf(stderr, "sysconf(_SC_CLK_TCK) => %f\n", ttclk);
}
times(&t);
if (find_start)
{
t0 = t;
while (t0.tms_utime == t.tms_utime)
times(&t);
}
/* use only the user time of this process - not realtime, which depends on OS-scheduler .. */
return ((double)t.tms_utime) / ttclk;
}
#elif 0
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
double uclock_sec(int find_start)
{
FILETIME a, b, c, d;
if (GetProcessTimes(GetCurrentProcess(), &a, &b, &c, &d) != 0)
{
// Returns total user time.
// Can be tweaked to include kernel times as well.
return
(double)(d.dwLowDateTime |
((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
}
else {
// Handle error
return 0;
}
}
#else
double uclock_sec(int find_start)
{ return (double)clock()/(double)CLOCKS_PER_SEC; }
#endif
void save(complexf * d, int B, int N, const char * fn)
{
if (!fn || !fn[0])
{
if (! SAVE_BY_DEFAULT)
return;
fn = "bench.bin";
}
FILE* f;
fopen_s(&f, fn, "wb");
if (!f) {
fprintf(stderr, "error writing result to %s\n", fn);
return;
}else
printf( "saving to %s\n", fn);
if ( N >= SAVE_LIMIT_MSPS * 1024 * 1024 )
N = SAVE_LIMIT_MSPS * 1024 * 1024;
for (int off = 0; off + B <= N; off += B)
{
fwrite(d+off, sizeof(complexf), B, f);
}
fclose(f);
}
double bench_shift_math_cc(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_math_cc(input+off, output+off, B, -0.0009F, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(output, B, off, BENCH_FILE_SHIFT_MATH_CC);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_table_cc(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
int table_size=65536;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_table_data_t table_data = shift_table_init(table_size);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_table_cc(input+off, output+off, B, -0.0009F, table_data, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(output, B, off, NULL);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_addfast(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_addfast_data_t state = shift_addfast_init(-0.0009F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_addfast_cc(input+off, output+off, B, &state, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(output, B, off, BENCH_FILE_ADD_FAST_CC);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_addfast_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_addfast_data_t state = shift_addfast_init(-0.0009F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_addfast_inp_c(input+off, B, &state, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_ADD_FAST_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_unroll_oop(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_unroll_data_t state = shift_unroll_init(-0.0009F, B);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_unroll_cc(input+off, output+off, B, &state, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(output, B, off, NULL);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_unroll_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_unroll_data_t state = shift_unroll_init(-0.0009F, B);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
phase = shift_unroll_inp_c(input+off, B, &state, phase);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_UNROLL_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_limited_unroll_oop(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_limited_unroll_data_t state = shift_limited_unroll_init(-0.0009F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_limited_unroll_cc(input+off, output+off, B, &state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(output, B, off, NULL);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_limited_unroll_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_limited_unroll_data_t state = shift_limited_unroll_init(-0.0009F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_limited_unroll_inp_c(input+off, B, &state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_LTD_UNROLL_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_limited_unroll_A_sse_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_limited_unroll_A_sse_data_t *state = malloc(sizeof(shift_limited_unroll_A_sse_data_t));
*state = shift_limited_unroll_A_sse_init(-0.0009F, 0.0F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_limited_unroll_A_sse_inp_c(input+off, B, state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_LTD_UNROLL_A_SSE_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_limited_unroll_B_sse_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_limited_unroll_B_sse_data_t *state = malloc(sizeof(shift_limited_unroll_B_sse_data_t));
*state = shift_limited_unroll_B_sse_init(-0.0009F, 0.0F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
//shift_recursive_osc_init(0.0F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_limited_unroll_B_sse_inp_c(input+off, B, state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_LTD_UNROLL_B_SSE_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_limited_unroll_C_sse_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_limited_unroll_C_sse_data_t *state = malloc(sizeof(shift_limited_unroll_C_sse_data_t));
*state = shift_limited_unroll_C_sse_init(-0.0009F, 0.0F);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_limited_unroll_C_sse_inp_c(input+off, B, state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_LTD_UNROLL_C_SSE_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_rec_osc_cc_oop(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
complexf *output = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state, shift_state;
shift_recursive_osc_conf_t gen_conf, shift_conf;
shift_recursive_osc_init(-0.0009F, 0.0F, &shift_conf, &shift_state);
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_recursive_osc_cc(input+off, output+off, B, &shift_conf, &shift_state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_REC_OSC_CC);
save(output, B, off, NULL);
free(input);
free(output);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_rec_osc_cc_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state, shift_state;
shift_recursive_osc_conf_t gen_conf, shift_conf;
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
shift_recursive_osc_init(-0.0009F, 0.0F, &shift_conf, &shift_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_recursive_osc_inp_c(input+off, B, &shift_conf, &shift_state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_REC_OSC_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
double bench_shift_rec_osc_sse_c_inp(int B, int N) {
double t0, t1, tstop, T, nI;
int iter, off;
float phase = 0.0F;
complexf *input = (complexf *)malloc(N * sizeof(complexf));
shift_recursive_osc_t gen_state;
shift_recursive_osc_conf_t gen_conf;
shift_recursive_osc_sse_t *shift_state = malloc(sizeof(shift_recursive_osc_sse_t));
shift_recursive_osc_sse_conf_t shift_conf;
shift_recursive_osc_init(0.001F, 0.0F, &gen_conf, &gen_state);
gen_recursive_osc_c(input, N, &gen_conf, &gen_state);
shift_recursive_osc_sse_init(-0.0009F, 0.0F, &shift_conf, shift_state);
iter = 0;
off = 0;
t0 = uclock_sec(1);
tstop = t0 + 0.5; /* benchmark duration: 500 ms */
do {
// work
shift_recursive_osc_sse_inp_c(input+off, B, &shift_conf, shift_state);
off += B;
++iter;
t1 = uclock_sec(0);
} while ( t1 < tstop && off + B < N );
save(input, B, off, BENCH_FILE_REC_OSC_SSE_INP_C);
free(input);
T = ( t1 - t0 ); /* duration per fft() */
printf("processed %f Msamples in %f ms\n", off * 1E-6, T*1E3);
nI = ((double)iter) * B; /* number of iterations "normalized" to O(N) = N */
return (nI / T); /* normalized iterations per second */
}
int main(int argc, char **argv)
{
double rt;
// process up to 64 MSample (512 MByte) in blocks of 8 kSamples (=64 kByte)
int B = 8 * 1024;
int N = 64 * 1024 * 1024;
int showUsage = 0;
if (argc == 1)
showUsage = 1;
if (1 < argc)
B = atoi(argv[1]);
if (2 < argc)
N = atoi(argv[2]) * 1024 * 1024;
if ( !B || !N || showUsage )
{
fprintf(stderr, "%s [<blockLength in samples> [<total # of MSamples>] ]\n", argv[0]);
if ( !B || !N )
return 0;
}
fprintf(stderr, "processing up to N = %d MSamples with blocke length of %d samples\n",
N / (1024 * 1024), B );
#if BENCH_REF_TRIG_FUNC
printf("\nstarting bench of shift_math_cc (out-of-place) with trig functions ..\n");
rt = bench_shift_math_cc(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
#endif
#if BENCH_OUT_OF_PLACE_ALGOS
printf("starting bench of shift_table_cc (out-of-place) ..\n");
rt = bench_shift_table_cc(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("starting bench of shift_addfast_cc (out-of-place) ..\n");
rt = bench_shift_addfast(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("\nstarting bench of shift_unroll_cc (out-of-place) ..\n");
rt = bench_shift_unroll_oop(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("\nstarting bench of shift_limited_unroll_cc (out-of-place) ..\n");
rt = bench_shift_limited_unroll_oop(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("\nstarting bench of shift_recursive_osc_cc (out-of-place) ..\n");
rt = bench_shift_rec_osc_cc_oop(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
#endif
#if BENCH_INPLACE_ALGOS
printf("starting bench of shift_addfast_inp_c in-place ..\n");
rt = bench_shift_addfast_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("starting bench of shift_unroll_inp_c in-place ..\n");
rt = bench_shift_unroll_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("starting bench of shift_limited_unroll_inp_c in-place ..\n");
rt = bench_shift_limited_unroll_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
if ( have_sse_shift_mixer_impl() )
{
printf("starting bench of shift_limited_unroll_A_sse_inp_c in-place ..\n");
rt = bench_shift_limited_unroll_A_sse_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("starting bench of shift_limited_unroll_B_sse_inp_c in-place ..\n");
rt = bench_shift_limited_unroll_B_sse_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
printf("starting bench of shift_limited_unroll_C_sse_inp_c in-place ..\n");
rt = bench_shift_limited_unroll_C_sse_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
}
printf("starting bench of shift_recursive_osc_cc in-place ..\n");
rt = bench_shift_rec_osc_cc_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
if ( have_sse_shift_mixer_impl() )
{
printf("starting bench of shift_recursive_osc_sse_c in-place ..\n");
rt = bench_shift_rec_osc_sse_c_inp(B, N);
printf(" %f MSamples/sec\n\n", rt * 1E-6);
}
#endif
return 0;
}

Wyświetl plik

@ -1,20 +0,0 @@
#ifndef FMV_H
#if HAVE_FUNC_ATTRIBUTE_IFUNC
#if defined(__has_attribute)
#if __has_attribute(target_clones)
#if defined(__x86_64)
// see https://gcc.gnu.org/wiki/FunctionMultiVersioning
#define PF_TARGET_CLONES __attribute__((target_clones("avx","sse4.2","sse3","sse2","sse","default")))
#define HAVE_PF_TARGET_CLONES 1
#endif
#endif
#endif
#endif
#ifndef PF_TARGET_CLONES
#define PF_TARGET_CLONES
#endif
#endif

Wyświetl plik

@ -1,283 +0,0 @@
/*
This software is part of pffft/pfdsp, a set of simple DSP routines.
Copyright (c) 2014, Andras Retzler <randras@sdr.hu>
Copyright (c) 2020 Hayati Ayguen <h_ayguen@web.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PF_MIXER_H_
#define _PF_MIXER_H_
#include <stdio.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
_____ _
/ ____| | |
| | ___ _ __ ___ _ __ | | _____ __
| | / _ \| '_ ` _ \| '_ \| |/ _ \ \/ /
| |___| (_) | | | | | | |_) | | __/> <
\_____\___/|_| |_| |_| .__/|_|\___/_/\_\
| |
|_|
*/
typedef struct complexf_s { float i; float q; } complexf;
// =================================================================================
int have_sse_shift_mixer_impl();
/*********************************************************************/
/**************/
/*** ALGO A ***/
/**************/
float shift_math_cc(complexf *input, complexf* output, int input_size, float rate, float starting_phase);
/*********************************************************************/
/**************/
/*** ALGO B ***/
/**************/
typedef struct shift_table_data_s
{
float* table;
int table_size;
} shift_table_data_t;
void shift_table_deinit(shift_table_data_t table_data);
shift_table_data_t shift_table_init(int table_size);
float shift_table_cc(complexf* input, complexf* output, int input_size, float rate, shift_table_data_t table_data, float starting_phase);
/*********************************************************************/
/**************/
/*** ALGO C ***/
/**************/
typedef struct shift_addfast_data_s
{
float dsin[4];
float dcos[4];
float phase_increment;
} shift_addfast_data_t;
shift_addfast_data_t shift_addfast_init(float rate);
float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase);
float shift_addfast_inp_c(complexf *in_out, int N_cplx, shift_addfast_data_t* d, float starting_phase);
/*********************************************************************/
/**************/
/*** ALGO D ***/
/**************/
typedef struct shift_unroll_data_s
{
float* dsin;
float* dcos;
float phase_increment;
int size;
} shift_unroll_data_t;
shift_unroll_data_t shift_unroll_init(float rate, int size);
void shift_unroll_deinit(shift_unroll_data_t* d);
float shift_unroll_cc(complexf *input, complexf* output, int size, shift_unroll_data_t* d, float starting_phase);
float shift_unroll_inp_c(complexf* in_out, int size, shift_unroll_data_t* d, float starting_phase);
/*********************************************************************/
/**************/
/*** ALGO E ***/
/**************/
/* similar to shift_unroll_cc() - but, have fixed and limited precalc size
* idea: smaller cache usage by table
* size must be multiple of CSDR_SHIFT_LIMITED_SIMD (= 4)
*/
#define PF_SHIFT_LIMITED_UNROLL_SIZE 128
#define PF_SHIFT_LIMITED_SIMD_SZ 4
typedef struct shift_limited_unroll_data_s
{
float dcos[PF_SHIFT_LIMITED_UNROLL_SIZE];
float dsin[PF_SHIFT_LIMITED_UNROLL_SIZE];
complexf complex_phase;
float phase_increment;
} shift_limited_unroll_data_t;
shift_limited_unroll_data_t shift_limited_unroll_init(float rate);
/* size must be multiple of PF_SHIFT_LIMITED_SIMD_SZ */
/* starting_phase for next call is kept internal in state */
void shift_limited_unroll_cc(const complexf *input, complexf* output, int size, shift_limited_unroll_data_t* d);
void shift_limited_unroll_inp_c(complexf* in_out, int size, shift_limited_unroll_data_t* d);
/*********************************************************************/
/**************/
/*** ALGO F ***/
/**************/
typedef struct shift_limited_unroll_A_sse_data_s
{
/* small/limited trig table */
float dcos[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ];
float dsin[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ];
/* 4 times complex phase */
float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ];
float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ];
/* N_cplx_per_block times increment - for future parallel variants */
float dcos_blk;
float dsin_blk;
/* */
float phase_increment;
} shift_limited_unroll_A_sse_data_t;
shift_limited_unroll_A_sse_data_t shift_limited_unroll_A_sse_init(float relative_freq, float phase_start_rad);
void shift_limited_unroll_A_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_A_sse_data_t* d);
/*********************************************************************/
/**************/
/*** ALGO G ***/
/**************/
typedef struct shift_limited_unroll_B_sse_data_s
{
/* small/limited trig table */
float dtrig[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ];
/* 4 times complex phase */
float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ];
float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ];
/* N_cplx_per_block times increment - for future parallel variants */
float dcos_blk;
float dsin_blk;
/* */
float phase_increment;
} shift_limited_unroll_B_sse_data_t;
shift_limited_unroll_B_sse_data_t shift_limited_unroll_B_sse_init(float relative_freq, float phase_start_rad);
void shift_limited_unroll_B_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_B_sse_data_t* d);
/*********************************************************************/
/**************/
/*** ALGO H ***/
/**************/
typedef struct shift_limited_unroll_C_sse_data_s
{
/* small/limited trig table - interleaved: 4 cos, 4 sin, 4 cos, .. */
float dinterl_trig[2*(PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ)];
/* 4 times complex phase */
float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ];
float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ];
/* N_cplx_per_block times increment - for future parallel variants */
float dcos_blk;
float dsin_blk;
/* */
float phase_increment;
} shift_limited_unroll_C_sse_data_t;
shift_limited_unroll_C_sse_data_t shift_limited_unroll_C_sse_init(float relative_freq, float phase_start_rad);
void shift_limited_unroll_C_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_C_sse_data_t* d);
/*********************************************************************/
/**************/
/*** ALGO I ***/
/**************/
/* Recursive Quadrature Oscillator functions "recursive_osc"
* see https://www.vicanek.de/articles/QuadOsc.pdf
*/
#define PF_SHIFT_RECURSIVE_SIMD_SZ 8
typedef struct shift_recursive_osc_s
{
float u_cos[PF_SHIFT_RECURSIVE_SIMD_SZ];
float v_sin[PF_SHIFT_RECURSIVE_SIMD_SZ];
} shift_recursive_osc_t;
typedef struct shift_recursive_osc_conf_s
{
float k1;
float k2;
} shift_recursive_osc_conf_t;
void shift_recursive_osc_init(float rate, float starting_phase, shift_recursive_osc_conf_t *conf, shift_recursive_osc_t *state);
void shift_recursive_osc_update_rate(float rate, shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state);
/* size must be multiple of PF_SHIFT_LIMITED_SIMD_SZ */
/* starting_phase for next call is kept internal in state */
void shift_recursive_osc_cc(const complexf *input, complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state);
void shift_recursive_osc_inp_c(complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state);
void gen_recursive_osc_c(complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state);
/*********************************************************************/
/**************/
/*** ALGO J ***/
/**************/
#define PF_SHIFT_RECURSIVE_SIMD_SSE_SZ 4
typedef struct shift_recursive_osc_sse_s
{
float u_cos[PF_SHIFT_RECURSIVE_SIMD_SSE_SZ];
float v_sin[PF_SHIFT_RECURSIVE_SIMD_SSE_SZ];
} shift_recursive_osc_sse_t;
typedef struct shift_recursive_osc_sse_conf_s
{
float k1;
float k2;
} shift_recursive_osc_sse_conf_t;
void shift_recursive_osc_sse_init(float rate, float starting_phase, shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t *state);
void shift_recursive_osc_sse_update_rate(float rate, shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t* state);
void shift_recursive_osc_sse_inp_c(complexf* in_out, int N_cplx, const shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t* state_ext);
#ifdef __cplusplus
}
#endif
#endif

Wyświetl plik

@ -1,50 +0,0 @@
#ifndef R2IQ_H
#define R2IQ_H
#include "license.txt"
#define NDECIDX 7 //number of srate
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include "dsp/ringbuffer.h"
struct r2iqThreadArg;
class r2iqControlClass {
public:
r2iqControlClass();
virtual ~r2iqControlClass() {}
int getRatio() {return mratio [mdecimation];}
void updateRand(bool v) { this->randADC = v; }
bool getRand() const { return this->randADC; }
void setSideband(bool lsb) { this->sideband = lsb; }
bool getSideband() const { return this->sideband; }
void setDecimate(int dec) {this->mdecimation = dec; }
virtual void Init(float gain, ringbuffer<int16_t>* input, ringbuffer<float>* obuffers) {}
virtual void TurnOn() { this->r2iqOn = true; }
virtual void TurnOff(void) { this->r2iqOn = false; }
virtual bool IsOn(void) { return this->r2iqOn; }
virtual void DataReady(void) {}
virtual float setFreqOffset(float offset) { return 0; };
protected:
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 randADC; // randomized ADC output
bool sideband;
};
#endif

Wyświetl plik

@ -1,145 +0,0 @@
#include "RadioHandler.h"
#define R820T_FREQ (32000000) // R820T reference frequency
#define R820T2_IF_CARRIER (4570000)
const float BBRF103Radio::steps[BBRF103Radio::step_size] = {
0.0f, 0.9f, 1.4f, 2.7f, 3.7f, 7.7f, 8.7f, 12.5f, 14.4f, 15.7f,
16.6f, 19.7f, 20.7f, 22.9f, 25.4f, 28.0f, 29.7f, 32.8f,
33.8f, 36.4f, 37.2f, 38.6f, 40.2f, 42.1f, 43.4f, 43.9f,
44.5f, 48.0f, 49.6f
};
const float BBRF103Radio::if_steps[BBRF103Radio::if_step_size] = {
-4.7f, -2.1f, 0.5f, 3.5f, 7.7f, 11.2f, 13.6f, 14.9f, 16.3f, 19.5f, 23.1f, 26.5f, 30.0f, 33.7f, 37.2f, 40.8f
};
const float BBRF103Radio::hfsteps[3] = {
-20.0f, -10.0f, 0.0f
};
BBRF103Radio::BBRF103Radio(fx3class* fx3)
: RadioHardware(fx3)
{
}
void BBRF103Radio::Initialize(uint32_t adc_rate)
{
this->SampleRate = adc_rate;
Fx3->Control(STARTADC, adc_rate);
}
rf_mode BBRF103Radio::PrepareLo(uint64_t freq)
{
if (freq < 10 * 1000) return NOMODE;
if (freq > 1750 * 1000 * 1000) return NOMODE;
if ( freq >= this->SampleRate / 2)
return VHFMODE;
else
return HFMODE;
}
bool BBRF103Radio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
{
// switch to VHF Attenna
FX3UnsetGPIO(ATT_SEL0 | ATT_SEL1);
// Initialize Tuner
return Fx3->Control(TUNERINIT, (uint32_t)R820T_FREQ);
}
else if (mode == HFMODE ) // (mode == HFMODE || mode == VLFMODE) no more VLFMODE
{
// Stop Tuner
Fx3->Control(TUNERSTDBY);
// switch to HF Attenna
return FX3SetGPIO(ATT_SEL0 | ATT_SEL1);
}
return false;
}
bool BBRF103Radio::UpdateattRF(int att)
{
if (gpios & (ATT_SEL0 | ATT_SEL1)) {
// this is in HF mode
if (att > 2) att = 2;
if (att < 0) att = 0;
switch (att)
{
case 1: //11
gpios |= ATT_SEL0 | ATT_SEL1;
break;
case 0: //01
gpios |= ATT_SEL0;
gpios &= ~ATT_SEL1;
break;
case 2: //10
default:
gpios |= ATT_SEL1;
gpios &= ~ATT_SEL0;
break;
}
return Fx3->Control(GPIOFX3, gpios);
}
else {
uint16_t index = att;
// this is in VHF mode
return Fx3->SetArgument(R82XX_ATTENUATOR, index);
}
}
uint64_t BBRF103Radio::TuneLo(uint64_t freq)
{
if (gpios & (ATT_SEL0 | ATT_SEL1)) {
// this is in HF mode
return 0;
}
else {
// this is in VHF mode
Fx3->Control(TUNERTUNE, freq);
return freq - R820T2_IF_CARRIER;
}
}
int BBRF103Radio::getRFSteps(const float** steps )
{
if (gpios & (ATT_SEL0 | ATT_SEL1)) {
*steps = this->hfsteps;
return 3;
}
else
{
*steps = this->steps;
return step_size;
}
}
int BBRF103Radio::getIFSteps(const float** steps )
{
if (gpios & (ATT_SEL0 | ATT_SEL1)) {
return 0;
}
else
{
*steps = this->if_steps;
return if_step_size;
}
}
bool BBRF103Radio::UpdateGainIF(int attIndex)
{
if (gpios & (ATT_SEL0 | ATT_SEL1)) {
// this is in HF mode
return false;
}
else {
// this is in VHF mode
return Fx3->SetArgument(R82XX_VGA, (uint16_t)attIndex);
}
}

Wyświetl plik

@ -1,50 +0,0 @@
#include "RadioHandler.h"
HF103Radio::HF103Radio(fx3class* fx3)
: RadioHardware(fx3)
{
// initialize steps
for (uint8_t i = 0 ; i < step_size; i++) {
this->steps[step_size - i - 1] = -(
((i & 0x01) != 0) * 0.5f +
((i & 0x02) != 0) * 1.0f +
((i & 0x04) != 0) * 2.0f +
((i & 0x08) != 0) * 4.0f +
((i & 0x010) != 0) * 8.0f +
((i & 0x020) != 0) * 16.0f
);
}
}
rf_mode HF103Radio::PrepareLo(uint64_t freq)
{
if (freq > 32 * 1000 * 1000) return NOMODE;
return HFMODE;
}
bool HF103Radio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
return false;
return true;
}
bool HF103Radio::UpdateattRF(int att)
{
if (att > step_size - 1) att = step_size - 1;
if (att < 0) att = 0;
uint8_t d = step_size - att - 1;
DbgPrintf("UpdateattRF %f \n", this->steps[att]);
return Fx3->SetArgument(DAT31_ATT, d);
}
int HF103Radio::getRFSteps(const float** steps )
{
*steps = this->steps;
return step_size;
}

Wyświetl plik

@ -1,178 +0,0 @@
#include "RadioHandler.h"
#define R828D_FREQ (16000000) // R820T reference frequency
#define R828D_IF_CARRIER (4570000)
#define HIGH_MODE 0x80
#define LOW_MODE 0x00
#define GAIN_SWEET_POINT 18
#define HIGH_GAIN_RATIO (0.409f)
#define LOW_GAIN_RATIO (0.059f)
#define MODE HIGH_MODE
const float RX888R2Radio::vhf_rf_steps[RX888R2Radio::vhf_rf_step_size] = {
0.0f, 0.9f, 1.4f, 2.7f, 3.7f, 7.7f, 8.7f, 12.5f, 14.4f, 15.7f,
16.6f, 19.7f, 20.7f, 22.9f, 25.4f, 28.0f, 29.7f, 32.8f,
33.8f, 36.4f, 37.2f, 38.6f, 40.2f, 42.1f, 43.4f, 43.9f,
44.5f, 48.0f, 49.6f};
const float RX888R2Radio::vhf_if_steps[RX888R2Radio::vhf_if_step_size] = {
-4.7f, -2.1f, 0.5f, 3.5f, 7.7f, 11.2f, 13.6f, 14.9f, 16.3f, 19.5f, 23.1f, 26.5f, 30.0f, 33.7f, 37.2f, 40.8f};
RX888R2Radio::RX888R2Radio(fx3class *fx3)
: RadioHardware(fx3)
{
for (uint8_t i = 0; i < hf_rf_step_size; i++)
{
this->hf_rf_steps[hf_rf_step_size - i - 1] = -(
((i & 0x01) != 0) * 0.5f +
((i & 0x02) != 0) * 1.0f +
((i & 0x04) != 0) * 2.0f +
((i & 0x08) != 0) * 4.0f +
((i & 0x010) != 0) * 8.0f +
((i & 0x020) != 0) * 16.0f);
}
for (uint8_t i = 0; i < hf_if_step_size; i++)
{
if (i > GAIN_SWEET_POINT)
this->hf_if_steps[i] = 20.0f * log10f(HIGH_GAIN_RATIO * (i - GAIN_SWEET_POINT + 3));
else
this->hf_if_steps[i] = 20.0f * log10f(LOW_GAIN_RATIO * (i + 1));
}
}
void RX888R2Radio::Initialize(uint32_t adc_rate)
{
SampleRate = adc_rate;
Fx3->Control(STARTADC, adc_rate);
}
rf_mode RX888R2Radio::PrepareLo(uint64_t freq)
{
if (freq < 10 * 1000) return NOMODE;
if (freq > 1750 * 1000 * 1000) return NOMODE;
if ( freq >= this->SampleRate / 2)
return VHFMODE;
else
return HFMODE;
}
bool RX888R2Radio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
{
// disable HF by set max ATT
UpdateattRF(0); // max att 0 -> -31.5 dB
// switch to VHF Attenna
FX3SetGPIO(VHF_EN);
// high gain, 0db
uint8_t gain = 0x80 | 3;
Fx3->SetArgument(AD8340_VGA, gain);
// Enable Tuner reference clock
uint32_t ref = R828D_FREQ;
return Fx3->Control(TUNERINIT, ref); // Initialize Tuner
}
else if (mode == HFMODE)
{
Fx3->Control(TUNERSTDBY); // Stop Tuner
return FX3UnsetGPIO(VHF_EN); // switch to HF Attenna
}
return false;
}
bool RX888R2Radio::UpdateattRF(int att)
{
if (!(gpios & VHF_EN))
{
// hf mode
if (att > hf_rf_step_size - 1)
att = hf_rf_step_size - 1;
if (att < 0)
att = 0;
uint8_t d = hf_rf_step_size - att - 1;
DbgPrintf("UpdateattRF %f \n", this->hf_rf_steps[att]);
return Fx3->SetArgument(DAT31_ATT, d);
}
else
{
uint16_t index = att;
// this is in VHF mode
return Fx3->SetArgument(R82XX_ATTENUATOR, index);
}
}
uint64_t RX888R2Radio::TuneLo(uint64_t freq)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
return 0;
}
else
{
// this is in VHF mode
Fx3->Control(TUNERTUNE, freq);
return freq - R828D_IF_CARRIER;
}
}
int RX888R2Radio::getRFSteps(const float **steps)
{
if (!(gpios & VHF_EN))
{
// hf mode
*steps = this->hf_rf_steps;
return hf_rf_step_size;
}
else
{
*steps = this->vhf_rf_steps;
return vhf_rf_step_size;
}
}
int RX888R2Radio::getIFSteps(const float **steps)
{
if (!(gpios & VHF_EN))
{
*steps = this->hf_if_steps;
return hf_if_step_size;
}
else
{
*steps = this->vhf_if_steps;
return vhf_if_step_size;
}
}
bool RX888R2Radio::UpdateGainIF(int gain_index)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
uint8_t gain;
if (gain_index > GAIN_SWEET_POINT)
gain = HIGH_MODE | (gain_index - GAIN_SWEET_POINT + 3);
else
gain = LOW_MODE | (gain_index + 1);
DbgPrintf("UpdateGainIF %d \n", gain);
return Fx3->SetArgument(AD8340_VGA, gain);
}
else
{
// this is in VHF mode
return Fx3->SetArgument(R82XX_VGA, (uint16_t)gain_index);
}
}

Wyświetl plik

@ -1,210 +0,0 @@
#include "RadioHandler.h"
#define REFCLK_FREQ (27000000) // R820T reference frequency
#define IF_FREQ (20000000)
#define HIGH_MODE 0x80
#define LOW_MODE 0x00
#define GAIN_SWEET_POINT 18
#define HIGH_GAIN_RATIO (0.409f)
#define LOW_GAIN_RATIO (0.059f)
#define MODE HIGH_MODE
const float RX888R3Radio::vhf_rf_steps[RX888R3Radio::vhf_rf_step_size] = {
0.0f, 0.9f, 1.4f, 2.7f, 3.7f, 7.7f, 8.7f, 12.5f, 14.4f, 15.7f,
16.6f, 19.7f, 20.7f, 22.9f, 25.4f, 28.0f, 29.7f, 32.8f,
33.8f, 36.4f, 37.2f, 38.6f, 40.2f, 42.1f, 43.4f, 43.9f,
44.5f, 48.0f, 49.6f};
const float RX888R3Radio::vhf_if_steps[RX888R3Radio::vhf_if_step_size] = {
-4.7f, -2.1f, 0.5f, 3.5f, 7.7f, 11.2f, 13.6f, 14.9f, 16.3f, 19.5f, 23.1f, 26.5f, 30.0f, 33.7f, 37.2f, 40.8f};
RX888R3Radio::RX888R3Radio(fx3class *fx3)
: RadioHardware(fx3)
{
for (uint8_t i = 0; i < hf_rf_step_size; i++)
{
this->hf_rf_steps[hf_rf_step_size - i - 1] = -(
((i & 0x01) != 0) * 0.5f +
((i & 0x02) != 0) * 1.0f +
((i & 0x04) != 0) * 2.0f +
((i & 0x08) != 0) * 4.0f +
((i & 0x010) != 0) * 8.0f +
((i & 0x020) != 0) * 16.0f);
}
for (uint8_t i = 0; i < hf_if_step_size; i++)
{
if (i > GAIN_SWEET_POINT)
this->hf_if_steps[i] = 20.0f * log10f(HIGH_GAIN_RATIO * (i - GAIN_SWEET_POINT + 3));
else
this->hf_if_steps[i] = 20.0f * log10f(LOW_GAIN_RATIO * (i + 1));
}
}
void RX888R3Radio::Initialize(uint32_t adc_rate)
{
SampleRate = adc_rate;
Fx3->Control(STARTADC, adc_rate);
}
rf_mode RX888R3Radio::PrepareLo(uint64_t freq)
{
if (freq < 10 * 1000) return NOMODE;
if (freq > 2150ll * 1000 * 1000) return NOMODE;
if ( freq >= 220 * 1000 * 1000)
return VHFMODE;
else
return HFMODE;
}
bool RX888R3Radio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
{
// disable HF by set max ATT
UpdateattRF(0); // max att 0 -> -31.5 dB
// switch to VHF Attenna
FX3SetGPIO(VHF_EN);
// high gain, 0db
uint8_t gain = 0x80 | 3;
Fx3->SetArgument(AD8340_VGA, gain);
// Enable Tuner reference clock
uint32_t ref = REFCLK_FREQ;
return Fx3->Control(TUNERINIT, ref); // Initialize Tuner
}
else if (mode == HFMODE)
{
Fx3->Control(TUNERSTDBY); // Stop Tuner
return FX3UnsetGPIO(VHF_EN); // switch to HF Attenna
}
return false;
}
bool RX888R3Radio::UpdateattRF(int att)
{
if (!(gpios & VHF_EN))
{
// hf mode
if (att > hf_rf_step_size - 1)
att = hf_rf_step_size - 1;
if (att < 0)
att = 0;
uint8_t d = hf_rf_step_size - att - 1;
DbgPrintf("UpdateattRF %f \n", this->hf_rf_steps[att]);
return Fx3->SetArgument(DAT31_ATT, d);
}
else
{
// uint16_t index = att;
// this is in VHF mode
// return Fx3->SetArgument(R82XX_ATTENUATOR, index);
return false;
}
}
#define M(x) ((x)*1000000)
uint64_t RX888R3Radio::TuneLo(uint64_t freq)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
// set bpf
int sel;
// set preselector
if (freq > M(64) && freq <= M(128))
sel = 0b001; // FM undersampling
else if (SampleRate < M(32))
sel = 0b101;
else
sel = 0b011;
Fx3->SetArgument(PRESELECTOR, sel);
if (freq < M(64))
return 0;
else if (freq < M(128))
return M(64);
else if (freq < M(192))
return M(64 * 2);
else if (freq < M(256))
return M(64 * 3);
return 0;
}
else
{
// this is in VHF mode
uint64_t targetVCO = freq + IF_FREQ;
uint32_t hardwareVCO = targetVCO / 1000000; // convert to MHz
int offset = targetVCO % 1000000;
DbgPrintf("Target VCO = %luHZ, hardware VCO= %dMHX, Actual IF = %dHZ\n", freq + IF_FREQ, hardwareVCO, IF_FREQ - offset);
Fx3->Control(TUNERTUNE, hardwareVCO);
return freq - (IF_FREQ - offset);
}
}
int RX888R3Radio::getRFSteps(const float **steps)
{
if (!(gpios & VHF_EN))
{
// hf mode
*steps = this->hf_rf_steps;
return hf_rf_step_size;
}
else
{
*steps = this->vhf_rf_steps;
return vhf_rf_step_size;
}
}
int RX888R3Radio::getIFSteps(const float **steps)
{
if (!(gpios & VHF_EN))
{
*steps = this->hf_if_steps;
return hf_if_step_size;
}
else
{
*steps = this->vhf_if_steps;
return vhf_if_step_size;
}
}
bool RX888R3Radio::UpdateGainIF(int gain_index)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
uint8_t gain;
if (gain_index > GAIN_SWEET_POINT)
gain = HIGH_MODE | (gain_index - GAIN_SWEET_POINT + 3);
else
gain = LOW_MODE | (gain_index + 1);
DbgPrintf("UpdateGainIF %d \n", gain);
return Fx3->SetArgument(AD8340_VGA, gain);
}
else
{
// this is in VHF mode
// return Fx3->SetArgument(R82XX_VGA, (uint16_t)gain_index);
return false;
}
}

Wyświetl plik

@ -1 +0,0 @@
#include "RadioHandler.h"

Wyświetl plik

@ -1,118 +0,0 @@
#include "RadioHandler.h"
#define ADC_FREQ (128u*1000*1000)
#define IF_FREQ (ADC_FREQ / 4)
#define HIGH_MODE 0x80
#define LOW_MODE 0x00
#define MODE HIGH_MODE
RX999Radio::RX999Radio(fx3class *fx3)
: RadioHardware(fx3)
{
// high mode gain = 0.409, start=-30
// low mode gain = 0.059, start = -30
#if (MODE == HIGH_MODE)
float ratio = 0.409f;
#else
float ratio = 0.059f;
#endif
for (uint8_t i = 0; i < if_step_size; i++)
{
this->if_steps[i] = -30.0f + ratio * (i + 1);
}
}
void RX999Radio::Initialize(uint32_t adc_rate)
{
SampleRate = adc_rate;
Fx3->Control(STARTADC, adc_rate);
}
rf_mode RX999Radio::PrepareLo(uint64_t freq)
{
if (freq < 10 * 1000) return NOMODE;
if (freq > 6000ll * 1000 * 1000) return NOMODE;
if ( freq >= this->SampleRate / 2)
return VHFMODE;
else
return HFMODE;
}
bool RX999Radio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
{
// switch to VHF Attenna
FX3SetGPIO(VHF_EN);
// Initialize VCO
// Initialize Mixer
return Fx3->Control(TUNERINIT, (uint32_t)0);
}
else if (mode == HFMODE)
{
Fx3->Control(TUNERSTDBY);
return FX3UnsetGPIO(VHF_EN); // switch to HF Attenna
}
return false;
}
bool RX999Radio::UpdateattRF(int att)
{
return false;
}
uint64_t RX999Radio::TuneLo(uint64_t freq)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
return 0;
}
else
{
int sel;
// set preselector
if (freq <= 120*1000*1000) sel = 0b111;
else if (freq <= 250*1000*1000) sel = 0b101;
else if (freq <= 300*1000*1000) sel = 0b110;
else if (freq <= 380*1000*1000) sel = 0b100;
else if (freq <= 500*1000*1000) sel = 0b000;
else if (freq <= 1000ll*1000*1000) sel = 0b010;
else if (freq <= 2000ll*1000*1000) sel = 0b001;
else sel = 0b011;
Fx3->Control(TUNERTUNE, freq + IF_FREQ);
Fx3->SetArgument(PRESELECTOR, sel);
// Set VCXO
return freq - IF_FREQ;
}
}
int RX999Radio::getRFSteps(const float **steps)
{
return 0;
}
int RX999Radio::getIFSteps(const float **steps)
{
*steps = this->if_steps;
return if_step_size;
}
bool RX999Radio::UpdateGainIF(int gain_index)
{
uint8_t gain = MODE | (gain_index + 1);
DbgPrintf("UpdateGainIF %d \n", gain);
return Fx3->SetArgument(AD8340_VGA, gain);
}

Wyświetl plik

@ -1,120 +0,0 @@
#include "RadioHandler.h"
#define ADC_FREQ (64u*1000*1000)
#define IF_FREQ (ADC_FREQ / 4)
#define HIGH_MODE 0x80
#define LOW_MODE 0x00
#define MODE HIGH_MODE
RXLucyRadio::RXLucyRadio(fx3class *fx3)
: RadioHardware(fx3)
{
// initialize steps
for (uint8_t i = 0; i < if_step_size; i++) {
this->if_steps[if_step_size - i - 1] = -(
((i & 0x01) != 0) * 0.5f +
((i & 0x02) != 0) * 1.0f +
((i & 0x04) != 0) * 2.0f +
((i & 0x08) != 0) * 4.0f +
((i & 0x010) != 0) * 8.0f +
((i & 0x020) != 0) * 16.0f
);
}
for (uint8_t i = 0; i < step_size; i++)
{
this->steps[step_size - i - 1] = -1.0f * i;
}
}
void RXLucyRadio::Initialize(uint32_t adc_rate)
{
SampleRate = adc_rate;
Fx3->Control(STARTADC, adc_rate);
}
rf_mode RXLucyRadio::PrepareLo(uint64_t freq)
{
if (freq < 35000ll * 1000) return NOMODE;
if (freq > 6000ll * 1000 * 1000) return NOMODE;
if ( freq >= this->SampleRate / 2)
return VHFMODE;
else
return HFMODE;
}
bool RXLucyRadio::UpdateattRF(int att)
{
if (att > step_size - 1) att = step_size - 1;
if (att < 0) att = 0;
uint8_t d = step_size - att - 1;
DbgPrintf("UpdateattRF %f \n", this->steps[att]);
return Fx3->SetArgument(VHF_ATTENUATOR, d);
}
bool RXLucyRadio::UpdateGainIF(int att) //HF103 now
{
if (att > if_step_size - 1) att = if_step_size - 1;
if (att < 0) att = 0;
uint8_t d = if_step_size - att - 1;
DbgPrintf("UpdateattRF %f \n", this->if_steps[att]);
return Fx3->SetArgument(DAT31_ATT, d);
}
uint64_t RXLucyRadio::TuneLo(uint64_t freq)
{
if (!(gpios & VHF_EN))
{
// this is in HF mode
return 0;
}
else
{
Fx3->Control(TUNERTUNE, freq + IF_FREQ);
// Set VCXO
return freq - IF_FREQ;
}
}
bool RXLucyRadio::UpdatemodeRF(rf_mode mode)
{
if (mode == VHFMODE)
{
// switch to VHF Attenna
FX3SetGPIO(VHF_EN);
// Initialize VCO
// Initialize Mixer
return Fx3->Control(TUNERINIT, (uint32_t)0);
}
else if (mode == HFMODE)
{
Fx3->Control(TUNERSTDBY);
return FX3UnsetGPIO(VHF_EN); // switch to HF Attenna
}
return false;
}
int RXLucyRadio::getRFSteps(const float **steps)
{
*steps = this->steps;
return step_size;
}
int RXLucyRadio::getIFSteps(const float** steps)
{
*steps = this->if_steps;
return if_step_size;
}

Wyświetl plik

@ -1,22 +0,0 @@
#include "RadioHandler.h"
bool RadioHardware::FX3SetGPIO(uint32_t mask)
{
gpios |= mask;
return Fx3->Control(GPIOFX3, gpios);
}
bool RadioHardware::FX3UnsetGPIO(uint32_t mask)
{
gpios &= ~mask;
return Fx3->Control(GPIOFX3, gpios);
}
RadioHardware::~RadioHardware()
{
if (Fx3) {
FX3SetGPIO(SHDWN);
}
}

Wyświetl plik

@ -1,8 +0,0 @@
#include "license.txt"
#include "sddc_config.h"
bool saveADCsamplesflag = false;
uint32_t adcnominalfreq = DEFAULT_ADC_FREQ;
uint32_t MIN_ADC_FREQ = 50000000; // ADC sampling frequency minimum
uint32_t MAX_ADC_FREQ = 140000000; // ADC sampling frequency minimum
uint32_t N2_BANDSWITCH = 80000000; // threshold 5 or 6 SR bandwidths

Wyświetl plik

@ -1,94 +0,0 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "license.txt"
#include "../Interface.h"
#include <math.h> // atan => PI
#include <thread>
#include <mutex>
#include <condition_variable>
//#define _DEBUG // defined in VS configuration
#ifdef __cplusplus
inline void null_func(const char *format, ...) { }
#define DbgEmpty null_func
#else
#define DbgEmpty { }
#endif
// macro to call callback function with just status extHWstatusT
#define EXTIO_STATUS_CHANGE( CB, STATUS ) \
do { \
SendMessage(h_dialog, WM_USER + 1, STATUS, 0); \
if (CB) { \
DbgPrintf("<==CALLBACK: %s\n", #STATUS); \
CB( -1, STATUS, 0, NULL );\
}\
}while(0)
#ifdef VERBOSE_DEBUG
#define EnterFunction() \
DbgPrintf("==>%s\n", __FUNCDNAME__)
#define EnterFunction1(v1) \
DbgPrintf("==>%s(%d)\n", __FUNCDNAME__, (v1))
#else
#define EnterFunction()
#define EnterFunction1(v1)
#endif
#ifdef _DEBUG
#define DbgPrintf (printf)
#else
#define DbgPrintf DbgEmpty
#endif
#define VERSION (1.2) // Dll version number x.xx
#define SWVERSION "1.2.1"
#define SETTINGS_IDENTIFIER "sddc_1.06"
#define SWNAME "ExtIO_sddc.dll"
#define QUEUE_SIZE 32
#define WIDEFFTN // test FFTN 8192
#define FFTN_R_ADC (8192) // FFTN used for ADC real stream DDC tested at 2048, 8192, 32768, 131072
// GAINFACTORS to be adjusted with lab reference source measured with HDSDR Smeter rms mode
#define BBRF103_GAINFACTOR (7.8e-8f) // BBRF103
#define HF103_GAINFACTOR (1.14e-8f) // HF103
#define RX888_GAINFACTOR (0.695e-8f) // RX888
#define RX888mk2_GAINFACTOR (1.08e-8f) // RX888mk2
enum rf_mode { NOMODE = 0, HFMODE = 0x1, VHFMODE = 0x2 };
#define HF_HIGH (32000000) // 32M
#define MW_HIGH ( 2000000)
#define EXT_BLOCKLEN 512 * 64 /* 32768 only multiples of 512 */
#define RFDDCNAME ("NVIA L768M256")
#define RFDDCVER ("v 1.0")
// URL definitions
#define URL1B "16bit SDR Receiver"
#define URL1 "<a>http://www.hdsdr.de/</a>"
#define URL_HDSR "http://www.hdsdr.de/"
#define URL_HDSDRA "<a>http://www.hdsdr.de/</a>"
extern bool saveADCsamplesflag;
extern uint32_t adcnominalfreq;
const uint32_t transferSize = 131072;
const uint32_t transferSamples = 131072 / sizeof(int16_t);
const uint32_t DEFAULT_ADC_FREQ = 64000000; // ADC sampling frequency
const uint32_t DEFAULT_TRANSFERS_PER_SEC = DEFAULT_ADC_FREQ / transferSamples;
extern uint32_t MIN_ADC_FREQ; // ADC sampling frequency minimum
extern uint32_t MAX_ADC_FREQ; // ADC sampling frequency minimum
extern uint32_t N2_BANDSWITCH; // threshold 5 or 6 SR bandwidths
#endif // _CONFIG_H_

Wyświetl plik

@ -1,44 +0,0 @@
/*
HWSDRtable.h v1.2
Hardware detection of BBRF103 family SDRs
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| SDR | MODEL | GPIO | GPIO | GPIO | GPIO | GPIO | GPIO | GPIO | GPIO | USED BY |
| | # | 33 | 36 | 45 | 50 | 51 | 52 | 53 | 54 | |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| BBRF103 | 0x01 | - | - | - | pd* | - | - | - | LED | Oscar Steila |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| HF103 | 0x02 | - | - | - | - | pd* | - | - | LED | Oscar Steila |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| RX888 | 0x03 | - | - | pd | - | - | - | - | - | Justin Peng / Howard Su |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| RX888 r2 | 0x04 | - | pd | - | - | - | - | - | - | Justin Peng / Howard Su |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| RX999 | 0x05 | pd | - | - | - | - | - | - | - | Justin Peng / Howard Su |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| LUCY | 0x06 | - | - | - | - | - | pd+ | pd+ | - | Wiktor Starzak |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| --- | - | - | - | - | pd | pd | pd | pd | LED | Oscar Steila |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| SDR-HF | - | - | - | - | pu | pd | pd | pd | LED | Pieter Ibelings |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
| | | - | - | | | | | | | ... |
+--------------+-------+------+------+------+------+------+------+------+------+----------------------------+
Where:
- floating no connection
pu 1k resistor pull-up to 3V3
pd 1k resistor pull-down to GND
pd* 1k resistor pull-down to GND to be added with a patch
pd+ 1k resistor pull-down all pd+ are connected to the same pull-down
LED plus resistor to 3V3 connected to GPIO54 on FX3 SuperSpeed Kit
The 1k value is low enough to be able to detect the resistor using the GPIO internal programmable pull-up pull-down vs a floating pin.
The value is high enough to not disturb use of GPIOs for other purpose after detection.
*/
// TODO

Wyświetl plik

@ -1,154 +0,0 @@
#pragma once
#define FIRMWARE_VER_MAJOR 2
#define FIRMWARE_VER_MINOR 1
// HF103 commands !!!
enum FX3Command {
// Start GPII engine and stream the data from ADC
// WRITE: UINT32
STARTFX3 = 0xAA,
// Stop GPII engine
// WRITE: UINT32
STOPFX3 = 0xAB,
// Get the information of device
// including model, version
// READ: UINT32
TESTFX3 = 0xAC,
// Control GPIOs
// WRITE: UINT32
GPIOFX3 = 0xAD,
// Write data to I2c bus
// WRITE: DATA
// INDEX: reg
// VALUE: i2c_addr
I2CWFX3 = 0xAE,
// Read data from I2c bus
// READ: DATA
// INDEX: reg
// VALUE: i2c_addr
I2CRFX3 = 0xAF,
// Reset USB chip and get back to bootloader mode
// WRITE: NONE
RESETFX3 = 0xB1,
// Set Argument, packet Index/Vaule contains the data
// WRITE: (Additional Data)
// INDEX: Argument_index
// VALUE: arguement value
SETARGFX3 = 0xB6,
// Start ADC with the specific frequency
// Optional, if ADC is running with crystal, this is not needed.
// WRITE: UINT32 -> adc frequency
STARTADC = 0xB2,
// R82XX family Tuner functions
// Initialize R82XX tuner
// WRITE: NONE
TUNERINIT = 0xB4,
// Tune to a sepcific frequency
// WRITE: UINT64
TUNERTUNE = 0xB5,
// Stop Tuner
// WRITE: NONE
TUNERSTDBY = 0xB8,
// Read Debug string if any
// READ:
READINFODEBUG = 0xBA,
};
#define OUTXIO0 (1U << 0) // ATT_LE
#define OUTXIO1 (1U << 1) // ATT_CLK
#define OUTXIO2 (1U << 2) // ATT_DATA
#define OUTXIO3 (1U << 3) // SEL0
#define OUTXIO4 (1U << 4) // SEL1
#define OUTXIO5 (1U << 5) // SHDWN
#define OUTXIO6 (1U << 6) // DITH
#define OUTXIO7 (1U << 7) // RAND
#define OUTXIO8 (1U << 8) // 256
#define OUTXIO9 (1U << 9) // 512
#define OUTXI10 (1U << 10) // 1024
#define OUTXI11 (1U << 11) // 2048
#define OUTXI12 (1U << 12) // 4096
#define OUTXI13 (1U << 13) // 8192
#define OUTXI14 (1U << 14) // 16384
#define OUTXI15 (1U << 15) // 32768
#define OUTXI16 (1U << 16)
enum GPIOPin {
SHDWN = OUTXIO5,
DITH = OUTXIO6,
RANDO = OUTXIO7,
BIAS_HF = OUTXIO8,
BIAS_VHF = OUTXIO9,
LED_YELLOW = OUTXI10,
LED_RED = OUTXI11,
LED_BLUE = OUTXI12,
ATT_SEL0 = OUTXI13,
ATT_SEL1 = OUTXI14,
// RX888r2
VHF_EN = OUTXI15,
PGA_EN = OUTXI16,
};
enum RadioModel {
NORADIO = 0x00,
BBRF103 = 0x01,
HF103 = 0x02,
RX888 = 0x03,
RX888r2 = 0x04,
RX999 = 0x05,
RXLUCY = 0x06,
RX888r3 = 0x07,
};
enum ArgumentList {
// Set R8xx lna/mixer gain
// value: 0-29
R82XX_ATTENUATOR = 1,
// Set R8xx vga gain
// value: 0-15
R82XX_VGA = 2,
// Set R8xx sideband
// value: 0/1
R82XX_SIDEBAND = 3,
// Set R8xx harmonic
// value: 0/1
R82XX_HARMONIC = 4,
// Set DAT-31 Att
// Value: 0-63
DAT31_ATT = 10,
// Set AD8340 chip vga
// Value: 0-255
AD8340_VGA = 11,
// Preselector
// Value: 0-2
PRESELECTOR = 12,
// VHFATT
// Value: 0-15
VHF_ATTENUATOR = 13,
};
#define _DEBUG_USB_
#define MAXLEN_D_USB (100)

Wyświetl plik

@ -1,23 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017-2020 Oscar Steila ik1xpv<at>gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.The MIT License (MIT)
The MIT License (MIT)

Wyświetl plik

@ -1,37 +0,0 @@
cmake_minimum_required(VERSION 3.13)
if (MSVC)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
endif (MSVC)
include_directories("." "../Core")
add_library(sddc SHARED
libsddc.cpp
)
if (MSVC)
target_link_libraries(sddc PUBLIC Setupapi.lib)
else()
target_include_directories(sddc PUBLIC "${LIBUSB_INCLUDE_DIR}")
target_link_directories(sddc PUBLIC "${LIBUSB_LIBRARY_DIRS}")
target_link_libraries(sddc PUBLIC ${LIBUSB_LIBRARIES})
endif (MSVC)
target_include_directories(sddc PUBLIC "${LIBFFTW_INCLUDE_DIR}")
target_link_directories(sddc PUBLIC "${LIBFFTW_LIBRARY_DIRS}")
target_link_libraries(sddc PUBLIC ${LIBFFTW_LIBRARIES})
target_link_libraries(sddc PRIVATE SDDC_CORE)
set_target_properties(sddc PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(sddc PROPERTIES SOVERSION 0)
# applications
add_executable(sddc_test sddc_test.c)
target_link_libraries(sddc_test PRIVATE sddc ${ASANLIB})
add_executable(sddc_stream_test sddc_stream_test.c wavewrite.c)
target_link_libraries(sddc_stream_test sddc ${ASANLIB})
add_executable(sddc_vhf_stream_test sddc_vhf_stream_test.c wavewrite.c)
target_link_libraries(sddc_vhf_stream_test sddc ${ASANLIB})

Wyświetl plik

@ -1,396 +0,0 @@
#include "libsddc.h"
#include "sddc_config.h"
#include "r2iq.h"
#include "RadioHandler.h"
struct sddc
{
SDDCStatus status;
RadioHandlerClass* handler;
uint8_t led;
int samplerateidx;
double freq;
sddc_read_async_cb_t callback;
void *callback_context;
};
sddc_t *current_running;
static void Callback(const float* data, uint32_t len)
{
}
class rawdata : public r2iqControlClass {
void Init(float gain, ringbuffer<int16_t>* buffers, ringbuffer<float>* obuffers) override
{
idx = 0;
}
void TurnOn() override
{
this->r2iqOn = true;
idx = 0;
}
private:
int idx;
};
int sddc_get_device_count()
{
return 1;
}
int sddc_get_device_info(struct sddc_device_info **sddc_device_infos)
{
auto ret = new sddc_device_info();
const char *todo = "TODO";
ret->manufacturer = todo;
ret->product = todo;
ret->serial_number = todo;
*sddc_device_infos = ret;
return 1;
}
int sddc_free_device_info(struct sddc_device_info *sddc_device_infos)
{
delete sddc_device_infos;
return 0;
}
sddc_t *sddc_open(int index, const char* imagefile)
{
auto ret_val = new sddc_t();
fx3class *fx3 = CreateUsbHandler();
if (fx3 == nullptr)
{
return nullptr;
}
// open the firmware
unsigned char* res_data;
uint32_t 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;
bool openOK = fx3->Open(res_data, res_size);
if (!openOK)
return nullptr;
ret_val->handler = new RadioHandlerClass();
if (ret_val->handler->Init(fx3, Callback, new rawdata()))
{
ret_val->status = SDDC_STATUS_READY;
ret_val->samplerateidx = 0;
}
return ret_val;
}
void sddc_close(sddc_t *that)
{
if (that->handler)
delete that->handler;
delete that;
}
enum SDDCStatus sddc_get_status(sddc_t *t)
{
return t->status;
}
enum SDDCHWModel sddc_get_hw_model(sddc_t *t)
{
switch(t->handler->getModel())
{
case RadioModel::BBRF103:
return HW_BBRF103;
case RadioModel::HF103:
return HW_HF103;
case RadioModel::RX888:
return HW_RX888;
case RadioModel::RX888r2:
return HW_RX888R2;
case RadioModel::RX888r3:
return HW_RX888R3;
case RadioModel::RX999:
return HW_RX999;
default:
return HW_NORADIO;
}
}
const char *sddc_get_hw_model_name(sddc_t *t)
{
return t->handler->getName();
}
uint16_t sddc_get_firmware(sddc_t *t)
{
return t->handler->GetFirmware();
}
const double *sddc_get_frequency_range(sddc_t *t)
{
return nullptr;
}
enum RFMode sddc_get_rf_mode(sddc_t *t)
{
switch(t->handler->GetmodeRF())
{
case HFMODE:
return RFMode::HF_MODE;
case VHFMODE:
return RFMode::VHF_MODE;
default:
return RFMode::NO_RF_MODE;
}
}
int sddc_set_rf_mode(sddc_t *t, enum RFMode rf_mode)
{
switch (rf_mode)
{
case VHF_MODE:
t->handler->UpdatemodeRF(VHFMODE);
break;
case HF_MODE:
t->handler->UpdatemodeRF(HFMODE);
default:
return -1;
}
return 0;
}
/* LED functions */
int sddc_led_on(sddc_t *t, uint8_t led_pattern)
{
if (led_pattern & YELLOW_LED)
t->handler->uptLed(0, true);
if (led_pattern & RED_LED)
t->handler->uptLed(1, true);
if (led_pattern & BLUE_LED)
t->handler->uptLed(2, true);
t->led |= led_pattern;
return 0;
}
int sddc_led_off(sddc_t *t, uint8_t led_pattern)
{
if (led_pattern & YELLOW_LED)
t->handler->uptLed(0, false);
if (led_pattern & RED_LED)
t->handler->uptLed(1, false);
if (led_pattern & BLUE_LED)
t->handler->uptLed(2, false);
t->led &= ~led_pattern;
return 0;
}
int sddc_led_toggle(sddc_t *t, uint8_t led_pattern)
{
t->led = t->led ^ led_pattern;
if (t->led & YELLOW_LED)
t->handler->uptLed(0, false);
if (t->led & RED_LED)
t->handler->uptLed(1, false);
if (t->led & BLUE_LED)
t->handler->uptLed(2, false);
return 0;
}
/* ADC functions */
int sddc_get_adc_dither(sddc_t *t)
{
return t->handler->GetDither();
}
int sddc_set_adc_dither(sddc_t *t, int dither)
{
t->handler->UptDither(dither != 0);
return 0;
}
int sddc_get_adc_random(sddc_t *t)
{
return t->handler->GetRand();
}
int sddc_set_adc_random(sddc_t *t, int random)
{
t->handler->UptRand(random != 0);
return 0;
}
/* HF block functions */
double sddc_get_hf_attenuation(sddc_t *t)
{
return 0;
}
int sddc_set_hf_attenuation(sddc_t *t, double attenuation)
{
return 0;
}
int sddc_get_hf_bias(sddc_t *t)
{
return t->handler->GetBiasT_HF();
}
int sddc_set_hf_bias(sddc_t *t, int bias)
{
t->handler->UpdBiasT_HF(bias != 0);
return 0;
}
/* VHF block and VHF/UHF tuner functions */
double sddc_get_tuner_frequency(sddc_t *t)
{
return t->freq;
}
int sddc_set_tuner_frequency(sddc_t *t, double frequency)
{
t->freq = t->handler->TuneLO((int64_t)frequency);
return 0;
}
int sddc_get_tuner_rf_attenuations(sddc_t *t, const double *attenuations[])
{
return 0;
}
double sddc_get_tuner_rf_attenuation(sddc_t *t)
{
return 0;
}
int sddc_set_tuner_rf_attenuation(sddc_t *t, double attenuation)
{
//TODO, convert double to index
t->handler->UpdateattRF(5);
return 0;
}
int sddc_get_tuner_if_attenuations(sddc_t *t, const double *attenuations[])
{
// TODO
return 0;
}
double sddc_get_tuner_if_attenuation(sddc_t *t)
{
return 0;
}
int sddc_set_tuner_if_attenuation(sddc_t *t, double attenuation)
{
return 0;
}
int sddc_get_vhf_bias(sddc_t *t)
{
return t->handler->GetBiasT_VHF();
}
int sddc_set_vhf_bias(sddc_t *t, int bias)
{
t->handler->UpdBiasT_VHF(bias != 0);
return 0;
}
double sddc_get_sample_rate(sddc_t *t)
{
return 0;
}
int sddc_set_sample_rate(sddc_t *t, double sample_rate)
{
switch((int64_t)sample_rate)
{
case 32000000:
t->samplerateidx = 0;
break;
case 16000000:
t->samplerateidx = 1;
break;
case 8000000:
t->samplerateidx = 2;
break;
case 4000000:
t->samplerateidx = 3;
break;
case 2000000:
t->samplerateidx = 4;
break;
default:
return -1;
}
return 0;
}
int sddc_set_async_params(sddc_t *t, uint32_t frame_size,
uint32_t num_frames, sddc_read_async_cb_t callback,
void *callback_context)
{
// TODO: ignore frame_size, num_frames
t->callback = callback;
t->callback_context = callback_context;
return 0;
}
int sddc_start_streaming(sddc_t *t)
{
current_running = t;
t->handler->Start(t->samplerateidx);
return 0;
}
int sddc_handle_events(sddc_t *t)
{
return 0;
}
int sddc_stop_streaming(sddc_t *t)
{
t->handler->Stop();
current_running = nullptr;
return 0;
}
int sddc_reset_status(sddc_t *t)
{
return 0;
}
int sddc_read_sync(sddc_t *t, uint8_t *data, int length, int *transferred)
{
return 0;
}

Wyświetl plik

@ -1,171 +0,0 @@
/*
* libsddc - low level functions for wideband SDR receivers like
* BBRF103, RX-666, RX888, HF103, etc
*
* Copyright (C) 2020 by Franco Venturi
*
* this program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* this program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef __LIBSDDC_H
#define __LIBSDDC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct sddc sddc_t;
struct sddc_device_info {
const char *manufacturer;
const char *product;
const char *serial_number;
};
enum SDDCStatus {
SDDC_STATUS_OFF,
SDDC_STATUS_READY,
SDDC_STATUS_STREAMING,
SDDC_STATUS_FAILED = 0xff
};
enum SDDCHWModel {
HW_NORADIO,
HW_BBRF103,
HW_HF103,
HW_RX888,
HW_RX888R2,
HW_RX999,
HW_RX888R3,
};
enum RFMode {
NO_RF_MODE,
HF_MODE,
VHF_MODE
};
enum LEDColors {
YELLOW_LED = 0x01,
RED_LED = 0x02,
BLUE_LED = 0x04
};
/* basic functions */
int sddc_get_device_count();
int sddc_get_device_info(struct sddc_device_info **sddc_device_infos);
int sddc_free_device_info(struct sddc_device_info *sddc_device_infos);
sddc_t *sddc_open(int index, const char* imagefile);
void sddc_close(sddc_t *t);
enum SDDCStatus sddc_get_status(sddc_t *t);
enum SDDCHWModel sddc_get_hw_model(sddc_t *t);
const char *sddc_get_hw_model_name(sddc_t *t);
uint16_t sddc_get_firmware(sddc_t *t);
const double *sddc_get_frequency_range(sddc_t *t);
enum RFMode sddc_get_rf_mode(sddc_t *t);
int sddc_set_rf_mode(sddc_t *t, enum RFMode rf_mode);
/* LED functions */
int sddc_led_on(sddc_t *t, uint8_t led_pattern);
int sddc_led_off(sddc_t *t, uint8_t led_pattern);
int sddc_led_toggle(sddc_t *t, uint8_t led_pattern);
/* ADC functions */
int sddc_get_adc_dither(sddc_t *t);
int sddc_set_adc_dither(sddc_t *t, int dither);
int sddc_get_adc_random(sddc_t *t);
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_get_hf_bias(sddc_t *t);
int sddc_set_hf_bias(sddc_t *t, int bias);
/* VHF block and VHF/UHF tuner functions */
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[]);
double sddc_get_tuner_rf_attenuation(sddc_t *t);
int sddc_set_tuner_rf_attenuation(sddc_t *t, double attenuation);
int sddc_get_tuner_if_attenuations(sddc_t *t, const double *attenuations[]);
double sddc_get_tuner_if_attenuation(sddc_t *t);
int sddc_set_tuner_if_attenuation(sddc_t *t, double attenuation);
int sddc_get_vhf_bias(sddc_t *t);
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,
void *context);
double sddc_get_sample_rate(sddc_t *t);
int sddc_set_sample_rate(sddc_t *t, double sample_rate);
int sddc_set_async_params(sddc_t *t, uint32_t frame_size,
uint32_t num_frames, sddc_read_async_cb_t callback,
void *callback_context);
int sddc_start_streaming(sddc_t *t);
int sddc_handle_events(sddc_t *t);
int sddc_stop_streaming(sddc_t *t);
int sddc_reset_status(sddc_t *t);
int sddc_read_sync(sddc_t *t, uint8_t *data, int length, int *transferred);
#ifdef __cplusplus
}
#endif
#endif /* __LIBSDDC_H */

Wyświetl plik

@ -1,102 +0,0 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WAVEHDR_H
#define __WAVEHDR_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#pragma pack(push)
#pragma pack(1)
typedef struct
{
char ID[4];
uint32_t size;
} chunk_hdr;
typedef struct
{
uint16_t wYear; /* 1601 through 30827 */
uint16_t wMonth; /* 1..12 */
uint16_t wDayOfWeek; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
uint16_t wDay; /* 1 .. 31 */
uint16_t wHour; /* 0 .. 23 */
uint16_t wMinute; /* 0 .. 59 */
uint16_t wSecond; /* 0 .. 59 */
uint16_t wMilliseconds; /* 0 .. 999 */
} Wind_SystemTime;
typedef struct
{
/* RIFF header */
chunk_hdr hdr; /* ID == "RIFF" string, size == full filesize - 8 bytes (maybe with some byte missing...) */
char waveID[4]; /* "WAVE" string */
} riff_chunk;
typedef struct
{
/* FMT header */
chunk_hdr hdr; /* ID == "fmt " */
int16_t wFormatTag;
int16_t nChannels;
int32_t nSamplesPerSec;
int32_t nAvgBytesPerSec;
int16_t nBlockAlign;
int16_t nBitsPerSample;
} fmt_chunk;
typedef struct
{
/* auxi header - used by SpectraVue / rfspace / HDSDR / ELAD FDM .. */
chunk_hdr hdr; /* ="auxi" (chunk rfspace) */
Wind_SystemTime StartTime;
Wind_SystemTime StopTime;
uint32_t centerFreq; /* receiver center frequency */
uint32_t ADsamplerate; /* A/D sample frequency before downsampling */
uint32_t IFFrequency; /* IF freq if an external down converter is used */
uint32_t Bandwidth; /* displayable BW if you want to limit the display to less than Nyquist band */
int32_t IQOffset; /* DC offset of the I and Q channels in 1/1000's of a count */
int32_t Unused2;
int32_t Unused3;
int32_t Unused4;
int32_t Unused5;
} auxi_chunk;
typedef struct
{
/* DATA header */
chunk_hdr hdr; /* ="data" */
} data_chunk;
typedef struct
{
riff_chunk r;
fmt_chunk f;
auxi_chunk a;
data_chunk d;
} waveFileHeader;
#pragma pack(pop)
#endif /* __WAVEHDR_H */
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

Wyświetl plik

@ -1,232 +0,0 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wavewrite.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#define _USE_MATH_DEFINES
#include <stdint.h> // portable: uint64_t MSVC: __int64
int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
// until 00:00:00 January 1, 1970
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime( &system_time );
SystemTimeToFileTime( &system_time, &file_time );
time = ((uint64_t)file_time.dwLowDateTime ) ;
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
return 0;
}
#endif
#include <math.h>
#include "wavehdr.h"
static waveFileHeader waveHdr;
static uint32_t waveDataSize = 0;
int waveHdrStarted = 0;
static void waveSetCurrTime(Wind_SystemTime *p)
{
struct timeval tv;
struct tm t;
gettimeofday(&tv, NULL);
p->wMilliseconds = tv.tv_usec / 1000;
#ifdef _WIN32
t = *gmtime(&tv.tv_sec);
#else
gmtime_r(&tv.tv_sec, &t);
#endif
p->wYear = t.tm_year + 1900; /* 1601 through 30827 */
p->wMonth = t.tm_mon + 1; /* 1..12 */
p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
p->wDay = t.tm_mday; /* 1 .. 31 */
p->wHour = t.tm_hour; /* 0 .. 23 */
p->wMinute = t.tm_min; /* 0 .. 59 */
p->wSecond = t.tm_sec; /* 0 .. 59 */
}
static void waveSetStartTimeInt(time_t tim, double fraction, Wind_SystemTime *p)
{
struct tm t = *gmtime( &tim );
p->wYear = t.tm_year + 1900; /* 1601 through 30827 */
p->wMonth = t.tm_mon + 1; /* 1..12 */
p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */
p->wDay = t.tm_mday; /* 1 .. 31 */
p->wHour = t.tm_hour; /* 0 .. 23 */
p->wMinute = t.tm_min; /* 0 .. 59 */
p->wSecond = t.tm_sec; /* 0 .. 59 */
p->wMilliseconds = (int)( fraction * 1000.0 );
if (p->wMilliseconds >= 1000)
p->wMilliseconds = 999;
}
void waveSetStartTime(time_t tim, double fraction)
{
waveSetStartTimeInt(tim, fraction, &waveHdr.a.StartTime );
waveHdr.a.StopTime = waveHdr.a.StartTime; /* to fix */
}
void wavePrepareHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels)
{
int bytesPerSample = bitsPerSample / 8;
int bytesPerFrame = bytesPerSample * numChannels;
memcpy( waveHdr.r.hdr.ID, "RIFF", 4 );
waveHdr.r.hdr.size = sizeof(waveFileHeader) - 8; /* to fix */
memcpy( waveHdr.r.waveID, "WAVE", 4 );
memcpy( waveHdr.f.hdr.ID, "fmt ", 4 );
waveHdr.f.hdr.size = 16;
waveHdr.f.wFormatTag = 1; /* PCM */
waveHdr.f.nChannels = numChannels; /* I and Q channels */
waveHdr.f.nSamplesPerSec = samplerate;
waveHdr.f.nAvgBytesPerSec = samplerate * bytesPerFrame;
waveHdr.f.nBlockAlign = waveHdr.f.nChannels;
waveHdr.f.nBitsPerSample = bitsPerSample;
memcpy( waveHdr.a.hdr.ID, "auxi", 4 );
waveHdr.a.hdr.size = 2 * sizeof(Wind_SystemTime) + 9 * sizeof(int32_t); /* = 2 * 16 + 9 * 4 = 68 */
waveSetCurrTime( &waveHdr.a.StartTime );
waveHdr.a.StopTime = waveHdr.a.StartTime; /* to fix */
waveHdr.a.centerFreq = freq;
waveHdr.a.ADsamplerate = samplerate;
waveHdr.a.IFFrequency = 0;
waveHdr.a.Bandwidth = 0;
waveHdr.a.IQOffset = 0;
waveHdr.a.Unused2 = 0;
waveHdr.a.Unused3 = 0;
waveHdr.a.Unused4 = 0;
waveHdr.a.Unused5 = 0;
memcpy( waveHdr.d.hdr.ID, "data", 4 );
waveHdr.d.hdr.size = 0; /* to fix later */
waveDataSize = 0;
}
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f)
{
if (f != stdout) {
assert( !waveHdrStarted );
wavePrepareHeader(samplerate, freq, bitsPerSample, numChannels);
fwrite(&waveHdr, sizeof(waveFileHeader), 1, f);
waveHdrStarted = 1;
}
}
int waveWriteSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fwrite(vpData, sizeof(uint8_t), numSamples, f);
waveDataSize += sizeof(uint8_t) * numSamples;
return (nw == numSamples) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fwrite(vpData, sizeof(int16_t), numSamples, f);
waveDataSize += sizeof(int16_t) * numSamples;
if ( needCleanData )
{
/* TODO: convert back endianness */
}
return (nw == numSamples) ? 0 : 1;
}
}
int waveWriteFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData)
{
size_t nw;
switch (waveHdr.f.nBitsPerSample)
{
case 0:
default:
return 1;
case 8:
/* no endian conversion needed for single bytes */
nw = fwrite(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);
waveDataSize += waveHdr.f.nChannels * sizeof(uint8_t) * numFrames;
return (nw == numFrames) ? 0 : 1;
case 16:
/* TODO: endian conversion needed */
nw = fwrite(vpData, waveHdr.f.nChannels * sizeof(int16_t), numFrames, f);
waveDataSize += waveHdr.f.nChannels * sizeof(int16_t) * numFrames;
if ( needCleanData )
{
/* TODO: convert back endianness */
}
return (nw == numFrames) ? 0 : 1;
}
}
int waveFinalizeHeader(FILE * f)
{
if (f != stdout) {
assert( waveHdrStarted );
waveSetCurrTime( &waveHdr.a.StopTime );
waveHdr.d.hdr.size = waveDataSize;
waveHdr.r.hdr.size += waveDataSize;
/* fprintf(stderr, "waveFinalizeHeader(): datasize = %d\n", waveHdr.dataSize); */
waveHdrStarted = 0;
if ( fseek(f, 0, SEEK_SET) )
return 1;
if ( 1 != fwrite(&waveHdr, sizeof(waveFileHeader), 1, f) )
return 1;
/* fprintf(stderr, "waveFinalizeHeader(): success writing header\n"); */
return 0;
}
return 1;
}
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab

Wyświetl plik

@ -1,55 +0,0 @@
/*
* Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WAVEWRITE_H
#define __WAVEWRITE_H
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
extern int waveHdrStarted;
/*!
* helper functions to write and finalize wave headers
* with compatibility to some SDR programs - showing frequency:
* raw sample data still have to be written by caller to FILE*.
* call waveWriteHeader() before writing anything to to file
* and call waveFinalizeHeader() afterwards,
* stdout/stderr can't be used, because seek to begin isn't possible.
*
*/
void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f);
/* waveWriteFrames() writes (numFrames * numChannels) samples
* waveWriteSamples()
* both return 0, when no errors occured
*/
int waveWriteFrames(FILE* f, void * vpData, size_t numFrames, int needCleanData);
int waveWriteSamples(FILE* f, void * vpData, size_t numSamples, int needCleanData); /* returns 0, when no errors occured */
void waveSetStartTime(time_t t, double fraction);
int waveFinalizeHeader(FILE * f); /* returns 0, when no errors occured */
#ifdef __cplusplus
}
#endif
#endif /*__WAVEWRITE_H*/

Wyświetl plik

@ -1,247 +0,0 @@
#include <imgui.h>
#include <spdlog/spdlog.h>
#include <module.h>
#include <gui/gui.h>
#include <signal_path/signal_path.h>
#include <core.h>
#include <gui/style.h>
#include <config.h>
#include <gui/widgets/stepped_slider.h>
#include <libsddc.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str())
SDRPP_MOD_INFO{
/* Name: */ "sddc_source",
/* Description: */ "SDDC source module for SDR++",
/* Author: */ "Ryzerth;pkuznetsov",
/* Version: */ 0, 1, 0,
/* Max instances */ 1
};
ConfigManager config;
const char* AGG_MODES_STR = "Off\0Low\0High\0";
class AirspyHFSourceModule : public ModuleManager::Instance {
public:
AirspyHFSourceModule(std::string name) {
this->name = name;
if (core::args["server"].b()) { return; }
sampleRate = 768000.0;
handler.ctx = this;
handler.selectHandler = menuSelected;
handler.deselectHandler = menuDeselected;
handler.menuHandler = menuHandler;
handler.startHandler = start;
handler.stopHandler = stop;
handler.tuneHandler = tune;
handler.stream = &stream;
refresh();
selectFirst();
sigpath::sourceManager.registerSource("SDDC", &handler);
}
~AirspyHFSourceModule() {
stop(this);
sigpath::sourceManager.unregisterSource("SDDC");
}
void postInit() {}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
bool isEnabled() {
return enabled;
}
void refresh() {
devListTxt = "";
devCount = sddc_get_device_count();
for (int i = 0; i < devCount; i++) {
// Open device
sddc_t* dev = sddc_open(i, "../sddc_source/res/firmwares/SDDC_FX3.img");
if (dev == NULL) { continue; }
// Get device name (check if implemented)
const char* name = sddc_get_hw_model_name(dev);
if (name == NULL) {
sddc_close(dev);
continue;
}
// Add to list
char tmp[256];
sprintf(tmp, "%s (%d)", name, i);
devNames.push_back(name);
devListTxt += name;
devListTxt += '\0';
sddc_close(dev);
}
}
void selectFirst() {
if (devCount != 0) {
selectById(0);
}
}
void selectByName(std::string name) {
for (int i = 0; i < devCount; i++) {
if (devNames[i] == name) {
selectById(i);
break;
}
}
}
void selectById(int id) {
if (id < 0 || id >= devCount) {
selectedDevName = "";
return;
}
devId = id;
selectedDevName = devNames[id];
}
private:
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);
}
static void menuSelected(void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
core::setInputSampleRate(_this->sampleRate);
spdlog::info("AirspyHFSourceModule '{0}': Menu Select!", _this->name);
}
static void menuDeselected(void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
spdlog::info("AirspyHFSourceModule '{0}': Menu Deselect!", _this->name);
}
static void start(void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
if (_this->running) { return; }
if (_this->selectedDevName == "") { return; }
// Start device
_this->running = true;
spdlog::info("AirspyHFSourceModule '{0}': Start!", _this->name);
}
static void stop(void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
if (!_this->running) { return; }
_this->running = false;
_this->stream.stopWriter();
// Stop device
_this->stream.clearWriteStop();
spdlog::info("AirspyHFSourceModule '{0}': Stop!", _this->name);
}
static void tune(double freq, void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
if (_this->running) {
// Tune device
}
_this->freq = freq;
spdlog::info("AirspyHFSourceModule '{0}': Tune: {1}!", _this->name, freq);
}
static void menuHandler(void* ctx) {
AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx;
float menuWidth = ImGui::GetContentRegionAvail().x;
if (_this->running) { style::beginDisabled(); }
ImGui::SetNextItemWidth(menuWidth);
if (ImGui::Combo(CONCAT("##_sddc_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) {
// Select here
}
if (ImGui::Combo(CONCAT("##_sddc_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) {
_this->sampleRate = _this->sampleRateList[_this->srId];
core::setInputSampleRate(_this->sampleRate);
// Select SR here
}
ImGui::SameLine();
float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX();
if (ImGui::Button(CONCAT("Refresh##_sddc_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) {
_this->refresh();
// Reselect and reset samplerate if it changed
}
if (_this->running) { style::endDisabled(); }
// All other controls
}
std::string name;
bool enabled = true;
dsp::stream<dsp::complex_t> stream;
double sampleRate;
SourceManager::SourceHandler handler;
bool running = false;
double freq;
int devId = 0;
int srId = 0;
sddc_t* openDev;
int devCount = 0;
std::vector<std::string> devNames;
std::string selectedDevName = "";
std::string devListTxt;
std::vector<uint32_t> sampleRateList;
std::string sampleRateListTxt;
};
MOD_EXPORT void _INIT_() {
json def = json({});
def["devices"] = json({});
def["device"] = "";
config.setPath(core::args["root"].s() + "/sddc_config.json");
config.load(def);
config.enableAutoSave();
}
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
return new AirspyHFSourceModule(name);
}
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
delete (AirspyHFSourceModule*)instance;
}
MOD_EXPORT void _END_() {
config.disableAutoSave();
config.save();
}