/*
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;
}