mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
197 lines
10 KiB
C++
197 lines
10 KiB
C++
#include "../webserver.h"
|
|
#include "autotrack.h"
|
|
#include "image/jpeg_utils.h"
|
|
#include "logger.h"
|
|
#include "utils/format.h"
|
|
#include "utils/time.h"
|
|
|
|
void AutoTrackApp::setup_webserver()
|
|
{
|
|
// If requested, boot up webserver
|
|
if (d_settings.contains("http_server"))
|
|
{
|
|
std::string http_addr = d_settings["http_server"].get<std::string>();
|
|
|
|
webserver::handle_callback = [this]()
|
|
{
|
|
nlohmann::json p;
|
|
|
|
live_pipeline_mtx.lock();
|
|
if (live_pipeline)
|
|
{
|
|
p["live_pipeline"] = live_pipeline->getModulesStats();
|
|
}
|
|
live_pipeline_mtx.unlock();
|
|
|
|
p["object_tracker"] = object_tracker.getStatus();
|
|
p["frequency"] = source_ptr->get_frequency();
|
|
|
|
vfos_mtx.lock();
|
|
if (vfo_list.size() > 0)
|
|
{
|
|
for (auto &vfo : vfo_list)
|
|
{
|
|
auto &pos = p["vfos"][vfo.id];
|
|
pos["frequency"] = vfo.freq;
|
|
if (vfo.selected_pipeline.id != "")
|
|
{
|
|
pos["live_pipeline"] = vfo.live_pipeline->getModulesStats();
|
|
}
|
|
if (vfo.file_sink)
|
|
{
|
|
pos["recording"]["written_size"] = vfo.file_sink->get_written();
|
|
pos["recording"]["written_raw_size"] = vfo.file_sink->get_written_raw();
|
|
}
|
|
}
|
|
}
|
|
vfos_mtx.unlock();
|
|
|
|
if (is_recording)
|
|
{
|
|
p["recording"]["written_size"] = file_sink->get_written();
|
|
p["recording"]["written_raw_size"] = file_sink->get_written_raw();
|
|
}
|
|
|
|
return p.dump(4);
|
|
};
|
|
|
|
webserver::add_polarplot_handler = true;
|
|
|
|
webserver::handle_callback_polarplot = [this]() -> std::vector<uint8_t>
|
|
{
|
|
auto img = object_tracker.getPolarPlotImg();
|
|
std::vector<uint8_t> vec = image::save_jpeg_mem(img);
|
|
return vec;
|
|
};
|
|
|
|
if (d_parameters.contains("fft_enable") && d_parameters["fft_enable"])
|
|
webserver::handle_callback_fft = [this]() -> std::vector<uint8_t>
|
|
{
|
|
if (!web_fft_is_enabled)
|
|
{
|
|
splitter->set_enabled("fft", true);
|
|
web_fft_is_enabled = true;
|
|
logger->trace("Enabling FFT");
|
|
}
|
|
web_last_fft_access = time(nullptr);
|
|
auto img = fft_plot->drawImg(512, 512);
|
|
std::vector<uint8_t> vec = image::save_jpeg_mem(img);
|
|
return vec;
|
|
};
|
|
|
|
webserver::handle_callback_schedule = [this]() -> std::vector<uint8_t>
|
|
{
|
|
auto img = auto_scheduler.getScheduleImage(512, satdump::getTime());
|
|
std::vector<uint8_t> vec = image::save_jpeg_mem(img);
|
|
return vec;
|
|
};
|
|
|
|
webserver::handle_callback_html = [this](std::string uri) -> std::string
|
|
{
|
|
if (uri == "/status")
|
|
{
|
|
live_pipeline_mtx.lock();
|
|
auto status = object_tracker.getStatus();
|
|
std::string rot_engaged;
|
|
std::string rot_tracking;
|
|
std::string aos_in;
|
|
std::string los_in;
|
|
std::string fft;
|
|
|
|
time_t cache_buster = time(nullptr);
|
|
|
|
if (status["rotator_engaged"].get<bool>() == true)
|
|
rot_engaged = "<span class=\"fakeinput true\">engaged</span>";
|
|
else
|
|
rot_engaged = "<span class=\"fakeinput false\">not engaged</span>";
|
|
|
|
if (status["rotator_tracking"].get<bool>() == true)
|
|
rot_tracking = "<span class=\"fakeinput true\">tracking</span>";
|
|
else
|
|
rot_tracking = "<span class=\"fakeinput false\">not tracking</span>";
|
|
|
|
if (status["next_event_is_aos"].get<bool>() == true)
|
|
{
|
|
aos_in = " (in <span class=\"fakeinput\">" + std::to_string((int)(status["next_event_in"].get<double>())) + "</span> seconds)";
|
|
los_in = "";
|
|
}
|
|
else
|
|
{
|
|
los_in = " (in <span class=\"fakeinput\">" + std::to_string((int)(status["next_event_in"].get<double>())) + "</span> seconds)";
|
|
aos_in = "";
|
|
}
|
|
|
|
if (d_parameters.contains("fft_enable") && d_parameters["fft_enable"])
|
|
fft = (std::string) "<h2>FFT</h2><img src=\"fft.jpeg?r=" + std::to_string(cache_buster) + "\" class=\"resp-img\" height=\"600\" width=\"600\" />";
|
|
|
|
std::string schedule = (std::string) "<h2>Schedule</h2><img src=\"schedule.jpeg?r=" + std::to_string(cache_buster) + "\" class=\"resp-img\" height=\"80\" width=\"600\" />";
|
|
|
|
std::string page =
|
|
(std::string) "<h2>Device</h2><p>Hardware: <span class=\"fakeinput\">" + selected_src.name + "</span></p>" + "<p>Started: <span class=\"fakeinput\">" +
|
|
std::string(is_started ? "YES" : "NO") + "</span></p>" + "<p>Sample rate: <span class=\"fakeinput\">" + std::to_string(source_ptr->get_samplerate() / 1e6) + "</span> Msps</p>" +
|
|
"<p>Frequency: <span class=\"fakeinput\">" + std::to_string(source_ptr->get_frequency() / 1e6) + "</span> MHz</p>" + "<h2>Object Tracker</h2>" +
|
|
"<div class=\"image-div\"><img src=\"polarplot.jpeg?r=" + std::to_string(cache_buster) + "\" width=256 height=256/></div>" + "<p>Next AOS time: <span class=\"fakeinput\">" +
|
|
satdump::timestamp_to_string(status["next_aos_time"].get<double>(), auto_scheduler.getAutoTrackCfg().use_localtime) + "</span>" + aos_in + "</p>" +
|
|
"<p>Next LOS time: <span class=\"fakeinput\">" + satdump::timestamp_to_string(status["next_los_time"].get<double>(), auto_scheduler.getAutoTrackCfg().use_localtime) + "</span>" +
|
|
los_in + "</p>" + "<p>Current object: <span class=\"fakeinput\">" + status["object_name"].get<std::string>() + "</span></p>" + "<p>Current position:<br />" +
|
|
"Azimuth <span class=\"fakeinput\">" + satdump::svformat("%.2f", (status["sat_current_pos"]["az"].get<double>())) + "</span> °<br />Elevation <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["sat_current_pos"]["el"].get<double>())) + "</span> °<br /> Range <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["sat_current_range"].get<double>())) + "</span> km</p>" + "<h2>Rotator Control</h2>" + "<p>Status:" + rot_engaged +
|
|
", <span class=\"fakeinput false\">" + rot_tracking + "</span></p>" + "<p>Azimuth: requested <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["rot_current_req_pos"]["az"].get<double>())) + "</span> °, actual <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["rot_current_pos"]["az"].get<double>())) + "</span> °</p>" + "<p>Elevation: requested <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["rot_current_req_pos"]["el"].get<double>())) + "</span> °, actual <span class=\"fakeinput\">" +
|
|
satdump::svformat("%.2f", (status["rot_current_pos"]["el"].get<double>())) + "</span> °</p>" + schedule + fft;
|
|
|
|
live_pipeline_mtx.unlock();
|
|
return page;
|
|
}
|
|
else if (uri == "/")
|
|
{
|
|
std::string page = (std::string) "<!DOCTYPE html><html lang=\"EN\"><head>" + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" +
|
|
"<meta charset=\"utf-8\"><title>SatDump Status Page</title>" + "<script type=\"text/javascript\">" + "function xhr() {\n" + "var http;\n" +
|
|
"if (window.XMLHttpRequest) {\n" + "http = new XMLHttpRequest();\n" + "} else {\n" + "http = new ActiveXObject(\"Microsoft.XMLHTTP\");\n" + "}" +
|
|
"var url = \"/status\";\n" + "http.open(\"GET\", url, true);\n" + "http.onreadystatechange = function() { \n" +
|
|
"if (http.readyState == 4 && http.status == 200) {\n" + "document.getElementById('main-content').innerHTML = http.responseText;\n" + "}\n" + "}\n" +
|
|
"http.setRequestHeader(\"If-Modified-Since\", \"Sat, 1 Jan 2000 00:00:00 GMT\");\n" + "http.send(null);\n" + "}\n" + "window.onload = function() {\n" +
|
|
"xhr();\n"
|
|
"setInterval(\"xhr()\", 1000)\n" +
|
|
"}\n" + "</script>" +
|
|
"<!--[if lt IE 7 ]><style>body{width:600px;}</style><![endif]-->"
|
|
"<style>body{background-color:#111;font-family:sans-serif;color:#ddd;" +
|
|
"max-width:600px;margin-left:auto;margin-right:auto}h1{text-align:center}" + "h2{padding:5px;border-radius:5px;background-color:#3e3e43}" +
|
|
".fakeinput{padding:2px;border-radius:1px;background-color:#232526}" + ".resp-img{max-width:100%;height:auto}img{vertical-align:middle}" +
|
|
".true{color:#0f0}.false{color:red}.image-div{background-color:black;width:256px;height:256px;}</style></head>" +
|
|
"<div id=\"main-content\"><h2>Loading...</h2><p>If you see this, your browser does not support JavaScript. <a href=\"/status\">Click here</a> to view the status "
|
|
"(you will need to refresh it manually) :)</p></div>" +
|
|
"</body></html>";
|
|
return page;
|
|
}
|
|
else
|
|
{
|
|
return "Error 404";
|
|
}
|
|
};
|
|
logger->info("Start webserver on %s", http_addr.c_str());
|
|
webserver::start(http_addr);
|
|
}
|
|
}
|
|
|
|
void AutoTrackApp::stop_webserver()
|
|
{
|
|
if (d_settings.contains("http_server"))
|
|
webserver::stop();
|
|
}
|
|
|
|
void AutoTrackApp::web_heartbeat()
|
|
{
|
|
if (web_fft_is_enabled)
|
|
{
|
|
if (time(0) - web_last_fft_access > 10)
|
|
{
|
|
splitter->set_enabled("fft", false);
|
|
web_fft_is_enabled = false;
|
|
logger->trace("Shutting down FFT");
|
|
}
|
|
}
|
|
}
|