From a958912da675b064ec720df859de6af8ef8bd026 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Wed, 30 Jan 2019 23:24:33 -0500 Subject: [PATCH] Move Session stuff to SessionMgr --- CMakeLists.txt | 2 + src/AppFrame.cpp | 226 +++++++-------------------------------------- src/AppFrame.h | 2 + src/CubicSDR.cpp | 8 +- src/CubicSDR.h | 3 + src/SessionMgr.cpp | 195 ++++++++++++++++++++++++++++++++++++++ src/SessionMgr.h | 14 +++ 7 files changed, 253 insertions(+), 197 deletions(-) create mode 100644 src/SessionMgr.cpp create mode 100644 src/SessionMgr.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b297ee3..b8b4f65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,7 @@ SET (cubicsdr_sources src/IOThread.cpp src/ModemProperties.cpp src/BookmarkMgr.cpp + src/SessionMgr.cpp src/sdr/SDRDeviceInfo.cpp src/sdr/SDRPostThread.cpp src/sdr/SDREnumerator.cpp @@ -433,6 +434,7 @@ SET (cubicsdr_headers src/IOThread.h src/ModemProperties.h src/BookmarkMgr.h + src/SessionMgr.h src/sdr/SDRDeviceInfo.h src/sdr/SDRPostThread.h src/sdr/SDREnumerator.h diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 29b3110..315f749 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -2500,42 +2500,7 @@ void AppFrame::OnAboutDialogClose(wxCommandEvent& /* event */) { } void AppFrame::saveSession(std::string fileName) { - - DataTree s("cubicsdr_session"); - DataNode *header = s.rootNode()->newChild("header"); - //save as wstring to prevent problems - header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring()); - - *header->newChild("center_freq") = wxGetApp().getFrequency(); - *header->newChild("sample_rate") = wxGetApp().getSampleRate(); - *header->newChild("solo_mode") = wxGetApp().getSoloMode()?1:0; - - if (waterfallCanvas->getViewState()) { - DataNode *viewState = header->newChild("view_state"); - - *viewState->newChild("center_freq") = waterfallCanvas->getCenterFrequency(); - *viewState->newChild("bandwidth") = waterfallCanvas->getBandwidth(); - } - - DataNode *demods = s.rootNode()->newChild("demodulators"); - - //make a local copy snapshot of the list - std::vector instances = wxGetApp().getDemodMgr().getDemodulators(); - - for (auto instance : instances) { - DataNode *demod = demods->newChild("demodulator"); - wxGetApp().getDemodMgr().saveInstance(demod, instance); - } //end for demodulators - - // Make sure the file name actually ends in .xml - std::string lcFileName = fileName; - std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower); - - if (lcFileName.find_last_of(".xml") != lcFileName.length()-1) { - fileName.append(".xml"); - } - - s.SaveToFileXML(fileName); + wxGetApp().getSessionMgr().saveSession(fileName); currentSessionFile = fileName; std::string filePart = fileName.substr(fileName.find_last_of(filePathSeparator) + 1); @@ -2544,167 +2509,31 @@ void AppFrame::saveSession(std::string fileName) { } bool AppFrame::loadSession(std::string fileName) { + bool result = wxGetApp().getSessionMgr().loadSession(fileName); - DataTree l; - if (!l.LoadFromFileXML(fileName)) { - return false; + int sample_rate = wxGetApp().getSampleRate(); + + //scan the available sample rates and see if it matches a predifined one + int menuIndex = -1; + for (auto discreteRate : sampleRates) { + if (discreteRate == sample_rate) { + menuIndex++; + //activate Bandwidth Menu entry matching this predefined sample_rate. + sampleRateMenuItems[wxID_BANDWIDTH_BASE + menuIndex]->Check(true); + break; + } + } //end for + //this is a manual entry + if (menuIndex == -1) { + manualSampleRate = sample_rate; + sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(true); + // Apply the manual value, activate the menu entry + + sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->SetItemLabel(wxString("Manual Entry : ") + frequencyToStr(sample_rate)); + sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Check(true); } - //Check if it is a session file, read the root node. - if (l.rootNode()->getName() != "cubicsdr_session") { - return false; - } - - wxGetApp().getDemodMgr().setActiveDemodulator(nullptr, false); - - wxGetApp().getDemodMgr().terminateAll(); - - try { - if (!l.rootNode()->hasAnother("header")) { - return false; - } - DataNode *header = l.rootNode()->getNext("header"); - - if (header->hasAnother("version")) { - //"Force" the retreiving of the value as string, even if its look like a number internally ! (ex: "0.2.0") - DataNode *versionNode = header->getNext("version"); - std::wstring version; - try { - versionNode->element()->get(version); - - std::cout << "Loading session file version: '" << version << "'..." << std::endl; - } - catch (DataTypeMismatchException e) { - //this is for managing the old session format NOT encoded as std:wstring, - //force current version - std::cout << "Warning while Loading session file version, probably old format :'" << e.what() << "' please consider re-saving the current session..." << std::endl << std::flush; - version = wxString(CUBICSDR_VERSION).ToStdWstring(); - } - } - - if (header->hasAnother("sample_rate")) { - - long sample_rate = *header->getNext("sample_rate"); - - SDRDeviceInfo *dev = wxGetApp().getSDRThread()->getDevice(); - if (dev) { - //retreive the available sample rates. A valid previously chosen manual - //value is constrained within these limits. If it doesn't behave, lets the device choose - //for us. - long minRate = MANUAL_SAMPLE_RATE_MIN; - long maxRate = MANUAL_SAMPLE_RATE_MAX; - - std::vector sampleRates = dev->getSampleRates(SOAPY_SDR_RX, 0); - - if (sampleRates.size()) { - minRate = sampleRates.front(); - maxRate = sampleRates.back(); - } - - //If it is beyond limits, make device choose a reasonable value - if (sample_rate < minRate || sample_rate > maxRate) { - sample_rate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sample_rate); - } - - //scan the available sample rates and see if it matches a predifined one - int menuIndex = -1; - for (auto discreteRate : sampleRates) { - if (discreteRate == sample_rate) { - menuIndex++; - //activate Bandwidth Menu entry matching this predefined sample_rate. - sampleRateMenuItems[wxID_BANDWIDTH_BASE + menuIndex]->Check(true); - break; - } - } //end for - //this is a manual entry - if (menuIndex == -1) { - manualSampleRate = sample_rate; - sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(true); - // Apply the manual value, activate the menu entry - - sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->SetItemLabel(wxString("Manual Entry : ") + frequencyToStr(sample_rate)); - sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Check(true); - } - //update applied value - wxGetApp().setSampleRate(sample_rate); - deviceChanged.store(true); - } else { - wxGetApp().setSampleRate(sample_rate); - } - } - - if (header->hasAnother("solo_mode")) { - - int solo_mode_activated = *header->getNext("solo_mode"); - - wxGetApp().setSoloMode((solo_mode_activated > 0) ? true : false); - } - else { - wxGetApp().setSoloMode(false); - } - - DemodulatorInstancePtr loadedActiveDemod = nullptr; - DemodulatorInstancePtr newDemod = nullptr; - - if (l.rootNode()->hasAnother("demodulators")) { - - DataNode *demodulators = l.rootNode()->getNext("demodulators"); - - std::vector demodsLoaded; - - while (demodulators->hasAnother("demodulator")) { - DataNode *demod = demodulators->getNext("demodulator"); - - if (!demod->hasAnother("bandwidth") || !demod->hasAnother("frequency")) { - continue; - } - - newDemod = wxGetApp().getDemodMgr().loadInstance(demod); - - if (demod->hasAnother("active")) { - loadedActiveDemod = newDemod; - } - - newDemod->run(); - newDemod->setActive(true); - demodsLoaded.push_back(newDemod); - } - - if (demodsLoaded.size()) { - wxGetApp().notifyDemodulatorsChanged(); - } - - } // if l.rootNode()->hasAnother("demodulators") - - if (header->hasAnother("center_freq")) { - long long center_freq = *header->getNext("center_freq"); - wxGetApp().setFrequency(center_freq); - // std::cout << "\tCenter Frequency: " << center_freq << std::endl; - } - - if (header->hasAnother("view_state")) { - DataNode *viewState = header->getNext("view_state"); - - if (viewState->hasAnother("center_freq") && viewState->hasAnother("bandwidth")) { - long long center_freq = *viewState->getNext("center_freq"); - int bandwidth = *viewState->getNext("bandwidth"); - spectrumCanvas->setView(center_freq, bandwidth); - waterfallCanvas->setView(center_freq, bandwidth); - } - } else { - spectrumCanvas->disableView(); - waterfallCanvas->disableView(); - spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); - waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency()); - } - - if (loadedActiveDemod || newDemod) { - wxGetApp().getDemodMgr().setActiveDemodulator(loadedActiveDemod?loadedActiveDemod:newDemod, false); - } - } catch (DataTypeMismatchException e) { - std::cout << e.what() << std::endl; - return false; - } + deviceChanged.store(true); currentSessionFile = fileName; @@ -2715,13 +2544,20 @@ bool AppFrame::loadSession(std::string fileName) { wxGetApp().getBookmarkMgr().updateActiveList(); - return true; + return result; } FFTVisualDataThread *AppFrame::getWaterfallDataThread() { return waterfallDataThread; } +WaterfallCanvas *AppFrame::getWaterfallCanvas() { + return waterfallCanvas; +} + +SpectrumCanvas *AppFrame::getSpectrumCanvas() { + return spectrumCanvas; +} void AppFrame::notifyUpdateModemProperties() { modemPropertiesUpdated.store(true); diff --git a/src/AppFrame.h b/src/AppFrame.h index 867e96e..ed2afa7 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -122,6 +122,8 @@ public: bool loadSession(std::string fileName); FFTVisualDataThread *getWaterfallDataThread(); + WaterfallCanvas *getWaterfallCanvas(); + SpectrumCanvas *getSpectrumCanvas(); void notifyUpdateModemProperties(); void setMainWaterfallFFTSize(int fftSize); diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 4c98b7e..8aba34e 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -864,12 +864,16 @@ DemodulatorThreadInputQueuePtr CubicSDR::getWaterfallVisualQueue() { return pipeWaterfallIQVisualData; } +BookmarkMgr &CubicSDR::getBookmarkMgr() { + return bookmarkMgr; +} + DemodulatorMgr &CubicSDR::getDemodMgr() { return demodMgr; } -BookmarkMgr &CubicSDR::getBookmarkMgr() { - return bookmarkMgr; +SessionMgr &CubicSDR::getSessionMgr() { + return sessionMgr; } SDRPostThread *CubicSDR::getSDRPostThread() { diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 93f6d36..b3102e6 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -23,6 +23,7 @@ #include "FrequencyDialog.h" #include "DemodLabelDialog.h" #include "BookmarkMgr.h" +#include "SessionMgr.h" #include "ScopeVisualProcessor.h" #include "SpectrumVisualProcessor.h" @@ -119,6 +120,7 @@ public: DemodulatorMgr &getDemodMgr(); BookmarkMgr &getBookmarkMgr(); + SessionMgr &getSessionMgr(); SDRPostThread *getSDRPostThread(); SDRThread *getSDRThread(); @@ -194,6 +196,7 @@ private: DemodulatorMgr demodMgr; BookmarkMgr bookmarkMgr; + SessionMgr sessionMgr; std::atomic_llong frequency; std::atomic_llong offset; diff --git a/src/SessionMgr.cpp b/src/SessionMgr.cpp new file mode 100644 index 0000000..517cccf --- /dev/null +++ b/src/SessionMgr.cpp @@ -0,0 +1,195 @@ +// Copyright (c) Charles J. Cliffe +// SPDX-License-Identifier: GPL-2.0+ + +#include "SessionMgr.h" +#include "CubicSDR.h" + +void SessionMgr::saveSession(std::string fileName) { + + DataTree s("cubicsdr_session"); + DataNode *header = s.rootNode()->newChild("header"); + //save as wstring to prevent problems + header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring()); + + *header->newChild("center_freq") = wxGetApp().getFrequency(); + *header->newChild("sample_rate") = wxGetApp().getSampleRate(); + *header->newChild("solo_mode") = wxGetApp().getSoloMode()?1:0; + + WaterfallCanvas *waterfallCanvas = wxGetApp().getAppFrame()->getWaterfallCanvas(); + + if (waterfallCanvas->getViewState()) { + DataNode *viewState = header->newChild("view_state"); + + *viewState->newChild("center_freq") = waterfallCanvas->getCenterFrequency(); + *viewState->newChild("bandwidth") = waterfallCanvas->getBandwidth(); + } + + DataNode *demods = s.rootNode()->newChild("demodulators"); + + //make a local copy snapshot of the list + std::vector instances = wxGetApp().getDemodMgr().getDemodulators(); + + for (const auto &instance : instances) { + DataNode *demod = demods->newChild("demodulator"); + wxGetApp().getDemodMgr().saveInstance(demod, instance); + } //end for demodulators + + // Make sure the file name actually ends in .xml + std::string lcFileName = fileName; + std::transform(lcFileName.begin(), lcFileName.end(), lcFileName.begin(), ::tolower); + + if (lcFileName.find_last_of(".xml") != lcFileName.length()-1) { + fileName.append(".xml"); + } + + s.SaveToFileXML(fileName); +} + +bool SessionMgr::loadSession(std::string fileName) { + + DataTree l; + if (!l.LoadFromFileXML(fileName)) { + return false; + } + + //Check if it is a session file, read the root node. + if (l.rootNode()->getName() != "cubicsdr_session") { + return false; + } + + wxGetApp().getDemodMgr().setActiveDemodulator(nullptr, false); + wxGetApp().getDemodMgr().terminateAll(); + + WaterfallCanvas *waterfallCanvas = wxGetApp().getAppFrame()->getWaterfallCanvas(); + SpectrumCanvas *spectrumCanvas = wxGetApp().getAppFrame()->getSpectrumCanvas(); + + try { + if (!l.rootNode()->hasAnother("header")) { + return false; + } + DataNode *header = l.rootNode()->getNext("header"); + + if (header->hasAnother("version")) { + //"Force" the retreiving of the value as string, even if its look like a number internally ! (ex: "0.2.0") + DataNode *versionNode = header->getNext("version"); + std::wstring version; + try { + versionNode->element()->get(version); + + std::cout << "Loading session file version: '" << version << "'..." << std::endl; + } + catch (DataTypeMismatchException &e) { + //this is for managing the old session format NOT encoded as std:wstring, + //force current version + std::cout << "Warning while Loading session file version, probably old format :'" << e.what() << "' please consider re-saving the current session..." << std::endl << std::flush; + version = wxString(CUBICSDR_VERSION).ToStdWstring(); + } + } + + if (header->hasAnother("sample_rate")) { + + long sample_rate = *header->getNext("sample_rate"); + + SDRDeviceInfo *dev = wxGetApp().getSDRThread()->getDevice(); + if (dev) { + //retreive the available sample rates. A valid previously chosen manual + //value is constrained within these limits. If it doesn't behave, lets the device choose + //for us. + long minRate = MANUAL_SAMPLE_RATE_MIN; + long maxRate = MANUAL_SAMPLE_RATE_MAX; + + std::vector sampleRates = dev->getSampleRates(SOAPY_SDR_RX, 0); + + if (!sampleRates.empty()) { + minRate = sampleRates.front(); + maxRate = sampleRates.back(); + } + + //If it is beyond limits, make device choose a reasonable value + if (sample_rate < minRate || sample_rate > maxRate) { + sample_rate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sample_rate); + } + + + //update applied value + wxGetApp().setSampleRate(sample_rate); + } else { + wxGetApp().setSampleRate(sample_rate); + } + } + + if (header->hasAnother("solo_mode")) { + + int solo_mode_activated = *header->getNext("solo_mode"); + + wxGetApp().setSoloMode(solo_mode_activated > 0); + } + else { + wxGetApp().setSoloMode(false); + } + + DemodulatorInstancePtr loadedActiveDemod = nullptr; + DemodulatorInstancePtr newDemod = nullptr; + + if (l.rootNode()->hasAnother("demodulators")) { + + DataNode *demodulators = l.rootNode()->getNext("demodulators"); + + std::vector demodsLoaded; + + while (demodulators->hasAnother("demodulator")) { + DataNode *demod = demodulators->getNext("demodulator"); + + if (!demod->hasAnother("bandwidth") || !demod->hasAnother("frequency")) { + continue; + } + + newDemod = wxGetApp().getDemodMgr().loadInstance(demod); + + if (demod->hasAnother("active")) { + loadedActiveDemod = newDemod; + } + + newDemod->run(); + newDemod->setActive(true); + demodsLoaded.push_back(newDemod); + } + + if (!demodsLoaded.empty()) { + wxGetApp().notifyDemodulatorsChanged(); + } + + } // if l.rootNode()->hasAnother("demodulators") + + if (header->hasAnother("center_freq")) { + long long center_freq = *header->getNext("center_freq"); + wxGetApp().setFrequency(center_freq); + // std::cout << "\tCenter Frequency: " << center_freq << std::endl; + } + + if (header->hasAnother("view_state")) { + DataNode *viewState = header->getNext("view_state"); + + if (viewState->hasAnother("center_freq") && viewState->hasAnother("bandwidth")) { + long long center_freq = *viewState->getNext("center_freq"); + int bandwidth = *viewState->getNext("bandwidth"); + spectrumCanvas->setView(center_freq, bandwidth); + waterfallCanvas->setView(center_freq, bandwidth); + } + } else { + spectrumCanvas->disableView(); + waterfallCanvas->disableView(); + spectrumCanvas->setCenterFrequency(wxGetApp().getFrequency()); + waterfallCanvas->setCenterFrequency(wxGetApp().getFrequency()); + } + + if (loadedActiveDemod || newDemod) { + wxGetApp().getDemodMgr().setActiveDemodulator(loadedActiveDemod?loadedActiveDemod:newDemod, false); + } + } catch (DataTypeMismatchException &e) { + std::cout << e.what() << std::endl; + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/SessionMgr.h b/src/SessionMgr.h new file mode 100644 index 0000000..87e7a9b --- /dev/null +++ b/src/SessionMgr.h @@ -0,0 +1,14 @@ +// Copyright (c) Charles J. Cliffe +// SPDX-License-Identifier: GPL-2.0+ + +#pragma once + +#include "DataTree.h" +#include "AppFrame.h" + + +class SessionMgr { +public: + void saveSession(std::string fileName); + bool loadSession(std::string fileName); +};