mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-06 02:37:32 +01:00
More work on RFSpace source
This commit is contained in:
parent
201a612c19
commit
33914a7316
@ -18,7 +18,7 @@ option(OPT_BUILD_FILE_SOURCE "Wav file source" ON)
|
||||
option(OPT_BUILD_HACKRF_SOURCE "Build HackRF Source Module (Dependencies: libhackrf)" ON)
|
||||
option(OPT_BUILD_LIMESDR_SOURCE "Build LimeSDR Source Module (Dependencies: liblimesuite)" OFF)
|
||||
option(OPT_BUILD_SDDC_SOURCE "Build SDDC Source Module (Dependencies: libusb-1.0)" OFF)
|
||||
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module no dependencies required)" OFF)
|
||||
option(OPT_BUILD_RFSPACE_SOURCE "Build RFspace Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_RTL_SDR_SOURCE "Build RTL-SDR Source Module (Dependencies: librtlsdr)" ON)
|
||||
option(OPT_BUILD_RTL_TCP_SOURCE "Build RTL-TCP Source Module (no dependencies required)" ON)
|
||||
option(OPT_BUILD_SDRPLAY_SOURCE "Build SDRplay Source Module (Dependencies: libsdrplay)" OFF)
|
||||
|
@ -111,7 +111,7 @@ private:
|
||||
txt = _txt.c_str();
|
||||
}
|
||||
|
||||
std::vector<std::string> keys;
|
||||
std::vector<K> keys;
|
||||
std::vector<std::string> names;
|
||||
std::vector<T> values;
|
||||
std::string _txt;
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <config.h>
|
||||
#include <options.h>
|
||||
#include <gui/widgets/stepped_slider.h>
|
||||
|
||||
#include <utils/optionlist.h>
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
|
||||
@ -23,9 +23,9 @@ SDRPP_MOD_INFO{
|
||||
|
||||
ConfigManager config;
|
||||
|
||||
class SpyServerSourceModule : public ModuleManager::Instance {
|
||||
class RFSpaceSource : public ModuleManager::Instance {
|
||||
public:
|
||||
SpyServerSourceModule(std::string name) {
|
||||
RFSpaceSource(std::string name) {
|
||||
this->name = name;
|
||||
|
||||
handler.ctx = this;
|
||||
@ -42,7 +42,7 @@ public:
|
||||
sigpath::sourceManager.registerSource("RFspace", &handler);
|
||||
}
|
||||
|
||||
~SpyServerSourceModule() {
|
||||
~RFSpaceSource() {
|
||||
stop(this);
|
||||
sigpath::sourceManager.unregisterSource("RFspace");
|
||||
}
|
||||
@ -77,49 +77,50 @@ private:
|
||||
}
|
||||
|
||||
static void menuSelected(void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
gui::mainWindow.playButtonLocked = !(_this->client && _this->client->isOpen());
|
||||
spdlog::info("SpyServerSourceModule '{0}': Menu Select!", _this->name);
|
||||
spdlog::info("RFSpaceSource '{0}': Menu Select!", _this->name);
|
||||
}
|
||||
|
||||
static void menuDeselected(void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
gui::mainWindow.playButtonLocked = false;
|
||||
spdlog::info("SpyServerSourceModule '{0}': Menu Deselect!", _this->name);
|
||||
spdlog::info("RFSpaceSource '{0}': Menu Deselect!", _this->name);
|
||||
}
|
||||
|
||||
static void start(void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
if (_this->running) { return; }
|
||||
|
||||
// TODO: Start
|
||||
// TODO: Set configuration here
|
||||
if (_this->client) { _this->client->start(rfspace::RFSPACE_SAMP_FORMAT_COMPLEX, rfspace::RFSPACE_SAMP_FORMAT_16BIT); }
|
||||
|
||||
_this->running = true;
|
||||
spdlog::info("SpyServerSourceModule '{0}': Start!", _this->name);
|
||||
spdlog::info("RFSpaceSource '{0}': Start!", _this->name);
|
||||
}
|
||||
|
||||
static void stop(void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
if (!_this->running) { return; }
|
||||
|
||||
// TODO: Stop
|
||||
if (_this->client) { _this->client->stop(); }
|
||||
|
||||
_this->running = false;
|
||||
spdlog::info("SpyServerSourceModule '{0}': Stop!", _this->name);
|
||||
spdlog::info("RFSpaceSource '{0}': Stop!", _this->name);
|
||||
}
|
||||
|
||||
static void tune(double freq, void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
if (_this->running) {
|
||||
// TODO: Tune
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
if (_this->running && _this->client) {
|
||||
_this->client->setFrequency(freq);
|
||||
}
|
||||
_this->freq = freq;
|
||||
spdlog::info("SpyServerSourceModule '{0}': Tune: {1}!", _this->name, freq);
|
||||
spdlog::info("RFSpaceSource '{0}': Tune: {1}!", _this->name, freq);
|
||||
}
|
||||
|
||||
static void menuHandler(void* ctx) {
|
||||
SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx;
|
||||
RFSpaceSource* _this = (RFSpaceSource*)ctx;
|
||||
float menuWidth = ImGui::GetContentRegionAvailWidth();
|
||||
|
||||
bool connected = (_this->client && _this->client->isOpen());
|
||||
@ -143,7 +144,9 @@ private:
|
||||
if (_this->running) { style::beginDisabled(); }
|
||||
if (!connected && ImGui::Button("Connect##rfspace_source", ImVec2(menuWidth, 0))) {
|
||||
try {
|
||||
if (_this->client) { _this->client.reset(); }
|
||||
_this->client = rfspace::connect(_this->hostname, _this->port, &_this->stream);
|
||||
_this->deviceInit();
|
||||
}
|
||||
catch (std::exception e) {
|
||||
spdlog::error("Could not connect to SDR: {0}", e.what());
|
||||
@ -158,9 +161,36 @@ private:
|
||||
if (connected) {
|
||||
// TODO: Options here
|
||||
|
||||
if (_this->running) { style::beginDisabled(); }
|
||||
|
||||
ImGui::LeftLabel("Samplerate");
|
||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::Combo("##rfspace_source_samp_rate", &_this->srId, _this->sampleRates.txt)) {
|
||||
_this->sampleRate = _this->sampleRates[_this->srId];
|
||||
_this->client->setSampleRate(_this->sampleRate);
|
||||
core::setInputSampleRate(_this->sampleRate);
|
||||
// TODO: Save config
|
||||
}
|
||||
|
||||
if (_this->running) { style::endDisabled(); }
|
||||
|
||||
ImGui::LeftLabel("Antenna Port");
|
||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::Combo("##rfspace_source_rf_port", &_this->rfPortId, _this->rfPorts.txt)) {
|
||||
_this->client->setPort(_this->rfPorts[_this->rfPortId]);
|
||||
// TODO: Save config
|
||||
}
|
||||
|
||||
ImGui::LeftLabel("Gain");
|
||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||
if (ImGui::SliderFloatWithSteps("##rfspace_source_gain", &_this->gain, -30, 0, 10, "%.0f dB")) {
|
||||
_this->client->setGain(_this->gain);
|
||||
// TODO: Save config (as int, in case we have to switch to an option list)
|
||||
}
|
||||
|
||||
ImGui::Text("Status:");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Connected (DEV NAME HERE)");
|
||||
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Connected (%s)", _this->deviceName.c_str());
|
||||
}
|
||||
else {
|
||||
ImGui::Text("Status:");
|
||||
@ -169,18 +199,53 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void deviceInit() {
|
||||
// Get device name
|
||||
if (deviceNames.find(client->deviceId) != deviceNames.end()) {
|
||||
deviceName = deviceNames[client->deviceId];
|
||||
}
|
||||
else {
|
||||
deviceName = "Unknown";
|
||||
}
|
||||
|
||||
// Create samplerate list (TODO: Depends on model)
|
||||
auto srs = client->getValidSampleRates();
|
||||
sampleRates.clear();
|
||||
for (auto& sr : srs) {
|
||||
sampleRates.define(sr, getBandwdithScaled(sr), sr);
|
||||
}
|
||||
|
||||
// Create RF port list (TODO: Depends on model)
|
||||
rfPorts.clear();
|
||||
rfPorts.define("Port 1", rfspace::RFSPACE_RF_PORT_1);
|
||||
rfPorts.define("Port 2", rfspace::RFSPACE_RF_PORT_2);
|
||||
|
||||
// TODO: Load config
|
||||
}
|
||||
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
bool running = false;
|
||||
double sampleRate = 1000000;
|
||||
double sampleRate = 1228800;
|
||||
double freq;
|
||||
|
||||
OptionList<uint32_t, uint32_t> sampleRates;
|
||||
int srId = 0;
|
||||
|
||||
OptionList<std::string, rfspace::RFPort> rfPorts;
|
||||
int rfPortId = 0;
|
||||
|
||||
float gain = 0;
|
||||
|
||||
char hostname[1024];
|
||||
int port = 50000;
|
||||
|
||||
int srId = 0;
|
||||
std::vector<double> sampleRates;
|
||||
std::string sampleRatesTxt;
|
||||
std::string deviceName = "Unknown";
|
||||
std::map<rfspace::DeviceID, std::string> deviceNames = {
|
||||
{ rfspace::RFSPACE_DEV_ID_CLOUD_SDR, "CloudSDR" },
|
||||
{ rfspace::RFSPACE_DEV_ID_CLOUD_IQ, "CloudIQ" },
|
||||
{ rfspace::RFSPACE_DEV_ID_NET_SDR, "NetSDR" }
|
||||
};
|
||||
|
||||
dsp::stream<dsp::complex_t> stream;
|
||||
SourceManager::SourceHandler handler;
|
||||
@ -208,11 +273,11 @@ MOD_EXPORT void _INIT_() {
|
||||
}
|
||||
|
||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||
return new SpyServerSourceModule(name);
|
||||
return new RFSpaceSource(name);
|
||||
}
|
||||
|
||||
MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) {
|
||||
delete (SpyServerSourceModule*)instance;
|
||||
delete (RFSpaceSource*)instance;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _END_() {
|
||||
|
@ -10,22 +10,40 @@ namespace rfspace {
|
||||
client = std::move(conn);
|
||||
udpClient = std::move(udpConn);
|
||||
output = out;
|
||||
|
||||
// Allocate buffers
|
||||
rbuffer = new uint8_t[RFSPACE_MAX_SIZE];
|
||||
sbuffer = new uint8_t[RFSPACE_MAX_SIZE];
|
||||
ubuffer = new uint8_t[RFSPACE_MAX_SIZE];
|
||||
|
||||
// Clear write stop of stream just in case
|
||||
output->clearWriteStop();
|
||||
|
||||
uint8_t test = 0x5A;
|
||||
udpClient->write(1, &test);
|
||||
// Send UDP packet so that a router opens the port
|
||||
sendDummyUDP();
|
||||
|
||||
// Start readers
|
||||
client->readAsync(sizeof(tcpHeader), (uint8_t*)&tcpHeader, tcpHandler, this);
|
||||
udpClient->readAsync(sizeof(udpHeader), (uint8_t*)&udpHeader, udpHandler, this);
|
||||
udpClient->readAsync(RFSPACE_MAX_SIZE, ubuffer, udpHandler, this);
|
||||
|
||||
// Start SDR
|
||||
uint8_t args[4] = { 0x70, 2, 0, 0 };
|
||||
setControlItem(0x18, args, 4);
|
||||
// Get device ID and wait for response
|
||||
getControlItem(RFSPACE_CTRL_ITEM_PROD_ID, NULL, 0);
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(devIdMtx);
|
||||
if (!devIdCnd.wait_for(lck, std::chrono::milliseconds(RFSPACE_TIMEOUT_MS), [=](){ return devIdAvailable; })) {
|
||||
throw std::runtime_error("Could not identify remote device");
|
||||
}
|
||||
}
|
||||
|
||||
// Default configuration
|
||||
stop();
|
||||
setSampleRate(1228800);
|
||||
setFrequency(8830000);
|
||||
setGain(0);
|
||||
setPort(RFSPACE_RF_PORT_1);
|
||||
|
||||
// Start heartbeat
|
||||
heartBeatThread = std::thread(&RFspaceClientClass::heartBeatWorker, this);
|
||||
}
|
||||
|
||||
RFspaceClientClass::~RFspaceClientClass() {
|
||||
@ -35,7 +53,12 @@ namespace rfspace {
|
||||
delete[] ubuffer;
|
||||
}
|
||||
|
||||
int RFspaceClientClass::getControlItem(uint16_t item, void* param, int len) {
|
||||
void RFspaceClientClass::sendDummyUDP() {
|
||||
uint8_t dummy = 0x5A;
|
||||
udpClient->write(1, &dummy);
|
||||
}
|
||||
|
||||
int RFspaceClientClass::getControlItem(ControlItem item, void* param, int len) {
|
||||
// Build packet
|
||||
uint16_t* header = (uint16_t*)&sbuffer[0];
|
||||
uint16_t* item_val = (uint16_t*)&sbuffer[2];
|
||||
@ -43,26 +66,12 @@ namespace rfspace {
|
||||
*item_val = item;
|
||||
|
||||
// Send packet
|
||||
SCIRRecv.release();
|
||||
client->write(4, sbuffer);
|
||||
|
||||
// Wait for a response
|
||||
if (!SCIRRecv.await(2000)) {
|
||||
SCIRRecv.release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Forward data
|
||||
int toRead = ((SCIRSize - 4) < len) ? (SCIRSize - 4) : len;
|
||||
memcpy(param, &rbuffer[4], toRead);
|
||||
|
||||
// Release receiving thread
|
||||
SCIRRecv.release();
|
||||
|
||||
return toRead;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setControlItem(uint16_t item, void* param, int len) {
|
||||
void RFspaceClientClass::setControlItem(ControlItem item, void* param, int len) {
|
||||
// Build packet
|
||||
uint16_t* header = (uint16_t*)&sbuffer[0];
|
||||
uint16_t* item_val = (uint16_t*)&sbuffer[2];
|
||||
@ -74,10 +83,78 @@ namespace rfspace {
|
||||
client->write(len + 4, sbuffer);
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setControlItemWithChanID(ControlItem item, uint8_t chanId, void* param, int len) {
|
||||
// Build packet
|
||||
uint16_t* header = (uint16_t*)&sbuffer[0];
|
||||
uint16_t* item_val = (uint16_t*)&sbuffer[2];
|
||||
uint8_t* chan = &sbuffer[4];
|
||||
*header = (len + 5) | (RFSPACE_MSG_TYPE_H2T_SET_CTRL_ITEM << 13);
|
||||
*item_val = item;
|
||||
*chan = chanId;
|
||||
memcpy(&sbuffer[5], param, len);
|
||||
|
||||
// Send packet
|
||||
client->write(len + 5, sbuffer);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> RFspaceClientClass::getValidSampleRates() {
|
||||
std::vector<uint32_t> sr;
|
||||
|
||||
switch (deviceId) {
|
||||
case RFSPACE_DEV_ID_CLOUD_SDR:
|
||||
case RFSPACE_DEV_ID_CLOUD_IQ:
|
||||
for (int n = 122880000 / (4 * 25); n >= 32000; n /= 2) {
|
||||
sr.push_back(n);
|
||||
}
|
||||
break;
|
||||
case RFSPACE_DEV_ID_NET_SDR:
|
||||
for (int n = 80000000 / (4 * 25); n >= 32000; n /= 2) {
|
||||
sr.push_back(n);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sr;
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setFrequency(uint64_t freq) {
|
||||
setControlItemWithChanID(RFSPACE_CTRL_ITEM_NCO_FREQUENCY, 0, &freq, 5);
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setPort(RFPort port) {
|
||||
uint8_t value = port;
|
||||
spdlog::warn("{0}", value);
|
||||
setControlItemWithChanID(RFSPACE_CTRL_ITEM_RF_PORT, 0, &value, sizeof(value));
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setGain(int8_t gain) {
|
||||
setControlItemWithChanID(RFSPACE_CTRL_ITEM_RF_GAIN, 0, &gain, sizeof(gain));
|
||||
}
|
||||
|
||||
void RFspaceClientClass::setSampleRate(uint32_t sampleRate) {
|
||||
setControlItemWithChanID(RFSPACE_CTRL_ITEM_IQ_SAMP_RATE, 0, &sampleRate, sizeof(sampleRate));
|
||||
}
|
||||
|
||||
void RFspaceClientClass::start(SampleFormat sampleFormat, SampleDepth sampleDepth) {
|
||||
uint8_t args[4] = { sampleFormat, RFSPACE_STATE_RUN, sampleDepth, 0 };
|
||||
setControlItem(RFSPACE_CTRL_ITEM_STATE, args, sizeof(args));
|
||||
}
|
||||
|
||||
void RFspaceClientClass::stop() {
|
||||
uint8_t args[4] = { 0, RFSPACE_STATE_IDLE, 0, 0 };
|
||||
setControlItem(RFSPACE_CTRL_ITEM_STATE, args, sizeof(args));
|
||||
}
|
||||
|
||||
void RFspaceClientClass::close() {
|
||||
output->stopWriter();
|
||||
stopHeartBeat = true;
|
||||
heartBeatCnd.notify_all();
|
||||
if (heartBeatThread.joinable()) { heartBeatThread.join(); }
|
||||
client->close();
|
||||
udpClient->close();
|
||||
output->clearWriteStop();
|
||||
}
|
||||
|
||||
bool RFspaceClientClass::isOpen() {
|
||||
@ -94,12 +171,17 @@ namespace rfspace {
|
||||
_this->client->read(size - 2, &_this->rbuffer[2]);
|
||||
}
|
||||
|
||||
spdlog::warn("TCP received: {0} {1}", type, size);
|
||||
// spdlog::warn("TCP received: {0} {1}", type, size);
|
||||
|
||||
// Process data
|
||||
if (type == RFSPACE_MSG_TYPE_T2H_SET_CTRL_ITEM_RESP) {
|
||||
_this->SCIRSize = size;
|
||||
_this->SCIRRecv.trigger();
|
||||
// Check for a device ID
|
||||
uint16_t* controlItem = (uint16_t*)&_this->rbuffer[2];
|
||||
if (type == RFSPACE_MSG_TYPE_T2H_SET_CTRL_ITEM_RESP && *controlItem == RFSPACE_CTRL_ITEM_PROD_ID) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(_this->devIdMtx);
|
||||
_this->deviceId = (DeviceID)*(uint32_t*)&_this->rbuffer[4];
|
||||
_this->devIdAvailable = true;
|
||||
}
|
||||
_this->devIdCnd.notify_all();
|
||||
}
|
||||
|
||||
// Restart an async read
|
||||
@ -108,18 +190,31 @@ namespace rfspace {
|
||||
|
||||
void RFspaceClientClass::udpHandler(int count, uint8_t* buf, void* ctx) {
|
||||
RFspaceClientClass* _this = (RFspaceClientClass*)ctx;
|
||||
uint8_t type = _this->udpHeader >> 13;
|
||||
uint16_t size = _this->udpHeader & 0b1111111111111;
|
||||
uint16_t hdr = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8);
|
||||
uint8_t type = hdr >> 13;
|
||||
uint16_t size = hdr & 0b1111111111111;
|
||||
|
||||
spdlog::warn("UDP received: {0} {1}", type, size);
|
||||
|
||||
// Read the rest of the data
|
||||
if (size > 2) {
|
||||
_this->client->read(size - 2, &_this->rbuffer[2]);
|
||||
if (type == RFSPACE_MSG_TYPE_T2H_DATA_ITEM_0) {
|
||||
int16_t* samples = (int16_t*)&buf[4];
|
||||
int sampCount = (size - 4) / (2 * sizeof(int16_t));
|
||||
volk_16i_s32f_convert_32f((float*)_this->output->writeBuf, samples, 32768.0f, sampCount * 2);
|
||||
_this->output->swap(sampCount);
|
||||
}
|
||||
|
||||
// Restart an async read
|
||||
_this->client->readAsync(sizeof(_this->udpHeader), (uint8_t*)&_this->udpHeader, udpHandler, _this);
|
||||
_this->udpClient->readAsync(RFSPACE_MAX_SIZE, _this->ubuffer, udpHandler, _this);
|
||||
}
|
||||
|
||||
void RFspaceClientClass::heartBeatWorker() {
|
||||
uint8_t dummy[4];
|
||||
while (true) {
|
||||
getControlItem(RFSPACE_CTRL_ITEM_STATE, dummy, sizeof(dummy));
|
||||
|
||||
std::unique_lock<std::mutex> lck(heartBeatMtx);
|
||||
bool to = heartBeatCnd.wait_for(lck, std::chrono::milliseconds(RFSPACE_HEARTBEAT_INTERVAL_MS), [=](){ return stopHeartBeat; });
|
||||
|
||||
if (to) { return; }
|
||||
}
|
||||
}
|
||||
|
||||
RFspaceClient connect(std::string host, uint16_t port, dsp::stream<dsp::complex_t>* out) {
|
||||
|
@ -3,11 +3,14 @@
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/types.h>
|
||||
#include <atomic>
|
||||
#include <queue>
|
||||
|
||||
#define RFSPACE_MAX_SIZE 8192
|
||||
#define RFSPACE_MAX_SIZE 8192
|
||||
#define RFSPACE_HEARTBEAT_INTERVAL_MS 1000
|
||||
#define RFSPACE_TIMEOUT_MS 3000
|
||||
|
||||
namespace rfspace {
|
||||
enum {
|
||||
enum H2TMessageType {
|
||||
RFSPACE_MSG_TYPE_H2T_SET_CTRL_ITEM,
|
||||
RFSPACE_MSG_TYPE_H2T_REQ_CTRL_ITEM,
|
||||
RFSPACE_MSG_TYPE_H2T_REQ_CTRL_ITEM_RANGE,
|
||||
@ -18,7 +21,7 @@ namespace rfspace {
|
||||
RFSPACE_MSG_TYPE_H2T_DATA_ITEM_3,
|
||||
};
|
||||
|
||||
enum {
|
||||
enum T2HMessageType {
|
||||
RFSPACE_MSG_TYPE_T2H_SET_CTRL_ITEM_RESP,
|
||||
RFSPACE_MSG_TYPE_T2H_UNSOL_CTRL_ITEM,
|
||||
RFSPACE_MSG_TYPE_T2H_REQ_CTRL_ITEM_RANGE_RESP,
|
||||
@ -29,63 +32,67 @@ namespace rfspace {
|
||||
RFSPACE_MSG_TYPE_T2H_DATA_ITEM_3,
|
||||
};
|
||||
|
||||
class SyncEvent {
|
||||
public:
|
||||
bool await(int timeoutMS) {
|
||||
// Mark as waiting
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(waitingmtx);
|
||||
waiting = true;
|
||||
}
|
||||
enum RFPort {
|
||||
RFSPACE_RF_PORT_AUTO,
|
||||
RFSPACE_RF_PORT_1,
|
||||
RFSPACE_RF_PORT_2
|
||||
};
|
||||
|
||||
// Wait for data
|
||||
std::unique_lock<std::mutex> lck(mtx);
|
||||
return cnd.wait_for(lck, std::chrono::milliseconds(timeoutMS), [this]() { return triggered; });
|
||||
enum SampleFormat {
|
||||
RFSPACE_SAMP_FORMAT_REAL = 0x00,
|
||||
RFSPACE_SAMP_FORMAT_COMPLEX = 0x80
|
||||
};
|
||||
|
||||
// Mark as not waiting
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(waitingmtx);
|
||||
waiting = false;
|
||||
}
|
||||
}
|
||||
enum State {
|
||||
RFSPACE_STATE_IDLE = 1,
|
||||
RFSPACE_STATE_RUN = 2
|
||||
};
|
||||
|
||||
void release() {
|
||||
// Mark as not waiting, and if last notify sender
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mtx);
|
||||
triggered = false;
|
||||
}
|
||||
cnd.notify_all();
|
||||
}
|
||||
enum SampleDepth {
|
||||
RFSPACE_SAMP_FORMAT_16BIT = 0x00,
|
||||
RFSPACE_SAMP_FORMAT_24BIT = 0x80
|
||||
};
|
||||
|
||||
void trigger() {
|
||||
// Check if a waiter is waiting
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(waitingmtx);
|
||||
if (waiting <= 0) { return; }
|
||||
}
|
||||
enum DeviceID {
|
||||
RFSPACE_DEV_ID_CLOUD_SDR = 0x44534C43,
|
||||
RFSPACE_DEV_ID_CLOUD_IQ = 0x51494C43,
|
||||
RFSPACE_DEV_ID_NET_SDR = 0xDEADBEEF // TODO
|
||||
};
|
||||
|
||||
// Notify waiters
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(mtx);
|
||||
triggered = true;
|
||||
}
|
||||
cnd.notify_all();
|
||||
|
||||
// Wait for waiter to handle
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(mtx);
|
||||
cnd.wait(lck, [this]() { return !triggered; });
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool triggered;
|
||||
std::mutex mtx;
|
||||
std::condition_variable cnd;
|
||||
|
||||
bool waiting;
|
||||
std::mutex waitingmtx;
|
||||
enum ControlItem {
|
||||
RFSPACE_CTRL_ITEM_MODEL_NAME = 0x0001,
|
||||
RFSPACE_CTRL_ITEM_SERIAL = 0x0002,
|
||||
RFSPACE_CTRL_ITEM_IFACE_VER = 0x0003,
|
||||
RFSPACE_CTRL_ITEM_VERSION = 0x0004,
|
||||
RFSPACE_CTRL_ITEM_STATUS = 0x0005,
|
||||
RFSPACE_CTRL_ITEM_DEV_NAME = 0x0008,
|
||||
RFSPACE_CTRL_ITEM_PROD_ID = 0x0009,
|
||||
RFSPACE_CTRL_ITEM_OPTIONS = 0x000A,
|
||||
RFSPACE_CTRL_ITEM_SECURE_CODE = 0x000B,
|
||||
RFSPACE_CTRL_ITEM_FPGA_CONF = 0x000C,
|
||||
RFSPACE_CTRL_ITEM_STATE = 0x0018,
|
||||
RFSPACE_CTRL_ITEM_NCO_FREQUENCY = 0x0020,
|
||||
RFSPACE_CTRL_ITEM_RF_PORT = 0x0030,
|
||||
RFSPACE_CTRL_ITEM_PORT_RANGE = 0x0032,
|
||||
RFSPACE_CTRL_ITEM_RF_GAIN = 0x0038,
|
||||
RFSPACE_CTRL_ITEM_DOWNCONV_GAIN = 0x003A,
|
||||
RFSPACE_CTRL_ITEM_RF_FILTER = 0x0044,
|
||||
RFSPACE_CTRL_ITEM_AD_MODE = 0x008A,
|
||||
RFSPACE_CTRL_ITEM_SAMP_RATE_CAL = 0x00B0,
|
||||
RFSPACE_CTRL_ITEM_TRIG_FREQ = 0x00B2,
|
||||
RFSPACE_CTRL_ITEM_TRIG_PHASE = 0x00B3,
|
||||
RFSPACE_CTRL_ITEM_SYNC_MODE = 0x00B4,
|
||||
RFSPACE_CTRL_ITEM_IQ_SAMP_RATE = 0x00B8,
|
||||
RFSPACE_CTRL_ITEM_UDP_PKT_SIZE = 0x00C4,
|
||||
RFSPACE_CTRL_ITEM_UDP_ADDR = 0x00C5,
|
||||
RFSPACE_CTRL_ITEM_TX_STATE = 0x0118,
|
||||
RFSPACE_CTRL_ITEM_TX_FREQUENCY = 0x0120,
|
||||
RFSPACE_CTRL_ITEM_TX_SAMP_RATE = 0x01B8,
|
||||
RFSPACE_CTRL_ITEM_SERIAL_OPEN = 0x0200,
|
||||
RFSPACE_CTRL_ITEM_SERIAL_CLOSE = 0x0201,
|
||||
RFSPACE_CTRL_ITEM_SER_BOOT_RATE = 0x0202,
|
||||
RFSPACE_CTRL_ITEM_AUX_SIG_MODE = 0x0280,
|
||||
RFSPACE_CTRL_ITEM_ERROR_LOG = 0x0410
|
||||
};
|
||||
|
||||
class RFspaceClientClass {
|
||||
@ -93,18 +100,31 @@ namespace rfspace {
|
||||
RFspaceClientClass(net::Conn conn, net::Conn udpConn, dsp::stream<dsp::complex_t>* out);
|
||||
~RFspaceClientClass();
|
||||
|
||||
int getControlItem(uint16_t item, void* param, int len);
|
||||
void setControlItem(uint16_t item, void* param, int len);
|
||||
void sendDummyUDP();
|
||||
|
||||
int getControlItem(ControlItem item, void* param, int len);
|
||||
void setControlItem(ControlItem item, void* param, int len);
|
||||
void setControlItemWithChanID(ControlItem item, uint8_t chanId, void* param, int len);
|
||||
|
||||
std::vector<uint32_t> getValidSampleRates();
|
||||
|
||||
void setFrequency(uint64_t freq);
|
||||
void setPort(RFPort port);
|
||||
void setGain(int8_t gain);
|
||||
void setSampleRate(uint32_t sampleRate);
|
||||
|
||||
void start(SampleFormat sampleFormat, SampleDepth sampleDepth);
|
||||
void stop();
|
||||
|
||||
void close();
|
||||
bool isOpen();
|
||||
|
||||
private:
|
||||
void sendCommand(uint32_t command, void* data, int len);
|
||||
void sendHandshake(std::string appName);
|
||||
DeviceID deviceId;
|
||||
|
||||
private:
|
||||
static void tcpHandler(int count, uint8_t* buf, void* ctx);
|
||||
static void udpHandler(int count, uint8_t* buf, void* ctx);
|
||||
void heartBeatWorker();
|
||||
|
||||
net::Conn client;
|
||||
net::Conn udpClient;
|
||||
@ -118,8 +138,14 @@ namespace rfspace {
|
||||
uint8_t* sbuffer = NULL;
|
||||
uint8_t* ubuffer = NULL;
|
||||
|
||||
SyncEvent SCIRRecv;
|
||||
int SCIRSize;
|
||||
std::thread heartBeatThread;
|
||||
std::mutex heartBeatMtx;
|
||||
std::condition_variable heartBeatCnd;
|
||||
volatile bool stopHeartBeat = false;
|
||||
|
||||
bool devIdAvailable = false;
|
||||
std::condition_variable devIdCnd;
|
||||
std::mutex devIdMtx;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<RFspaceClientClass> RFspaceClient;
|
||||
|
@ -178,6 +178,7 @@ private:
|
||||
if (_this->running) { style::beginDisabled(); }
|
||||
if (!connected && ImGui::Button("Connect##spyserver_source", ImVec2(menuWidth, 0))) {
|
||||
try {
|
||||
if (_this->client) { _this->client.reset(); }
|
||||
_this->client = spyserver::connect(_this->hostname, _this->port, &_this->stream);
|
||||
|
||||
if (!_this->client->waitForDevInfo(3000)) {
|
||||
|
Loading…
Reference in New Issue
Block a user