/* Copyright 2018 Michal Fratczak This file is part of habdec. habdec is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. habdec is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with habdec. If not, see . */ #include "program_options.h" #include #include #include #include #include #include #include "IQSource/IQSource_SoapySDR.h" #include "Decoder/Decoder.h" #include "common/console_colors.h" #include "GLOBALS.h" #include "server.h" bool G_DO_EXIT = false; using namespace std; void PrintDevicesList(const SoapySDR::KwargsList& device_list) { int DEV_NUM = 0; cout< sampling_rates = p_device->listSampleRates(SOAPY_SDR_RX, 0); sort(sampling_rates.begin(), sampling_rates.end()); cout<<"\tSampling Rates:"<= int(device_list.size()) ) { cout<setOption("SoapySDR_Kwargs", &device); if( !GLOBALS::get().p_iq_source_->init() ) { cout<setOption("frequency_double", &freq); double gain = GLOBALS::get().gain_; GLOBALS::get().p_iq_source_->setOption("gain_double", &gain); double biastee = GLOBALS::get().biast_; GLOBALS::get().p_iq_source_->setOption("biastee_double", &biastee); GLOBALS::get().p_iq_source_->setOption("sampling_rate_double", &GLOBALS::get().sampling_rate_); return true; } void DECODER_FEED_THREAD() { using namespace std; cout<<"Start DECODER_FEED_THREAD"<start()) { cout<isRunning()) { cout< samples; samples.resize(256*256); samples.samplingRate( p_iq_src->samplingRate() ); while(!G_DO_EXIT) { auto _start = std::chrono::high_resolution_clock::now(); size_t count = p_iq_src->get( samples.data(), samples.size() ); DECODER.pushSamples(samples); DECODER(); // DECODE ! // AFC - don't do this too often. Too unstable, needs more work. static auto last_afc_time = std::chrono::high_resolution_clock::now(); if( std::chrono::duration_cast< std::chrono::seconds > (std::chrono::high_resolution_clock::now() - last_afc_time).count() > 5 ) { double freq_corr = DECODER.getFrequencyCorrection(); if(GLOBALS::get().afc_) { if( 100 < abs(freq_corr) ) { GLOBALS::get().frequency_ += freq_corr; double f = GLOBALS::get().frequency_; p_iq_src->setOption("frequency_double", &f); DECODER.resetFrequencyCorrection(freq_corr); last_afc_time = std::chrono::high_resolution_clock::now(); // notify webgui { lock_guard _lock( GLOBALS::get().out_commands_mtx_ ); GLOBALS::get().out_commands_.emplace_back("cmd::set:frequency=" + to_string(f / 1e6)); } } } } TDur _duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - _start); // accumulate demod samples to display more { std::lock_guard _lock(GLOBALS::get().demod_accumulated_mtx_); const size_t max_sz = DECODER.getDecimatedSamplingRate() / DECODER.getSymbolRate() * 50; // 50 symbols auto demod = DECODER.getDemodulated(); auto& demod_acc = GLOBALS::get().demod_accumulated_; demod_acc.insert( demod_acc.end(), demod.cbegin(), demod.cend() ); // remove leading values if( demod_acc.size() > max_sz) demod_acc.erase( demod_acc.begin(), demod_acc.begin() + demod_acc.size() - max_sz ); } } } void HAB_UPLOAD_THREAD() { using namespace std; while(!G_DO_EXIT) { this_thread::sleep_for( chrono::duration(500) ); vector sentences; { lock_guard _lock( GLOBALS::get().senteces_to_log_mtx_ ); sentences = move( GLOBALS::get().senteces_to_log_ ); } if(GLOBALS::get().station_callsign_ != "") { for(auto& sentence : sentences) { string cmd = "python ./habLogger.py "; cmd += sentence; cmd += " "; cmd += GLOBALS::get().station_callsign_; auto res = system(cmd.c_str()); cout<<"HAB upload res: "< { char do_thousands_sep() const { return ','; } string do_grouping() const { return "\3"; } }; try{ std::cout.imbue( std::locale(locale(""), new thousand_separators) ); } catch(exception& e) { } // setup GLOBALS prog_opts(argc, argv); // setup SoapySDR device if(!SetupDevice()) { cout< _lock( GLOBALS::get().senteces_to_log_mtx_ ); GLOBALS::get().senteces_to_log_.emplace_back( callsign + "," + data + "*" + crc ); } { lock_guard _lock( GLOBALS::get().senteces_to_web_mtx_ ); GLOBALS::get().senteces_to_web_.emplace_back( callsign + "," + data + "*" + crc ); } GLOBALS::DumpToFile("./habdecWebsocketServer.opts"); }; // feed decoder with IQ samples std::thread* decoder_feed_thread = new std::thread(DECODER_FEED_THREAD); // HAB upload std::thread* hab_upload_thread = new std::thread(HAB_UPLOAD_THREAD); // websocket server thread. this call is blocking RunCommandServer( GLOBALS::get().command_host_ , GLOBALS::get().command_port_ ); G_DO_EXIT = true; decoder_feed_thread->join(); hab_upload_thread->join(); return 0; }