2021-07-19 15:07:12 +02:00
|
|
|
#include "logger.h"
|
|
|
|
|
#include "module.h"
|
|
|
|
|
#include "pipeline.h"
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include "nlohmann/json.hpp"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include "sdr/sdr.h"
|
|
|
|
|
#include "init.h"
|
|
|
|
|
#include "live_pipeline.h"
|
|
|
|
|
#include <volk/volk_alloc.hh>
|
2021-07-19 15:11:37 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#endif
|
2021-07-21 00:54:48 +02:00
|
|
|
#include <nng/nng.h>
|
|
|
|
|
#include <nng/supplemental/http/http.h>
|
|
|
|
|
#include <nng/supplemental/util/platform.h>
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<LivePipeline> live_pipeline;
|
|
|
|
|
|
2021-08-02 22:51:12 +02:00
|
|
|
bool should_stop = false;
|
|
|
|
|
|
2021-08-02 23:05:54 +02:00
|
|
|
#ifndef _WIN32
|
2021-08-02 22:51:12 +02:00
|
|
|
// SIGINT Handler
|
2021-08-04 15:24:05 +02:00
|
|
|
void sigint_handler(int /*s*/)
|
2021-08-02 22:51:12 +02:00
|
|
|
{
|
|
|
|
|
should_stop = true;
|
|
|
|
|
}
|
2021-08-02 23:05:54 +02:00
|
|
|
#endif
|
2021-08-02 22:51:12 +02:00
|
|
|
|
2021-07-21 00:54:48 +02:00
|
|
|
// HTTP Handler for stats
|
|
|
|
|
void http_handle(nng_aio *aio)
|
|
|
|
|
{
|
2021-07-21 11:02:25 +02:00
|
|
|
std::string jsonstr = live_pipeline->getModulesStats().dump(4);
|
2021-07-21 00:54:48 +02:00
|
|
|
|
|
|
|
|
nng_http_res *res;
|
|
|
|
|
nng_http_res_alloc(&res);
|
2021-07-21 11:02:25 +02:00
|
|
|
nng_http_res_copy_data(res, jsonstr.c_str(), jsonstr.size());
|
2021-07-21 00:54:48 +02:00
|
|
|
nng_aio_set_output(aio, 0, res);
|
|
|
|
|
nng_aio_finish(aio, 0);
|
|
|
|
|
}
|
2021-07-19 15:07:12 +02:00
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
if (argc < 2)
|
|
|
|
|
{
|
|
|
|
|
printf("Usage : %s ingestor_config.json\n", argv[0]);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 13:14:12 +02:00
|
|
|
std::string ingestor_cfg_path = argv[1];
|
|
|
|
|
|
2021-07-19 15:07:12 +02:00
|
|
|
// SatDump init
|
|
|
|
|
initLogger();
|
|
|
|
|
initSatdump();
|
|
|
|
|
|
2021-08-02 23:05:54 +02:00
|
|
|
#ifndef _WIN32
|
2021-08-02 22:51:12 +02:00
|
|
|
// Setup SIGINT handler
|
|
|
|
|
struct sigaction siginthandler;
|
|
|
|
|
siginthandler.sa_handler = sigint_handler;
|
|
|
|
|
sigemptyset(&siginthandler.sa_mask);
|
|
|
|
|
siginthandler.sa_flags = 0;
|
|
|
|
|
sigaction(SIGINT, &siginthandler, NULL);
|
2021-08-02 23:05:54 +02:00
|
|
|
#endif
|
2021-08-02 22:51:12 +02:00
|
|
|
|
2021-07-19 15:07:12 +02:00
|
|
|
logger->warn("Keep in mind this ingestor is still WIP! Features such as SDR selection are lacking and coming shortly.");
|
|
|
|
|
|
|
|
|
|
// Init thread pool
|
|
|
|
|
ctpl::thread_pool processThreadPool(8);
|
|
|
|
|
|
|
|
|
|
// Init SDR Devices
|
|
|
|
|
initSDRs();
|
|
|
|
|
std::vector<std::tuple<std::string, sdr_device_type, uint64_t>> devices = getAllDevices();
|
|
|
|
|
for (std::tuple<std::string, sdr_device_type, uint64_t> dev : devices)
|
|
|
|
|
logger->info(std::get<0>(dev));
|
|
|
|
|
|
|
|
|
|
// Settings we're gonna be using
|
2021-08-06 13:14:12 +02:00
|
|
|
if (!std::filesystem::exists(ingestor_cfg_path))
|
2021-07-19 15:07:12 +02:00
|
|
|
{
|
2021-08-06 13:14:12 +02:00
|
|
|
logger->error("Could not find config file " + ingestor_cfg_path + "!");
|
2021-07-19 15:07:12 +02:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
nlohmann::json ingestor_cfg;
|
|
|
|
|
{
|
2021-08-06 13:14:12 +02:00
|
|
|
std::ifstream istream(ingestor_cfg_path);
|
2021-07-19 15:07:12 +02:00
|
|
|
istream >> ingestor_cfg;
|
|
|
|
|
istream.close();
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-13 12:00:18 +02:00
|
|
|
sdr_device_type sdr_type = ingestor_cfg.count("sdr_type") > 0 ? getDeviceIDbyIDString(ingestor_cfg["sdr_type"].get<std::string>()) : NONE;
|
2021-07-19 15:07:12 +02:00
|
|
|
float samplerate = std::stoi(ingestor_cfg["samplerate"].get<std::string>());
|
|
|
|
|
float frequency = std::stof(ingestor_cfg["frequency"].get<std::string>());
|
|
|
|
|
std::map<std::string, std::string> device_parameters = ingestor_cfg["sdr_settings"].get<std::map<std::string, std::string>>();
|
|
|
|
|
std::string downlink_pipeline = ingestor_cfg["pipeline"].get<std::string>();
|
|
|
|
|
std::string output_folder = ingestor_cfg["output_folder"].get<std::string>();
|
2021-07-21 00:54:48 +02:00
|
|
|
std::string http_server_url = "http://" + ingestor_cfg["http_server"].get<std::string>();
|
2021-07-19 15:07:12 +02:00
|
|
|
|
2021-08-13 12:00:18 +02:00
|
|
|
if (sdr_type == NONE)
|
|
|
|
|
{
|
|
|
|
|
logger->warn("SDR Type is invalid / unspecified! Using first device found.");
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 15:07:12 +02:00
|
|
|
// Prepare other parameters
|
|
|
|
|
std::map<std::string, std::string> parameters;
|
|
|
|
|
parameters.emplace("samplerate", std::to_string(samplerate));
|
|
|
|
|
parameters.emplace("baseband_format", "f32");
|
|
|
|
|
|
|
|
|
|
// Init the device
|
2021-08-13 12:00:18 +02:00
|
|
|
std::string devID = sdr_type == NONE ? getDeviceIDStringByID(devices, 0) : ingestor_cfg["sdr_type"].get<std::string>();
|
2021-07-19 15:07:12 +02:00
|
|
|
logger->debug("Device parameters " + devID + ":");
|
|
|
|
|
for (const std::pair<std::string, std::string> param : device_parameters)
|
|
|
|
|
logger->debug(" - " + param.first + " : " + param.second);
|
|
|
|
|
|
2021-08-13 12:00:18 +02:00
|
|
|
std::shared_ptr<SDRDevice> radio;
|
|
|
|
|
if (sdr_type == NONE)
|
|
|
|
|
{
|
|
|
|
|
radio = getDeviceByID(devices, device_parameters, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool found = false;
|
2021-08-13 12:05:38 +02:00
|
|
|
for (int i = 0; i < (int)devices.size(); i++)
|
2021-08-13 12:00:18 +02:00
|
|
|
{
|
|
|
|
|
std::tuple<std::string, sdr_device_type, uint64_t> &devListing = devices[i];
|
|
|
|
|
if (std::get<1>(devListing) == sdr_type)
|
|
|
|
|
{
|
|
|
|
|
radio = getDeviceByID(devices, device_parameters, i);
|
|
|
|
|
found = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
{
|
|
|
|
|
logger->error("Could not requested find SDR Device!");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-19 15:07:12 +02:00
|
|
|
radio->setFrequency(frequency * 1e6);
|
|
|
|
|
radio->setSamplerate(samplerate);
|
|
|
|
|
radio->start();
|
|
|
|
|
|
|
|
|
|
// Init pipeline
|
|
|
|
|
logger->info("Init pipeline...");
|
|
|
|
|
std::vector<Pipeline>::iterator it = std::find_if(pipelines.begin(),
|
|
|
|
|
pipelines.end(),
|
|
|
|
|
[&downlink_pipeline](const Pipeline &e)
|
|
|
|
|
{
|
|
|
|
|
return e.name == downlink_pipeline;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (it == pipelines.end())
|
|
|
|
|
{
|
|
|
|
|
logger->error("Pipeline " + downlink_pipeline + " does not exist!");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!std::filesystem::exists(output_folder))
|
|
|
|
|
std::filesystem::create_directory(output_folder);
|
|
|
|
|
|
2021-07-21 00:54:48 +02:00
|
|
|
live_pipeline = std::make_shared<LivePipeline>(*it, parameters, output_folder);
|
2021-07-19 15:07:12 +02:00
|
|
|
|
|
|
|
|
// Start processing
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
logger->info("Setting process priority to Realtime");
|
|
|
|
|
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-10-22 15:26:17 +02:00
|
|
|
std::shared_ptr<dsp::stream<complex_t>> pipelineStream = std::make_shared<dsp::stream<complex_t>>();
|
2021-07-19 15:07:12 +02:00
|
|
|
live_pipeline->start(pipelineStream, processThreadPool);
|
|
|
|
|
|
2021-07-21 00:54:48 +02:00
|
|
|
// HTTP
|
|
|
|
|
logger->info("Starting HTTP Server...");
|
|
|
|
|
nng_http_server *http_server;
|
|
|
|
|
nng_url *url;
|
|
|
|
|
nng_http_handler *handler;
|
|
|
|
|
nng_url_parse(&url, http_server_url.c_str());
|
|
|
|
|
nng_http_server_hold(&http_server, url);
|
|
|
|
|
nng_http_handler_alloc(&handler, url->u_path, http_handle);
|
|
|
|
|
nng_http_handler_set_method(handler, "GET");
|
|
|
|
|
nng_http_server_add_handler(http_server, handler);
|
|
|
|
|
nng_http_server_start(http_server);
|
|
|
|
|
nng_url_free(url);
|
|
|
|
|
|
2021-07-19 15:07:12 +02:00
|
|
|
// Loop to pass samples from the SDR into set buffers for the pipeline
|
2021-10-22 15:26:17 +02:00
|
|
|
volk::vector<complex_t> sample_buffer_vec;
|
2021-07-19 15:07:12 +02:00
|
|
|
int cnt = 0;
|
|
|
|
|
int buf_size = 8192;
|
2021-08-02 22:51:12 +02:00
|
|
|
while (!should_stop)
|
2021-07-19 15:07:12 +02:00
|
|
|
{
|
|
|
|
|
if ((int)sample_buffer_vec.size() < buf_size)
|
|
|
|
|
{
|
|
|
|
|
cnt = radio->output_stream->read();
|
|
|
|
|
if (cnt > 0)
|
|
|
|
|
{
|
|
|
|
|
sample_buffer_vec.insert(sample_buffer_vec.end(), radio->output_stream->readBuf, &radio->output_stream->readBuf[cnt]);
|
|
|
|
|
radio->output_stream->flush();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-08-12 23:22:49 +02:00
|
|
|
|
2021-08-13 12:05:38 +02:00
|
|
|
if ((int)sample_buffer_vec.size() < buf_size) // Still too small
|
2021-08-12 23:22:49 +02:00
|
|
|
continue;
|
2021-07-19 15:07:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-22 15:26:17 +02:00
|
|
|
std::memcpy(pipelineStream->writeBuf, sample_buffer_vec.data(), buf_size * sizeof(complex_t));
|
2021-07-19 15:07:12 +02:00
|
|
|
pipelineStream->swap(buf_size);
|
|
|
|
|
sample_buffer_vec.erase(sample_buffer_vec.begin(), sample_buffer_vec.begin() + buf_size);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-02 22:51:12 +02:00
|
|
|
logger->info("Stop pipeline...");
|
|
|
|
|
live_pipeline->stop();
|
|
|
|
|
|
2021-08-08 00:29:53 +02:00
|
|
|
//logger->info("Stopping SDR...");
|
|
|
|
|
//radio->stop();
|
2021-08-02 22:51:12 +02:00
|
|
|
|
2021-07-19 15:07:12 +02:00
|
|
|
logger->info("Done! Goodbye");
|
|
|
|
|
}
|