mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-10-30 00:18:10 +01:00 
			
		
		
		
	SDR++ server beta :)
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -9,6 +9,7 @@ build/ | ||||
| *.wav | ||||
| .DS_Store | ||||
| root_dev/ | ||||
| root_dev_srv/ | ||||
| Folder.DotSettings.user | ||||
| CMakeSettings.json | ||||
| poggers_decoder | ||||
|   | ||||
| @@ -18,6 +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_SDRPP_SERVER_SOURCE "Build SDR++ Server Source Module (no dependencies required)" ON) | ||||
| 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) | ||||
| @@ -83,6 +84,10 @@ if (OPT_BUILD_SDDC_SOURCE) | ||||
| add_subdirectory("source_modules/sddc_source") | ||||
| endif (OPT_BUILD_SDDC_SOURCE) | ||||
|  | ||||
| if (OPT_BUILD_SDRPP_SERVER_SOURCE) | ||||
| add_subdirectory("source_modules/sdrpp_server_source") | ||||
| endif (OPT_BUILD_SDRPP_SERVER_SOURCE) | ||||
|  | ||||
| if (OPT_BUILD_RFSPACE_SOURCE) | ||||
| add_subdirectory("source_modules/rfspace_source") | ||||
| endif (OPT_BUILD_RFSPACE_SOURCE) | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| #include <server.h> | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_glfw.h" | ||||
| #include "imgui_impl_opengl3.h" | ||||
| @@ -18,7 +19,6 @@ | ||||
| #include <options.h> | ||||
| #include <filesystem> | ||||
| #include <gui/menus/theme.h> | ||||
| #include <server.h> | ||||
|  | ||||
| #define STB_IMAGE_RESIZE_IMPLEMENTATION | ||||
| #include <stb_image_resize.h> | ||||
| @@ -70,6 +70,9 @@ namespace core { | ||||
|     GLFWwindow* window; | ||||
|  | ||||
|     void setInputSampleRate(double samplerate) { | ||||
|         // Forward this to the server | ||||
|         if (options::opts.serverMode) { server::setInputSampleRate(samplerate); return; } | ||||
|          | ||||
|         sigpath::signalPath.sourceSampleRate = samplerate; | ||||
|         double effectiveSr = samplerate / ((double)(1 << sigpath::signalPath.decimation)); | ||||
|         // NOTE: Zoom controls won't work | ||||
| @@ -297,7 +300,7 @@ int sdrpp_main(int argc, char* argv[]) { | ||||
|  | ||||
|     core::configManager.release(true); | ||||
|  | ||||
|     if (options::opts.serverMode) { return server_main(); } | ||||
|     if (options::opts.serverMode) { return server::main(); } | ||||
|  | ||||
|     core::configManager.acquire(); | ||||
|     int winWidth = core::configManager.conf["windowSize"]["w"]; | ||||
|   | ||||
| @@ -2,16 +2,16 @@ | ||||
| #include <dsp/block.h> | ||||
|  | ||||
| namespace dsp { | ||||
|     enum PCMType { | ||||
|         PCM_TYPE_I8, | ||||
|         PCM_TYPE_I16, | ||||
|         PCM_TYPE_F32 | ||||
|     }; | ||||
|  | ||||
|     class DynamicRangeCompressor : public generic_block<DynamicRangeCompressor> { | ||||
|     public: | ||||
|         DynamicRangeCompressor() {} | ||||
|  | ||||
|         enum PCMType { | ||||
|             PCM_TYPE_I8, | ||||
|             PCM_TYPE_I16, | ||||
|             PCM_TYPE_F32 | ||||
|         }; | ||||
|  | ||||
|         DynamicRangeCompressor(stream<complex_t>* in, PCMType pcmType) { init(in, pcmType); } | ||||
|  | ||||
|         void init(stream<complex_t>* in, PCMType pcmType) { | ||||
| @@ -41,44 +41,42 @@ namespace dsp { | ||||
|         int run() { | ||||
|             int count = _in->read(); | ||||
|             if (count < 0) { return -1; } | ||||
|             PCMType type = _pcmType; | ||||
|  | ||||
|             float* scaler = (float*)out.writeBuf; | ||||
|             void* dataBuf = &out.writeBuf[4]; | ||||
|             uint16_t* compressionType = (uint16_t*)out.writeBuf; | ||||
|             uint16_t* sampleType = (uint16_t*)&out.writeBuf[2]; | ||||
|             float* scaler = (float*)&out.writeBuf[4]; | ||||
|             void* dataBuf = &out.writeBuf[8]; | ||||
|  | ||||
|             // If no dynamic range compression is to be done, just pass the data to the output with a null scaler | ||||
|             if (_pcmType == PCM_TYPE_F32) { | ||||
|             // Write options and leave blank space for compression | ||||
|             *compressionType = 0; | ||||
|             *sampleType = type; | ||||
|  | ||||
|             // If type is float32, no compression is needed | ||||
|             if (type == PCM_TYPE_F32) { | ||||
|                 *scaler = 0; | ||||
|                 memcpy(dataBuf, _in->readBuf, count * sizeof(complex_t)); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(4 + (count * sizeof(complex_t)))) { return -1; } | ||||
|                 if (!out.swap(8 + (count * sizeof(complex_t)))) { return -1; } | ||||
|                 return count; | ||||
|             } | ||||
|  | ||||
|             // Find maximum value | ||||
|             complex_t val; | ||||
|             float absre; | ||||
|             float absim; | ||||
|             float maxVal = 0; | ||||
|             for (int i = 0; i < count; i++) { | ||||
|                 val = _in->readBuf[i]; | ||||
|                 absre = fabsf(val.re); | ||||
|                 absim = fabsf(val.im); | ||||
|                 if (absre > maxVal) { maxVal = absre; } | ||||
|                 if (absim > maxVal) { maxVal = absim; } | ||||
|             } | ||||
|             uint32_t maxIdx; | ||||
|             volk_32f_index_max_32u(&maxIdx, (float*)_in->readBuf, count * 2); | ||||
|             float maxVal = ((float*)_in->readBuf)[maxIdx]; | ||||
|             *scaler = maxVal; | ||||
|  | ||||
|             // Convert to the right type and send it out (sign bit determins pcm type) | ||||
|             if (_pcmType == PCM_TYPE_I8) { | ||||
|                 *scaler = maxVal; | ||||
|             if (type == PCM_TYPE_I8) { | ||||
|                 volk_32f_s32f_convert_8i((int8_t*)dataBuf, (float*)_in->readBuf, 128.0f / maxVal, count * 2); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(4 + (count * sizeof(int8_t) * 2))) { return -1; } | ||||
|                 if (!out.swap(8 + (count * sizeof(int8_t) * 2))) { return -1; } | ||||
|             } | ||||
|             else if (_pcmType == PCM_TYPE_I16) { | ||||
|                 *scaler = -maxVal; | ||||
|             else if (type == PCM_TYPE_I16) { | ||||
|                 volk_32f_s32f_convert_16i((int16_t*)dataBuf, (float*)_in->readBuf, 32768.0f / maxVal, count * 2); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(4 + (count * sizeof(int16_t) * 2))) { return -1; } | ||||
|                 if (!out.swap(8 + (count * sizeof(int16_t) * 2))) { return -1; } | ||||
|             } | ||||
|             else { | ||||
|                 _in->flush(); | ||||
| @@ -121,31 +119,29 @@ namespace dsp { | ||||
|             int count = _in->read(); | ||||
|             if (count < 0) { return -1; } | ||||
|  | ||||
|             float* scaler = (float*)_in->readBuf; | ||||
|             void* dataBuf = &_in->readBuf[4]; | ||||
|             uint16_t sampleType = *(uint16_t*)&_in->readBuf[2]; | ||||
|             float scaler = *(float*)&_in->readBuf[4]; | ||||
|             void* dataBuf = &_in->readBuf[8]; | ||||
|  | ||||
|             // If the scaler is null, data is F32 | ||||
|             if (*scaler == 0) { | ||||
|                 memcpy(out.writeBuf, dataBuf, count - 4); | ||||
|             if (sampleType == PCM_TYPE_F32) { | ||||
|                 memcpy(out.writeBuf, dataBuf, count - 8); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap((count - 4) / sizeof(complex_t))) { return -1; } | ||||
|                 return count; | ||||
|                 if (!out.swap((count - 8) / sizeof(complex_t))) { return -1; } | ||||
|             } | ||||
|  | ||||
|             // Convert back to f32 from the pcm type | ||||
|             float absScale = fabsf(*scaler); | ||||
|             if (*scaler > 0) { | ||||
|                 spdlog::warn("{0}", absScale); | ||||
|                 int outCount = (count - 4) / (sizeof(int8_t) * 2); | ||||
|                 volk_8i_s32f_convert_32f((float*)out.writeBuf, (int8_t*)dataBuf, 128.0f / absScale, outCount * 2); | ||||
|             else if (sampleType == PCM_TYPE_I16) { | ||||
|                 int outCount = (count - 8) / (sizeof(int16_t) * 2); | ||||
|                 volk_16i_s32f_convert_32f((float*)out.writeBuf, (int16_t*)dataBuf, 32768.0f / scaler, outCount * 2); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(outCount)) { return -1; } | ||||
|             } | ||||
|             else if (sampleType == PCM_TYPE_I8) { | ||||
|                 int outCount = (count - 8) / (sizeof(int8_t) * 2); | ||||
|                 volk_8i_s32f_convert_32f((float*)out.writeBuf, (int8_t*)dataBuf, 128.0f / scaler, outCount * 2); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(outCount)) { return -1; } | ||||
|             } | ||||
|             else { | ||||
|                 int outCount = (count - 4) / (sizeof(int16_t) * 2); | ||||
|                 volk_16i_s32f_convert_32f((float*)out.writeBuf, (int16_t*)dataBuf, 32768.0f / absScale, outCount * 2); | ||||
|                 _in->flush(); | ||||
|                 if (!out.swap(outCount)) { return -1; } | ||||
|             } | ||||
|  | ||||
|             return count; | ||||
|   | ||||
							
								
								
									
										54
									
								
								core/src/dsp/link.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								core/src/dsp/link.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #pragma once | ||||
| #include <dsp/block.h> | ||||
|  | ||||
| namespace dsp { | ||||
|     template <class T> | ||||
|     class Link : public generic_block<Link<T>> { | ||||
|     public: | ||||
|         Link() {} | ||||
|  | ||||
|         Link(stream<T>* a, stream<T>* b) { init(a, b); } | ||||
|  | ||||
|         void init(stream<T>* in, stream<T>* out) { | ||||
|             _in = in; | ||||
|             _out = out; | ||||
|             generic_block<Link<T>>::registerInput(_in); | ||||
|             generic_block<Link<T>>::registerOutput(_out); | ||||
|             generic_block<Link<T>>::_block_init = true; | ||||
|         } | ||||
|  | ||||
|         void setInput(stream<T>* in) { | ||||
|             assert(generic_block<Link<T>>::_block_init); | ||||
|             std::lock_guard<std::mutex> lck(generic_block<Link<T>>::ctrlMtx); | ||||
|             generic_block<Link<T>>::tempStop(); | ||||
|             generic_block<Link<T>>::unregisterInput(_in); | ||||
|             _in = in; | ||||
|             generic_block<Link<T>>::registerInput(_in); | ||||
|             generic_block<Link<T>>::tempStart(); | ||||
|         } | ||||
|  | ||||
|         void setOutput(stream<T>* out) { | ||||
|             assert(generic_block<Link<T>>::_block_init); | ||||
|             std::lock_guard<std::mutex> lck(generic_block<Link<T>>::ctrlMtx); | ||||
|             generic_block<Link<T>>::tempStop(); | ||||
|             generic_block<Link<T>>::unregisterOutput(_out); | ||||
|             _out = out; | ||||
|             generic_block<Link<T>>::registerOutput(_out); | ||||
|             generic_block<Link<T>>::tempStart(); | ||||
|         } | ||||
|  | ||||
|         int run() { | ||||
|             int count = _in->read(); | ||||
|             if (count < 0) { return -1; } | ||||
|  | ||||
|             memcpy(_out->writeBuf, _in->readBuf, count * sizeof(T)); | ||||
|  | ||||
|             _in->flush(); | ||||
|             return _out->swap(count) ? count : -1; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         stream<T>* _in; | ||||
|         stream<T>* _out; | ||||
|     }; | ||||
| } | ||||
| @@ -516,7 +516,7 @@ void MainWindow::draw() { | ||||
|         } | ||||
|  | ||||
|         if (ImGui::CollapsingHeader("Debug")) { | ||||
|             ImGui::Text("Frame time: %.3f ms/frame", 1000.0 / ImGui::GetIO().Framerate); | ||||
|             ImGui::Text("Frame time: %.3f ms/frame", ImGui::GetIO().DeltaTime * 1000.0f); | ||||
|             ImGui::Text("Framerate: %.1f FPS", ImGui::GetIO().Framerate); | ||||
|             ImGui::Text("Center Frequency: %.0f Hz", gui::waterfall.getCenterFrequency()); | ||||
|             ImGui::Text("Source name: %s", sourceName.c_str()); | ||||
|   | ||||
							
								
								
									
										745
									
								
								core/src/gui/smgui.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										745
									
								
								core/src/gui/smgui.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,745 @@ | ||||
| #include "smgui.h" | ||||
| #include "style.h" | ||||
| #include <options.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <gui/gui.h> | ||||
|  | ||||
| namespace SmGui { | ||||
|     std::map<FormatString, const char*> fmtStr = { | ||||
|         { FMT_STR_NONE, "" }, | ||||
|         { FMT_STR_INT_DEFAULT, "%d" }, | ||||
|         { FMT_STR_INT_DB, "%d dB" }, | ||||
|         { FMT_STR_FLOAT_DEFAULT, "%f" }, | ||||
|         { FMT_STR_FLOAT_NO_DECIMAL, "%.0f" }, | ||||
|         { FMT_STR_FLOAT_ONE_DECIMAL, "%.1f" }, | ||||
|         { FMT_STR_FLOAT_TWO_DECIMAL, "%.2f" }, | ||||
|         { FMT_STR_FLOAT_THREE_DECIMAL, "%.3f" }, | ||||
|         { FMT_STR_FLOAT_DB_NO_DECIMAL, "%.0f dB" }, | ||||
|         { FMT_STR_FLOAT_DB_ONE_DECIMAL, "%.1f dB" }, | ||||
|         { FMT_STR_FLOAT_DB_TWO_DECIMAL, "%.2f dB" }, | ||||
|         { FMT_STR_FLOAT_DB_THREE_DECIMAL, "%.3f dB" } | ||||
|     }; | ||||
|  | ||||
|     DrawList* rdl = NULL; | ||||
|     bool forceSyncForNext = false; | ||||
|     std::string diffId = ""; | ||||
|     DrawListElem diffValue; | ||||
|     bool nextItemFillWidth = false; | ||||
|  | ||||
|     std::string ImStrToString(const char* imstr) { | ||||
|         int len = 0; | ||||
|         const char* end = imstr; | ||||
|         while (*end) { end += strlen(end) + 1; } | ||||
|         return std::string(imstr, end); | ||||
|     } | ||||
|  | ||||
|     // Rec/Play functions | ||||
|     void setDiff(std::string id, SmGui::DrawListElem value) { | ||||
|         diffId = id; | ||||
|         diffValue = value; | ||||
|     } | ||||
|  | ||||
|     // TODO: Add getDiff function for client | ||||
|  | ||||
|     void startRecord(DrawList* dl) { | ||||
|         rdl = dl; | ||||
|     } | ||||
|  | ||||
|     void stopRecord() { | ||||
|         rdl = NULL; | ||||
|     } | ||||
|  | ||||
|     #define SET_DIFF_VOID(id)       diffId = id; syncRequired = elem.forceSync; | ||||
|     #define SET_DIFF_BOOL(id, bo)   diffId = id; diffValue.type = DRAW_LIST_ELEM_TYPE_BOOL; diffValue.b = bo; syncRequired = elem.forceSync; | ||||
|     #define SET_DIFF_INT(id, in)    diffId = id; diffValue.type = DRAW_LIST_ELEM_TYPE_INT; diffValue.i = in; syncRequired = elem.forceSync; | ||||
|     #define SET_DIFF_FLOAT(id, fl)  diffId = id; diffValue.type = DRAW_LIST_ELEM_TYPE_FLOAT; diffValue.f = fl; syncRequired = elem.forceSync; | ||||
|     #define SET_DIFF_STRING(id, st) diffId = id; diffValue.type = DRAW_LIST_ELEM_TYPE_STRING; diffValue.str = st; syncRequired = elem.forceSync; | ||||
|  | ||||
|     void DrawList::draw(std::string& diffId, DrawListElem& diffValue, bool& syncRequired) { | ||||
|         int elemCount = elements.size(); | ||||
|         nextItemFillWidth = false; | ||||
|  | ||||
|         for (int i = 0; i < elemCount;) { | ||||
|             // Get element | ||||
|             DrawListElem& elem = elements[i++]; | ||||
|             if (elem.type != DRAW_LIST_ELEM_TYPE_DRAW_STEP) { continue; } | ||||
|  | ||||
|             // Format calls | ||||
|             if (elem.step == DRAW_STEP_FILL_WIDTH) { FillWidth(); } | ||||
|             else if (elem.step == DRAW_STEP_SAME_LINE) { SameLine(); } | ||||
|             else if (elem.step == DRAW_STEP_BEGIN_DISABLED) { BeginDisabled(); } | ||||
|             else if (elem.step == DRAW_STEP_END_DISABLED) { EndDisabled(); } | ||||
|  | ||||
|             // Widget Calls | ||||
|             else if (elem.step == DRAW_STEP_COMBO) { | ||||
|                 if (Combo(elements[i].str.c_str(), &elements[i+1].i, elements[i+2].str.c_str(), elements[i+3].i)) { | ||||
|                     SET_DIFF_INT(elements[i].str, elements[i+1].i); | ||||
|                 } | ||||
|                 i += 4; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_BUTTON) { | ||||
|                 if (Button(elements[i].str.c_str(), ImVec2(elements[i+1].f, elements[i+2].f))) { | ||||
|                     SET_DIFF_VOID(elements[i].str); | ||||
|                 } | ||||
|                 i += 3; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_COLUMNS) { | ||||
|                 Columns(elements[i].i, elements[i+1].str.c_str(), elements[i+2].b); | ||||
|                 i += 3; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_NEXT_COLUMN) { NextColumn(); } | ||||
|             else if (elem.step == DRAW_STEP_RADIO_BUTTON) { | ||||
|                 if (RadioButton(elements[i].str.c_str(), elements[i+1].b)) { | ||||
|                     SET_DIFF_VOID(elements[i].str); | ||||
|                 } | ||||
|                 i += 2; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_BEGIN_GROUP) { BeginGroup(); } | ||||
|             else if (elem.step == DRAW_STEP_END_GROUP) { EndGroup(); } | ||||
|             else if (elem.step == DRAW_STEP_LEFT_LABEL) { | ||||
|                 LeftLabel(elements[i].str.c_str()); | ||||
|                 i++; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_SLIDER_INT) { | ||||
|                 if (SliderInt(elements[i].str.c_str(), &elements[i+1].i, elements[i+2].i, elements[i+3].i, (FormatString)elements[i+4].i, elements[i+5].i)) { | ||||
|                     SET_DIFF_INT(elements[i].str, elements[i+1].i); | ||||
|                 } | ||||
|                 i += 6; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_SLIDER_FLOAT_WITH_STEPS) { | ||||
|                 if (SliderFloatWithSteps(elements[i].str.c_str(), &elements[i+1].f, elements[i+2].f, elements[i+3].f, elements[i+4].f, (FormatString)elements[i+5].i)) { | ||||
|                     SET_DIFF_FLOAT(elements[i].str, elements[i+1].f); | ||||
|                 } | ||||
|                 i += 6; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_INPUT_INT) { | ||||
|                 if (InputInt(elements[i].str.c_str(), &elements[i+1].i, elements[i+2].i, elements[i+3].i, elements[i+4].i)) { | ||||
|                     SET_DIFF_INT(elements[i].str, elements[i+1].i); | ||||
|                 } | ||||
|                 i += 5; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_CHECKBOX) { | ||||
|                 if (Checkbox(elements[i].str.c_str(), &elements[i+1].b)) { | ||||
|                     SET_DIFF_BOOL(elements[i].str, elements[i+1].b); | ||||
|                 } | ||||
|                 i += 2; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_SLIDER_FLOAT) { | ||||
|                 if (SliderFloat(elements[i].str.c_str(), &elements[i+1].f, elements[i+2].f, elements[i+3].f, (FormatString)elements[i+4].i, elements[i+5].i)) { | ||||
|                     SET_DIFF_FLOAT(elements[i].str, elements[i+1].f); | ||||
|                 } | ||||
|                 i += 6; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_INPUT_TEXT) { | ||||
|                 char tmpBuf[4096]; | ||||
|                 strcpy(tmpBuf, elements[i+1].str.c_str()); | ||||
|                 if (InputText(elements[i].str.c_str(), tmpBuf, elements[i+2].i, elements[i+3].i)) { | ||||
|                     elements[i+1].str = tmpBuf; | ||||
|                     SET_DIFF_STRING(elements[i].str, tmpBuf); | ||||
|                 } | ||||
|                 i += 4; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_TEXT) { | ||||
|                 Text(elements[i].str.c_str()); | ||||
|                 i++; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_TEXT_COLORED) { | ||||
|                 TextColored(ImVec4(elements[i].f, elements[i+1].f, elements[i+2].f, elements[i+3].f), elements[i+4].str.c_str()); | ||||
|                 i += 5; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_OPEN_POPUP) { | ||||
|                 OpenPopup(elements[i].str.c_str(), elements[i+1].i); | ||||
|                 i += 2; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_BEGIN_POPUP) { | ||||
|                 gui::mainWindow.lockWaterfallControls = true; | ||||
|                 if (!BeginPopup(elements[i].str.c_str(), elements[i+1].i)) { | ||||
|                     i += 2; | ||||
|                     while (i < elemCount && !(elements[i].type == DRAW_LIST_ELEM_TYPE_DRAW_STEP && elements[i].step == DRAW_STEP_END_POPUP)) { i++; } | ||||
|                     i++; | ||||
|                 } | ||||
|                 else { | ||||
|                     i += 2; | ||||
|                 } | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_END_POPUP) { | ||||
|                 EndPopup(); | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_BEGIN_TABLE) { | ||||
|                 if (!BeginTable(elements[i].str.c_str(), elements[i+1].i, elements[i+2].i, ImVec2(elements[i+3].f, elements[i+4].f), elements[i+5].f)) { | ||||
|                     i += 6; | ||||
|                     while (i < elemCount && !(elements[i].type == DRAW_LIST_ELEM_TYPE_DRAW_STEP && elements[i].step == DRAW_STEP_END_TABLE)) { i++; } | ||||
|                     i++; | ||||
|                 } | ||||
|                 else { | ||||
|                     i += 6; | ||||
|                 } | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_END_TABLE) { | ||||
|                 EndTable(); | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_TABLE_NEXT_ROW) { | ||||
|                 TableNextRow(elements[i].i, elements[i+1].f); | ||||
|                 i += 2; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_TABLE_SET_COLUMN_INDEX) { | ||||
|                 TableSetColumnIndex(elements[i].i); | ||||
|                 i++; | ||||
|             } | ||||
|             else if (elem.step == DRAW_STEP_SET_NEXT_ITEM_WIDTH) { | ||||
|                 SetNextItemWidth(elements[i].f); | ||||
|                 i++; | ||||
|             } | ||||
|             else { | ||||
|                 spdlog::error("Invalid widget in Drawlist"); | ||||
|             } | ||||
|  | ||||
|             if (elem.step != DRAW_STEP_FILL_WIDTH) { nextItemFillWidth = false; } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Drawlist stuff | ||||
|     void DrawList::pushStep(DrawStep step, bool forceSync) { | ||||
|         DrawListElem elem; | ||||
|         elem.type = DRAW_LIST_ELEM_TYPE_DRAW_STEP; | ||||
|         elem.step = step; | ||||
|         elem.forceSync = forceSync; | ||||
|         elements.push_back(elem); | ||||
|     } | ||||
|  | ||||
|     void DrawList::pushBool(bool b) { | ||||
|         DrawListElem elem; | ||||
|         elem.type = DRAW_LIST_ELEM_TYPE_BOOL; | ||||
|         elem.b = b; | ||||
|         elements.push_back(elem); | ||||
|     } | ||||
|      | ||||
|     void DrawList::pushInt(int i) { | ||||
|         DrawListElem elem; | ||||
|         elem.type = DRAW_LIST_ELEM_TYPE_INT; | ||||
|         elem.i = i; | ||||
|         elements.push_back(elem); | ||||
|     } | ||||
|      | ||||
|     void DrawList::pushFloat(float f) { | ||||
|         DrawListElem elem; | ||||
|         elem.type = DRAW_LIST_ELEM_TYPE_FLOAT; | ||||
|         elem.f = f; | ||||
|         elements.push_back(elem); | ||||
|     } | ||||
|      | ||||
|     void DrawList::pushString(std::string str) { | ||||
|         DrawListElem elem; | ||||
|         elem.type = DRAW_LIST_ELEM_TYPE_STRING; | ||||
|         elem.str = str; | ||||
|         elements.push_back(elem); | ||||
|     } | ||||
|  | ||||
|     int DrawList::loadItem(DrawListElem& elem, uint8_t* data, int len) { | ||||
|         // Get type | ||||
|         int i = 0; | ||||
|         elem.type = (DrawListElemType)data[i++]; | ||||
|  | ||||
|         // Read data depending on type | ||||
|         if (elem.type == DRAW_LIST_ELEM_TYPE_DRAW_STEP && len >= 2) { | ||||
|             elem.step = (DrawStep)data[i++]; | ||||
|             elem.forceSync = data[i++]; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_BOOL && len-- >= 1) { | ||||
|             elem.b = data[i++]; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_INT && len >= 4) { | ||||
|             elem.i = *(int*)&data[i]; | ||||
|             i += 4; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_FLOAT && len >= 4) { | ||||
|             elem.f = *(float*)&data[i]; | ||||
|             i += 4; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_STRING && len >= 2) { | ||||
|             uint16_t slen = *(uint16_t*)&data[i]; | ||||
|             if (len < slen + 2) { return -1; } | ||||
|             elem.str = std::string(&data[i + 2], &data[i + 2 + slen]); | ||||
|             i += slen + 2; | ||||
|         } | ||||
|         else { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         return i; | ||||
|     } | ||||
|      | ||||
|     int DrawList::load(void* data, int len) { | ||||
|         uint8_t* buf = (uint8_t*)data; | ||||
|         elements.clear(); | ||||
|         int i = 0; | ||||
|  | ||||
|         // Load all entries | ||||
|         while (len > 0) { | ||||
|             // Load entry type | ||||
|             DrawListElem elem; | ||||
|             int consumed = loadItem(elem, &buf[i], len); | ||||
|             if (consumed < 0) { return -1; } | ||||
|             i += consumed; | ||||
|             len -= consumed; | ||||
|  | ||||
|             // Add element to list | ||||
|             elements.push_back(elem); | ||||
|         } | ||||
|  | ||||
|         // Validate and clear if invalid | ||||
|         if (!validate()) { | ||||
|             spdlog::error("Drawlist validation failed"); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         return i; | ||||
|     } | ||||
|  | ||||
|     int DrawList::storeItem(DrawListElem& elem, void* data, int len) { | ||||
|         // Check size requirement | ||||
|         uint8_t* buf = (uint8_t*)data; | ||||
|         if (len < 1) { return -1; } | ||||
|         int i = 0; | ||||
|         len--; | ||||
|  | ||||
|         // Save entry type | ||||
|         buf[i++] = elem.type; | ||||
|  | ||||
|         // Check type and save data accordingly             | ||||
|         if (elem.type == DRAW_LIST_ELEM_TYPE_DRAW_STEP && len >= 2) { | ||||
|             buf[i++] = elem.step; | ||||
|             buf[i++] = elem.forceSync; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_BOOL && len >= 1) { | ||||
|             buf[i++] = elem.b; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_INT && len >= 4) { | ||||
|             *(int*)&buf[i] = elem.i; | ||||
|             i += 4; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_FLOAT && len >= 4) { | ||||
|             *(float*)&buf[i] = elem.f; | ||||
|             i += 4; | ||||
|         } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_STRING) { | ||||
|             int slen = elem.str.size(); | ||||
|             if (len < slen + 2) { return -1; } | ||||
|             *(uint16_t*)&buf[i] = slen; | ||||
|             memcpy(&buf[i + 2], elem.str.c_str(), slen); | ||||
|             i += slen + 2; | ||||
|         } | ||||
|         else { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         return i; | ||||
|     } | ||||
|  | ||||
|     int DrawList::store(void* data, int len) { | ||||
|         uint8_t* buf = (uint8_t*)data; | ||||
|         int i = 0; | ||||
|  | ||||
|         // Iterate through all element and write the data in the buffer | ||||
|         for (auto& elem : elements) { | ||||
|             int count = storeItem(elem, &buf[i], len); | ||||
|             if (count < 0) { return -1; } | ||||
|             i += count; | ||||
|             len -= count; | ||||
|         } | ||||
|  | ||||
|         return i; | ||||
|     } | ||||
|  | ||||
|     int DrawList::getItemSize(DrawListElem& elem) { | ||||
|         if (elem.type == DRAW_LIST_ELEM_TYPE_DRAW_STEP) { return 3; } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_BOOL) { return 2; } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_INT) { return 5; } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_FLOAT) { return 5; } | ||||
|         else if (elem.type == DRAW_LIST_ELEM_TYPE_STRING) { return 3 + elem.str.size(); } | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     int DrawList::getSize() { | ||||
|         int size = 0; | ||||
|  | ||||
|         // Iterate through all element to add up the total size | ||||
|         for (auto& elem : elements) { | ||||
|             size += getItemSize(elem); | ||||
|         } | ||||
|  | ||||
|         return size; | ||||
|     } | ||||
|  | ||||
|     bool DrawList::checkTypes(int firstId, int n, ...) { | ||||
|         va_list args; | ||||
|         va_start(args, n); | ||||
|  | ||||
|         // Check if enough elements are left | ||||
|         if (elements.size() - firstId < n) { return false; } | ||||
|  | ||||
|         // Check the type of each element | ||||
|         for (int i = 0; i < n; i++) { | ||||
|             if (va_arg(args, DrawListElemType) != elements[firstId + i].type) { | ||||
|                 va_end(args); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         va_end(args); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     #define VALIDATE_WIDGET(n, ws, ...)     if (step == ws) { if (!checkTypes(i, n, __VA_ARGS__)) { return false; }; i += n; } | ||||
|     #define E_VALIDATE_WIDGET(n, ws, ...)   else VALIDATE_WIDGET(n, ws, __VA_ARGS__) | ||||
|  | ||||
|     bool DrawList::validate() { | ||||
|         int count = elements.size(); | ||||
|         for (int i = 0; i < count;) { | ||||
|             if (elements[i].type != DRAW_LIST_ELEM_TYPE_DRAW_STEP) { return false; } | ||||
|             DrawStep step = elements[i++].step; | ||||
|  | ||||
|             VALIDATE_WIDGET(4, DRAW_STEP_COMBO, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(3, DRAW_STEP_BUTTON, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT) | ||||
|             E_VALIDATE_WIDGET(3, DRAW_STEP_COLUMNS, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) | ||||
|             E_VALIDATE_WIDGET(2, DRAW_STEP_RADIO_BUTTON, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) | ||||
|             E_VALIDATE_WIDGET(1, DRAW_STEP_LEFT_LABEL, DRAW_LIST_ELEM_TYPE_STRING) | ||||
|             E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, | ||||
|                                                         DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_FLOAT_WITH_STEPS, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, | ||||
|                                                         DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(5, DRAW_STEP_INPUT_INT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, | ||||
|                                                         DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(2, DRAW_STEP_CHECKBOX, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_BOOL) | ||||
|             E_VALIDATE_WIDGET(6, DRAW_STEP_SLIDER_FLOAT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, | ||||
|                                                         DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(4, DRAW_STEP_INPUT_TEXT, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(1, DRAW_STEP_TEXT, DRAW_LIST_ELEM_TYPE_STRING) | ||||
|             E_VALIDATE_WIDGET(5, DRAW_STEP_TEXT_COLORED, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, | ||||
|                                                 DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_STRING) | ||||
|             E_VALIDATE_WIDGET(2, DRAW_STEP_OPEN_POPUP, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(2, DRAW_STEP_BEGIN_POPUP, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(6, DRAW_STEP_BEGIN_TABLE, DRAW_LIST_ELEM_TYPE_STRING, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_INT, | ||||
|                                                         DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT, DRAW_LIST_ELEM_TYPE_FLOAT) | ||||
|             E_VALIDATE_WIDGET(2, DRAW_STEP_TABLE_NEXT_ROW, DRAW_LIST_ELEM_TYPE_INT, DRAW_LIST_ELEM_TYPE_FLOAT) | ||||
|             E_VALIDATE_WIDGET(1, DRAW_STEP_TABLE_SET_COLUMN_INDEX, DRAW_LIST_ELEM_TYPE_INT) | ||||
|             E_VALIDATE_WIDGET(1, DRAW_STEP_SET_NEXT_ITEM_WIDTH, DRAW_LIST_ELEM_TYPE_FLOAT) | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // Signaling functions | ||||
|     void ForceSync() { | ||||
|         forceSyncForNext = true; | ||||
|     } | ||||
|  | ||||
|     // Format functions | ||||
|     void FillWidth() { | ||||
|         if (!options::opts.serverMode) { | ||||
|             nextItemFillWidth = true; | ||||
|             ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); | ||||
|             return; | ||||
|         } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_FILL_WIDTH, false); } | ||||
|     } | ||||
|  | ||||
|     void SameLine() { | ||||
|         if (!options::opts.serverMode) { ImGui::SameLine(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_SAME_LINE, false); } | ||||
|     } | ||||
|  | ||||
|     void BeginDisabled() { | ||||
|         if (!options::opts.serverMode) { style::beginDisabled(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_BEGIN_DISABLED, false); } | ||||
|     } | ||||
|  | ||||
|     void EndDisabled() { | ||||
|         if (!options::opts.serverMode) { style::endDisabled(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_END_DISABLED, false); } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // Widget functions | ||||
|     bool Combo(const char *label, int *current_item, const char *items_separated_by_zeros, int popup_max_height_in_items) { | ||||
|         if (!options::opts.serverMode) { return ImGui::Combo(label, current_item, items_separated_by_zeros, popup_max_height_in_items); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_COMBO, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushInt(*current_item); | ||||
|             rdl->pushString(ImStrToString(items_separated_by_zeros)); | ||||
|             rdl->pushInt(popup_max_height_in_items); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_INT) { | ||||
|             *current_item = diffValue.i; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool Button(const char *label, ImVec2 size) { | ||||
|         if (!options::opts.serverMode) { | ||||
|             if (nextItemFillWidth) { size.x = ImGui::GetContentRegionAvailWidth(); } | ||||
|             return ImGui::Button(label, size); | ||||
|         } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_BUTTON, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushFloat(size.x); | ||||
|             rdl->pushFloat(size.y); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         return (diffId == label); | ||||
|     } | ||||
|  | ||||
|     void Columns(int count, const char *id, bool border) { | ||||
|         if (!options::opts.serverMode) { ImGui::Columns(count, id, border); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_COLUMNS, forceSyncForNext); | ||||
|             rdl->pushInt(count); | ||||
|             rdl->pushString(id); | ||||
|             rdl->pushBool(border); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     void NextColumn() { | ||||
|         if (!options::opts.serverMode) { ImGui::NextColumn(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_NEXT_COLUMN, false); } | ||||
|     } | ||||
|      | ||||
|     bool RadioButton(const char *label, bool active) { | ||||
|         if (!options::opts.serverMode) { return ImGui::RadioButton(label, active); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_RADIO_BUTTON, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushBool(active); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         return (diffId == label); | ||||
|     } | ||||
|      | ||||
|     void BeginGroup() { | ||||
|         if (!options::opts.serverMode) { ImGui::BeginGroup(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_BEGIN_GROUP, false); } | ||||
|     } | ||||
|      | ||||
|     void EndGroup() { | ||||
|         if (!options::opts.serverMode) { ImGui::EndGroup(); return; } | ||||
|         if (rdl) { rdl->pushStep(DRAW_STEP_END_GROUP, false); } | ||||
|     } | ||||
|      | ||||
|     void LeftLabel(const char *text) { | ||||
|         if (!options::opts.serverMode) { ImGui::LeftLabel(text); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_LEFT_LABEL, forceSyncForNext); | ||||
|             rdl->pushString(text); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     bool SliderInt(const char *label, int *v, int v_min, int v_max, FormatString format, ImGuiSliderFlags flags) { | ||||
|         if (!options::opts.serverMode) { return ImGui::SliderInt(label, v, v_min, v_max, fmtStr[format], flags); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_SLIDER_INT, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushInt(*v); | ||||
|             rdl->pushInt(v_min); | ||||
|             rdl->pushInt(v_max); | ||||
|             rdl->pushInt(format); | ||||
|             rdl->pushInt(flags); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_INT) { | ||||
|             *v = diffValue.i; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool SliderFloatWithSteps(const char *label, float *v, float v_min, float v_max, float v_step, FormatString display_format) { | ||||
|         if (!options::opts.serverMode) { return ImGui::SliderFloatWithSteps(label, v, v_min, v_max, v_step, fmtStr[display_format]); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_SLIDER_FLOAT_WITH_STEPS, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushFloat(*v); | ||||
|             rdl->pushFloat(v_min); | ||||
|             rdl->pushFloat(v_max); | ||||
|             rdl->pushFloat(v_step); | ||||
|             rdl->pushInt(display_format); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_FLOAT) { | ||||
|             *v = diffValue.f; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool InputInt(const char *label, int *v, int step, int step_fast, ImGuiInputTextFlags flags) { | ||||
|         if (!options::opts.serverMode) { return ImGui::InputInt(label, v, step, step_fast, flags); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_INPUT_INT, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushInt(*v); | ||||
|             rdl->pushInt(step); | ||||
|             rdl->pushInt(step_fast); | ||||
|             rdl->pushInt(flags); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_INT) { | ||||
|             *v = diffValue.i; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     bool Checkbox(const char *label, bool *v) { | ||||
|         if (!options::opts.serverMode) { return ImGui::Checkbox(label, v); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_CHECKBOX, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushBool(*v); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_BOOL) { | ||||
|             *v = diffValue.b; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool SliderFloat(const char *label, float *v, float v_min, float v_max, FormatString format, ImGuiSliderFlags flags) { | ||||
|         if (!options::opts.serverMode) { return ImGui::SliderFloat(label, v, v_min, v_max, fmtStr[format], flags); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_SLIDER_FLOAT, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushFloat(*v); | ||||
|             rdl->pushFloat(v_min); | ||||
|             rdl->pushFloat(v_max); | ||||
|             rdl->pushInt(format); | ||||
|             rdl->pushInt(flags); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_FLOAT) { | ||||
|             *v = diffValue.f; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags) { | ||||
|         if (!options::opts.serverMode) { return ImGui::InputText(label, buf, buf_size, flags); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_INPUT_TEXT, forceSyncForNext); | ||||
|             rdl->pushString(label); | ||||
|             rdl->pushString(buf); | ||||
|             rdl->pushInt(buf_size); | ||||
|             rdl->pushInt(flags); | ||||
|             forceSyncForNext = false; | ||||
|         } | ||||
|         if (diffId == label && diffValue.type == DRAW_LIST_ELEM_TYPE_STRING && diffValue.str.size() <= buf_size) { | ||||
|             strcpy(buf, diffValue.str.c_str()); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void Text(const char* str) { | ||||
|         if (!options::opts.serverMode) { ImGui::Text("%s", str); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_TEXT, false); | ||||
|             rdl->pushString(str); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void TextColored(const ImVec4 &col, const char *str) { | ||||
|         if (!options::opts.serverMode) { ImGui::TextColored(col, "%s", str); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_TEXT_COLORED, false); | ||||
|             rdl->pushFloat(col.x); | ||||
|             rdl->pushFloat(col.y); | ||||
|             rdl->pushFloat(col.z); | ||||
|             rdl->pushFloat(col.w); | ||||
|             rdl->pushString(str); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void OpenPopup(const char *str_id, ImGuiPopupFlags popup_flags) { | ||||
|         if (!options::opts.serverMode) { ImGui::OpenPopup(str_id, popup_flags); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_OPEN_POPUP, false); | ||||
|             rdl->pushString(str_id); | ||||
|             rdl->pushInt(popup_flags); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool BeginPopup(const char *str_id, ImGuiWindowFlags flags) { | ||||
|         if (!options::opts.serverMode) { return ImGui::BeginPopup(str_id, flags); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_BEGIN_POPUP, false); | ||||
|             rdl->pushString(str_id); | ||||
|             rdl->pushInt(flags); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void EndPopup() { | ||||
|         if (!options::opts.serverMode) { ImGui::EndPopup(); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_END_POPUP, false); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool BeginTable(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width) { | ||||
|         if (!options::opts.serverMode) { return ImGui::BeginTable(str_id, column, flags, outer_size, inner_width); } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_BEGIN_TABLE, false); | ||||
|             rdl->pushString(str_id); | ||||
|             rdl->pushInt(column); | ||||
|             rdl->pushInt(flags); | ||||
|             rdl->pushFloat(outer_size.x); | ||||
|             rdl->pushFloat(outer_size.y); | ||||
|             rdl->pushFloat(inner_width); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void EndTable() { | ||||
|         if (!options::opts.serverMode) { ImGui::EndTable(); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_END_TABLE, false); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void TableNextRow(ImGuiTableRowFlags row_flags, float min_row_height) { | ||||
|         if (!options::opts.serverMode) { ImGui::TableNextRow(row_flags, min_row_height); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_TABLE_NEXT_ROW, false); | ||||
|             rdl->pushInt(row_flags); | ||||
|             rdl->pushFloat(min_row_height); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void TableSetColumnIndex(int column_n) { | ||||
|         if (!options::opts.serverMode) { ImGui::TableSetColumnIndex(column_n); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_TABLE_SET_COLUMN_INDEX, false); | ||||
|             rdl->pushInt(column_n); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     void SetNextItemWidth(float item_width) { | ||||
|         if (!options::opts.serverMode) { ImGui::SetNextItemWidth(item_width); return; } | ||||
|         if (rdl) { | ||||
|             rdl->pushStep(DRAW_STEP_SET_NEXT_ITEM_WIDTH, false); | ||||
|             rdl->pushFloat(item_width); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Config configs | ||||
|     void ForceSyncForNext() { | ||||
|         forceSyncForNext = true; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										146
									
								
								core/src/gui/smgui.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								core/src/gui/smgui.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| #pragma once | ||||
| #include <imgui.h> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <map> | ||||
|  | ||||
| namespace SmGui { | ||||
|     enum DrawStep { | ||||
|         // Format calls | ||||
|         DRAW_STEP_FILL_WIDTH = 0x00, | ||||
|         DRAW_STEP_SAME_LINE, | ||||
|         DRAW_STEP_BEGIN_DISABLED, | ||||
|         DRAW_STEP_END_DISABLED,         | ||||
|          | ||||
|         // Widget calls | ||||
|         DRAW_STEP_COMBO = 0x80, | ||||
|         DRAW_STEP_BUTTON, | ||||
|         DRAW_STEP_COLUMNS, | ||||
|         DRAW_STEP_NEXT_COLUMN, | ||||
|         DRAW_STEP_RADIO_BUTTON, | ||||
|         DRAW_STEP_BEGIN_GROUP, | ||||
|         DRAW_STEP_END_GROUP, | ||||
|         DRAW_STEP_LEFT_LABEL, | ||||
|         DRAW_STEP_SLIDER_INT, | ||||
|         DRAW_STEP_SLIDER_FLOAT_WITH_STEPS, | ||||
|         DRAW_STEP_INPUT_INT, | ||||
|         DRAW_STEP_CHECKBOX, | ||||
|         DRAW_STEP_SLIDER_FLOAT, | ||||
|         DRAW_STEP_INPUT_TEXT, | ||||
|         DRAW_STEP_TEXT, | ||||
|         DRAW_STEP_TEXT_COLORED, | ||||
|         DRAW_STEP_OPEN_POPUP, | ||||
|         DRAW_STEP_BEGIN_POPUP, | ||||
|         DRAW_STEP_END_POPUP, | ||||
|         DRAW_STEP_BEGIN_TABLE, | ||||
|         DRAW_STEP_END_TABLE, | ||||
|         DRAW_STEP_TABLE_NEXT_ROW, | ||||
|         DRAW_STEP_TABLE_SET_COLUMN_INDEX, | ||||
|         DRAW_STEP_SET_NEXT_ITEM_WIDTH | ||||
|     }; | ||||
|  | ||||
|     enum DrawListElemType { | ||||
|         DRAW_LIST_ELEM_TYPE_DRAW_STEP, | ||||
|         DRAW_LIST_ELEM_TYPE_BOOL, | ||||
|         DRAW_LIST_ELEM_TYPE_INT, | ||||
|         DRAW_LIST_ELEM_TYPE_FLOAT, | ||||
|         DRAW_LIST_ELEM_TYPE_STRING, | ||||
|     }; | ||||
|  | ||||
|     struct DrawListElem { | ||||
|         DrawListElemType type; | ||||
|         DrawStep step; | ||||
|         bool forceSync; | ||||
|         bool b; | ||||
|         int i; | ||||
|         float f; | ||||
|         std::string str; | ||||
|     }; | ||||
|  | ||||
|     enum FormatString { | ||||
|         FMT_STR_NONE, | ||||
|         FMT_STR_INT_DEFAULT, | ||||
|         FMT_STR_INT_DB, | ||||
|         FMT_STR_FLOAT_DEFAULT, | ||||
|         FMT_STR_FLOAT_NO_DECIMAL, | ||||
|         FMT_STR_FLOAT_ONE_DECIMAL, | ||||
|         FMT_STR_FLOAT_TWO_DECIMAL, | ||||
|         FMT_STR_FLOAT_THREE_DECIMAL, | ||||
|         FMT_STR_FLOAT_DB_NO_DECIMAL, | ||||
|         FMT_STR_FLOAT_DB_ONE_DECIMAL, | ||||
|         FMT_STR_FLOAT_DB_TWO_DECIMAL, | ||||
|         FMT_STR_FLOAT_DB_THREE_DECIMAL | ||||
|     }; | ||||
|  | ||||
|     extern std::map<FormatString, const char*> fmtStr; | ||||
|  | ||||
|     std::string ImStrToString(const char* imstr); | ||||
|  | ||||
|     class DrawList { | ||||
|     public: | ||||
|         void pushStep(DrawStep step, bool forceSync); | ||||
|         void pushBool(bool b); | ||||
|         void pushInt(int i); | ||||
|         void pushFloat(float f); | ||||
|         void pushString(std::string str); | ||||
|  | ||||
|         void draw(std::string& diffId, DrawListElem& diffValue, bool& syncRequired); | ||||
|          | ||||
|         static int loadItem(DrawListElem& elem, uint8_t* data, int len); | ||||
|         int load(void* data, int len); | ||||
|         static int storeItem(DrawListElem& elem, void* data, int len); | ||||
|         int store(void* data, int len); | ||||
|         static int getItemSize(DrawListElem& elem); | ||||
|         int getSize(); | ||||
|         bool checkTypes(int firstId, int n, ...); | ||||
|         bool validate(); | ||||
|  | ||||
|         std::vector<DrawListElem> elements; | ||||
|     }; | ||||
|  | ||||
|     // Rec/Play functions | ||||
|     // TODO: Maybe move verification to the load function instead of checking in drawFrame | ||||
|     void setDiff(std::string id, SmGui::DrawListElem value); | ||||
|     void startRecord(DrawList* dl); | ||||
|     void stopRecord(); | ||||
|  | ||||
|     // Signaling Functions | ||||
|     void ForceSync(); | ||||
|      | ||||
|     // Format functions | ||||
|     void FillWidth(); | ||||
|     void SameLine(); | ||||
|     void BeginDisabled(); | ||||
|     void EndDisabled(); | ||||
|  | ||||
|     // Widget functions | ||||
|     bool Combo(const char *label, int *current_item, const char *items_separated_by_zeros, int popup_max_height_in_items = -1); | ||||
|     bool Button(const char *label, ImVec2 size = ImVec2(0, 0)); | ||||
|     void Columns(int count = 1, const char *id = (const char *)0, bool border = true); | ||||
|     void NextColumn(); | ||||
|     bool RadioButton(const char *label, bool active); | ||||
|     void BeginGroup(); | ||||
|     void EndGroup(); | ||||
|     void LeftLabel(const char *text); | ||||
|     bool SliderInt(const char *label, int *v, int v_min, int v_max, FormatString format = FMT_STR_INT_DEFAULT, ImGuiSliderFlags flags = 0); | ||||
|     bool SliderFloatWithSteps(const char *label, float *v, float v_min, float v_max, float v_step, FormatString display_format = FMT_STR_FLOAT_THREE_DECIMAL); | ||||
|     bool InputInt(const char *label, int *v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); | ||||
|     bool Checkbox(const char *label, bool *v); | ||||
|     bool SliderFloat(const char *label, float *v, float v_min, float v_max, FormatString format = FMT_STR_FLOAT_THREE_DECIMAL, ImGuiSliderFlags flags = 0); | ||||
|     bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags = 0); | ||||
|     void Text(const char* str); | ||||
|     void TextColored(const ImVec4 &col, const char *str); | ||||
|     void OpenPopup(const char *str_id, ImGuiPopupFlags popup_flags = 0); | ||||
|     bool BeginPopup(const char *str_id, ImGuiWindowFlags flags = 0); | ||||
|     void EndPopup(); | ||||
|  | ||||
|     bool BeginTable(const char *str_id, int column, ImGuiTableFlags flags = 0, const ImVec2 &outer_size = ImVec2((0.0F), (0.0F)), float inner_width = (0.0F)); | ||||
|     void EndTable(); | ||||
|     void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = (0.0F)); | ||||
|     void TableSetColumnIndex(int column_n); | ||||
|     void SetNextItemWidth(float item_width); | ||||
|  | ||||
|     // Config configs | ||||
|     void ForceSyncForNext(); | ||||
|  | ||||
| } | ||||
| @@ -53,4 +53,8 @@ namespace ImGui { | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetCursorPosY(vpos); | ||||
|     } | ||||
|  | ||||
|     void FillWidth() { | ||||
|         ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth()); | ||||
|     } | ||||
| } | ||||
| @@ -16,4 +16,5 @@ namespace style { | ||||
|  | ||||
| namespace ImGui { | ||||
|     void LeftLabel(const char* text); | ||||
|     void FillWidth(); | ||||
| } | ||||
| @@ -18,6 +18,8 @@ namespace options { | ||||
|         opts.root = homedir + "/.config/sdrpp"; | ||||
| #endif | ||||
|         opts.root = std::filesystem::absolute(opts.root).string(); | ||||
|         opts.serverHost = "0.0.0.0"; | ||||
|         opts.serverPort = 5259; | ||||
|     } | ||||
|  | ||||
|     bool parse(int argc, char* argv[]) { | ||||
| @@ -33,6 +35,16 @@ namespace options { | ||||
|             else if (!strcmp(arg, "--server")) { | ||||
|                 opts.serverMode = true; | ||||
|             } | ||||
|             else if (!strcmp(arg, "-a") || !strcmp(arg, "--addr")) { | ||||
|                 if (i == argc - 1) { return false; } | ||||
|                 opts.serverHost = argv[++i]; | ||||
|                 opts.showConsole = true; | ||||
|             } | ||||
|             else if (!strcmp(arg, "-p") || !strcmp(arg, "--port")) { | ||||
|                 if (i == argc - 1) { return false; } | ||||
|                 sscanf(argv[++i], "%d", &opts.serverPort); | ||||
|                 opts.showConsole = true; | ||||
|             } | ||||
|             else { | ||||
|                 spdlog::error("Invalid command line option: {0}", arg); | ||||
|                 return false; | ||||
|   | ||||
| @@ -7,6 +7,8 @@ namespace options { | ||||
|         std::string root; | ||||
|         bool showConsole; | ||||
|         bool serverMode; | ||||
|         std::string serverHost; | ||||
|         int serverPort; | ||||
|     }; | ||||
|  | ||||
|     SDRPP_EXPORT CMDLineOptions opts; | ||||
|   | ||||
| @@ -1,7 +1,354 @@ | ||||
| #include <server.h> | ||||
| #include "server.h" | ||||
| #include "core.h" | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <version.h> | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <filesystem> | ||||
| #include <dsp/types.h> | ||||
| #include <signal_path/signal_path.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <utils/optionlist.h> | ||||
| #include <dsp/compression.h> | ||||
|  | ||||
| int server_main() { | ||||
|     spdlog::error("Server mode is not implemented yet."); | ||||
|     return 0; | ||||
| } | ||||
| namespace server { | ||||
|     dsp::stream<dsp::complex_t> dummyInput; | ||||
|     dsp::DynamicRangeCompressor comp; | ||||
|     dsp::HandlerSink<uint8_t> hnd; | ||||
|     net::Conn client; | ||||
|     uint8_t* rbuf = NULL; | ||||
|     uint8_t* sbuf = NULL; | ||||
|     uint8_t* bbuf = NULL; | ||||
|  | ||||
|     PacketHeader* r_pkt_hdr = NULL; | ||||
|     uint8_t* r_pkt_data = NULL; | ||||
|     CommandHeader* r_cmd_hdr = NULL; | ||||
|     uint8_t* r_cmd_data = NULL; | ||||
|  | ||||
|     PacketHeader* s_pkt_hdr = NULL; | ||||
|     uint8_t* s_pkt_data = NULL; | ||||
|     CommandHeader* s_cmd_hdr = NULL; | ||||
|     uint8_t* s_cmd_data = NULL; | ||||
|  | ||||
|     PacketHeader* bb_pkt_hdr = NULL; | ||||
|     uint8_t* bb_pkt_data = NULL; | ||||
|  | ||||
|     SmGui::DrawListElem dummyElem; | ||||
|  | ||||
|     net::Listener listener; | ||||
|  | ||||
|     OptionList<std::string, std::string> sourceList; | ||||
|     int sourceId = 0; | ||||
|     bool running = false; | ||||
|     double sampleRate = 1000000.0; | ||||
|  | ||||
|     int main() { | ||||
|         spdlog::info("=====| SERVER MODE |====="); | ||||
|  | ||||
|         // Init DSP | ||||
|         comp.init(&dummyInput, dsp::PCM_TYPE_I8); | ||||
|         hnd.init(&comp.out, _testServerHandler, NULL); | ||||
|         rbuf = new uint8_t[SERVER_MAX_PACKET_SIZE]; | ||||
|         sbuf = new uint8_t[SERVER_MAX_PACKET_SIZE]; | ||||
|         bbuf = new uint8_t[SERVER_MAX_PACKET_SIZE]; | ||||
|         comp.start(); | ||||
|         hnd.start(); | ||||
|  | ||||
|         // Initialize headers | ||||
|         r_pkt_hdr = (PacketHeader*)rbuf; | ||||
|         r_pkt_data = &rbuf[sizeof(PacketHeader)]; | ||||
|         r_cmd_hdr = (CommandHeader*)r_pkt_data; | ||||
|         r_cmd_data = &rbuf[sizeof(PacketHeader) + sizeof(CommandHeader)]; | ||||
|  | ||||
|         s_pkt_hdr = (PacketHeader*)sbuf; | ||||
|         s_pkt_data = &sbuf[sizeof(PacketHeader)]; | ||||
|         s_cmd_hdr = (CommandHeader*)s_pkt_data; | ||||
|         s_cmd_data = &sbuf[sizeof(PacketHeader) + sizeof(CommandHeader)]; | ||||
|  | ||||
|         bb_pkt_hdr = (PacketHeader*)bbuf; | ||||
|         bb_pkt_data = &bbuf[sizeof(PacketHeader)]; | ||||
|  | ||||
|         // Terminate config manager | ||||
|         core::configManager.disableAutoSave(); | ||||
|         core::configManager.save(); | ||||
|  | ||||
|         core::configManager.acquire(); | ||||
|         std::string modulesDir = core::configManager.conf["modulesDirectory"]; | ||||
|         std::vector<std::string> modules = core::configManager.conf["modules"]; | ||||
|         auto modList = core::configManager.conf["moduleInstances"].items(); | ||||
|         core::configManager.release(); | ||||
|         modulesDir = std::filesystem::absolute(modulesDir).string(); | ||||
|  | ||||
|         spdlog::info("Loading modules"); | ||||
|  | ||||
|         // Load modules and check type to only load sources ( TODO: Have a proper type parameter int the info ) | ||||
|         // TODO LATER: Add whitelist/blacklist stuff | ||||
|         if (std::filesystem::is_directory(modulesDir)) { | ||||
|             for (const auto& file : std::filesystem::directory_iterator(modulesDir)) { | ||||
|                 std::string path = file.path().generic_string(); | ||||
|                 std::string fn = file.path().filename().string(); | ||||
|                 if (file.path().extension().generic_string() != SDRPP_MOD_EXTENTSION) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (!file.is_regular_file()) { continue; } | ||||
|                 if (fn.find("source") == std::string::npos) { continue; } | ||||
|  | ||||
|                 spdlog::info("Loading {0}", path); | ||||
|                 core::moduleManager.loadModule(path); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             spdlog::warn("Module directory {0} does not exist, not loading modules from directory", modulesDir); | ||||
|         } | ||||
|  | ||||
|         // Load additional modules through the config ( TODO: Have a proper type parameter int the info ) | ||||
|         // TODO LATER: Add whitelist/blacklist stuff | ||||
|         for (auto const& apath : modules) { | ||||
|             std::filesystem::path file = std::filesystem::absolute(apath); | ||||
|             std::string path = file.generic_string(); | ||||
|             std::string fn = file.filename().string(); | ||||
|             if (file.extension().generic_string() != SDRPP_MOD_EXTENTSION) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (!std::filesystem::is_regular_file(file)) { continue; } | ||||
|             if (fn.find("source") == std::string::npos) { continue; } | ||||
|  | ||||
|             spdlog::info("Loading {0}", path); | ||||
|             core::moduleManager.loadModule(path); | ||||
|         } | ||||
|  | ||||
|         // Create module instances | ||||
|         for (auto const& [name, _module] : modList) { | ||||
|             std::string mod = _module["module"]; | ||||
|             bool enabled = _module["enabled"]; | ||||
|             if (core::moduleManager.modules.find(mod) == core::moduleManager.modules.end()) { continue; } | ||||
|             spdlog::info("Initializing {0} ({1})", name, mod); | ||||
|             core::moduleManager.createInstance(name, mod); | ||||
|             if (!enabled) { core::moduleManager.disableInstance(name); } | ||||
|         } | ||||
|  | ||||
|         // Do post-init | ||||
|         core::moduleManager.doPostInitAll(); | ||||
|  | ||||
|         // Generate source list | ||||
|         auto list = sigpath::sourceManager.getSourceNames(); | ||||
|         for (auto& name : list) { | ||||
|             sourceList.define(name, name); | ||||
|         } | ||||
|  | ||||
|         // TODO: Load sourceId from config | ||||
|  | ||||
|         sigpath::sourceManager.selectSource(sourceList[sourceId]); | ||||
|  | ||||
|         // TODO: Use command line option | ||||
|         listener = net::listen(options::opts.serverHost, options::opts.serverPort); | ||||
|         listener->acceptAsync(_clientHandler, NULL); | ||||
|  | ||||
|         spdlog::info("Ready, listening on {0}:{1}", options::opts.serverHost, options::opts.serverPort); | ||||
|         while(1) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     void _clientHandler(net::Conn conn, void* ctx) { | ||||
|         spdlog::info("Connection from {0}:{1}", "TODO", "TODO"); | ||||
|         client = std::move(conn); | ||||
|         client->readAsync(sizeof(PacketHeader), rbuf, _packetHandler, NULL); | ||||
|  | ||||
|         // Perform settings reset | ||||
|         sigpath::sourceManager.stop(); | ||||
|         comp.setPCMType(dsp::PCM_TYPE_I16); | ||||
|  | ||||
|         sendSampleRate(sampleRate); | ||||
|  | ||||
|         // TODO: Wait otherwise someone else could connect | ||||
|  | ||||
|         listener->acceptAsync(_clientHandler, NULL); | ||||
|     } | ||||
|  | ||||
|     void _packetHandler(int count, uint8_t* buf, void* ctx) { | ||||
|         PacketHeader* hdr = (PacketHeader*)buf; | ||||
|  | ||||
|         // Read the rest of the data (TODO: CHECK SIZE OR SHIT WILL BE FUCKED + ADD TIMEOUT) | ||||
|         int len = 0; | ||||
|         int read = 0; | ||||
|         int goal = hdr->size - sizeof(PacketHeader); | ||||
|         while (len < goal) { | ||||
|             read = client->read(goal - len, &buf[sizeof(PacketHeader) + len]); | ||||
|             if (read < 0) { return; }; | ||||
|             len += read; | ||||
|         } | ||||
|  | ||||
|         // Parse and process | ||||
|         if (hdr->type == PACKET_TYPE_COMMAND && hdr->size >= sizeof(PacketHeader) + sizeof(CommandHeader)) { | ||||
|             CommandHeader* chdr = (CommandHeader*)&buf[sizeof(PacketHeader)]; | ||||
|             commandHandler((Command)chdr->cmd, &buf[sizeof(PacketHeader) + sizeof(CommandHeader)], hdr->size - sizeof(PacketHeader) - sizeof(CommandHeader)); | ||||
|         } | ||||
|         else { | ||||
|             sendError(ERROR_INVALID_PACKET); | ||||
|         } | ||||
|  | ||||
|         // Start another async read | ||||
|         client->readAsync(sizeof(PacketHeader), rbuf, _packetHandler, NULL); | ||||
|     } | ||||
|  | ||||
|     // void _testServerHandler(dsp::complex_t* data, int count, void* ctx) { | ||||
|     //     // Build data packet | ||||
|     //     PacketHeader* hdr = (PacketHeader*)bbuf; | ||||
|     //     hdr->type = PACKET_TYPE_BASEBAND; | ||||
|     //     hdr->size = sizeof(PacketHeader) + (count * sizeof(dsp::complex_t)); | ||||
|     //     memcpy(&bbuf[sizeof(PacketHeader)], data, count * sizeof(dsp::complex_t)); | ||||
|  | ||||
|     //     // Write to network | ||||
|     //     if (client && client->isOpen()) { client->write(hdr->size, bbuf); } | ||||
|     // } | ||||
|  | ||||
|     void _testServerHandler(uint8_t* data, int count, void* ctx) { | ||||
|         // Build data packet | ||||
|         PacketHeader* hdr = (PacketHeader*)bbuf; | ||||
|         hdr->type = PACKET_TYPE_BASEBAND; | ||||
|         hdr->size = sizeof(PacketHeader) + count; | ||||
|         memcpy(&bbuf[sizeof(PacketHeader)], data, count); | ||||
|  | ||||
|         // Write to network | ||||
|         if (client && client->isOpen()) { client->write(hdr->size, bbuf); } | ||||
|     } | ||||
|  | ||||
|     void setInput(dsp::stream<dsp::complex_t>* stream) { | ||||
|         comp.setInput(stream); | ||||
|     } | ||||
|  | ||||
|     void commandHandler(Command cmd, uint8_t* data, int len) { | ||||
|         if (cmd == COMMAND_GET_UI) { | ||||
|             sendUI(COMMAND_GET_UI, "", dummyElem); | ||||
|         } | ||||
|         else if (cmd == COMMAND_UI_ACTION && len >= 3) { | ||||
|             // Check if sending back data is needed | ||||
|             int i = 0; | ||||
|             bool sendback = data[i++]; | ||||
|             len--; | ||||
|              | ||||
|             // Load id | ||||
|             SmGui::DrawListElem diffId; | ||||
|             int count = SmGui::DrawList::loadItem(diffId, &data[i], len); | ||||
|             if (count < 0) { sendError(ERROR_INVALID_ARGUMENT); return; } | ||||
|             if (diffId.type != SmGui::DRAW_LIST_ELEM_TYPE_STRING) { sendError(ERROR_INVALID_ARGUMENT); return; }  | ||||
|             i += count; | ||||
|             len -= count; | ||||
|  | ||||
|             // Load value | ||||
|             SmGui::DrawListElem diffValue; | ||||
|             count = SmGui::DrawList::loadItem(diffValue, &data[i], len); | ||||
|             if (count < 0) { sendError(ERROR_INVALID_ARGUMENT); return; } | ||||
|             i += count; | ||||
|             len -= count; | ||||
|  | ||||
|             // Render and send back | ||||
|             if (sendback) { | ||||
|                 sendUI(COMMAND_UI_ACTION, diffId.str, diffValue); | ||||
|             } | ||||
|             else { | ||||
|                 renderUI(NULL, diffId.str, diffValue); | ||||
|             } | ||||
|         } | ||||
|         else if (cmd == COMMAND_START) { | ||||
|             sigpath::sourceManager.start(); | ||||
|             running = true; | ||||
|         } | ||||
|         else if (cmd == COMMAND_STOP) { | ||||
|             sigpath::sourceManager.stop(); | ||||
|             running = false; | ||||
|         } | ||||
|         else if (cmd == COMMAND_SET_FREQUENCY && len == 8) { | ||||
|             sigpath::sourceManager.tune(*(double*)data); | ||||
|             sendCommandAck(COMMAND_SET_FREQUENCY, 0); | ||||
|         } | ||||
|         else if (cmd == COMMAND_SET_SAMPLE_TYPE && len == 1) { | ||||
|             dsp::PCMType type = (dsp::PCMType)*(uint8_t*)data; | ||||
|             comp.setPCMType(type); | ||||
|         } | ||||
|         else { | ||||
|             spdlog::error("Invalid Command: {0} (len = {1})", cmd, len); | ||||
|             sendError(ERROR_INVALID_COMMAND); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void drawMenu() { | ||||
|         if (running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo("##sdrpp_server_src_sel", &sourceId, sourceList.txt)) { | ||||
|             sigpath::sourceManager.selectSource(sourceList[sourceId]); | ||||
|             // TODO: Save config | ||||
|         } | ||||
|         if (running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         sigpath::sourceManager.showSelectedMenu(); | ||||
|     } | ||||
|  | ||||
|     void renderUI(SmGui::DrawList* dl, std::string diffId, SmGui::DrawListElem diffValue) { | ||||
|         // If we're recording and there's an action, render once with the action and record without | ||||
|  | ||||
|         if (dl && !diffId.empty()) { | ||||
|             SmGui::setDiff(diffId, diffValue); | ||||
|             drawMenu(); | ||||
|  | ||||
|             SmGui::setDiff("", dummyElem); | ||||
|             SmGui::startRecord(dl); | ||||
|             drawMenu(); | ||||
|             SmGui::stopRecord(); | ||||
|         } | ||||
|         else { | ||||
|             SmGui::setDiff(diffId, diffValue); | ||||
|             SmGui::startRecord(dl); | ||||
|             drawMenu(); | ||||
|             SmGui::stopRecord(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void sendUI(Command originCmd, std::string diffId, SmGui::DrawListElem diffValue) { | ||||
|         // Render UI | ||||
|         SmGui::DrawList dl; | ||||
|         renderUI(&dl, diffId, diffValue); | ||||
|  | ||||
|         // Create response | ||||
|         int size = dl.getSize(); | ||||
|         dl.store(s_cmd_data, size); | ||||
|  | ||||
|         // Send to network | ||||
|         sendCommandAck(originCmd, size); | ||||
|     } | ||||
|  | ||||
|     void sendError(Error err) { | ||||
|         PacketHeader* hdr = (PacketHeader*)sbuf; | ||||
|         s_pkt_data[0] = err; | ||||
|         sendPacket(PACKET_TYPE_ERROR, 1); | ||||
|     } | ||||
|  | ||||
|     void sendSampleRate(double sampleRate) { | ||||
|         *(double*)s_cmd_data = sampleRate; | ||||
|         sendCommand(COMMAND_SET_SAMPLERATE, sizeof(double)); | ||||
|     } | ||||
|  | ||||
|     void setInputSampleRate(double samplerate) { | ||||
|         sampleRate = samplerate; | ||||
|         if (!client || !client->isOpen()) { return; } | ||||
|         sendSampleRate(sampleRate); | ||||
|     } | ||||
|  | ||||
|     void sendPacket(PacketType type, int len) { | ||||
|         s_pkt_hdr->type = type; | ||||
|         s_pkt_hdr->size = sizeof(PacketHeader) + len; | ||||
|         client->write(s_pkt_hdr->size, sbuf); | ||||
|     } | ||||
|  | ||||
|     void sendCommand(Command cmd, int len) { | ||||
|         s_cmd_hdr->cmd = cmd; | ||||
|         sendPacket(PACKET_TYPE_COMMAND, sizeof(CommandHeader) + len); | ||||
|     } | ||||
|  | ||||
|     void sendCommandAck(Command cmd, int len) { | ||||
|         s_cmd_hdr->cmd = cmd; | ||||
|         sendPacket(PACKET_TYPE_COMMAND_ACK, sizeof(CommandHeader) + len); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,3 +1,27 @@ | ||||
| #pragma once | ||||
| #include <utils/networking.h> | ||||
| #include <dsp/stream.h> | ||||
| #include <dsp/types.h> | ||||
| #include <server_protocol.h> | ||||
|  | ||||
| int server_main(); | ||||
| namespace server { | ||||
|     void setInput(dsp::stream<dsp::complex_t>* stream); | ||||
|     int main(); | ||||
|  | ||||
|     void _clientHandler(net::Conn conn, void* ctx); | ||||
|     void _packetHandler(int count, uint8_t* buf, void* ctx); | ||||
|     void _testServerHandler(uint8_t* data, int count, void* ctx); | ||||
|  | ||||
|     void drawMenu(); | ||||
|  | ||||
|     void commandHandler(Command cmd, uint8_t* data, int len); | ||||
|     void renderUI(SmGui::DrawList* dl, std::string diffId, SmGui::DrawListElem diffValue); | ||||
|     void sendUI(Command originCmd, std::string diffId, SmGui::DrawListElem diffValue); | ||||
|     void sendError(Error err); | ||||
|     void sendSampleRate(double sampleRate); | ||||
|     void setInputSampleRate(double samplerate); | ||||
|  | ||||
|     void sendPacket(PacketType type, int len); | ||||
|     void sendCommand(Command cmd, int len); | ||||
|     void sendCommandAck(Command cmd, int len); | ||||
| } | ||||
|   | ||||
							
								
								
									
										49
									
								
								core/src/server_protocol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								core/src/server_protocol.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <dsp/types.h> | ||||
|  | ||||
| #define SERVER_MAX_PACKET_SIZE  (STREAM_BUFFER_SIZE * sizeof(dsp::complex_t) * 2) | ||||
|  | ||||
| namespace server { | ||||
|     enum PacketType { | ||||
|         // Client to Server | ||||
|         PACKET_TYPE_COMMAND, | ||||
|         PACKET_TYPE_COMMAND_ACK, | ||||
|         PACKET_TYPE_BASEBAND, | ||||
|         PACKET_TYPE_VFO, | ||||
|         PACKET_TYPE_FFT, | ||||
|         PACKET_TYPE_ERROR | ||||
|     }; | ||||
|  | ||||
|     enum Command { | ||||
|         // Client to Server | ||||
|         COMMAND_GET_UI = 0x00, | ||||
|         COMMAND_UI_ACTION, | ||||
|         COMMAND_START, | ||||
|         COMMAND_STOP, | ||||
|         COMMAND_SET_FREQUENCY, | ||||
|         COMMAND_GET_SAMPLERATE, | ||||
|         COMMAND_SET_SAMPLE_TYPE, | ||||
|  | ||||
|         // Server to client | ||||
|         COMMAND_SET_SAMPLERATE = 0x80 | ||||
|     }; | ||||
|  | ||||
|     enum Error { | ||||
|         ERROR_NONE = 0x00, | ||||
|         ERROR_INVALID_PACKET, | ||||
|         ERROR_INVALID_COMMAND, | ||||
|         ERROR_INVALID_ARGUMENT | ||||
|     }; | ||||
|      | ||||
|     // TODO: Pack | ||||
|     struct PacketHeader { | ||||
|         uint32_t type; | ||||
|         uint32_t size; | ||||
|     }; | ||||
|  | ||||
|     struct CommandHeader { | ||||
|         uint32_t cmd; | ||||
|     }; | ||||
| } | ||||
| @@ -1,6 +1,8 @@ | ||||
| #include <server.h> | ||||
| #include <signal_path/source.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <signal_path/signal_path.h> | ||||
| #include <options.h> | ||||
|  | ||||
| SourceManager::SourceManager() { | ||||
| } | ||||
| @@ -48,7 +50,13 @@ void SourceManager::selectSource(std::string name) { | ||||
|     selectedHandler = sources[name]; | ||||
|     selectedHandler->selectHandler(selectedHandler->ctx); | ||||
|     selectedName = name; | ||||
|     sigpath::signalPath.setInput(selectedHandler->stream); | ||||
|     if (options::opts.serverMode) { | ||||
|         server::setInput(selectedHandler->stream); | ||||
|     } | ||||
|     else { | ||||
|         sigpath::signalPath.setInput(selectedHandler->stream); | ||||
|     } | ||||
|     // Set server input here | ||||
| } | ||||
|  | ||||
| void SourceManager::showSelectedMenu() { | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #include <utils/networking.h> | ||||
| #include <assert.h> | ||||
| #include <spdlog/spdlog.h> | ||||
|  | ||||
| namespace net { | ||||
|  | ||||
| @@ -70,19 +71,34 @@ namespace net { | ||||
|         if (_udp) { | ||||
|             socklen_t fromLen = sizeof(remoteAddr); | ||||
|             ret = recvfrom(_sock, (char*)buf, count, 0, (struct sockaddr*)&remoteAddr, &fromLen); | ||||
|         } | ||||
|         else { | ||||
|             ret = recv(_sock, (char*)buf, count, 0); | ||||
|             if (ret <= 0) { | ||||
|                 { | ||||
|                     std::lock_guard lck(connectionOpenMtx); | ||||
|                     connectionOpen = false; | ||||
|                 } | ||||
|                 connectionOpenCnd.notify_all(); | ||||
|                 return -1; | ||||
|             } | ||||
|             return count; | ||||
|         } | ||||
|  | ||||
|         if (ret <= 0) { | ||||
|             { | ||||
|                 std::lock_guard lck(connectionOpenMtx); | ||||
|                 connectionOpen = false; | ||||
|         int beenRead = 0; | ||||
|         while (beenRead < count) { | ||||
|             ret = recv(_sock, (char*)&buf[beenRead], count - beenRead, 0); | ||||
|  | ||||
|             if (ret <= 0) { | ||||
|                 { | ||||
|                     std::lock_guard lck(connectionOpenMtx); | ||||
|                     connectionOpen = false; | ||||
|                 } | ||||
|                 connectionOpenCnd.notify_all(); | ||||
|                 return -1; | ||||
|             } | ||||
|             connectionOpenCnd.notify_all(); | ||||
|  | ||||
|             beenRead += ret; | ||||
|         } | ||||
|         return ret; | ||||
|  | ||||
|         return beenRead; | ||||
|     } | ||||
|  | ||||
|     bool ConnClass::write(int count, uint8_t* buf) { | ||||
| @@ -93,19 +109,31 @@ namespace net { | ||||
|         if (_udp) { | ||||
|             int fromLen = sizeof(remoteAddr); | ||||
|             ret = sendto(_sock, (char*)buf, count, 0, (struct sockaddr*)&remoteAddr, sizeof(remoteAddr)); | ||||
|         } | ||||
|         else { | ||||
|             ret = send(_sock, (char*)buf, count, 0); | ||||
|             if (ret <= 0) { | ||||
|                 { | ||||
|                     std::lock_guard lck(connectionOpenMtx); | ||||
|                     connectionOpen = false; | ||||
|                 } | ||||
|                 connectionOpenCnd.notify_all(); | ||||
|             } | ||||
|             return (ret > 0); | ||||
|         } | ||||
|  | ||||
|         if (ret <= 0) { | ||||
|             { | ||||
|                 std::lock_guard lck(connectionOpenMtx); | ||||
|                 connectionOpen = false; | ||||
|         int beenWritten = 0; | ||||
|         while (beenWritten < count) { | ||||
|             ret = send(_sock, (char*)buf, count, 0); | ||||
|             if (ret <= 0) { | ||||
|                 { | ||||
|                     std::lock_guard lck(connectionOpenMtx); | ||||
|                     connectionOpen = false; | ||||
|                 } | ||||
|                 connectionOpenCnd.notify_all(); | ||||
|                 return false; | ||||
|             } | ||||
|             connectionOpenCnd.notify_all(); | ||||
|             beenWritten += ret; | ||||
|         } | ||||
|         return (ret > 0); | ||||
|          | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void ConnClass::readAsync(int count, uint8_t* buf, void (*handler)(int count, uint8_t* buf, void* ctx), void* ctx) { | ||||
|   | ||||
							
								
								
									
										2
									
								
								core/src/utils/new_networking.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								core/src/utils/new_networking.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #include "new_networking.h" | ||||
|  | ||||
							
								
								
									
										95
									
								
								core/src/utils/new_networking.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								core/src/utils/new_networking.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| #pragma once | ||||
| #include <queue> | ||||
| #include <memory> | ||||
| #include <thread> | ||||
| #include <mutex> | ||||
|  | ||||
| /* | ||||
|     Ryzerth's Epic Networking Functins | ||||
| */ | ||||
|  | ||||
| namespace net { | ||||
|     enum SocketType { | ||||
|         SOCK_TYPE_TCP, | ||||
|         SOCK_TYPE_UDP | ||||
|     }; | ||||
|  | ||||
|     struct ReadHandler { | ||||
|         int count; | ||||
|         void* buf; | ||||
|         void (*handle)(int count, void* buf, void* ctx); | ||||
|         void* ctx; | ||||
|     }; | ||||
|  | ||||
|     class SocketClass { | ||||
|     public: | ||||
|         SocketClass(struct addrinfo* localAddr, struct addrinfo* remoteAddr, SocketType sockType); | ||||
|         ~SocketClass(); | ||||
|  | ||||
|         int read(int count, void* buf, int timeout); | ||||
|         int write(int count, void* buf); | ||||
|  | ||||
|         void readAsync(int count, void* buf, void (*handle)(int count, void* buf, void* ctx), void* ctx); | ||||
|  | ||||
|         bool isOpen(); | ||||
|         void close(); | ||||
|  | ||||
|     private: | ||||
|         void readWorker(); | ||||
|  | ||||
|         bool open = false; | ||||
|  | ||||
|         struct addrinfo* laddr; | ||||
|         struct addrinfo* raddr; | ||||
|         SocketType type; | ||||
|  | ||||
|         std::queue<ReadHandler> readQueue; | ||||
|         std::thread readThread; | ||||
|         std::mutex readMtx; | ||||
|         std::condition_variable readCnd; | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     typedef std::shared_ptr<SocketClass> Socket; | ||||
|  | ||||
|     namespace tcp { | ||||
|         struct AcceptHandler { | ||||
|             void (*handle)(Socket client, void* ctx); | ||||
|             void* ctx; | ||||
|         }; | ||||
|  | ||||
|         class ListenerClass { | ||||
|         public: | ||||
|             ListenerClass(struct addrinfo* addr); | ||||
|             ~ListenerClass(); | ||||
|  | ||||
|             Socket accept(int count, void* buf, int timeout); | ||||
|             void acceptAsync(void (*handle)(int count, void* buf, void* ctx), void* ctx); | ||||
|  | ||||
|             bool isOpen(); | ||||
|             void close(); | ||||
|  | ||||
|         private: | ||||
|             void acceptWorker(); | ||||
|  | ||||
|             bool open = false; | ||||
|  | ||||
|             struct addrinfo* addr; | ||||
|  | ||||
|             std::queue<AcceptHandler> acceptQueue; | ||||
|             std::thread acceptThread; | ||||
|             std::mutex acceptMtx; | ||||
|             std::condition_variable acceptCnd; | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         typedef std::shared_ptr<ListenerClass> Listener; | ||||
|  | ||||
|         Socket connect(std::string host, int port); | ||||
|         Listener listen(std::string host, int port); | ||||
|     } | ||||
|  | ||||
|     namespace udp { | ||||
|         Socket open(std::string remoteHost, int remotePort, std::string localHost = "", int localPort = -1); | ||||
|     } | ||||
| } | ||||
| @@ -7,9 +7,9 @@ | ||||
| #include <gui/style.h> | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <airspy.h> | ||||
|  | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| SDRPP_MOD_INFO{ | ||||
| @@ -313,12 +313,12 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         AirspySourceModule* _this = (AirspySourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_airspy_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_airspy_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectBySerial(_this->devList[_this->devId]); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedSerStr != "") { | ||||
| @@ -328,7 +328,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_airspy_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_airspy_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|             _this->sampleRate = _this->sampleRateList[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedSerStr != "") { | ||||
| @@ -338,9 +338,10 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_airspy_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_airspy_refr_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             config.acquire(); | ||||
|             std::string devSerial = config.conf["device"]; | ||||
| @@ -349,11 +350,12 @@ private: | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::BeginGroup(); | ||||
|         ImGui::Columns(3, CONCAT("AirspyGainModeColumns##_", _this->name), false); | ||||
|         if (ImGui::RadioButton(CONCAT("Sensitive##_airspy_gm_", _this->name), _this->gainMode == 0)) { | ||||
|         SmGui::BeginGroup(); | ||||
|         SmGui::Columns(3, CONCAT("AirspyGainModeColumns##_", _this->name), false); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::RadioButton(CONCAT("Sensitive##_airspy_gm_", _this->name), _this->gainMode == 0)) { | ||||
|             _this->gainMode = 0; | ||||
|             if (_this->running) { | ||||
|                 airspy_set_lna_agc(_this->openDev, 0); | ||||
| @@ -366,8 +368,9 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|         } | ||||
|         ImGui::NextColumn(); | ||||
|         if (ImGui::RadioButton(CONCAT("Linear##_airspy_gm_", _this->name), _this->gainMode == 1)) { | ||||
|         SmGui::NextColumn(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::RadioButton(CONCAT("Linear##_airspy_gm_", _this->name), _this->gainMode == 1)) { | ||||
|             _this->gainMode = 1; | ||||
|             if (_this->running) { | ||||
|                 airspy_set_lna_agc(_this->openDev, 0); | ||||
| @@ -380,8 +383,9 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|         } | ||||
|         ImGui::NextColumn(); | ||||
|         if (ImGui::RadioButton(CONCAT("Free##_airspy_gm_", _this->name), _this->gainMode == 2)) { | ||||
|         SmGui::NextColumn(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::RadioButton(CONCAT("Free##_airspy_gm_", _this->name), _this->gainMode == 2)) { | ||||
|             _this->gainMode = 2; | ||||
|             if (_this->running) { | ||||
|                 if (_this->lnaAgc) { | ||||
| @@ -406,15 +410,15 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|         } | ||||
|         ImGui::Columns(1, CONCAT("EndAirspyGainModeColumns##_", _this->name), false); | ||||
|         ImGui::EndGroup(); | ||||
|         SmGui::Columns(1, CONCAT("EndAirspyGainModeColumns##_", _this->name), false); | ||||
|         SmGui::EndGroup(); | ||||
|  | ||||
|         // Gain menus | ||||
|  | ||||
|         if (_this->gainMode == 0) { | ||||
|             ImGui::LeftLabel("Gain"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) { | ||||
|             SmGui::LeftLabel("Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##_airspy_sens_gain_", _this->name), &_this->sensitiveGain, 0, 21)) { | ||||
|                 if (_this->running) { | ||||
|                     airspy_set_sensitivity_gain(_this->openDev, _this->sensitiveGain); | ||||
|                 } | ||||
| @@ -426,9 +430,9 @@ private: | ||||
|             } | ||||
|         } | ||||
|         else if (_this->gainMode == 1) { | ||||
|             ImGui::LeftLabel("Gain"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21)) { | ||||
|             SmGui::LeftLabel("Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##_airspy_lin_gain_", _this->name), &_this->linearGain, 0, 21)) { | ||||
|                 if (_this->running) { | ||||
|                     airspy_set_linearity_gain(_this->openDev, _this->linearGain); | ||||
|                 } | ||||
| @@ -440,14 +444,11 @@ private: | ||||
|             } | ||||
|         } | ||||
|         else if (_this->gainMode == 2) { | ||||
|             // Calculate position of sliders | ||||
|             float pos = ImGui::CalcTextSize("Mixer Gain").x + 10; | ||||
|  | ||||
|             if (_this->lnaAgc) { style::beginDisabled(); } | ||||
|             ImGui::LeftLabel("LNA Gain"); | ||||
|             ImGui::SetCursorPosX(pos); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) { | ||||
|             // TODO: Switch to a table for alignement | ||||
|             if (_this->lnaAgc) { SmGui::BeginDisabled(); } | ||||
|             SmGui::LeftLabel("LNA Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##_airspy_lna_gain_", _this->name), &_this->lnaGain, 0, 15)) { | ||||
|                 if (_this->running) { | ||||
|                     airspy_set_lna_gain(_this->openDev, _this->lnaGain); | ||||
|                 } | ||||
| @@ -457,13 +458,12 @@ private: | ||||
|                     config.release(true); | ||||
|                 } | ||||
|             } | ||||
|             if (_this->lnaAgc) { style::endDisabled(); } | ||||
|             if (_this->lnaAgc) { SmGui::EndDisabled(); } | ||||
|  | ||||
|             if (_this->mixerAgc) { style::beginDisabled(); } | ||||
|             ImGui::LeftLabel("Mixer Gain"); | ||||
|             ImGui::SetCursorPosX(pos); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) { | ||||
|             if (_this->mixerAgc) { SmGui::BeginDisabled(); } | ||||
|             SmGui::LeftLabel("Mixer Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##_airspy_mix_gain_", _this->name), &_this->mixerGain, 0, 15)) { | ||||
|                 if (_this->running) { | ||||
|                     airspy_set_mixer_gain(_this->openDev, _this->mixerGain); | ||||
|                 } | ||||
| @@ -473,12 +473,11 @@ private: | ||||
|                     config.release(true); | ||||
|                 } | ||||
|             } | ||||
|             if (_this->mixerAgc) { style::endDisabled(); } | ||||
|             if (_this->mixerAgc) { SmGui::EndDisabled(); } | ||||
|  | ||||
|             ImGui::LeftLabel("VGA Gain"); | ||||
|             ImGui::SetCursorPosX(pos); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) { | ||||
|             SmGui::LeftLabel("VGA Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##_airspy_vga_gain_", _this->name), &_this->vgaGain, 0, 15)) { | ||||
|                 if (_this->running) { | ||||
|                     airspy_set_vga_gain(_this->openDev, _this->vgaGain); | ||||
|                 } | ||||
| @@ -490,7 +489,8 @@ private: | ||||
|             } | ||||
|  | ||||
|             // AGC Control | ||||
|             if (ImGui::Checkbox(CONCAT("LNA AGC##_airspy_", _this->name), &_this->lnaAgc)) { | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Checkbox(CONCAT("LNA AGC##_airspy_", _this->name), &_this->lnaAgc)) { | ||||
|                 if (_this->running) { | ||||
|                     if (_this->lnaAgc) { | ||||
|                         airspy_set_lna_agc(_this->openDev, 1); | ||||
| @@ -506,7 +506,8 @@ private: | ||||
|                     config.release(true); | ||||
|                 } | ||||
|             } | ||||
|             if (ImGui::Checkbox(CONCAT("Mixer AGC##_airspy_", _this->name), &_this->mixerAgc)) { | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Checkbox(CONCAT("Mixer AGC##_airspy_", _this->name), &_this->mixerAgc)) { | ||||
|                 if (_this->running) { | ||||
|                     if (_this->mixerAgc) { | ||||
|                         airspy_set_mixer_agc(_this->openDev, 1); | ||||
| @@ -525,8 +526,7 @@ private: | ||||
|         } | ||||
|  | ||||
|         // Bias T | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Bias T##_airspy_", _this->name), &_this->biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias T##_airspy_", _this->name), &_this->biasT)) { | ||||
|             if (_this->running) { | ||||
|                 airspy_set_rf_bias(_this->openDev, _this->biasT); | ||||
|             } | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| #include <imgui.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <module.h> | ||||
| #include <gui/gui.h> | ||||
| @@ -7,6 +6,7 @@ | ||||
| #include <gui/style.h> | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <airspyhf.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
|  | ||||
| @@ -265,12 +265,12 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         AirspyHFSourceModule* _this = (AirspyHFSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_airspyhf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectBySerial(_this->devList[_this->devId]); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedSerStr != "") { | ||||
| @@ -280,7 +280,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_airspyhf_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_airspyhf_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|             _this->sampleRate = _this->sampleRateList[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedSerStr != "") { | ||||
| @@ -290,9 +290,10 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_airspyhf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_airspyhf_refr_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             config.acquire(); | ||||
|             std::string devSerial = config.conf["device"]; | ||||
| @@ -301,11 +302,11 @@ private: | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("AGC Mode"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_airspyhf_agc_", _this->name), &_this->agcMode, AGG_MODES_STR)) { | ||||
|         SmGui::LeftLabel("AGC Mode"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_airspyhf_agc_", _this->name), &_this->agcMode, AGG_MODES_STR)) { | ||||
|             if (_this->running) { | ||||
|                 airspyhf_set_hf_agc(_this->openDev, (_this->agcMode != 0)); | ||||
|                 if (_this->agcMode > 0) { | ||||
| @@ -319,9 +320,9 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("Attenuation"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::SliderFloatWithSteps(CONCAT("##_airspyhf_attn_", _this->name), &_this->atten, 0, 48, 6, "%.0f dB")) { | ||||
|         SmGui::LeftLabel("Attenuation"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderFloatWithSteps(CONCAT("##_airspyhf_attn_", _this->name), &_this->atten, 0, 48, 6, SmGui::FMT_STR_FLOAT_DB_NO_DECIMAL)) { | ||||
|             if (_this->running) { | ||||
|                 airspyhf_set_hf_att(_this->openDev, _this->atten / 6.0f); | ||||
|             } | ||||
| @@ -332,7 +333,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("HF LNA##_airspyhf_lna_", _this->name), &_this->hfLNA)) { | ||||
|         if (SmGui::Checkbox(CONCAT("HF LNA##_airspyhf_lna_", _this->name), &_this->hfLNA)) { | ||||
|             if (_this->running) { | ||||
|                 airspyhf_set_hf_lna(_this->openDev, _this->hfLNA); | ||||
|             } | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <libbladeRF.h> | ||||
| #include <dsp/processing.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <algorithm> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
| @@ -426,12 +427,12 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         BladeRFSourceModule* _this = (BladeRFSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_balderf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_balderf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             bladerf_devinfo info = _this->devInfoList[_this->devId]; | ||||
|             _this->selectByInfo(&info); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
| @@ -440,7 +441,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_balderf_sr_sel_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_balderf_sr_sel_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|             _this->sampleRate = _this->sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedSerial != "") { | ||||
| @@ -451,9 +452,10 @@ private: | ||||
|         } | ||||
|  | ||||
|         // Refresh button | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_balderf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_balderf_refr_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             _this->selectBySerial(_this->selectedSerial, false); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
| @@ -461,9 +463,9 @@ private: | ||||
|  | ||||
|         // Channel selection (only show if more than one channel) | ||||
|         if (_this->channelCount > 1) { | ||||
|             ImGui::LeftLabel("RX Channel"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             ImGui::Combo(CONCAT("##_balderf_ch_sel_", _this->name), &_this->chanId, _this->channelNamesTxt.c_str()); | ||||
|             SmGui::LeftLabel("RX Channel"); | ||||
|             SmGui::FillWidth(); | ||||
|             SmGui::Combo(CONCAT("##_balderf_ch_sel_", _this->name), &_this->chanId, _this->channelNamesTxt.c_str()); | ||||
|             if (_this->selectedSerial != "") { | ||||
|                 config.acquire(); | ||||
|                 config.conf["devices"][_this->selectedSerial]["channelId"] = _this->chanId; | ||||
| @@ -471,11 +473,11 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("Bandwidth"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_balderf_bw_sel_", _this->name), &_this->bwId, _this->bandwidthsTxt.c_str())) { | ||||
|         SmGui::LeftLabel("Bandwidth"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_balderf_bw_sel_", _this->name), &_this->bwId, _this->bandwidthsTxt.c_str())) { | ||||
|             if (_this->running) { | ||||
|                 bladerf_set_bandwidth(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), (_this->bwId == _this->bandwidths.size()) ? std::clamp<uint64_t>(_this->sampleRate, _this->bwRange->min, _this->bwRange->max) : _this->bandwidths[_this->bwId], NULL); | ||||
|             } | ||||
| @@ -487,9 +489,10 @@ private: | ||||
|         } | ||||
|  | ||||
|         // General config BS | ||||
|         ImGui::LeftLabel("Gain control mode"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_balderf_gm_sel_", _this->name), &_this->gainMode, _this->gainModesTxt.c_str()) && _this->selectedSerial != "") { | ||||
|         SmGui::LeftLabel("Gain control mode"); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_balderf_gm_sel_", _this->name), &_this->gainMode, _this->gainModesTxt.c_str()) && _this->selectedSerial != "") { | ||||
|             if (_this->running) { | ||||
|                 bladerf_set_gain_mode(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->gainModes[_this->gainMode].mode); | ||||
|             } | ||||
| @@ -505,11 +508,11 @@ private: | ||||
|         } | ||||
|  | ||||
|         if (_this->selectedSerial != "") { | ||||
|             if (_this->gainModes[_this->gainMode].mode != BLADERF_GAIN_MANUAL) { style::beginDisabled(); } | ||||
|             if (_this->gainModes[_this->gainMode].mode != BLADERF_GAIN_MANUAL) { SmGui::BeginDisabled(); } | ||||
|         } | ||||
|         ImGui::LeftLabel("Gain"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::SliderInt("##_balderf_oag_sel_", &_this->overallGain, (_this->gainRange != NULL) ? _this->gainRange->min : 0, (_this->gainRange != NULL) ? _this->gainRange->max : 60)) { | ||||
|         SmGui::LeftLabel("Gain"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderInt("##_balderf_oag_sel_", &_this->overallGain, (_this->gainRange != NULL) ? _this->gainRange->min : 0, (_this->gainRange != NULL) ? _this->gainRange->max : 60)) { | ||||
|             if (_this->running) { | ||||
|                 spdlog::info("Setting gain to {0}", _this->overallGain); | ||||
|                 bladerf_set_gain(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->overallGain); | ||||
| @@ -521,11 +524,11 @@ private: | ||||
|             } | ||||
|         } | ||||
|         if (_this->selectedSerial != "") { | ||||
|             if (_this->gainModes[_this->gainMode].mode != BLADERF_GAIN_MANUAL) { style::endDisabled(); } | ||||
|             if (_this->gainModes[_this->gainMode].mode != BLADERF_GAIN_MANUAL) { SmGui::EndDisabled(); } | ||||
|         } | ||||
|  | ||||
|         if (_this->selectedBladeType == BLADERF_TYPE_V2) { | ||||
|             if (ImGui::Checkbox("Bias-T##_balderf_biast_", &_this->biasT)) { | ||||
|             if (SmGui::Checkbox("Bias-T##_balderf_biast_", &_this->biasT)) { | ||||
|                 if (_this->running) { | ||||
|                     bladerf_set_bias_tee(_this->openDev, BLADERF_CHANNEL_RX(_this->chanId), _this->biasT); | ||||
|                 } | ||||
|   | ||||
| @@ -28,6 +28,8 @@ public: | ||||
|     FileSourceModule(std::string name) : fileSelect("", { "Wav IQ Files (*.wav)", "*.wav", "All Files", "*" }) { | ||||
|         this->name = name; | ||||
|  | ||||
|         if (options::opts.serverMode) { return; } | ||||
|  | ||||
|         config.acquire(); | ||||
|         fileSelect.setPath(config.conf["path"], true); | ||||
|         config.release(); | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| #include <imgui.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <module.h> | ||||
| #include <gui/gui.h> | ||||
| @@ -9,6 +8,7 @@ | ||||
| #include <libhackrf/hackrf.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| @@ -275,19 +275,18 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         HackRFSourceModule* _this = (HackRFSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_hackrf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectedSerial = _this->devList[_this->devId]; | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_hackrf_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectBySerial(_this->devList[_this->devId]); | ||||
|             config.acquire(); | ||||
|             config.conf["device"] = _this->selectedSerial; | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_hackrf_sr_sel_", _this->name), &_this->srId, sampleRatesTxt)) { | ||||
|         if (SmGui::Combo(CONCAT("##_hackrf_sr_sel_", _this->name), &_this->srId, sampleRatesTxt)) { | ||||
|             _this->sampleRate = sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             config.acquire(); | ||||
| @@ -295,19 +294,20 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_hackrf_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_hackrf_refr_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             _this->selectBySerial(_this->selectedSerial); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("Bandwidth"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_hackrf_bw_sel_", _this->name), &_this->bwId, bandwidthsTxt)) { | ||||
|         SmGui::LeftLabel("Bandwidth"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_hackrf_bw_sel_", _this->name), &_this->bwId, bandwidthsTxt)) { | ||||
|             if (_this->running) { | ||||
|                 hackrf_set_baseband_filter_bandwidth(_this->openDev, _this->bandwidthIdToBw(_this->bwId)); | ||||
|             } | ||||
| @@ -316,9 +316,9 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("LNA Gain"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::SliderFloatWithSteps(CONCAT("##_hackrf_lna_", _this->name), &_this->lna, 0, 40, 8, "%.0fdB")) { | ||||
|         SmGui::LeftLabel("LNA Gain"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderFloatWithSteps(CONCAT("##_hackrf_lna_", _this->name), &_this->lna, 0, 40, 8, SmGui::FMT_STR_FLOAT_DB_NO_DECIMAL)) { | ||||
|             if (_this->running) { | ||||
|                 hackrf_set_lna_gain(_this->openDev, _this->lna); | ||||
|             } | ||||
| @@ -327,9 +327,9 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("VGA Gain"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::SliderFloatWithSteps(CONCAT("##_hackrf_vga_", _this->name), &_this->vga, 0, 62, 2, "%.0fdB")) { | ||||
|         SmGui::LeftLabel("VGA Gain"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderFloatWithSteps(CONCAT("##_hackrf_vga_", _this->name), &_this->vga, 0, 62, 2, SmGui::FMT_STR_FLOAT_DB_NO_DECIMAL)) { | ||||
|             if (_this->running) { | ||||
|                 hackrf_set_vga_gain(_this->openDev, _this->vga); | ||||
|             } | ||||
| @@ -338,7 +338,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##_hackrf_bt_", _this->name), &_this->biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##_hackrf_bt_", _this->name), &_this->biasT)) { | ||||
|             if (_this->running) { | ||||
|                 hackrf_set_antenna_enable(_this->openDev, _this->biasT); | ||||
|             } | ||||
| @@ -347,7 +347,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Amp Enabled##_hackrf_amp_", _this->name), &_this->amp)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Amp Enabled##_hackrf_amp_", _this->name), &_this->amp)) { | ||||
|             if (_this->running) { | ||||
|                 hackrf_set_amp_enable(_this->openDev, _this->amp); | ||||
|             } | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| #include <imgui.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <module.h> | ||||
| #include <gui/gui.h> | ||||
| @@ -7,6 +6,7 @@ | ||||
| #include <gui/style.h> | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <lime/LimeSuite.h> | ||||
|  | ||||
|  | ||||
| @@ -382,12 +382,12 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         LimeSDRSourceModule* _this = (LimeSDRSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo("##limesdr_dev_sel", &_this->devId, _this->devListTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo("##limesdr_dev_sel", &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectByInfoStr(_this->devList[_this->devId]); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             config.acquire(); | ||||
| @@ -395,7 +395,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_limesdr_sr_sel_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_limesdr_sr_sel_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|             _this->sampleRate = _this->sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedDevName != "") { | ||||
| @@ -406,29 +406,30 @@ private: | ||||
|         } | ||||
|  | ||||
|         // Refresh button | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_limesdr_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_limesdr_refr_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             _this->selectByName(_this->selectedDevName); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|         } | ||||
|  | ||||
|         if (_this->channelCount > 1) { | ||||
|             ImGui::LeftLabel("RX Channel"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo("##limesdr_ch_sel", &_this->chanId, _this->channelNamesTxt.c_str()) && _this->selectedDevName != "") { | ||||
|             SmGui::LeftLabel("RX Channel"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo("##limesdr_ch_sel", &_this->chanId, _this->channelNamesTxt.c_str()) && _this->selectedDevName != "") { | ||||
|                 config.acquire(); | ||||
|                 config.conf["devices"][_this->selectedDevName]["channel"] = _this->chanId; | ||||
|                 config.release(true); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("Antenna"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo("##limesdr_ant_sel", &_this->antennaId, _this->antennaListTxt.c_str())) { | ||||
|         SmGui::LeftLabel("Antenna"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo("##limesdr_ant_sel", &_this->antennaId, _this->antennaListTxt.c_str())) { | ||||
|             if (_this->running) { | ||||
|                 LMS_SetAntenna(_this->openDev, false, _this->chanId, _this->antennaId); | ||||
|             } | ||||
| @@ -439,9 +440,9 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("Bandwidth"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo("##limesdr_bw_sel", &_this->bwId, _this->bandwidthsTxt.c_str())) { | ||||
|         SmGui::LeftLabel("Bandwidth"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo("##limesdr_bw_sel", &_this->bwId, _this->bandwidthsTxt.c_str())) { | ||||
|             if (_this->running) { | ||||
|                 LMS_SetLPFBW(_this->openDev, false, _this->chanId, (_this->bwId == _this->bandwidths.size()) ? _this->getBestBandwidth(_this->sampleRate) : _this->bandwidths[_this->bwId]); | ||||
|             } | ||||
| @@ -452,9 +453,9 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("Gain"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::SliderInt("##limesdr_gain_sel", &_this->gain, 0, 73, "%ddB")) { | ||||
|         SmGui::LeftLabel("Gain"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderInt("##limesdr_gain_sel", &_this->gain, 0, 73, SmGui::FMT_STR_INT_DB)) { | ||||
|             if (_this->running) { | ||||
|                 LMS_SetGaindB(_this->openDev, false, _this->chanId, _this->gain); | ||||
|             } | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #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 <gui/smgui.h> | ||||
| #include <iio.h> | ||||
| #include <ad9361.h> | ||||
| #include <options.h> | ||||
| @@ -185,32 +185,31 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         PlutoSDRSourceModule* _this = (PlutoSDRSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         ImGui::LeftLabel("IP"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputText(CONCAT("##_pluto_ip_", _this->name), &_this->ip[3], 16)) { | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::LeftLabel("IP"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputText(CONCAT("##_pluto_ip_", _this->name), &_this->ip[3], 16)) { | ||||
|             config.acquire(); | ||||
|             config.conf["IP"] = &_this->ip[3]; | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("Samplerate"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_pluto_sr_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|         SmGui::LeftLabel("Samplerate"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_pluto_sr_", _this->name), &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|             _this->sampleRate = _this->sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             config.acquire(); | ||||
|             config.conf["sampleRate"] = _this->sampleRate; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("Gain Mode"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_gainmode_select_", _this->name), &_this->gainMode, gainModesTxt)) { | ||||
|         SmGui::LeftLabel("Gain Mode"); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_gainmode_select_", _this->name), &_this->gainMode, gainModesTxt)) { | ||||
|             if (_this->running) { | ||||
|                 iio_channel_attr_write(iio_device_find_channel(_this->phy, "voltage0", false), "gain_control_mode", gainModes[_this->gainMode]); | ||||
|             } | ||||
| @@ -219,10 +218,10 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("PGA Gain"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (_this->gainMode) { style::beginDisabled(); } | ||||
|         if (ImGui::SliderFloat(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 76)) { | ||||
|         SmGui::LeftLabel("PGA Gain"); | ||||
|         if (_this->gainMode) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderFloat(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 76)) { | ||||
|             if (_this->running) { | ||||
|                 iio_channel_attr_write_longlong(iio_device_find_channel(_this->phy, "voltage0", false), "hardwaregain", round(_this->gain)); | ||||
|             } | ||||
| @@ -230,7 +229,7 @@ private: | ||||
|             config.conf["gain"] = _this->gain; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (_this->gainMode) { style::endDisabled(); } | ||||
|         if (_this->gainMode) { SmGui::EndDisabled(); } | ||||
|     } | ||||
|  | ||||
|     static void worker(void* ctx) { | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include <options.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <utils/optionlist.h> | ||||
| #include <gui/smgui.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| @@ -23,9 +24,9 @@ SDRPP_MOD_INFO{ | ||||
|  | ||||
| ConfigManager config; | ||||
|  | ||||
| class RFSpaceSource : public ModuleManager::Instance { | ||||
| class RFSpaceSourceModule : public ModuleManager::Instance { | ||||
| public: | ||||
|     RFSpaceSource(std::string name) { | ||||
|     RFSpaceSourceModule(std::string name) { | ||||
|         this->name = name; | ||||
|  | ||||
|         handler.ctx = this; | ||||
| @@ -47,7 +48,7 @@ public: | ||||
|         sigpath::sourceManager.registerSource("RFspace", &handler); | ||||
|     } | ||||
|  | ||||
|     ~RFSpaceSource() { | ||||
|     ~RFSpaceSourceModule() { | ||||
|         stop(this); | ||||
|         sigpath::sourceManager.unregisterSource("RFspace"); | ||||
|     } | ||||
| @@ -82,72 +83,73 @@ private: | ||||
|     } | ||||
|  | ||||
|     static void menuSelected(void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|         core::setInputSampleRate(_this->sampleRate); | ||||
|         gui::mainWindow.playButtonLocked = !(_this->client && _this->client->isOpen()); | ||||
|         spdlog::info("RFSpaceSource '{0}': Menu Select!", _this->name); | ||||
|         spdlog::info("RFSpaceSourceModule '{0}': Menu Select!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void menuDeselected(void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|         gui::mainWindow.playButtonLocked = false; | ||||
|         spdlog::info("RFSpaceSource '{0}': Menu Deselect!", _this->name); | ||||
|         spdlog::info("RFSpaceSourceModule '{0}': Menu Deselect!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void start(void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|         if (_this->running) { return; } | ||||
|  | ||||
|         // 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("RFSpaceSource '{0}': Start!", _this->name); | ||||
|         spdlog::info("RFSpaceSourceModule '{0}': Start!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void stop(void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|         if (!_this->running) { return; } | ||||
|  | ||||
|         if (_this->client) { _this->client->stop(); } | ||||
|  | ||||
|         _this->running = false; | ||||
|         spdlog::info("RFSpaceSource '{0}': Stop!", _this->name); | ||||
|         spdlog::info("RFSpaceSourceModule '{0}': Stop!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void tune(double freq, void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|         if (_this->running && _this->client) { | ||||
|             _this->client->setFrequency(freq); | ||||
|         } | ||||
|         _this->freq = freq; | ||||
|         spdlog::info("RFSpaceSource '{0}': Tune: {1}!", _this->name, freq); | ||||
|         spdlog::info("RFSpaceSourceModule '{0}': Tune: {1}!", _this->name, freq); | ||||
|     } | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         RFSpaceSource* _this = (RFSpaceSource*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|         RFSpaceSourceModule* _this = (RFSpaceSourceModule*)ctx; | ||||
|  | ||||
|         bool connected = (_this->client && _this->client->isOpen()); | ||||
|         gui::mainWindow.playButtonLocked = !connected; | ||||
|  | ||||
|         if (connected) { style::beginDisabled(); } | ||||
|         if (ImGui::InputText(CONCAT("##_rfspace_srv_host_", _this->name), _this->hostname, 1023)) { | ||||
|         if (connected) { SmGui::BeginDisabled(); } | ||||
|         if (SmGui::InputText(CONCAT("##_rfspace_srv_host_", _this->name), _this->hostname, 1023)) { | ||||
|             config.acquire(); | ||||
|             config.conf["hostname"] = _this->hostname; | ||||
|             config.release(true); | ||||
|         } | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputInt(CONCAT("##_rfspace_srv_port_", _this->name), &_this->port, 0, 0)) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputInt(CONCAT("##_rfspace_srv_port_", _this->name), &_this->port, 0, 0)) { | ||||
|             config.acquire(); | ||||
|             config.conf["port"] = _this->port; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (connected) { style::endDisabled(); } | ||||
|         if (connected) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (!connected && ImGui::Button("Connect##rfspace_source", ImVec2(menuWidth, 0))) { | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (!connected && SmGui::Button("Connect##rfspace_source")) { | ||||
|             try { | ||||
|                 if (_this->client) { _this->client.reset(); } | ||||
|                 _this->client = rfspace::connect(_this->hostname, _this->port, &_this->stream); | ||||
| @@ -157,18 +159,18 @@ private: | ||||
|                 spdlog::error("Could not connect to SDR: {0}", e.what()); | ||||
|             } | ||||
|         } | ||||
|         else if (connected && ImGui::Button("Disconnect##rfspace_source", ImVec2(menuWidth, 0))) { | ||||
|         else if (connected && SmGui::Button("Disconnect##rfspace_source")) { | ||||
|             _this->client->close(); | ||||
|         } | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|  | ||||
|         if (connected) { | ||||
|             if (_this->running) { style::beginDisabled(); } | ||||
|             if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|             ImGui::LeftLabel("Samplerate"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo("##rfspace_source_samp_rate", &_this->srId, _this->sampleRates.txt)) { | ||||
|             SmGui::LeftLabel("Samplerate"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::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); | ||||
| @@ -178,12 +180,12 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|  | ||||
|             if (_this->running) { style::endDisabled(); } | ||||
|             if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|             if (_this->client->deviceId == rfspace::RFSPACE_DEV_ID_CLOUD_IQ) { | ||||
|                 ImGui::LeftLabel("Antenna Port"); | ||||
|                 ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|                 if (ImGui::Combo("##rfspace_source_rf_port", &_this->rfPortId, _this->rfPorts.txt)) { | ||||
|                 SmGui::LeftLabel("Antenna Port"); | ||||
|                 SmGui::FillWidth(); | ||||
|                 if (SmGui::Combo("##rfspace_source_rf_port", &_this->rfPortId, _this->rfPorts.txt)) { | ||||
|                     _this->client->setPort(_this->rfPorts[_this->rfPortId]); | ||||
|  | ||||
|                     config.acquire(); | ||||
| @@ -192,9 +194,9 @@ private: | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             ImGui::LeftLabel("Gain"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::SliderFloatWithSteps("##rfspace_source_gain", &_this->gain, -30, 0, 10, "%.0f dB")) { | ||||
|             SmGui::LeftLabel("Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderFloatWithSteps("##rfspace_source_gain", &_this->gain, -30, 0, 10, SmGui::FMT_STR_FLOAT_DB_NO_DECIMAL)) { | ||||
|                 _this->client->setGain(_this->gain); | ||||
|  | ||||
|                 config.acquire(); | ||||
| @@ -202,14 +204,14 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|  | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Connected (%s)", _this->deviceName.c_str()); | ||||
|             SmGui::Text("Status:"); | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), _this->connectedStr.c_str()); | ||||
|         } | ||||
|         else { | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::Text("Not connected"); | ||||
|             SmGui::Text("Status:"); | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::Text("Not connected"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -218,6 +220,8 @@ private: | ||||
|         char buf[4096]; | ||||
|         sprintf(buf, "%s:%05d", hostname, port); | ||||
|         devConfName = buf; | ||||
|         sprintf(buf, "Connected (%s:%05d)", hostname, port); | ||||
|         connectedStr = buf; | ||||
|  | ||||
|         // Get device name | ||||
|         if (deviceNames.find(client->deviceId) != deviceNames.end()) { | ||||
| @@ -301,6 +305,7 @@ private: | ||||
|     char hostname[1024]; | ||||
|     int port = 50000; | ||||
|     std::string devConfName = ""; | ||||
|     std::string connectedStr = ""; | ||||
|  | ||||
|     std::string deviceName = "Unknown"; | ||||
|     std::map<rfspace::DeviceID, std::string> deviceNames = { | ||||
| @@ -321,7 +326,7 @@ MOD_EXPORT void _INIT_() { | ||||
|     def["hostname"] = "192.168.0.111"; | ||||
|     def["port"] = 50000; | ||||
|     def["devices"] = json::object(); | ||||
|     config.setPath(options::opts.root + "/rfspace_config.json"); | ||||
|     config.setPath(options::opts.root + "/rfspace_source_config.json"); | ||||
|     config.load(def); | ||||
|     config.enableAutoSave(); | ||||
|  | ||||
| @@ -336,11 +341,11 @@ MOD_EXPORT void _INIT_() { | ||||
| } | ||||
|  | ||||
| MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { | ||||
|     return new RFSpaceSource(name); | ||||
|     return new RFSpaceSourceModule(name); | ||||
| } | ||||
|  | ||||
| MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { | ||||
|     delete (RFSpaceSource*)instance; | ||||
|     delete (RFSpaceSourceModule*)instance; | ||||
| } | ||||
|  | ||||
| MOD_EXPORT void _END_() { | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| #include <imgui.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <module.h> | ||||
| #include <gui/gui.h> | ||||
| @@ -7,6 +6,7 @@ | ||||
| #include <gui/style.h> | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <rtl-sdr.h> | ||||
|  | ||||
|  | ||||
| @@ -315,12 +315,11 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         RTLSDRSourceModule* _this = (RTLSDRSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_rtlsdr_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_rtlsdr_dev_sel_", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectById(_this->devId); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedDevName != "") { | ||||
| @@ -330,7 +329,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_rtlsdr_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_rtlsdr_sr_sel_", _this->name), &_this->srId, _this->sampleRateListTxt.c_str())) { | ||||
|             _this->sampleRate = sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             if (_this->selectedDevName != "") { | ||||
| @@ -340,20 +339,21 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_rtlsdr_refr_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_rtlsdr_refr_", _this->name)/*, ImVec2(refreshBtnWdith, 0)*/)) { | ||||
|             _this->refresh(); | ||||
|             _this->selectByName(_this->selectedDevName); | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         // Rest of rtlsdr config here | ||||
|         ImGui::LeftLabel("Direct Sampling"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_rtlsdr_ds_", _this->name), &_this->directSamplingMode, directSamplingModesTxt)) { | ||||
|         SmGui::LeftLabel("Direct Sampling"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_rtlsdr_ds_", _this->name), &_this->directSamplingMode, directSamplingModesTxt)) { | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_direct_sampling(_this->openDev, _this->directSamplingMode); | ||||
|  | ||||
| @@ -376,9 +376,9 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("PPM Correction"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputInt(CONCAT("##_rtlsdr_ppm_", _this->name), &_this->ppm, 1, 10)) { | ||||
|         SmGui::LeftLabel("PPM Correction"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputInt(CONCAT("##_rtlsdr_ppm_", _this->name), &_this->ppm, 1, 10)) { | ||||
|             _this->ppm = std::clamp<int>(_this->ppm, -1000000, 1000000); | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_freq_correction(_this->openDev, _this->ppm); | ||||
| @@ -390,22 +390,42 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (_this->tunerAgc || _this->gainList.size() == 0) { style::beginDisabled(); } | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::SliderInt(CONCAT("##_rtlsdr_gain_", _this->name), &_this->gainId, 0, _this->gainList.size() - 1, _this->dbTxt)) { | ||||
|             _this->updateGainTxt(); | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_tuner_gain(_this->openDev, _this->gainList[_this->gainId]); | ||||
|             } | ||||
|             if (_this->selectedDevName != "") { | ||||
|                 config.acquire(); | ||||
|                 config.conf["devices"][_this->selectedDevName]["gain"] = _this->gainId; | ||||
|                 config.release(true); | ||||
|         if (_this->tunerAgc || _this->gainList.size() == 0) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|  | ||||
|         // TODO: FIND ANOTHER WAY | ||||
|         if (options::opts.serverMode) { | ||||
|             if (SmGui::SliderInt(CONCAT("##_rtlsdr_gain_", _this->name), &_this->gainId, 0, _this->gainList.size() - 1, SmGui::FMT_STR_NONE)) { | ||||
|                 _this->updateGainTxt(); | ||||
|                 if (_this->running) { | ||||
|                     rtlsdr_set_tuner_gain(_this->openDev, _this->gainList[_this->gainId]); | ||||
|                 } | ||||
|                 if (_this->selectedDevName != "") { | ||||
|                     config.acquire(); | ||||
|                     config.conf["devices"][_this->selectedDevName]["gain"] = _this->gainId; | ||||
|                     config.release(true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             if (ImGui::SliderInt(CONCAT("##_rtlsdr_gain_", _this->name), &_this->gainId, 0, _this->gainList.size() - 1, _this->dbTxt)) { | ||||
|                 _this->updateGainTxt(); | ||||
|                 if (_this->running) { | ||||
|                     rtlsdr_set_tuner_gain(_this->openDev, _this->gainList[_this->gainId]); | ||||
|                 } | ||||
|                 if (_this->selectedDevName != "") { | ||||
|                     config.acquire(); | ||||
|                     config.conf["devices"][_this->selectedDevName]["gain"] = _this->gainId; | ||||
|                     config.release(true); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (_this->tunerAgc || _this->gainList.size() == 0) { style::endDisabled(); } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Bias T##_rtlsdr_rtl_biast_", _this->name), &_this->biasT)) { | ||||
|          | ||||
|         if (_this->tunerAgc || _this->gainList.size() == 0) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (SmGui::Checkbox(CONCAT("Bias T##_rtlsdr_rtl_biast_", _this->name), &_this->biasT)) { | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_bias_tee(_this->openDev, _this->biasT); | ||||
|             } | ||||
| @@ -416,7 +436,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Offset Tuning##_rtlsdr_rtl_ofs_", _this->name), &_this->offsetTuning)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Offset Tuning##_rtlsdr_rtl_ofs_", _this->name), &_this->offsetTuning)) { | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_offset_tuning(_this->openDev, _this->offsetTuning); | ||||
|             } | ||||
| @@ -427,7 +447,7 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("RTL AGC##_rtlsdr_rtl_agc_", _this->name), &_this->rtlAgc)) { | ||||
|         if (SmGui::Checkbox(CONCAT("RTL AGC##_rtlsdr_rtl_agc_", _this->name), &_this->rtlAgc)) { | ||||
|             if (_this->running) { | ||||
|                 rtlsdr_set_agc_mode(_this->openDev, _this->rtlAgc); | ||||
|             } | ||||
| @@ -438,7 +458,8 @@ private: | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Tuner AGC##_rtlsdr_tuner_agc_", _this->name), &_this->tunerAgc)) { | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Checkbox(CONCAT("Tuner AGC##_rtlsdr_tuner_agc_", _this->name), &_this->tunerAgc)) { | ||||
|             if (_this->running) { | ||||
|                 if (_this->tunerAgc) { | ||||
|                     rtlsdr_set_tuner_gain_mode(_this->openDev, 0); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include <signal_path/signal_path.h> | ||||
| #include <core.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
| #include <gui/style.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
| @@ -188,27 +189,24 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         RTLTCPSourceModule* _this = (RTLTCPSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|         float portWidth = ImGui::CalcTextSize("00000").x + 20; | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth - portWidth); | ||||
|         if (ImGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024)) { | ||||
|         if (SmGui::InputText(CONCAT("##_ip_select_", _this->name), _this->ip, 1024)) { | ||||
|             config.acquire(); | ||||
|             config.conf["host"] = std::string(_this->ip); | ||||
|             config.release(true); | ||||
|         } | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(portWidth); | ||||
|         if (ImGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0)) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputInt(CONCAT("##_port_select_", _this->name), &_this->port, 0)) { | ||||
|             config.acquire(); | ||||
|             config.conf["port"] = _this->port; | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_rtltcp_sr_", _this->name), &_this->srId, _this->srTxt.c_str())) { | ||||
|             _this->sampleRate = sampleRates[_this->srId]; | ||||
|             core::setInputSampleRate(_this->sampleRate); | ||||
|             config.acquire(); | ||||
| @@ -216,11 +214,11 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         ImGui::LeftLabel("Direct Sampling"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##_rtltcp_ds_", _this->name), &_this->directSamplingMode, "Disabled\0I branch\0Q branch\0")) { | ||||
|         SmGui::LeftLabel("Direct Sampling"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##_rtltcp_ds_", _this->name), &_this->directSamplingMode, "Disabled\0I branch\0Q branch\0")) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setDirectSampling(_this->directSamplingMode); | ||||
|                 _this->client.setGainIndex(_this->gain); | ||||
| @@ -230,9 +228,9 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         ImGui::LeftLabel("PPM Correction"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputInt(CONCAT("##_rtltcp_ppm_", _this->name), &_this->ppm, 1, 10)) { | ||||
|         SmGui::LeftLabel("PPM Correction"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputInt(CONCAT("##_rtltcp_ppm_", _this->name), &_this->ppm, 1, 10)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setPPM(_this->ppm); | ||||
|             } | ||||
| @@ -241,9 +239,9 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (_this->tunerAGC) { style::beginDisabled(); } | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::SliderInt(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 28, "")) { | ||||
|         if (_this->tunerAGC) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::SliderInt(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 28, SmGui::FMT_STR_NONE)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setGainIndex(_this->gain); | ||||
|             } | ||||
| @@ -251,9 +249,9 @@ private: | ||||
|             config.conf["gainIndex"] = _this->gain; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (_this->tunerAGC) { style::endDisabled(); } | ||||
|         if (_this->tunerAGC) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##_biast_select_", _this->name), &_this->biasTee)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##_biast_select_", _this->name), &_this->biasTee)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setBiasTee(_this->biasTee); | ||||
|             } | ||||
| @@ -262,7 +260,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("Offset Tuning##_biast_select_", _this->name), &_this->offsetTuning)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Offset Tuning##_biast_select_", _this->name), &_this->offsetTuning)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setOffsetTuning(_this->offsetTuning); | ||||
|             } | ||||
| @@ -271,7 +269,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox("RTL AGC", &_this->rtlAGC)) { | ||||
|         if (SmGui::Checkbox("RTL AGC", &_this->rtlAGC)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setAGCMode(_this->rtlAGC); | ||||
|                 if (!_this->rtlAGC) { | ||||
| @@ -283,7 +281,8 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox("Tuner AGC", &_this->tunerAGC)) { | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Checkbox("Tuner AGC", &_this->tunerAGC)) { | ||||
|             if (_this->running) { | ||||
|                 _this->client.setGainMode(!_this->tunerAGC); | ||||
|                 if (!_this->tunerAGC) { | ||||
|   | ||||
| @@ -29,6 +29,8 @@ public: | ||||
|     AirspyHFSourceModule(std::string name) { | ||||
|         this->name = name; | ||||
|  | ||||
|         if (options::opts.serverMode) { return; } | ||||
|  | ||||
|         sampleRate = 768000.0; | ||||
|  | ||||
|         handler.ctx = this; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <sdrplay_api.h> | ||||
|  | ||||
| #include <gui/smgui.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| @@ -697,14 +697,12 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         SDRPlaySourceModule* _this = (SDRPlaySourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|  | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##sdrplay_dev", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##sdrplay_dev", _this->name), &_this->devId, _this->devListTxt.c_str())) { | ||||
|             _this->selectById(_this->devId); | ||||
|             config.acquire(); | ||||
|             config.conf["device"] = _this->devNameList[_this->devId]; | ||||
| @@ -712,7 +710,7 @@ private: | ||||
|         } | ||||
|  | ||||
|         if (_this->ifModeId == 0) { | ||||
|             if (ImGui::Combo(CONCAT("##sdrplay_sr", _this->name), &_this->srId, sampleRatesTxt)) { | ||||
|             if (SmGui::Combo(CONCAT("##sdrplay_sr", _this->name), &_this->srId, sampleRatesTxt)) { | ||||
|                 _this->sampleRate = sampleRates[_this->srId]; | ||||
|                 if (_this->bandwidthId == 8) { | ||||
|                     _this->bandwidth = preferedBandwidth[_this->srId]; | ||||
| @@ -723,15 +721,16 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|  | ||||
|             ImGui::SameLine(); | ||||
|             float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|             if (ImGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::FillWidth(); | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name))) { | ||||
|                 _this->refresh(); | ||||
|                 _this->selectByName(_this->selectedName); | ||||
|             } | ||||
|  | ||||
|             ImGui::SetNextItemWidth(menuWidth); | ||||
|             if (ImGui::Combo(CONCAT("##sdrplay_bw", _this->name), &_this->bandwidthId, bandwidthsTxt)) { | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo(CONCAT("##sdrplay_bw", _this->name), &_this->bandwidthId, bandwidthsTxt)) { | ||||
|                 _this->bandwidth = (_this->bandwidthId == 8) ? preferedBandwidth[_this->srId] : bandwidths[_this->bandwidthId]; | ||||
|                 if (_this->running) { | ||||
|                     _this->channelParams->tunerParams.bwType = _this->bandwidth; | ||||
| @@ -743,16 +742,18 @@ private: | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             if (ImGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name), ImVec2(menuWidth, 0))) { | ||||
|             SmGui::FillWidth(); | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button(CONCAT("Refresh##sdrplay_refresh", _this->name))) { | ||||
|                 _this->refresh(); | ||||
|                 _this->selectByName(_this->selectedName); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ImGui::Text("IF Mode"); | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##sdrplay_ifmode", _this->name), &_this->ifModeId, ifModeTxt)) { | ||||
|         SmGui::LeftLabel("IF Mode"); | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##sdrplay_ifmode", _this->name), &_this->ifModeId, ifModeTxt)) { | ||||
|             if (_this->ifModeId != 0) { | ||||
|                 _this->bandwidth = ifModes[_this->ifModeId].bw; | ||||
|                 _this->sampleRate = ifModes[_this->ifModeId].effectiveSamplerate; | ||||
| @@ -770,13 +771,12 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (_this->selectedName != "") { | ||||
|             ImGui::PushItemWidth(menuWidth - ImGui::CalcTextSize("LNA Gain").x - 10); | ||||
|             ImGui::LeftLabel("LNA Gain"); | ||||
|             float pos = ImGui::GetCursorPosX(); | ||||
|             if (ImGui::SliderInt(CONCAT("##sdrplay_lna_gain", _this->name), &_this->lnaGain, _this->lnaSteps - 1, 0, "")) { | ||||
|             SmGui::LeftLabel("LNA Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##sdrplay_lna_gain", _this->name), &_this->lnaGain, _this->lnaSteps - 1, 0, SmGui::FMT_STR_NONE)) { | ||||
|                 if (_this->running) { | ||||
|                     _this->channelParams->tunerParams.gain.LNAstate = _this->lnaGain; | ||||
|                     sdrplay_api_Update(_this->openDev.dev, _this->openDev.tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); | ||||
| @@ -786,10 +786,10 @@ private: | ||||
|                 config.release(true); | ||||
|             } | ||||
|  | ||||
|             if (_this->agc > 0) { style::beginDisabled(); } | ||||
|             ImGui::LeftLabel("IF Gain"); | ||||
|             ImGui::SetCursorPosX(pos); | ||||
|             if (ImGui::SliderInt(CONCAT("##sdrplay_gain", _this->name), &_this->gain, 59, 20, "")) { | ||||
|             if (_this->agc > 0) { SmGui::BeginDisabled(); } | ||||
|             SmGui::LeftLabel("IF Gain"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::SliderInt(CONCAT("##sdrplay_gain", _this->name), &_this->gain, 59, 20, SmGui::FMT_STR_NONE)) { | ||||
|                 if (_this->running) { | ||||
|                     _this->channelParams->tunerParams.gain.gRdB = _this->gain; | ||||
|                     sdrplay_api_Update(_this->openDev.dev, _this->openDev.tuner, sdrplay_api_Update_Tuner_Gr, sdrplay_api_Update_Ext1_None); | ||||
| @@ -798,8 +798,7 @@ private: | ||||
|                 config.conf["devices"][_this->selectedName]["ifGain"] = _this->gain; | ||||
|                 config.release(true); | ||||
|             } | ||||
|             ImGui::PopItemWidth(); | ||||
|             if (_this->agc > 0) { style::endDisabled(); } | ||||
|             if (_this->agc > 0) { SmGui::EndDisabled(); } | ||||
|  | ||||
|  | ||||
|             if (_this->agcParamEdit) { | ||||
| @@ -831,7 +830,8 @@ private: | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (ImGui::Checkbox(CONCAT("IF AGC##sdrplay_agc", _this->name), &_this->agc)) { | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Checkbox(CONCAT("IF AGC##sdrplay_agc", _this->name), &_this->agc)) { | ||||
|                 if (_this->running) { | ||||
|                     _this->channelParams->ctrlParams.agc.enable = _this->agc ? sdrplay_api_AGC_CTRL_EN : sdrplay_api_AGC_DISABLE; | ||||
|                     if (_this->agc) { | ||||
| @@ -852,8 +852,10 @@ private: | ||||
|                 config.conf["devices"][_this->selectedName]["agc"] = _this->agc; | ||||
|                 config.release(true); | ||||
|             } | ||||
|             ImGui::SameLine(); | ||||
|             if (ImGui::Button(CONCAT("Parameters##sdrplay_agc_edit_btn", _this->name), ImVec2(menuWidth - ImGui::GetCursorPosX(), 0))) { | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::FillWidth(); | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button(CONCAT("Parameters##sdrplay_agc_edit_btn", _this->name))) { | ||||
|                 _this->agcParamEdit = true; | ||||
|                 _this->_agcAttack = _this->agcAttack; | ||||
|                 _this->_agcDecay = _this->agcDecay; | ||||
| @@ -864,100 +866,101 @@ private: | ||||
|  | ||||
|             switch (_this->openDev.hwVer) { | ||||
|             case SDRPLAY_RSP1_ID: | ||||
|                 _this->RSP1Menu(menuWidth); | ||||
|                 _this->RSP1Menu(); | ||||
|                 break; | ||||
|             case SDRPLAY_RSP1A_ID: | ||||
|                 _this->RSP1AMenu(menuWidth); | ||||
|                 _this->RSP1AMenu(); | ||||
|                 break; | ||||
|             case SDRPLAY_RSP2_ID: | ||||
|                 _this->RSP2Menu(menuWidth); | ||||
|                 _this->RSP2Menu(); | ||||
|                 break; | ||||
|             case SDRPLAY_RSPduo_ID: | ||||
|                 _this->RSPduoMenu(menuWidth); | ||||
|                 _this->RSPduoMenu(); | ||||
|                 break; | ||||
|             case SDRPLAY_RSPdx_ID: | ||||
|                 _this->RSPdxMenu(menuWidth); | ||||
|                 _this->RSPdxMenu(); | ||||
|                 break; | ||||
|             default: | ||||
|                 _this->RSPUnsupportedMenu(menuWidth); | ||||
|                 _this->RSPUnsupportedMenu(); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "No device available"); | ||||
|             SmGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "No device available"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool agcParamMenu(bool& valid) { | ||||
|         bool open = true; | ||||
|         gui::mainWindow.lockWaterfallControls = true; | ||||
|         ImGui::OpenPopup("Edit##sdrplay_source_edit_agc_params_"); | ||||
|         if (ImGui::BeginPopup("Edit##sdrplay_source_edit_agc_params_", ImGuiWindowFlags_NoResize)) { | ||||
|         SmGui::OpenPopup("Edit##sdrplay_source_edit_agc_params_"); | ||||
|         if (SmGui::BeginPopup("Edit##sdrplay_source_edit_agc_params_", ImGuiWindowFlags_NoResize)) { | ||||
|             if (SmGui::BeginTable(("sdrplay_source_agc_param_tbl" + name).c_str(), 2)) { | ||||
|                 SmGui::TableNextRow(); | ||||
|                 SmGui::TableSetColumnIndex(0); | ||||
|                 SmGui::LeftLabel("Attack"); | ||||
|                 SmGui::TableSetColumnIndex(1); | ||||
|                 SmGui::SetNextItemWidth(100); | ||||
|                 SmGui::InputInt("ms##sdrplay_source_agc_attack", &_agcAttack); | ||||
|                 _agcAttack = std::clamp<int>(_agcAttack, 0, 65535); | ||||
|  | ||||
|             ImGui::BeginTable(("sdrplay_source_agc_param_tbl" + name).c_str(), 2); | ||||
|                 SmGui::TableNextRow(); | ||||
|                 SmGui::TableSetColumnIndex(0); | ||||
|                 SmGui::LeftLabel("Decay"); | ||||
|                 SmGui::TableSetColumnIndex(1); | ||||
|                 SmGui::SetNextItemWidth(100); | ||||
|                 SmGui::InputInt("ms##sdrplay_source_agc_decay", &_agcDecay); | ||||
|                 _agcDecay = std::clamp<int>(_agcDecay, 0, 65535); | ||||
|  | ||||
|             ImGui::TableNextRow(); | ||||
|             ImGui::TableSetColumnIndex(0); | ||||
|             ImGui::LeftLabel("Attack"); | ||||
|             ImGui::TableSetColumnIndex(1); | ||||
|             ImGui::SetNextItemWidth(100); | ||||
|             ImGui::InputInt("ms##sdrplay_source_agc_attack", &_agcAttack); | ||||
|             _agcAttack = std::clamp<int>(_agcAttack, 0, 65535); | ||||
|                 SmGui::TableNextRow(); | ||||
|                 SmGui::TableSetColumnIndex(0); | ||||
|                 SmGui::LeftLabel("Decay Delay"); | ||||
|                 SmGui::TableSetColumnIndex(1); | ||||
|                 SmGui::SetNextItemWidth(100); | ||||
|                 SmGui::InputInt("ms##sdrplay_source_agc_decay_delay", &_agcDecayDelay); | ||||
|                 _agcDecayDelay = std::clamp<int>(_agcDecayDelay, 0, 65535); | ||||
|  | ||||
|             ImGui::TableNextRow(); | ||||
|             ImGui::TableSetColumnIndex(0); | ||||
|             ImGui::LeftLabel("Decay"); | ||||
|             ImGui::TableSetColumnIndex(1); | ||||
|             ImGui::SetNextItemWidth(100); | ||||
|             ImGui::InputInt("ms##sdrplay_source_agc_decay", &_agcDecay); | ||||
|             _agcDecay = std::clamp<int>(_agcDecay, 0, 65535); | ||||
|                 SmGui::TableNextRow(); | ||||
|                 SmGui::TableSetColumnIndex(0); | ||||
|                 SmGui::LeftLabel("Decay Threshold"); | ||||
|                 SmGui::TableSetColumnIndex(1); | ||||
|                 SmGui::SetNextItemWidth(100); | ||||
|                 SmGui::InputInt("dB##sdrplay_source_agc_decay_thresh", &_agcDecayThreshold); | ||||
|                 _agcDecayThreshold = std::clamp<int>(_agcDecayThreshold, 0, 100); | ||||
|  | ||||
|             ImGui::TableNextRow(); | ||||
|             ImGui::TableSetColumnIndex(0); | ||||
|             ImGui::LeftLabel("Decay Delay"); | ||||
|             ImGui::TableSetColumnIndex(1); | ||||
|             ImGui::SetNextItemWidth(100); | ||||
|             ImGui::InputInt("ms##sdrplay_source_agc_decay_delay", &_agcDecayDelay); | ||||
|             _agcDecayDelay = std::clamp<int>(_agcDecayDelay, 0, 65535); | ||||
|                 SmGui::TableNextRow(); | ||||
|                 SmGui::TableSetColumnIndex(0); | ||||
|                 SmGui::LeftLabel("Setpoint"); | ||||
|                 SmGui::TableSetColumnIndex(1); | ||||
|                 SmGui::SetNextItemWidth(100); | ||||
|                 SmGui::InputInt("dBFS##sdrplay_source_agc_setpoint", &_agcSetPoint); | ||||
|                 _agcSetPoint = std::clamp<int>(_agcSetPoint, -60, -20); | ||||
|  | ||||
|             ImGui::TableNextRow(); | ||||
|             ImGui::TableSetColumnIndex(0); | ||||
|             ImGui::LeftLabel("Decay Threshold"); | ||||
|             ImGui::TableSetColumnIndex(1); | ||||
|             ImGui::SetNextItemWidth(100); | ||||
|             ImGui::InputInt("dB##sdrplay_source_agc_decay_thresh", &_agcDecayThreshold); | ||||
|             _agcDecayThreshold = std::clamp<int>(_agcDecayThreshold, 0, 100); | ||||
|                 SmGui::EndTable(); | ||||
|             } | ||||
|  | ||||
|             ImGui::TableNextRow(); | ||||
|             ImGui::TableSetColumnIndex(0); | ||||
|             ImGui::LeftLabel("Setpoint"); | ||||
|             ImGui::TableSetColumnIndex(1); | ||||
|             ImGui::SetNextItemWidth(100); | ||||
|             ImGui::InputInt("dBFS##sdrplay_source_agc_setpoint", &_agcSetPoint); | ||||
|             _agcSetPoint = std::clamp<int>(_agcSetPoint, -60, -20); | ||||
|  | ||||
|             ImGui::EndTable(); | ||||
|  | ||||
|             if (ImGui::Button("Apply")) { | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button("Apply")) { | ||||
|                 open = false; | ||||
|                 valid = true; | ||||
|             } | ||||
|             ImGui::SameLine(); | ||||
|             if (ImGui::Button("Cancel")) { | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button("Cancel")) { | ||||
|                 open = false; | ||||
|                 valid = false; | ||||
|             } | ||||
|             ImGui::EndPopup(); | ||||
|             SmGui::EndPopup(); | ||||
|         } | ||||
|         return open; | ||||
|     } | ||||
|  | ||||
|     void RSP1Menu(float menuWidth) { | ||||
|     void RSP1Menu() { | ||||
|         // No options? | ||||
|     } | ||||
|  | ||||
|     void RSP1AMenu(float menuWidth) { | ||||
|         if (ImGui::Checkbox(CONCAT("FM Notch##sdrplay_rsp1a_fmnotch", name), &rsp1a_fmNotch)) { | ||||
|     void RSP1AMenu() { | ||||
|         if (SmGui::Checkbox(CONCAT("FM Notch##sdrplay_rsp1a_fmnotch", name), &rsp1a_fmNotch)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rsp1aParams.rfNotchEnable = rsp1a_fmNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_Rsp1a_RfNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -966,7 +969,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["fmNotch"] = rsp1a_fmNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("DAB Notch##sdrplay_rsp1a_dabnotch", name), &rsp1a_dabNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("DAB Notch##sdrplay_rsp1a_dabnotch", name), &rsp1a_dabNotch)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rsp1aParams.rfNotchEnable = rsp1a_dabNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_Rsp1a_RfDabNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -975,7 +978,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["dabNotch"] = rsp1a_dabNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##sdrplay_rsp1a_biast", name), &rsp1a_biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##sdrplay_rsp1a_biast", name), &rsp1a_biasT)) { | ||||
|             if (running) { | ||||
|                 channelParams->rsp1aTunerParams.biasTEnable = rsp1a_biasT; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_Rsp1a_BiasTControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -986,10 +989,10 @@ private: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RSP2Menu(float menuWidth) { | ||||
|         ImGui::LeftLabel("Antenna"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##sdrplay_rsp2_ant", name), &rsp2_antennaPort, rsp2_antennaPortsTxt)) { | ||||
|     void RSP2Menu() { | ||||
|         SmGui::LeftLabel("Antenna"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##sdrplay_rsp2_ant", name), &rsp2_antennaPort, rsp2_antennaPortsTxt)) { | ||||
|             if (running) { | ||||
|                 channelParams->rsp2TunerParams.antennaSel = rsp2_antennaPorts[rsp2_antennaPort]; | ||||
|                 channelParams->rsp2TunerParams.amPortSel = (rsp2_antennaPort == 2) ? sdrplay_api_Rsp2_AMPORT_1 : sdrplay_api_Rsp2_AMPORT_2; | ||||
| @@ -1000,7 +1003,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["antenna"] = rsp2_antennaPort; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("MW/FM Notch##sdrplay_rsp2_notch", name), &rsp2_notch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("MW/FM Notch##sdrplay_rsp2_notch", name), &rsp2_notch)) { | ||||
|             if (running) { | ||||
|                 channelParams->rsp2TunerParams.rfNotchEnable = rsp2_notch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_Rsp2_RfNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1009,7 +1012,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["notch"] = rsp2_notch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##sdrplay_rsp2_biast", name), &rsp2_biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##sdrplay_rsp2_biast", name), &rsp2_biasT)) { | ||||
|             if (running) { | ||||
|                 channelParams->rsp2TunerParams.biasTEnable = rsp2_biasT; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_Rsp2_BiasTControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1020,11 +1023,10 @@ private: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RSPduoMenu(float menuWidth) { | ||||
|         ImGui::LeftLabel("Antenna"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##sdrplay_rspduo_ant", name), &rspduo_antennaPort, rspduo_antennaPortsTxt)) { | ||||
|     void RSPduoMenu() { | ||||
|         SmGui::LeftLabel("Antenna"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##sdrplay_rspduo_ant", name), &rspduo_antennaPort, rspduo_antennaPortsTxt)) { | ||||
|             if (running) { | ||||
|                 rspDuoSelectAntennaPort(rspduo_antennaPort); | ||||
|             } | ||||
| @@ -1032,7 +1034,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["antenna"] = rspduo_antennaPort; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("FM Notch##sdrplay_rspduo_notch", name), &rspduo_fmNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("FM Notch##sdrplay_rspduo_notch", name), &rspduo_fmNotch)) { | ||||
|             if (running) { | ||||
|                 channelParams->rspDuoTunerParams.rfNotchEnable = rspduo_fmNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_RspDuo_RfNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1041,7 +1043,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["fmNotch"] = rspduo_fmNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("DAB Notch##sdrplay_rspduo_dabnotch", name), &rspduo_dabNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("DAB Notch##sdrplay_rspduo_dabnotch", name), &rspduo_dabNotch)) { | ||||
|             if (running) { | ||||
|                 channelParams->rspDuoTunerParams.rfDabNotchEnable = rspduo_dabNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_RspDuo_RfDabNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1050,7 +1052,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["dabNotch"] = rspduo_dabNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("AM Notch##sdrplay_rspduo_dabnotch", name), &rspduo_amNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("AM Notch##sdrplay_rspduo_dabnotch", name), &rspduo_amNotch)) { | ||||
|             if (running) { | ||||
|                 channelParams->rspDuoTunerParams.tuner1AmNotchEnable = rspduo_amNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_RspDuo_Tuner1AmNotchControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1059,7 +1061,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["amNotch"] = rspduo_amNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##sdrplay_rspduo_biast", name), &rspduo_biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##sdrplay_rspduo_biast", name), &rspduo_biasT)) { | ||||
|             if (running) { | ||||
|                 channelParams->rspDuoTunerParams.biasTEnable = rspduo_biasT; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_RspDuo_BiasTControl, sdrplay_api_Update_Ext1_None); | ||||
| @@ -1070,10 +1072,10 @@ private: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RSPdxMenu(float menuWidth) { | ||||
|         ImGui::LeftLabel("Antenna"); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo(CONCAT("##sdrplay_rspdx_ant", name), &rspdx_antennaPort, rspdx_antennaPortsTxt)) { | ||||
|     void RSPdxMenu() { | ||||
|         SmGui::LeftLabel("Antenna"); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Combo(CONCAT("##sdrplay_rspdx_ant", name), &rspdx_antennaPort, rspdx_antennaPortsTxt)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rspDxParams.antennaSel = rspdx_antennaPorts[rspdx_antennaPort]; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_AntennaControl); | ||||
| @@ -1083,7 +1085,7 @@ private: | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Checkbox(CONCAT("FM Notch##sdrplay_rspdx_fmnotch", name), &rspdx_fmNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("FM Notch##sdrplay_rspdx_fmnotch", name), &rspdx_fmNotch)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rspDxParams.rfNotchEnable = rspdx_fmNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfNotchControl); | ||||
| @@ -1092,7 +1094,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["fmNotch"] = rspdx_fmNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("DAB Notch##sdrplay_rspdx_dabnotch", name), &rspdx_dabNotch)) { | ||||
|         if (SmGui::Checkbox(CONCAT("DAB Notch##sdrplay_rspdx_dabnotch", name), &rspdx_dabNotch)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rspDxParams.rfDabNotchEnable = rspdx_dabNotch; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_RfDabNotchControl); | ||||
| @@ -1101,7 +1103,7 @@ private: | ||||
|             config.conf["devices"][selectedName]["dabNotch"] = rspdx_dabNotch; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (ImGui::Checkbox(CONCAT("Bias-T##sdrplay_rspdx_biast", name), &rspdx_biasT)) { | ||||
|         if (SmGui::Checkbox(CONCAT("Bias-T##sdrplay_rspdx_biast", name), &rspdx_biasT)) { | ||||
|             if (running) { | ||||
|                 openDevParams->devParams->rspDxParams.biasTEnable = rspdx_biasT; | ||||
|                 sdrplay_api_Update(openDev.dev, openDev.tuner, sdrplay_api_Update_None, sdrplay_api_Update_RspDx_BiasTControl); | ||||
| @@ -1112,8 +1114,8 @@ private: | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void RSPUnsupportedMenu(float menuWidth) { | ||||
|         ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Device currently unsupported"); | ||||
|     void RSPUnsupportedMenu() { | ||||
|         SmGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Device currently unsupported"); | ||||
|     } | ||||
|  | ||||
|     static void streamCB(short* xi, short* xq, sdrplay_api_StreamCbParamsT* params, | ||||
|   | ||||
							
								
								
									
										25
									
								
								source_modules/sdrpp_server_source/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								source_modules/sdrpp_server_source/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| cmake_minimum_required(VERSION 3.13) | ||||
| project(sdrpp_server_source) | ||||
|  | ||||
| file(GLOB SRC "src/*.cpp") | ||||
|  | ||||
| add_library(sdrpp_server_source SHARED ${SRC}) | ||||
| target_link_libraries(sdrpp_server_source PRIVATE sdrpp_core) | ||||
| set_target_properties(sdrpp_server_source PROPERTIES PREFIX "") | ||||
|  | ||||
| target_include_directories(sdrpp_server_source PRIVATE "src/") | ||||
|  | ||||
| if (MSVC) | ||||
|     target_compile_options(sdrpp_server_source PRIVATE /O2 /Ob2 /std:c++17 /EHsc) | ||||
| elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||||
|     target_compile_options(sdrpp_server_source PRIVATE -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup) | ||||
| else () | ||||
|     target_compile_options(sdrpp_server_source PRIVATE -O3 -std=c++17) | ||||
| endif () | ||||
|  | ||||
| if(WIN32) | ||||
|   target_link_libraries(sdrpp_server_source PRIVATE wsock32 ws2_32) | ||||
| endif() | ||||
|  | ||||
| # Install directives | ||||
| install(TARGETS sdrpp_server_source DESTINATION lib/sdrpp/plugins) | ||||
							
								
								
									
										279
									
								
								source_modules/sdrpp_server_source/src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								source_modules/sdrpp_server_source/src/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
| #include "sdrpp_server_client.h" | ||||
| #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 <options.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <utils/optionlist.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| SDRPP_MOD_INFO{ | ||||
|     /* Name:            */ "sdrpp_server_source", | ||||
|     /* Description:     */ "SDR++ Server source module for SDR++", | ||||
|     /* Author:          */ "Ryzerth", | ||||
|     /* Version:         */ 0, 1, 0, | ||||
|     /* Max instances    */ 1 | ||||
| }; | ||||
|  | ||||
| ConfigManager config; | ||||
|  | ||||
| class SDRPPServerSourceModule : public ModuleManager::Instance { | ||||
| public: | ||||
|     SDRPPServerSourceModule(std::string name) { | ||||
|         this->name = name; | ||||
|  | ||||
|         // Yeah no server-ception, sorry... | ||||
|         if (options::opts.serverMode) { return; } | ||||
|  | ||||
|         // Initialize lists | ||||
|         sampleTypeList.define("Int8", dsp::PCM_TYPE_I8); | ||||
|         sampleTypeList.define("Int16", dsp::PCM_TYPE_I16); | ||||
|         sampleTypeList.define("Float32", dsp::PCM_TYPE_F32); | ||||
|         sampleTypeId = sampleTypeList.valueId(dsp::PCM_TYPE_I16); | ||||
|  | ||||
|         handler.ctx = this; | ||||
|         handler.selectHandler = menuSelected; | ||||
|         handler.deselectHandler = menuDeselected; | ||||
|         handler.menuHandler = menuHandler; | ||||
|         handler.startHandler = start; | ||||
|         handler.stopHandler = stop; | ||||
|         handler.tuneHandler = tune; | ||||
|         handler.stream = &stream; | ||||
|  | ||||
|         // Load config | ||||
|         config.acquire(); | ||||
|         std::string hostStr = config.conf["hostname"]; | ||||
|         strcpy(hostname, hostStr.c_str()); | ||||
|         port = config.conf["port"]; | ||||
|         config.release(); | ||||
|  | ||||
|         sigpath::sourceManager.registerSource("SDR++ Server", &handler); | ||||
|     } | ||||
|  | ||||
|     ~SDRPPServerSourceModule() { | ||||
|         stop(this); | ||||
|         sigpath::sourceManager.unregisterSource("SDR++ Server"); | ||||
|     } | ||||
|  | ||||
|     void postInit() {} | ||||
|  | ||||
|     void enable() { | ||||
|         enabled = true; | ||||
|     } | ||||
|  | ||||
|     void disable() { | ||||
|         enabled = false; | ||||
|     } | ||||
|  | ||||
|     bool isEnabled() { | ||||
|         return enabled; | ||||
|     } | ||||
|  | ||||
| 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) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         if (_this->client) { | ||||
|             core::setInputSampleRate(_this->client->getSampleRate()); | ||||
|         } | ||||
|         gui::mainWindow.playButtonLocked = !(_this->client && _this->client->isOpen()); | ||||
|         spdlog::info("SDRPPServerSourceModule '{0}': Menu Select!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void menuDeselected(void* ctx) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         gui::mainWindow.playButtonLocked = false; | ||||
|         spdlog::info("SDRPPServerSourceModule '{0}': Menu Deselect!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void start(void* ctx) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         if (_this->running) { return; } | ||||
|  | ||||
|         // TODO: Set configuration here | ||||
|         if (_this->client) { _this->client->start(); } | ||||
|  | ||||
|         _this->running = true; | ||||
|         spdlog::info("SDRPPServerSourceModule '{0}': Start!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void stop(void* ctx) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         if (!_this->running) { return; } | ||||
|  | ||||
|         if (_this->client) { _this->client->stop(); } | ||||
|  | ||||
|         _this->running = false; | ||||
|         spdlog::info("SDRPPServerSourceModule '{0}': Stop!", _this->name); | ||||
|     } | ||||
|  | ||||
|     static void tune(double freq, void* ctx) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         if (_this->running && _this->client) { | ||||
|             _this->client->setFrequency(freq); | ||||
|         } | ||||
|         _this->freq = freq; | ||||
|         spdlog::info("SDRPPServerSourceModule '{0}': Tune: {1}!", _this->name, freq); | ||||
|     } | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         SDRPPServerSourceModule* _this = (SDRPPServerSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         bool connected = (_this->client && _this->client->isOpen()); | ||||
|         gui::mainWindow.playButtonLocked = !connected; | ||||
|  | ||||
|         if (connected) { style::beginDisabled(); } | ||||
|         if (ImGui::InputText(CONCAT("##sdrpp_srv_srv_host_", _this->name), _this->hostname, 1023)) { | ||||
|             config.acquire(); | ||||
|             config.conf["hostname"] = _this->hostname; | ||||
|             config.release(true); | ||||
|         } | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputInt(CONCAT("##sdrpp_srv_srv_port_", _this->name), &_this->port, 0, 0)) { | ||||
|             config.acquire(); | ||||
|             config.conf["port"] = _this->port; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (connected) { style::endDisabled(); } | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (!connected && ImGui::Button("Connect##sdrpp_srv_source", ImVec2(menuWidth, 0))) { | ||||
|             try { | ||||
|                 if (_this->client) { _this->client.reset(); } | ||||
|                 _this->client = server::connect(_this->hostname, _this->port, &_this->stream); | ||||
|                 _this->deviceInit(); | ||||
|             } | ||||
|             catch (std::exception e) { | ||||
|                 spdlog::error("Could not connect to SDR: {0}", e.what()); | ||||
|             } | ||||
|         } | ||||
|         else if (connected && ImGui::Button("Disconnect##sdrpp_srv_source", ImVec2(menuWidth, 0))) { | ||||
|             _this->client->close(); | ||||
|         } | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|  | ||||
|  | ||||
|         if (connected) { | ||||
|             ImGui::LeftLabel("Sample type"); | ||||
|             ImGui::FillWidth(); | ||||
|             if (ImGui::Combo("##sdrpp_srv_source_samp_type", &_this->sampleTypeId, _this->sampleTypeList.txt)) { | ||||
|                 _this->client->setSampleType(_this->sampleTypeList[_this->sampleTypeId]); | ||||
|  | ||||
|                 // Save config | ||||
|                 config.acquire(); | ||||
|                 config.conf["servers"][_this->devConfName]["sampleType"] = _this->sampleTypeList.key(_this->sampleTypeId); | ||||
|                 config.release(true); | ||||
|             } | ||||
|  | ||||
|             bool dummy = false; | ||||
|             style::beginDisabled(); | ||||
|             ImGui::Checkbox("Compression", &dummy); | ||||
|             dummy = true; | ||||
|             ImGui::Checkbox("Full IQ", &dummy); | ||||
|             style::endDisabled(); | ||||
|  | ||||
|             // Calculate datarate | ||||
|             _this->frametimeCounter += ImGui::GetIO().DeltaTime; | ||||
|             if (_this->frametimeCounter >= 0.2f) { | ||||
|                 _this->datarate = ((float)_this->client->bytes / (_this->frametimeCounter * 1024.0f * 1024.0f)) * 8; | ||||
|                 _this->frametimeCounter = 0; | ||||
|                 _this->client->bytes = 0; | ||||
|             } | ||||
|  | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Connected (%.3f Mbit/s)", _this->datarate); | ||||
|  | ||||
|             ImGui::CollapsingHeader("Source [REMOTE]", ImGuiTreeNodeFlags_DefaultOpen); | ||||
|  | ||||
|             _this->client->showMenu(); | ||||
|         } | ||||
|         else { | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::Text("Not connected (--.--- Mbit/s)"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void deviceInit() { | ||||
|         // Generate the config name | ||||
|         char buf[4096]; | ||||
|         sprintf(buf, "%s:%05d", hostname, port); | ||||
|         devConfName = buf; | ||||
|  | ||||
|         // Load settings | ||||
|         sampleTypeId = sampleTypeList.valueId(dsp::PCM_TYPE_I16); | ||||
|         if (config.conf["servers"][devConfName].contains("sampleType")) { | ||||
|             std::string key = config.conf["servers"][devConfName]["sampleType"]; | ||||
|             if (sampleTypeList.keyExists(key)) { sampleTypeId = sampleTypeList.keyId(key); } | ||||
|         } | ||||
|  | ||||
|         // Set settings | ||||
|         client->setSampleType(sampleTypeList[sampleTypeId]); | ||||
|     } | ||||
|  | ||||
|     std::string name; | ||||
|     bool enabled = true; | ||||
|     bool running = false; | ||||
|      | ||||
|     double freq; | ||||
|  | ||||
|     float datarate = 0; | ||||
|     float frametimeCounter = 0; | ||||
|  | ||||
|     char hostname[1024]; | ||||
|     int port = 50000; | ||||
|     std::string devConfName = ""; | ||||
|  | ||||
|     dsp::stream<dsp::complex_t> stream; | ||||
|     SourceManager::SourceHandler handler; | ||||
|  | ||||
|     OptionList<std::string, dsp::PCMType> sampleTypeList; | ||||
|     int sampleTypeId; | ||||
|  | ||||
|     server::Client client; | ||||
| }; | ||||
|  | ||||
| MOD_EXPORT void _INIT_() { | ||||
|     json def = json({}); | ||||
|     def["hostname"] = "localhost"; | ||||
|     def["port"] = 5259; | ||||
|     def["servers"] = json::object(); | ||||
|     config.setPath(options::opts.root + "/sdrpp_server_source_config.json"); | ||||
|     config.load(def); | ||||
|     config.enableAutoSave(); | ||||
| } | ||||
|  | ||||
| MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { | ||||
|     return new SDRPPServerSourceModule(name); | ||||
| } | ||||
|  | ||||
| MOD_EXPORT void _DELETE_INSTANCE_(ModuleManager::Instance* instance) { | ||||
|     delete (SDRPPServerSourceModule*)instance; | ||||
| } | ||||
|  | ||||
| MOD_EXPORT void _END_() { | ||||
|     config.disableAutoSave(); | ||||
|     config.save(); | ||||
| } | ||||
							
								
								
									
										233
									
								
								source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								source_modules/sdrpp_server_source/src/sdrpp_server_client.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| #include "sdrpp_server_client.h" | ||||
| #include <volk/volk.h> | ||||
| #include <cstring> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <core.h> | ||||
|  | ||||
| using namespace std::chrono_literals; | ||||
|  | ||||
| namespace server { | ||||
|     ClientClass::ClientClass(net::Conn conn, dsp::stream<dsp::complex_t>* out) { | ||||
|         client = std::move(conn); | ||||
|         output = out; | ||||
|  | ||||
|         // Allocate buffers | ||||
|         rbuffer = new uint8_t[SERVER_MAX_PACKET_SIZE]; | ||||
|         sbuffer = new uint8_t[SERVER_MAX_PACKET_SIZE]; | ||||
|  | ||||
|         // Initialize headers | ||||
|         r_pkt_hdr = (PacketHeader*)rbuffer; | ||||
|         r_pkt_data = &rbuffer[sizeof(PacketHeader)]; | ||||
|         r_cmd_hdr = (CommandHeader*)r_pkt_data; | ||||
|         r_cmd_data = &rbuffer[sizeof(PacketHeader) + sizeof(CommandHeader)]; | ||||
|  | ||||
|         s_pkt_hdr = (PacketHeader*)sbuffer; | ||||
|         s_pkt_data = &sbuffer[sizeof(PacketHeader)]; | ||||
|         s_cmd_hdr = (CommandHeader*)s_pkt_data; | ||||
|         s_cmd_data = &sbuffer[sizeof(PacketHeader) + sizeof(CommandHeader)]; | ||||
|  | ||||
|         // Initialize DSP | ||||
|         decomp.init(&decompIn); | ||||
|         link.init(&decomp.out, output); | ||||
|         decomp.start(); | ||||
|         link.start(); | ||||
|  | ||||
|         // Start readers | ||||
|         client->readAsync(sizeof(PacketHeader), rbuffer, tcpHandler, this); | ||||
|  | ||||
|         // Default configuration | ||||
|         stop(); | ||||
|  | ||||
|         // Ask for a UI | ||||
|         getUI(); | ||||
|     } | ||||
|  | ||||
|     ClientClass::~ClientClass() { | ||||
|         close(); | ||||
|         delete[] rbuffer; | ||||
|         delete[] sbuffer; | ||||
|     } | ||||
|  | ||||
|     void ClientClass::showMenu() { | ||||
|         std::string diffId = ""; | ||||
|         SmGui::DrawListElem diffValue; | ||||
|         bool syncRequired = false; | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lck(dlMtx); | ||||
|             dl.draw(diffId, diffValue, syncRequired); | ||||
|         } | ||||
|  | ||||
|         if (!diffId.empty()) { | ||||
|             // Save ID | ||||
|             SmGui::DrawListElem elemId; | ||||
|             elemId.type = SmGui::DRAW_LIST_ELEM_TYPE_STRING; | ||||
|             elemId.str = diffId; | ||||
|  | ||||
|             // Encore packet | ||||
|             int size = 0; | ||||
|             s_cmd_data[size++] = syncRequired; | ||||
|             size += SmGui::DrawList::storeItem(elemId, &s_cmd_data[size], SERVER_MAX_PACKET_SIZE - size); | ||||
|             size += SmGui::DrawList::storeItem(diffValue, &s_cmd_data[size], SERVER_MAX_PACKET_SIZE - size); | ||||
|  | ||||
|             // Send | ||||
|             if (syncRequired) { | ||||
|                 spdlog::warn("Action requires resync"); | ||||
|                 auto waiter = awaitCommandAck(COMMAND_UI_ACTION); | ||||
|                 sendCommand(COMMAND_UI_ACTION, size); | ||||
|                 if (waiter->await(PROTOCOL_TIMEOUT_MS)) { | ||||
|                     std::lock_guard lck(dlMtx); | ||||
|                     dl.load(r_cmd_data, r_pkt_hdr->size - sizeof(PacketHeader) - sizeof(CommandHeader)); | ||||
|                 } | ||||
|                 else { | ||||
|                     spdlog::error("Timeout out after asking for UI"); | ||||
|                 } | ||||
|                 waiter->handled(); | ||||
|                 spdlog::warn("Resync done"); | ||||
|             } | ||||
|             else { | ||||
|                 spdlog::warn("Action does not require resync"); | ||||
|                 sendCommand(COMMAND_UI_ACTION, size); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void ClientClass::setFrequency(double freq) { | ||||
|         if (!client || !client->isOpen()) { return; } | ||||
|         *(double*)s_cmd_data = freq; | ||||
|         sendCommand(COMMAND_SET_FREQUENCY, sizeof(double)); | ||||
|         auto waiter = awaitCommandAck(COMMAND_SET_FREQUENCY); | ||||
|         waiter->await(PROTOCOL_TIMEOUT_MS); | ||||
|         waiter->handled(); | ||||
|     } | ||||
|  | ||||
|     double ClientClass::getSampleRate() { | ||||
|         return currentSampleRate; | ||||
|     } | ||||
|  | ||||
|     void ClientClass::setSampleType(dsp::PCMType type) { | ||||
|         s_cmd_data[0] = type; | ||||
|         sendCommand(COMMAND_SET_SAMPLE_TYPE, 1); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::start() { | ||||
|         if (!client || !client->isOpen()) { return; } | ||||
|         sendCommand(COMMAND_START, 0); | ||||
|         getUI(); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::stop() { | ||||
|         if (!client || !client->isOpen()) { return; } | ||||
|         sendCommand(COMMAND_STOP, 0); | ||||
|         getUI(); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::close() { | ||||
|         decomp.stop(); | ||||
|         link.stop(); | ||||
|         client->close(); | ||||
|     } | ||||
|  | ||||
|     bool ClientClass::isOpen() { | ||||
|         return client->isOpen(); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::tcpHandler(int count, uint8_t* buf, void* ctx) { | ||||
|         ClientClass* _this = (ClientClass*)ctx; | ||||
|          | ||||
|         // Read the rest of the data (TODO: CHECK SIZE OR SHIT WILL BE FUCKED) | ||||
|         int len = 0; | ||||
|         int read = 0; | ||||
|         int goal = _this->r_pkt_hdr->size - sizeof(PacketHeader); | ||||
|         while (len < goal) { | ||||
|             read = _this->client->read(goal - len, &buf[sizeof(PacketHeader) + len]); | ||||
|             if (read < 0) { | ||||
|                 return;  | ||||
|             }; | ||||
|             len += read; | ||||
|         } | ||||
|         _this->bytes += _this->r_pkt_hdr->size; | ||||
|          | ||||
|         if (_this->r_pkt_hdr->type == PACKET_TYPE_COMMAND) { | ||||
|             // TODO: Move to command handler | ||||
|             if (_this->r_cmd_hdr->cmd == COMMAND_SET_SAMPLERATE && _this->r_pkt_hdr->size == sizeof(PacketHeader) + sizeof(CommandHeader) + sizeof(double)) { | ||||
|                 _this->currentSampleRate = *(double*)_this->r_cmd_data; | ||||
|                 core::setInputSampleRate(_this->currentSampleRate); | ||||
|             } | ||||
|         } | ||||
|         else if (_this->r_pkt_hdr->type == PACKET_TYPE_COMMAND_ACK) { | ||||
|             // Notify waiters | ||||
|             std::vector<PacketWaiter*> toBeRemoved; | ||||
|             for (auto& [waiter, cmd] : _this->commandAckWaiters) { | ||||
|                 if (cmd != _this->r_cmd_hdr->cmd) { continue; } | ||||
|                 waiter->notify(); | ||||
|                 toBeRemoved.push_back(waiter); | ||||
|             } | ||||
|  | ||||
|             // Remove handled waiters | ||||
|             for (auto& waiter : toBeRemoved) { | ||||
|                 _this->commandAckWaiters.erase(waiter); | ||||
|                 delete waiter; | ||||
|             } | ||||
|         } | ||||
|         else if (_this->r_pkt_hdr->type == PACKET_TYPE_BASEBAND) { | ||||
|             memcpy(_this->decompIn.writeBuf, &buf[sizeof(PacketHeader)], _this->r_pkt_hdr->size - sizeof(PacketHeader)); | ||||
|             _this->decompIn.swap(_this->r_pkt_hdr->size - sizeof(PacketHeader)); | ||||
|         } | ||||
|         else if (_this->r_pkt_hdr->type == PACKET_TYPE_ERROR) { | ||||
|             spdlog::error("SDR++ Server Error: {0}", buf[sizeof(PacketHeader)]); | ||||
|         } | ||||
|         else { | ||||
|             spdlog::error("Invalid packet type: {0}", _this->r_pkt_hdr->type); | ||||
|         } | ||||
|  | ||||
|         // Restart an async read | ||||
|         _this->client->readAsync(sizeof(PacketHeader), _this->rbuffer, tcpHandler, _this); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::getUI() { | ||||
|         auto waiter = awaitCommandAck(COMMAND_GET_UI); | ||||
|         sendCommand(COMMAND_GET_UI, 0); | ||||
|         if (waiter->await(PROTOCOL_TIMEOUT_MS)) { | ||||
|             std::lock_guard lck(dlMtx); | ||||
|             dl.load(r_cmd_data, r_pkt_hdr->size - sizeof(PacketHeader) - sizeof(CommandHeader)); | ||||
|         } | ||||
|         else { | ||||
|             spdlog::error("Timeout out after asking for UI"); | ||||
|         } | ||||
|         waiter->handled(); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::sendPacket(PacketType type, int len) { | ||||
|         s_pkt_hdr->type = type; | ||||
|         s_pkt_hdr->size = sizeof(PacketHeader) + len; | ||||
|         client->write(s_pkt_hdr->size, sbuffer); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::sendCommand(Command cmd, int len) { | ||||
|         s_cmd_hdr->cmd = cmd; | ||||
|         sendPacket(PACKET_TYPE_COMMAND, sizeof(CommandHeader) + len); | ||||
|     } | ||||
|  | ||||
|     void ClientClass::sendCommandAck(Command cmd, int len) { | ||||
|         s_cmd_hdr->cmd = cmd; | ||||
|         sendPacket(PACKET_TYPE_COMMAND_ACK, sizeof(CommandHeader) + len); | ||||
|     } | ||||
|  | ||||
|     PacketWaiter* ClientClass::awaitCommandAck(Command cmd) { | ||||
|         PacketWaiter* waiter = new PacketWaiter; | ||||
|         commandAckWaiters[waiter] = cmd; | ||||
|         return waiter; | ||||
|     } | ||||
|  | ||||
|     void ClientClass::dHandler(dsp::complex_t *data, int count, void *ctx) { | ||||
|         ClientClass* _this = (ClientClass*)ctx; | ||||
|         memcpy(_this->output->writeBuf, data, count * sizeof(dsp::complex_t)); | ||||
|         _this->output->swap(count); | ||||
|     } | ||||
|  | ||||
|     Client connect(std::string host, uint16_t port, dsp::stream<dsp::complex_t>* out) { | ||||
|         net::Conn conn = net::connect(host, port); | ||||
|         if (!conn) { return NULL; } | ||||
|         return Client(new ClientClass(std::move(conn), out)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										134
									
								
								source_modules/sdrpp_server_source/src/sdrpp_server_client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								source_modules/sdrpp_server_source/src/sdrpp_server_client.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| #pragma once | ||||
| #include <utils/networking.h> | ||||
| #include <dsp/stream.h> | ||||
| #include <dsp/types.h> | ||||
| #include <atomic> | ||||
| #include <queue> | ||||
| #include <server_protocol.h> | ||||
| #include <atomic> | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <dsp/compression.h> | ||||
| #include <dsp/sink.h> | ||||
| #include <dsp/link.h> | ||||
|  | ||||
| #define RFSPACE_MAX_SIZE                8192 | ||||
| #define RFSPACE_HEARTBEAT_INTERVAL_MS   1000 | ||||
| #define RFSPACE_TIMEOUT_MS              3000 | ||||
|  | ||||
| #define PROTOCOL_TIMEOUT_MS             10000 | ||||
|  | ||||
| namespace server { | ||||
|     class PacketWaiter { | ||||
|     public: | ||||
|         bool await(int timeout) { | ||||
|             std::unique_lock lck(readyMtx); | ||||
|             return readyCnd.wait_for(lck, std::chrono::milliseconds(timeout), [=](){ return dataReady; }); | ||||
|         } | ||||
|  | ||||
|         void handled() { | ||||
|             { | ||||
|                 std::lock_guard lck(handledMtx); | ||||
|                 dataHandled = true; | ||||
|             } | ||||
|             handledCnd.notify_all(); | ||||
|         } | ||||
|  | ||||
|         void notify() { | ||||
|             // Tell waiter that data is ready | ||||
|             { | ||||
|                 std::lock_guard lck(readyMtx); | ||||
|                 dataReady = true; | ||||
|             } | ||||
|             readyCnd.notify_all(); | ||||
|  | ||||
|             // Wait for waiter to handle the request | ||||
|             { | ||||
|                 std::unique_lock lck(readyMtx); | ||||
|                 handledCnd.wait(lck, [=](){ return dataHandled; }); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         void reset() { | ||||
|             std::lock_guard lck1(readyMtx); | ||||
|             std::lock_guard lck2(handledMtx); | ||||
|             dataReady = false; | ||||
|             dataHandled = false; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         bool dataReady = false; | ||||
|         bool dataHandled = false; | ||||
|          | ||||
|         std::condition_variable readyCnd; | ||||
|         std::condition_variable handledCnd; | ||||
|  | ||||
|         std::mutex readyMtx; | ||||
|         std::mutex handledMtx; | ||||
|     }; | ||||
|  | ||||
|     class ClientClass { | ||||
|     public: | ||||
|         ClientClass(net::Conn conn, dsp::stream<dsp::complex_t>* out); | ||||
|         ~ClientClass(); | ||||
|  | ||||
|         void showMenu(); | ||||
|  | ||||
|         void setFrequency(double freq); | ||||
|         double getSampleRate(); | ||||
|          | ||||
|         void setSampleType(dsp::PCMType type); | ||||
|  | ||||
|         void start(); | ||||
|         void stop(); | ||||
|  | ||||
|         void close(); | ||||
|         bool isOpen(); | ||||
|  | ||||
|         int bytes = 0; | ||||
|  | ||||
|     private: | ||||
|         static void tcpHandler(int count, uint8_t* buf, void* ctx); | ||||
|  | ||||
|         void getUI(); | ||||
|  | ||||
|         void sendPacket(PacketType type, int len); | ||||
|         void sendCommand(Command cmd, int len); | ||||
|         void sendCommandAck(Command cmd, int len); | ||||
|  | ||||
|         PacketWaiter* awaitCommandAck(Command cmd); | ||||
|         void commandAckHandled(PacketWaiter* waiter); | ||||
|         std::map<PacketWaiter*, Command> commandAckWaiters; | ||||
|  | ||||
|         static void dHandler(dsp::complex_t *data, int count, void *ctx); | ||||
|  | ||||
|         net::Conn client; | ||||
|  | ||||
|         dsp::stream<uint8_t> decompIn; | ||||
|         dsp::DynamicRangeDecompressor decomp; | ||||
|         dsp::Link<dsp::complex_t> link; | ||||
|         dsp::stream<dsp::complex_t>* output; | ||||
|  | ||||
|         uint8_t* rbuffer = NULL; | ||||
|         uint8_t* sbuffer = NULL; | ||||
|  | ||||
|         PacketHeader* r_pkt_hdr = NULL; | ||||
|         uint8_t* r_pkt_data = NULL; | ||||
|         CommandHeader* r_cmd_hdr = NULL; | ||||
|         uint8_t* r_cmd_data = NULL; | ||||
|  | ||||
|         PacketHeader* s_pkt_hdr = NULL; | ||||
|         uint8_t* s_pkt_data = NULL; | ||||
|         CommandHeader* s_cmd_hdr = NULL; | ||||
|         uint8_t* s_cmd_data = NULL; | ||||
|  | ||||
|         SmGui::DrawList dl; | ||||
|         std::mutex dlMtx; | ||||
|  | ||||
|         double currentSampleRate = 1000000.0; | ||||
|     }; | ||||
|  | ||||
|     typedef std::unique_ptr<ClientClass> Client; | ||||
|  | ||||
|     Client connect(std::string host, uint16_t port, dsp::stream<dsp::complex_t>* out); | ||||
| } | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include <core.h> | ||||
| #include <gui/style.h> | ||||
| #include <options.h> | ||||
| #include <gui/smgui.h> | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
|  | ||||
| @@ -365,65 +366,66 @@ private: | ||||
|     static void menuHandler(void* ctx) { | ||||
|         SoapyModule* _this = (SoapyModule*)ctx; | ||||
|  | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         // If no device is selected, draw only the refresh button | ||||
|         if (_this->devId < 0) { | ||||
|             if (ImGui::Button(CONCAT("Refresh##_dev_select_", _this->name), ImVec2(menuWidth, 0))) { | ||||
|             SmGui::FillWidth(); | ||||
|             SmGui::ForceSync(); | ||||
|             if (SmGui::Button(CONCAT("Refresh##_dev_select_", _this->name))) { | ||||
|                 _this->refresh(); | ||||
|                 _this->selectDevice(config.conf["device"]); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(menuWidth); | ||||
|         if (ImGui::Combo(CONCAT("##_dev_select_", _this->name), &_this->devId, _this->txtDevList.c_str())) { | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (SmGui::Combo(CONCAT("##_dev_select_", _this->name), &_this->devId, _this->txtDevList.c_str())) { | ||||
|             _this->selectDevice(_this->devList[_this->devId]["label"]); | ||||
|             config.acquire(); | ||||
|             config.conf["device"] = _this->devList[_this->devId]["label"]; | ||||
|             config.release(true); | ||||
|         } | ||||
|  | ||||
|         if (ImGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) { | ||||
|         if (SmGui::Combo(CONCAT("##_sr_select_", _this->name), &_this->srId, _this->txtSrList.c_str())) { | ||||
|             _this->selectSampleRate(_this->sampleRates[_this->srId]); | ||||
|             if (_this->bandwidthList.size() > 2 && _this->running && _this->bandwidthList[_this->uiBandwidthId] == -1) | ||||
|                 _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); | ||||
|             _this->saveCurrent(); | ||||
|         } | ||||
|  | ||||
|         ImGui::SameLine(); | ||||
|         float refreshBtnWdith = menuWidth - ImGui::GetCursorPosX(); | ||||
|         if (ImGui::Button(CONCAT("Refresh##_dev_select_", _this->name), ImVec2(refreshBtnWdith, 0))) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::Button(CONCAT("Refresh##_dev_select_", _this->name))) { | ||||
|             _this->refresh(); | ||||
|             _this->selectDevice(config.conf["device"]); | ||||
|         } | ||||
|  | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (_this->antennaList.size() > 1) { | ||||
|             ImGui::LeftLabel("Antenna"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo(CONCAT("##_antenna_select_", _this->name), &_this->uiAntennaId, _this->txtAntennaList.c_str())) { | ||||
|             SmGui::LeftLabel("Antenna"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo(CONCAT("##_antenna_select_", _this->name), &_this->uiAntennaId, _this->txtAntennaList.c_str())) { | ||||
|                 if (_this->running) | ||||
|                     _this->dev->setAntenna(SOAPY_SDR_RX, _this->channelId, _this->antennaList[_this->uiAntennaId]); | ||||
|                 _this->saveCurrent(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         float gainNameLen = 0; | ||||
|         float len; | ||||
|         for (auto gain : _this->gainList) { | ||||
|             len = ImGui::CalcTextSize((gain + " gain").c_str()).x; | ||||
|             if (len > gainNameLen) { | ||||
|                 gainNameLen = len; | ||||
|             } | ||||
|         } | ||||
|         gainNameLen += 5.0f; | ||||
|         // float gainNameLen = 0; | ||||
|         // float len; | ||||
|         // for (auto gain : _this->gainList) { | ||||
|         //     len = ImGui::CalcTextSize((gain + " gain").c_str()).x; | ||||
|         //     if (len > gainNameLen) { | ||||
|         //         gainNameLen = len; | ||||
|         //     } | ||||
|         // } | ||||
|         // gainNameLen += 5.0f; | ||||
|  | ||||
|         if (_this->hasAgc) { | ||||
|             if (ImGui::Checkbox((std::string("AGC##_agc_sel_") + _this->name).c_str(), &_this->agc)) { | ||||
|             if (SmGui::Checkbox((std::string("AGC##_agc_sel_") + _this->name).c_str(), &_this->agc)) { | ||||
|                 if (_this->running) { _this->dev->setGainMode(SOAPY_SDR_RX, _this->channelId, _this->agc); } | ||||
|                 // When disabled, reset the gains | ||||
|                 if (!_this->agc) { | ||||
| @@ -441,16 +443,17 @@ private: | ||||
|         char buf[128]; | ||||
|         for (auto gain : _this->gainList) { | ||||
|             sprintf(buf, "%s gain", gain.c_str()); | ||||
|             ImGui::LeftLabel(buf); | ||||
|             ImGui::SetCursorPosX(gainNameLen); | ||||
|             ImGui::SetNextItemWidth(menuWidth - gainNameLen); | ||||
|             SmGui::LeftLabel(buf); | ||||
|             // ImGui::SetCursorPosX(gainNameLen); | ||||
|             // ImGui::SetNextItemWidth(menuWidth - gainNameLen); | ||||
|             float step = _this->gainRanges[i].step(); | ||||
|             bool res; | ||||
|             SmGui::FillWidth(); | ||||
|             if (step == 0.0f) { | ||||
|                 res = ImGui::SliderFloat((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum()); | ||||
|                 res = SmGui::SliderFloat((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum()); | ||||
|             } | ||||
|             else { | ||||
|                 res = ImGui::SliderFloatWithSteps((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum(), step); | ||||
|                 res = SmGui::SliderFloatWithSteps((std::string("##_gain_sel_") + _this->name + gain).c_str(), &_this->uiGains[i], _this->gainRanges[i].minimum(), _this->gainRanges[i].maximum(), step); | ||||
|             } | ||||
|             if (res) { | ||||
|                 if (_this->running) { | ||||
| @@ -461,9 +464,9 @@ private: | ||||
|             i++; | ||||
|         } | ||||
|         if (_this->bandwidthList.size() > 2) { | ||||
|             ImGui::LeftLabel("Bandwidth"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo(CONCAT("##_bw_select_", _this->name), &_this->uiBandwidthId, _this->txtBwList.c_str())) { | ||||
|             SmGui::LeftLabel("Bandwidth"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo(CONCAT("##_bw_select_", _this->name), &_this->uiBandwidthId, _this->txtBwList.c_str())) { | ||||
|                 if (_this->running) { | ||||
|                     if (_this->bandwidthList[_this->uiBandwidthId] == -1) | ||||
|                         _this->dev->setBandwidth(SOAPY_SDR_RX, _this->channelId, _this->selectBwBySr(_this->sampleRates[_this->srId])); | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include <config.h> | ||||
| #include <options.h> | ||||
| #include <gui/widgets/stepped_slider.h> | ||||
| #include <gui/smgui.h> | ||||
|  | ||||
|  | ||||
| #define CONCAT(a, b) ((std::string(a) + b).c_str()) | ||||
| @@ -155,28 +156,29 @@ private: | ||||
|  | ||||
|     static void menuHandler(void* ctx) { | ||||
|         SpyServerSourceModule* _this = (SpyServerSourceModule*)ctx; | ||||
|         float menuWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|  | ||||
|         bool connected = (_this->client && _this->client->isOpen()); | ||||
|         gui::mainWindow.playButtonLocked = !connected; | ||||
|  | ||||
|         if (connected) { style::beginDisabled(); } | ||||
|         if (ImGui::InputText(CONCAT("##_spyserver_srv_host_", _this->name), _this->hostname, 1023)) { | ||||
|         if (connected) { SmGui::BeginDisabled(); } | ||||
|         if (SmGui::InputText(CONCAT("##_spyserver_srv_host_", _this->name), _this->hostname, 1023)) { | ||||
|             config.acquire(); | ||||
|             config.conf["hostname"] = _this->hostname; | ||||
|             config.release(true); | ||||
|         } | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::InputInt(CONCAT("##_spyserver_srv_port_", _this->name), &_this->port, 0, 0)) { | ||||
|         SmGui::SameLine(); | ||||
|         SmGui::FillWidth(); | ||||
|         if (SmGui::InputInt(CONCAT("##_spyserver_srv_port_", _this->name), &_this->port, 0, 0)) { | ||||
|             config.acquire(); | ||||
|             config.conf["port"] = _this->port; | ||||
|             config.release(true); | ||||
|         } | ||||
|         if (connected) { style::endDisabled(); } | ||||
|         if (connected) { SmGui::EndDisabled(); } | ||||
|  | ||||
|         if (_this->running) { style::beginDisabled(); } | ||||
|         if (!connected && ImGui::Button("Connect##spyserver_source", ImVec2(menuWidth, 0))) { | ||||
|         if (_this->running) { SmGui::BeginDisabled(); } | ||||
|         SmGui::FillWidth(); | ||||
|         SmGui::ForceSync(); | ||||
|         if (!connected && SmGui::Button("Connect##spyserver_source")) { | ||||
|             try { | ||||
|                 if (_this->client) { _this->client.reset(); } | ||||
|                 _this->client = spyserver::connect(_this->hostname, _this->port, &_this->stream); | ||||
| @@ -223,17 +225,17 @@ private: | ||||
|                 spdlog::error("Could not connect to spyserver {0}", e.what()); | ||||
|             } | ||||
|         } | ||||
|         else if (connected && ImGui::Button("Disconnect##spyserver_source", ImVec2(menuWidth, 0))) { | ||||
|         else if (connected && SmGui::Button("Disconnect##spyserver_source")) { | ||||
|             _this->client->close(); | ||||
|         } | ||||
|         if (_this->running) { style::endDisabled(); } | ||||
|         if (_this->running) { SmGui::EndDisabled(); } | ||||
|  | ||||
|  | ||||
|         if (connected) { | ||||
|             if (_this->running) { style::beginDisabled(); } | ||||
|             ImGui::LeftLabel("Samplerate"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo("##spyserver_source_sr", &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|             SmGui::LeftLabel("Samplerate"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo("##spyserver_source_sr", &_this->srId, _this->sampleRatesTxt.c_str())) { | ||||
|                 _this->sampleRate = _this->sampleRates[_this->srId]; | ||||
|                 core::setInputSampleRate(_this->sampleRate); | ||||
|                 config.acquire(); | ||||
| @@ -242,9 +244,9 @@ private: | ||||
|             } | ||||
|             if (_this->running) { style::endDisabled(); } | ||||
|  | ||||
|             ImGui::LeftLabel("Sample bit depth"); | ||||
|             ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); | ||||
|             if (ImGui::Combo("##spyserver_source_type", &_this->iqType, streamFormatStr)) { | ||||
|             SmGui::LeftLabel("Sample bit depth"); | ||||
|             SmGui::FillWidth(); | ||||
|             if (SmGui::Combo("##spyserver_source_type", &_this->iqType, streamFormatStr)) { | ||||
|                 int srvBits = streamFormatsBitCount[_this->iqType]; | ||||
|                 _this->client->setSetting(SPYSERVER_SETTING_IQ_FORMAT, streamFormats[_this->iqType]); | ||||
|                 _this->client->setSetting(SPYSERVER_SETTING_IQ_DIGITAL_GAIN, _this->client->computeDigitalGain(srvBits, _this->gain, _this->srId + _this->client->devInfo.MinimumIQDecimation)); | ||||
| @@ -255,8 +257,8 @@ private: | ||||
|             } | ||||
|  | ||||
|             if (_this->client->devInfo.MaximumGainIndex) { | ||||
|                 ImGui::SetNextItemWidth(menuWidth); | ||||
|                 if (ImGui::SliderInt("##spyserver_source_gain", (int*)&_this->gain, 0, _this->client->devInfo.MaximumGainIndex)) { | ||||
|                 SmGui::FillWidth(); | ||||
|                 if (SmGui::SliderInt("##spyserver_source_gain", (int*)&_this->gain, 0, _this->client->devInfo.MaximumGainIndex)) { | ||||
|                     int srvBits = streamFormatsBitCount[_this->iqType]; | ||||
|                     _this->client->setSetting(SPYSERVER_SETTING_GAIN, _this->gain); | ||||
|                     _this->client->setSetting(SPYSERVER_SETTING_IQ_DIGITAL_GAIN, _this->client->computeDigitalGain(srvBits, _this->gain, _this->srId + _this->client->devInfo.MinimumIQDecimation)); | ||||
| @@ -266,14 +268,14 @@ private: | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             SmGui::Text("Status:"); | ||||
|             SmGui::SameLine(); | ||||
|             ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "Connected (%s)", deviceTypesStr[_this->client->devInfo.DeviceType]); | ||||
|         } | ||||
|         else { | ||||
|             ImGui::Text("Status:"); | ||||
|             ImGui::SameLine(); | ||||
|             ImGui::Text("Not connected"); | ||||
|             SmGui::Text("Status:"); | ||||
|             SmGui::SameLine(); | ||||
|             SmGui::Text("Not connected"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user