mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-01-11 10:47:11 +01:00
removed broken SDDC source
This commit is contained in:
parent
dbedc0d352
commit
d3e9ebef72
@ -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)
|
Binary file not shown.
@ -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)
|
@ -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()
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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_
|
@ -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);
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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*/
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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"
|
@ -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__
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
};
|
@ -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
|
||||
}
|
@ -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
|
||||
};
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
int KaiserWindow(int num_taps, float Astop, float normFpass, float normFstop, float * Coef);
|
@ -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_
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include "RadioHandler.h"
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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_
|
||||
|
@ -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
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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})
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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
|
||||
|
@ -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
|
@ -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*/
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user