diff --git a/CMakeLists.txt b/CMakeLists.txt index a817a1d..2bda349 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,18 +7,67 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "2") SET(CUBICSDR_VERSION_PATCH "0") -SET(CUBICSDR_VERSION_REL "") -SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}${CUBICSDR_VERSION_REL}") +SET(CUBICSDR_VERSION_SUFFIX "") +SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}${CUBICSDR_VERSION_SUFFIX}") SET(CPACK_PACKAGE_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}") SET(CPACK_PACKAGE_VERSION_MAJOR ${CUBICSDR_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${CUBICSDR_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${CUBICSDR_VERSION_PATCH}) -SET (VERSION_SUFFIX "" CACHE STRING "Add custom version suffix to CubicSDR application title.") +SET (CUSTOM_BUILD OFF CACHE BOOL "Enable custom build options") +# Build options for custom deploys, optimization and debugging +IF(CUSTOM_BUILD) + SET (CUBICSDR_BUILD_TITLE CACHE STRING "Custom Title") + # bundle flags + SET (CUBICSDR_INSTALL_NAME CACHE "CubicSDR" "Installation Name") + SET (CUBICSDR_INSTALL_TITLE CACHE "CubicSDR" "Installation Title") + SET (CUBICSDR_HEADER_IMAGE CACHE "" "Image file to display in header") + SET (CUBICSDR_HEADER_BG CACHE "000000" "Background Color (HEX) for header") + # feature flags + SET (CUBICSDR_ENABLE_VIEW_DEMOD ON CACHE BOOL "Enable Second Demodulator Spectrum/Waterfall view.") + SET (CUBICSDR_ENABLE_VIEW_SCOPE ON CACHE BOOL "Enable Demodulator Scope/Spectrum view.") + SET (CUBICSDR_MODEM_EXCLUDE CACHE "" "Comma-separated list of modems to exclude.") + + IF (NOT CUBICSDR_HEADER_IMAGE STREQUAL "") + SET(CUBICSDR_HAS_HEADER_IMAGE TRUE) + GET_FILENAME_COMPONENT(CUBICSDR_HEADER_IMAGE_FILE "${CUBICSDR_HEADER_IMAGE}" NAME) + GET_FILENAME_COMPONENT(CUBICSDR_HEADER_IMAGE_DIR "${CUBICSDR_HEADER_IMAGE}" PATH) + ADD_DEFINITIONS( + -DCUBICSDR_HEADER_IMAGE="${CUBICSDR_HEADER_IMAGE_FILE}" + -DCUBICSDR_HEADER_BG="${CUBICSDR_HEADER_BG}" + ) + ENDIF() + + IF (NOT CUBICSDR_MODEM_EXCLUDE STREQUAL "") + ADD_DEFINITIONS( + -DCUBICSDR_MODEM_EXCLUDE="${CUBICSDR_MODEM_EXCLUDE}" + ) + ENDIF() +ELSE() + SET (CUBICSDR_BUILD_TITLE "CubicSDR v{$CUBICSDR_VERSION} by Charles J. Cliffe (@ccliffe) :: www.cubicsdr.com") + # bundle flags + SET (CUBICSDR_INSTALL_NAME "CubicSDR") + SET (CUBICSDR_INSTALL_TITLE "CubicSDR ${CUBICSDR_VERSION} Installer") + SET (CUBICSDR_HEADER_IMAGE "") + SET (CUBICSDR_HEADER_BG "") + # feature flags + SET (CUBICSDR_ENABLE_VIEW_DEMOD TRUE) + SET (CUBICSDR_ENABLE_VIEW_SCOPE TRUE) + SET (CUBICSDR_EXCLUDE_MODEM "") +ENDIF() + +IF(CUBICSDR_ENABLE_VIEW_DEMOD) + ADD_DEFINITIONS( -DCUBICSDR_ENABLE_VIEW_DEMOD=1 ) +ENDIF() + +IF(CUBICSDR_ENABLE_VIEW_SCOPE) + ADD_DEFINITIONS( -DCUBICSDR_ENABLE_VIEW_SCOPE=1 ) +ENDIF() ADD_DEFINITIONS( - -DCUBICSDR_VERSION="${CUBICSDR_VERSION}${VERSION_SUFFIX}" + -DCUBICSDR_VERSION="${CUBICSDR_VERSION}" + -DCUBICSDR_BUILD_TITLE="${CUBICSDR_BUILD_TITLE}" ) SET (ENABLE_DIGITAL_LAB OFF CACHE BOOL "Enable 'Digital Lab' testing features.") @@ -561,6 +610,9 @@ IF (NOT BUNDLE_APP) IF(MSVC) configure_files(${PROJECT_SOURCE_DIR}/external/liquid-dsp/msvc/${EX_PLATFORM}/ ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} "*.dll") ENDIF() + IF (CUBICSDR_HAS_HEADER_IMAGE) + configure_files(${CUBICSDR_HEADER_IMAGE_DIR} ${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME} ${CUBICSDR_HEADER_IMAGE_FILE}) + ENDIF() add_executable(CubicSDR ${cubicsdr_sources} ${cubicsdr_headers} ${RES_FILES}) target_link_libraries(CubicSDR ${LIQUID_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES}) ENDIF (NOT BUNDLE_APP) @@ -639,7 +691,7 @@ IF (APPLE AND BUNDLE_APP) MACOSX_BUNDLE_INFO_STRING "CubicSDR Open-Source Software-Defined Radio Application" MACOSX_BUNDLE_BUNDLE_NAME "CubicSDR" MACOSX_BUNDLE_BUNDLE_VERSION "${CUBICSDR_VERSION}" - MACOSX_BUNDLE_LONG_VERSION_STRING "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}.${CUBICSDR_VERSION_REL}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}${CUBICSDR_VERSION_SUFFIX}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}" MACOSX_BUNDLE_GUI_IDENTIFIER "com.cubicproductions.cubicsdr" MACOSX_BUNDLE_ICON_FILE "CubicSDR.icns" @@ -734,6 +786,7 @@ IF (APPLE AND BUNDLE_APP) include(CPack) ENDIF() + IF(APPLE AND NOT BUNDLE_APP) IF (NOT CMAKE_INSTALL_PREFIX) SET(CMAKE_INSTALL_PREFIX "/usr/") @@ -790,16 +843,23 @@ IF (WIN32 AND NOT BUILD_INSTALLER) INSTALL(FILES ${CUBICSDR_FONTS} DESTINATION share/cubicsdr/fonts) + + IF (CUBICSDR_HAS_HEADER_IMAGE) + INSTALL(FILES + ${CUBICSDR_HEADER_IMAGE} + DESTINATION share/cubicsdr/) + ENDIF() + ENDIF() IF (WIN32 AND BUILD_INSTALLER) set(BUNDLE_SOAPY_MODS OFF CACHE BOOL "Bundle local SoapySDR modules") set(CPACK_GENERATOR NSIS) - set(CPACK_PACKAGE_NAME "CubicSDR") + set(CPACK_PACKAGE_NAME "${CUBICSDR_INSTALL_NAME}") set(CPACK_PACKAGE_VENDOR "cubicsdr.com") - set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CubicSDR ${CUBICSDR_VERSION} Installer") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "CubicSDR") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${CUBICSDR_INSTALL_TITLE}") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CUBICSDR_INSTALL_NAME}") SET(CPACK_NSIS_INSTALLED_ICON_NAME "CubicSDR.ico") SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/icon\\\\NSIS_Header.bmp") @@ -826,6 +886,12 @@ IF (WIN32 AND BUILD_INSTALLER) install(FILES ${CUBICSDR_FONTS} DESTINATION fonts) + + IF (CUBICSDR_HAS_HEADER_IMAGE) + INSTALL(FILES + ${CUBICSDR_HEADER_IMAGE} + DESTINATION .) + ENDIF() IF(USE_HAMLIB) FOREACH(HAMLIB_DLL ${HAMLIB_DLLS}) @@ -938,6 +1004,13 @@ IF(UNIX AND NOT APPLE AND NOT BUILD_DEB) ${CUBICSDR_FONTS} DESTINATION share/cubicsdr/fonts) + + IF (CUBICSDR_HAS_HEADER_IMAGE) + INSTALL(FILES + ${CUBICSDR_HEADER_IMAGE} + DESTINATION share/cubicsdr) + ENDIF() + INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/CubicSDR.desktop" DESTINATION share/applications) diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 39d2f4d..2772ddb 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -28,7 +28,6 @@ long long DeviceConfig::getOffset() { return offset.load(); } - void DeviceConfig::setSampleRate(long srate) { sampleRate.store(srate); } @@ -289,6 +288,7 @@ AppConfig::AppConfig() : configName("") { centerFreq.store(100000000); waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS); spectrumAvgSpeed.store(0.65f); + dbOffset.store(0); modemPropsCollapsed.store(false); #ifdef USE_HAMLIB rigEnabled.store(false); @@ -425,6 +425,14 @@ float AppConfig::getSpectrumAvgSpeed() { return spectrumAvgSpeed.load(); } +void AppConfig::setDBOffset(int offset) { + this->dbOffset.store(offset); +} + +int AppConfig::getDBOffset() { + return dbOffset.load(); +} + void AppConfig::setManualDevices(std::vector manuals) { manualDevices = manuals; } @@ -478,6 +486,7 @@ bool AppConfig::save() { *window_node->newChild("waterfall_lps") = waterfallLinesPerSec.load(); *window_node->newChild("spectrum_avg") = spectrumAvgSpeed.load(); *window_node->newChild("modemprops_collapsed") = modemPropsCollapsed.load();; + *window_node->newChild("db_offset") = dbOffset.load(); } DataNode *devices_node = cfg.rootNode()->newChild("devices"); @@ -628,6 +637,13 @@ bool AppConfig::load() { win_node->getNext("modemprops_collapsed")->element()->get(mpc); modemPropsCollapsed.store(mpc?true:false); } + + if (win_node->hasAnother("db_offset")) { + DataNode *offset_node = win_node->getNext("db_offset"); + int offsetValue = 0; + offset_node->element()->get(offsetValue); + setDBOffset(offsetValue); + } } if (cfg.rootNode()->hasAnother("devices")) { diff --git a/src/AppConfig.h b/src/AppConfig.h index 96570aa..f8d31e3 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -112,6 +112,9 @@ public: void setSpectrumAvgSpeed(float avgSpeed); float getSpectrumAvgSpeed(); + void setDBOffset(int offset); + int getDBOffset(); + void setManualDevices(std::vector manuals); std::vector getManualDevices(); @@ -158,6 +161,7 @@ private: std::atomic_llong centerFreq; std::atomic_int waterfallLinesPerSec; std::atomic spectrumAvgSpeed; + std::atomic_int dbOffset; std::vector manualDevices; #if USE_HAMLIB std::atomic_int rigModel, rigRate; diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index d9eb0ce..8f7cb21 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -43,6 +43,10 @@ wxEND_EVENT_TABLE() #include "RigThread.h" #endif + +/* split a string by 'seperator' into a vector of string */ +std::vector str_explode(const std::string &seperator, const std::string &in_str); + #define APPFRAME_MODEMPROPS_MINSIZE 20 #define APPFRAME_MODEMPROPS_MAXSIZE 240 @@ -54,7 +58,6 @@ AppFrame::AppFrame() : #endif wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *demodVisuals = new wxBoxSizer(wxVERTICAL); demodTray = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL); wxBoxSizer *demodTunerTray = new wxBoxSizer(wxHORIZONTAL); @@ -69,6 +72,21 @@ AppFrame::AppFrame() : mainSplitter->SetMinimumPaneSize(1); wxPanel *demodPanel = new wxPanel(mainSplitter, wxID_ANY); + +#ifdef CUBICSDR_HEADER_IMAGE + //get the dir path of the executable + wxFileName exePath = wxFileName(wxStandardPaths::Get().GetExecutablePath()); + std::string headerPath = exePath.GetPath().ToStdString(); + headerPath += filePathSeparator + std::string("" CUBICSDR_HEADER_IMAGE); + wxInitAllImageHandlers(); + wxStaticBitmap *headerImgStatic = new wxStaticBitmap(demodPanel, wxID_ANY, wxBitmap( headerPath, wxBITMAP_TYPE_ANY )); + std::string headerBgColor = "" CUBICSDR_HEADER_BG; + if (headerBgColor != "") { + demodPanel->SetBackgroundColour(wxColour(headerBgColor)); + } + demodTray->Add(headerImgStatic, 0, wxALIGN_CENTER_VERTICAL | wxALL, 0); + demodTray->AddSpacer(1); +#endif gainCanvas = new GainCanvas(demodPanel, attribList); @@ -77,16 +95,24 @@ AppFrame::AppFrame() : gainSpacerItem = demodTray->AddSpacer(1); gainSpacerItem->Show(false); + std::string modemListArr[] = { "FM", "FMS", "NBFM", "AM", "LSB", "USB", "DSB", "I/Q" }; + std::vector modemList( modemListArr, modemListArr + 8 ); + +#ifdef CUBICSDR_MODEM_EXCLUDE + std::string excludeListStr = "" CUBICSDR_MODEM_EXCLUDE; + std::vector excludeList = str_explode(",",excludeListStr); + for (auto ex_i : excludeList) { + std::vector::iterator found_i = std::find(modemList.begin(),modemList.end(),ex_i); + if (found_i != modemList.end()) { + modemList.erase(found_i); + } + } +#endif + demodModeSelector = new ModeSelectorCanvas(demodPanel, attribList); - demodModeSelector->addChoice("FM"); - demodModeSelector->addChoice("FMS"); - demodModeSelector->addChoice("NBFM"); - demodModeSelector->addChoice("AM"); - demodModeSelector->addChoice("LSB"); - demodModeSelector->addChoice("USB"); - demodModeSelector->addChoice("DSB"); - demodModeSelector->addChoice("I/Q"); - demodModeSelector->setSelection("FM"); + for (auto mt_i : modemList) { + demodModeSelector->addChoice(mt_i); + } demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation (Hotkey F), Amplitude Modulation (A) and Lower (L), Upper (U), Double Side-Band and more."); demodModeSelector->SetMinSize(wxSize(50,-1)); demodModeSelector->SetMaxSize(wxSize(50,-1)); @@ -117,13 +143,19 @@ AppFrame::AppFrame() : modemProps->SetMinSize(wxSize(APPFRAME_MODEMPROPS_MAXSIZE,-1)); modemProps->SetMaxSize(wxSize(APPFRAME_MODEMPROPS_MAXSIZE,-1)); - modemProps->Hide(); + ModemArgInfoList dummyInfo; + modemProps->initProperties(dummyInfo, nullptr); + modemProps->updateTheme(); + demodTray->Add(modemProps, 15, wxEXPAND | wxALL, 0); #ifndef __APPLE__ demodTray->AddSpacer(1); #endif - + +#if CUBICSDR_ENABLE_VIEW_DEMOD + wxBoxSizer *demodVisuals = new wxBoxSizer(wxVERTICAL); + wxGetApp().getDemodSpectrumProcessor()->setup(1024); demodSpectrumCanvas = new SpectrumCanvas(demodPanel, attribList); demodSpectrumCanvas->setView(wxGetApp().getConfig()->getCenterFreq(), 300000); @@ -147,7 +179,11 @@ AppFrame::AppFrame() : demodTray->Add(demodVisuals, 30, wxEXPAND | wxALL, 0); demodTray->AddSpacer(1); - +#else + demodSpectrumCanvas = nullptr; + demodWaterfallCanvas = nullptr; +#endif + demodSignalMeter = new MeterCanvas(demodPanel, attribList); demodSignalMeter->setMax(DEMOD_SIGNAL_MAX); demodSignalMeter->setMin(DEMOD_SIGNAL_MIN); @@ -160,6 +196,7 @@ AppFrame::AppFrame() : demodTray->AddSpacer(1); +#if CUBICSDR_ENABLE_VIEW_SCOPE scopeCanvas = new ScopeCanvas(demodPanel, attribList); scopeCanvas->setHelpTip("Audio Visuals, drag left/right to toggle Scope or Spectrum."); scopeCanvas->SetMinSize(wxSize(128,-1)); @@ -168,7 +205,10 @@ AppFrame::AppFrame() : wxGetApp().getScopeProcessor()->attachOutput(scopeCanvas->getInputQueue()); demodScopeTray->AddSpacer(1); - +#else + scopeCanvas = nullptr; +#endif + deltaLockButton = new ModeSelectorCanvas(demodPanel, attribList); deltaLockButton->addChoice(1, "V"); deltaLockButton->setPadding(-1,-1); @@ -245,6 +285,7 @@ AppFrame::AppFrame() : wxGetApp().getSpectrumProcessor()->setup(2048); spectrumCanvas = new SpectrumCanvas(spectrumPanel, attribList); spectrumCanvas->setShowDb(true); + spectrumCanvas->setUseDBOfs(true); spectrumCanvas->setScaleFactorEnabled(true); wxGetApp().getSpectrumProcessor()->attachOutput(spectrumCanvas->getVisualDataQueue()); @@ -649,6 +690,7 @@ void AppFrame::updateDeviceParams() { newSettingsMenu->AppendSeparator(); + newSettingsMenu->Append(wxID_SET_DB_OFFSET, "Power Level Offset"); newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset"); if (devInfo->hasCORR(SOAPY_SDR_RX, 0)) { @@ -864,6 +906,12 @@ void AppFrame::OnMenu(wxCommandEvent& event) { if (ofs != -1) { wxGetApp().setOffset(ofs); } + } else if (event.GetId() == wxID_SET_DB_OFFSET) { + long ofs = wxGetNumberFromUser("Shift the displayed RF power level by this amount.\ni.e. -30 for -30 dB", "Decibels (dB)", + "Power Level Offset", wxGetApp().getConfig()->getDBOffset(), -1000, 1000, this); + if (ofs != -1) { + wxGetApp().getConfig()->setDBOffset(ofs); + } } else if (event.GetId() == wxID_AGC_CONTROL) { if (wxGetApp().getDevice() == NULL) { agcMenuItem->Check(true); @@ -1209,8 +1257,10 @@ void AppFrame::OnMenu(wxCommandEvent& event) { void AppFrame::OnClose(wxCloseEvent& event) { wxGetApp().closeDeviceSelector(); - wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodSpectrumCanvas->getVisualDataQueue()); - wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodWaterfallCanvas->getVisualDataQueue()); + if (wxGetApp().getDemodSpectrumProcessor()) { + wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodSpectrumCanvas->getVisualDataQueue()); + wxGetApp().getDemodSpectrumProcessor()->removeOutput(demodWaterfallCanvas->getVisualDataQueue()); + } wxGetApp().getSpectrumProcessor()->removeOutput(spectrumCanvas->getVisualDataQueue()); wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize()); @@ -1281,7 +1331,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodGainMeter->setInputValue(demod->getGain()); wxGetApp().getDemodMgr().setLastGain(demod->getGain()); int outputDevice = demod->getOutputDevice(); - scopeCanvas->setDeviceName(outputDevices[outputDevice].name); + if (scopeCanvas) scopeCanvas->setDeviceName(outputDevices[outputDevice].name); // outputDeviceMenuItems[outputDevice]->Check(true); std::string dType = demod->getDemodulatorType(); demodModeSelector->setSelection(dType); @@ -1293,7 +1343,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { modemPropertiesUpdated.store(true); demodTuner->setHalfBand(dType=="USB" || dType=="LSB"); } - if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { + if (!demodWaterfallCanvas || demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { long long centerFreq = demod->getFrequency(); unsigned int demodBw = (unsigned int) ceil((float) demod->getBandwidth() * 2.25); @@ -1314,7 +1364,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodBw = 20000; } - if (centerFreq != demodWaterfallCanvas->getCenterFrequency()) { + if (demodWaterfallCanvas && centerFreq != demodWaterfallCanvas->getCenterFrequency()) { demodWaterfallCanvas->setCenterFrequency(centerFreq); demodSpectrumCanvas->setCenterFrequency(centerFreq); } @@ -1400,8 +1450,10 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } } - demodWaterfallCanvas->setBandwidth(demodBw); - demodSpectrumCanvas->setBandwidth(demodBw); + if (demodWaterfallCanvas) { + demodWaterfallCanvas->setBandwidth(demodBw); + demodSpectrumCanvas->setBandwidth(demodBw); + } } demodSignalMeter->setLevel(demod->getSignalLevel()); @@ -1457,9 +1509,9 @@ void AppFrame::OnIdle(wxIdleEvent& event) { demodGainMeter->setLevel(demodGainMeter->getInputValue()); } - if (wxGetApp().getFrequency() != demodWaterfallCanvas->getCenterFrequency()) { + if (demodWaterfallCanvas && wxGetApp().getFrequency() != demodWaterfallCanvas->getCenterFrequency()) { demodWaterfallCanvas->setCenterFrequency(wxGetApp().getFrequency()); - demodSpectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); + if (demodSpectrumCanvas) demodSpectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); } if (spectrumCanvas->getViewState() && abs(wxGetApp().getFrequency()-spectrumCanvas->getCenterFrequency()) > (wxGetApp().getSampleRate()/2)) { spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); @@ -1476,15 +1528,17 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } } - scopeCanvas->setPPMMode(demodTuner->isAltDown()); + if (scopeCanvas) { + scopeCanvas->setPPMMode(demodTuner->isAltDown()); + + scopeCanvas->setShowDb(spectrumCanvas->getShowDb()); + wxGetApp().getScopeProcessor()->setScopeEnabled(scopeCanvas->scopeVisible()); + wxGetApp().getScopeProcessor()->setSpectrumEnabled(scopeCanvas->spectrumVisible()); + wxGetApp().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0)); + + wxGetApp().getScopeProcessor()->run(); + } - scopeCanvas->setShowDb(spectrumCanvas->getShowDb()); - wxGetApp().getScopeProcessor()->setScopeEnabled(scopeCanvas->scopeVisible()); - wxGetApp().getScopeProcessor()->setSpectrumEnabled(scopeCanvas->spectrumVisible()); - wxGetApp().getAudioVisualQueue()->set_max_num_items((scopeCanvas->scopeVisible()?1:0) + (scopeCanvas->spectrumVisible()?1:0)); - - wxGetApp().getScopeProcessor()->run(); - SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor(); if (spectrumAvgMeter->inputChanged()) { @@ -1502,9 +1556,11 @@ void AppFrame::OnIdle(wxIdleEvent& event) { } SpectrumVisualProcessor *dproc = wxGetApp().getDemodSpectrumProcessor(); - - dproc->setView(demodWaterfallCanvas->getViewState(), demodWaterfallCanvas->getCenterFrequency(),demodWaterfallCanvas->getBandwidth()); + if (dproc) { + dproc->setView(demodWaterfallCanvas->getViewState(), demodWaterfallCanvas->getCenterFrequency(),demodWaterfallCanvas->getBandwidth()); + } + SpectrumVisualProcessor *wproc = waterfallDataThread->getProcessor(); if (waterfallSpeedMeter->inputChanged()) { @@ -1536,13 +1592,15 @@ void AppFrame::OnIdle(wxIdleEvent& event) { ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput(); if (!outp->getDialog()) { outp->setTitle(demod->getDemodulatorType() + ": " + frequencyToStr(demod->getFrequency())); - outp->setDialog(new DigitalConsole(this, outp)); + outp->setDialog(new DigitalConsole(this, outp)) ; } demod->showOutput(); } #endif - } else if (!demod) { - modemProps->Hide(); + } else if (!demod && modemPropertiesUpdated.load()) { + ModemArgInfoList dummyInfo; + modemProps->initProperties(dummyInfo, nullptr); + modemProps->updateTheme(); demodTray->Layout(); } @@ -1563,7 +1621,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { wxGetApp().getSpectrumProcessor()->setPeakHold(peakHoldMode == 1); //make the peak hold act on the current dmod also, like a zoomed-in version. - wxGetApp().getDemodSpectrumProcessor()->setPeakHold(peakHoldMode == 1); + if (wxGetApp().getDemodSpectrumProcessor()) wxGetApp().getDemodSpectrumProcessor()->setPeakHold(peakHoldMode == 1); peakHoldButton->clearModeChanged(); } @@ -1577,7 +1635,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { #endif #ifdef _WIN32 - if (scopeCanvas->HasFocus()) { + if (scopeCanvas && scopeCanvas->HasFocus()) { waterfallCanvas->SetFocus(); } #endif @@ -1942,7 +2000,7 @@ void AppFrame::setMainWaterfallFFTSize(int fftSize) { } void AppFrame::setScopeDeviceName(std::string deviceName) { - scopeCanvas->setDeviceName(deviceName); + if (scopeCanvas) scopeCanvas->setDeviceName(deviceName); } @@ -1954,7 +2012,7 @@ void AppFrame::refreshGainUI() { bool AppFrame::isUserDemodBusy() { return (modemProps && modemProps->isMouseInView()) || (waterfallCanvas->isMouseInView() && waterfallCanvas->isMouseDown()) - || (demodWaterfallCanvas->isMouseInView() && demodWaterfallCanvas->isMouseDown()) + || (demodWaterfallCanvas && demodWaterfallCanvas->isMouseInView() && demodWaterfallCanvas->isMouseDown()) || (wxGetApp().getDemodMgr().getLastActiveDemodulator() && wxGetApp().getDemodMgr().getActiveDemodulator() && wxGetApp().getDemodMgr().getLastActiveDemodulator() != wxGetApp().getDemodMgr().getActiveDemodulator()); @@ -2192,7 +2250,7 @@ int AppFrame::OnGlobalKeyUp(wxKeyEvent &event) { break; case 'P': wxGetApp().getSpectrumProcessor()->setPeakHold(!wxGetApp().getSpectrumProcessor()->getPeakHold()); - wxGetApp().getDemodSpectrumProcessor()->setPeakHold(wxGetApp().getSpectrumProcessor()->getPeakHold()); + if (wxGetApp().getDemodSpectrumProcessor()) wxGetApp().getDemodSpectrumProcessor()->setPeakHold(wxGetApp().getSpectrumProcessor()->getPeakHold()); peakHoldButton->setSelection(wxGetApp().getSpectrumProcessor()->getPeakHold()?1:0); peakHoldButton->clearModeChanged(); break; @@ -2243,3 +2301,31 @@ void AppFrame::setViewState(long long center_freq) { spectrumCanvas->disableView(); waterfallCanvas->disableView(); } + + +/* split a string by 'seperator' into a vector of string */ +std::vector str_explode(const std::string &seperator, const std::string &in_str) +{ + std::vector vect_out; + + int i = 0, j = 0; + int seperator_len = seperator.length(); + int str_len = in_str.length(); + + while(i < str_len) + { + j = in_str.find_first_of(seperator,i); + + if (j == std::string::npos && i < str_len) j = str_len; + + if (j == std::string::npos) break; + + vect_out.push_back(in_str.substr(i,j-i)); + + i = j; + + i+=seperator_len; + } + + return vect_out; +} diff --git a/src/AppFrame.h b/src/AppFrame.h index 4c2acee..5f36d72 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -32,6 +32,7 @@ #define wxID_AGC_CONTROL 2009 #define wxID_SDR_START_STOP 2010 #define wxID_LOW_PERF 2011 +#define wxID_SET_DB_OFFSET 2012 #define wxID_MAIN_SPLITTER 2050 #define wxID_VIS_SPLITTER 2051 diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 11195f9..19bd023 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -228,25 +228,16 @@ bool CubicSDR::OnInit() { // Visual Data spectrumVisualThread = new SpectrumVisualDataThread(); - demodVisualThread = new SpectrumVisualDataThread(); pipeIQVisualData = new DemodulatorThreadInputQueue(); pipeIQVisualData->set_max_num_items(1); - - pipeDemodIQVisualData = new DemodulatorThreadInputQueue(); - pipeDemodIQVisualData->set_max_num_items(1); pipeWaterfallIQVisualData = new DemodulatorThreadInputQueue(); pipeWaterfallIQVisualData->set_max_num_items(128); - getDemodSpectrumProcessor()->setInput(pipeDemodIQVisualData); getSpectrumProcessor()->setInput(pipeIQVisualData); getSpectrumProcessor()->setHideDC(true); - pipeAudioVisualData = new DemodulatorThreadOutputQueue(); - pipeAudioVisualData->set_max_num_items(1); - - scopeProcessor.setInput(pipeAudioVisualData); // I/Q Data pipeSDRIQData = new SDRThreadIQDataQueue(); @@ -260,12 +251,32 @@ bool CubicSDR::OnInit() { sdrPostThread->setOutputQueue("IQVisualDataOutput", pipeIQVisualData); sdrPostThread->setOutputQueue("IQDataOutput", pipeWaterfallIQVisualData); - sdrPostThread->setOutputQueue("IQActiveDemodVisualDataOutput", pipeDemodIQVisualData); t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread); t_SpectrumVisual = new std::thread(&SpectrumVisualDataThread::threadMain, spectrumVisualThread); + +#if CUBICSDR_ENABLE_VIEW_SCOPE + pipeAudioVisualData = new DemodulatorThreadOutputQueue(); + pipeAudioVisualData->set_max_num_items(1); + + scopeProcessor.setInput(pipeAudioVisualData); +#else + pipeAudioVisualData = nullptr; +#endif + +#if CUBICSDR_ENABLE_VIEW_DEMOD + demodVisualThread = new SpectrumVisualDataThread(); + pipeDemodIQVisualData = new DemodulatorThreadInputQueue(); + pipeDemodIQVisualData->set_max_num_items(1); + if (getDemodSpectrumProcessor()) getDemodSpectrumProcessor()->setInput(pipeDemodIQVisualData); + sdrPostThread->setOutputQueue("IQActiveDemodVisualDataOutput", pipeDemodIQVisualData); t_DemodVisual = new std::thread(&SpectrumVisualDataThread::threadMain, demodVisualThread); - +#else + demodVisualThread = nullptr; + pipeDemodIQVisualData = nullptr; + t_DemodVisual = nullptr; +#endif + sdrEnum = new SDREnumerator(); SDREnumerator::setManuals(config.getManualDevices()); @@ -313,16 +324,20 @@ int CubicSDR::OnExit() { std::cout << "Terminating Visual Processor threads.." << std::endl; spectrumVisualThread->terminate(); - demodVisualThread->terminate(); - + if (demodVisualThread) { + demodVisualThread->terminate(); + } + //Wait nicely sdrPostThread->isTerminated(1000); spectrumVisualThread->isTerminated(1000); - demodVisualThread->isTerminated(1000); + if (demodVisualThread) { + demodVisualThread->isTerminated(1000); + } //Then join the thread themselves t_PostSDR->join(); - t_DemodVisual->join(); + if (t_DemodVisual) t_DemodVisual->join(); t_SpectrumVisual->join(); //Now only we can delete @@ -491,7 +506,9 @@ void CubicSDR::setFrequency(long long freq) { getSpectrumProcessor()->setPeakHold(getSpectrumProcessor()->getPeakHold()); //make the peak hold act on the current dmod also, like a zoomed-in version. - getDemodSpectrumProcessor()->setPeakHold(getSpectrumProcessor()->getPeakHold()); + if (getDemodSpectrumProcessor()) { + getDemodSpectrumProcessor()->setPeakHold(getSpectrumProcessor()->getPeakHold()); + } } long long CubicSDR::getOffset() { @@ -652,7 +669,11 @@ SpectrumVisualProcessor *CubicSDR::getSpectrumProcessor() { } SpectrumVisualProcessor *CubicSDR::getDemodSpectrumProcessor() { - return demodVisualThread->getProcessor(); + if (demodVisualThread) { + return demodVisualThread->getProcessor(); + } else { + return nullptr; + } } DemodulatorThreadOutputQueue* CubicSDR::getAudioVisualQueue() { @@ -704,6 +725,7 @@ void CubicSDR::removeDemodulator(DemodulatorInstance *demod) { } demod->setActive(false); sdrPostThread->removeDemodulator(demod); + wxGetApp().getAppFrame()->notifyUpdateModemProperties(); } std::vector* CubicSDR::getDevices() { diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 07b28cb..c6fd209 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -93,6 +93,9 @@ public: void setOffset(long long ofs); long long getOffset(); + + void setDBOffset(int ofs); + int getDBOffset(); void setSampleRate(long long rate_in); long long getSampleRate(); diff --git a/src/CubicSDRDefs.h b/src/CubicSDRDefs.h index 210126c..c0505a3 100644 --- a/src/CubicSDRDefs.h +++ b/src/CubicSDRDefs.h @@ -1,6 +1,6 @@ #pragma once -#define CUBICSDR_TITLE "CubicSDR v" CUBICSDR_VERSION " by Charles J. Cliffe (@ccliffe) :: www.cubicsdr.com" +#define CUBICSDR_TITLE "" CUBICSDR_BUILD_TITLE #ifndef __BYTE_ORDER #ifdef _WIN32 diff --git a/src/ModemProperties.cpp b/src/ModemProperties.cpp index be3e6ba..fc58a8d 100644 --- a/src/ModemProperties.cpp +++ b/src/ModemProperties.cpp @@ -122,10 +122,8 @@ void ModemProperties::initProperties(ModemArgInfoList newArgs, DemodulatorInstan m_propertyGrid->Clear(); if (!demodInstance) { - Hide(); + m_propertyGrid->Append(new wxPropertyCategory("Modem Settings")); return; - } else { - Show(); } m_propertyGrid->Append(new wxPropertyCategory(demodInstance->getDemodulatorType() + " Settings")); diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 60dfcd3..b6ba22f 100644 --- a/src/panel/SpectrumPanel.cpp +++ b/src/panel/SpectrumPanel.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "CubicSDR.h" #include "ColorTheme.h" #include "CubicSDRDefs.h" @@ -10,6 +11,7 @@ SpectrumPanel::SpectrumPanel() { floorValue = 0; ceilValue = 1; showDb = false; + useDbOfs = false; fftSize = DEFAULT_FFT_SIZE; bandwidth = DEFAULT_DEMOD_BW; freq = 0; @@ -83,6 +85,14 @@ bool SpectrumPanel::getShowDb() { return showDb; } +void SpectrumPanel::setUseDBOffset(bool useOfs) { + this->useDbOfs = useOfs; +} + +bool SpectrumPanel::getUseDBOffset() { + return useDbOfs; +} + void SpectrumPanel::setPoints(std::vector &points) { this->points.assign(points.begin(), points.end()); @@ -269,11 +279,11 @@ void SpectrumPanel::drawPanelContents() { if (showDb) { float dbPanelWidth = (1.0 / viewWidth)*88.0 * GLFont::getScaleFactor(); float dbPanelHeight = (1.0/viewHeight)*14.0 * GLFont::getScaleFactor(); - + float dbOfs = useDbOfs?wxGetApp().getConfig()->getDBOffset():0; std::stringstream ssLabel(""); if (getCeilValue() != getFloorValue() && fftSize) { - ssLabel << std::fixed << std::setprecision(1) << (20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB"; + ssLabel << std::fixed << std::setprecision(1) << (dbOfs + 20.0 * log10(2.0*(getCeilValue())/(double)fftSize)) << "dB"; } dbPanelCeil.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT); dbPanelCeil.setSize(dbPanelWidth, dbPanelHeight); @@ -282,7 +292,7 @@ void SpectrumPanel::drawPanelContents() { ssLabel.str(""); if (getCeilValue() != getFloorValue() && fftSize) { - ssLabel << (20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB"; + ssLabel << (dbOfs + 20.0 * log10(2.0*(getFloorValue())/(double)fftSize)) << "dB"; } dbPanelFloor.setText(ssLabel.str(), GLFont::GLFONT_ALIGN_RIGHT); diff --git a/src/panel/SpectrumPanel.h b/src/panel/SpectrumPanel.h index 39aa3fe..ea45588 100644 --- a/src/panel/SpectrumPanel.h +++ b/src/panel/SpectrumPanel.h @@ -26,7 +26,10 @@ public: void setShowDb(bool showDb); bool getShowDb(); - + + void setUseDBOffset(bool useOfs); + bool getUseDBOffset(); + protected: void drawPanelContents(); @@ -40,5 +43,5 @@ private: GLTextPanel dbPanelCeil; GLTextPanel dbPanelFloor; - bool showDb; -}; \ No newline at end of file + bool showDb, useDbOfs; +}; diff --git a/src/visual/SpectrumCanvas.cpp b/src/visual/SpectrumCanvas.cpp index 8a31c85..fcb8399 100644 --- a/src/visual/SpectrumCanvas.cpp +++ b/src/visual/SpectrumCanvas.cpp @@ -174,6 +174,14 @@ bool SpectrumCanvas::getShowDb() { return spectrumPanel.getShowDb(); } +void SpectrumCanvas::setUseDBOfs(bool showDb) { + spectrumPanel.setUseDBOffset(showDb); +} + +bool SpectrumCanvas::getUseDBOfs() { + return spectrumPanel.getUseDBOffset(); +} + void SpectrumCanvas::setView(long long center_freq_in, int bandwidth_in) { bwChange += bandwidth_in-bandwidth; #define BW_RESET_TH 400000 @@ -293,7 +301,9 @@ void SpectrumCanvas::OnMouseRightReleased(wxMouseEvent& event) { wxGetApp().getSpectrumProcessor()->setPeakHold(wxGetApp().getSpectrumProcessor()->getPeakHold()); //make the peak hold act on the current dmod also, like a zoomed-in version. - wxGetApp().getDemodSpectrumProcessor()->setPeakHold(wxGetApp().getSpectrumProcessor()->getPeakHold()); + if (wxGetApp().getDemodSpectrumProcessor()) { + wxGetApp().getDemodSpectrumProcessor()->setPeakHold(wxGetApp().getSpectrumProcessor()->getPeakHold()); + } } mouseTracker.OnMouseRightReleased(event); } diff --git a/src/visual/SpectrumCanvas.h b/src/visual/SpectrumCanvas.h index 85af252..2b47e14 100644 --- a/src/visual/SpectrumCanvas.h +++ b/src/visual/SpectrumCanvas.h @@ -22,6 +22,9 @@ public: void setShowDb(bool showDb); bool getShowDb(); + void setUseDBOfs(bool showDb); + bool getUseDBOfs(); + void setView(long long center_freq_in, int bandwidth_in); void disableView();