Work on the spectran HTTP source

pull/1049/head
AlexandreRouma 2023-04-19 02:25:44 +02:00
rodzic 604f95fd96
commit 9c0b57a036
4 zmienionych plików z 140 dodań i 5 usunięć

Wyświetl plik

@ -0,0 +1,51 @@
#pragma once
#include <functional>
#include <stdexcept>
#include <mutex>
#include <map>
typedef int HandlerID;
template <typename... Args>
class NewEvent {
using Handler = std::function<void(Args...)>;
public:
HandlerID bind(const Handler& handler) {
std::lock_guard<std::mutex> lck(mtx);
HandlerID id = genID();
handlers[id] = handler;
return id;
}
template<typename MHandler, class T>
HandlerID bind(MHandler handler, T* ctx) {
return bind([=](Args... args){
(ctx->*handler)(args...);
});
}
void unbind(HandlerID id) {
std::lock_guard<std::mutex> lck(mtx);
if (handlers.find(id) == handlers.end()) {
throw std::runtime_error("Could not unbind handler, unknown ID");
}
handlers.erase(id);
}
void operator()(Args... args) {
std::lock_guard<std::mutex> lck(mtx);
for (const auto& [desc, handler] : handlers) {
handler(args...);
}
}
private:
HandlerID genID() {
int id;
for (id = 1; handlers.find(id) != handlers.end(); id++);
return id;
}
std::map<HandlerID, Handler> handlers;
std::mutex mtx;
};

Wyświetl plik

@ -28,7 +28,7 @@ public:
this->name = name;
strcpy(hostname, "localhost");
sampleRate = 41000000.0;
sampleRate = 5750000.0;
handler.ctx = this;
handler.selectHandler = menuSelected;
@ -103,8 +103,14 @@ private:
static void tune(double freq, void* ctx) {
SpectranHTTPSourceModule* _this = (SpectranHTTPSourceModule*)ctx;
if (_this->running) {
// TODO
bool connected = (_this->client && _this->client->isOpen());
if (connected) {
int64_t newfreq = round(freq);
if (newfreq != _this->lastReportedFreq && _this->gotReport) {
flog::debug("Sending tuning command");
_this->lastReportedFreq = newfreq;
_this->client->setCenterFrequency(newfreq);
}
}
_this->freq = freq;
flog::info("SpectranHTTPSourceModule '{0}': Tune: {1}!", _this->name, freq);
@ -138,6 +144,7 @@ private:
_this->tryConnect();
}
else if (connected && SmGui::Button("Disconnect##spectran_http_source")) {
_this->client->onCenterFrequencyChanged.unbind(_this->onFreqChangedId);
_this->client->close();
}
if (_this->running) { style::endDisabled(); }
@ -154,13 +161,23 @@ private:
void tryConnect() {
try {
gotReport = false;
client = std::make_shared<SpectranHTTPClient>(hostname, port, &stream);
onFreqChangedId = client->onCenterFrequencyChanged.bind(&SpectranHTTPSourceModule::onFreqChanged, this);
client->startWorker();
}
catch (std::runtime_error e) {
flog::error("Could not connect: {0}", e.what());
}
}
void onFreqChanged(double newFreq) {
if (lastReportedFreq == newFreq) { return; }
lastReportedFreq = newFreq;
tuner::tune(tuner::TUNER_MODE_IQ_ONLY, "", newFreq);
gotReport = true;
}
std::string name;
bool enabled = true;
double sampleRate;
@ -168,11 +185,15 @@ private:
bool running = false;
std::shared_ptr<SpectranHTTPClient> client;
HandlerID onFreqChangedId;
double freq;
int64_t lastReportedFreq = 0;
bool gotReport;
char hostname[1024];
int port = 80;
int port = 54664;
dsp::stream<dsp::complex_t> stream;
};

Wyświetl plik

@ -5,6 +5,8 @@ SpectranHTTPClient::SpectranHTTPClient(std::string host, int port, dsp::stream<d
this->stream = stream;
// Connect to server
this->host = host;
this->port = port;
sock = net::connect(host, port);
http = net::http::Client(sock);
@ -14,6 +16,13 @@ SpectranHTTPClient::SpectranHTTPClient(std::string host, int port, dsp::stream<d
net::http::ResponseHeader rshdr;
http.recvResponseHeader(rshdr, 5000);
if (rshdr.getStatusCode() != net::http::STATUS_CODE_OK) {
flog::error("HTTP request did not return ok: {}", rshdr.getStatusString());
throw std::runtime_error("HTTP request did not return ok");
}
}
void SpectranHTTPClient::startWorker() {
// Start chunk worker
workerThread = std::thread(&SpectranHTTPClient::worker, this);
}
@ -33,6 +42,27 @@ void SpectranHTTPClient::close() {
stream->clearWriteStop();
}
void SpectranHTTPClient::setCenterFrequency(uint64_t freq) {
// Connect to control endpoint (TODO: Switch to an always connected endpoint)
auto controlSock = net::connect(host, port);
auto controlHttp = net::http::Client(controlSock);
// Make request
net::http::RequestHeader rqhdr(net::http::METHOD_PUT, "/control", host);
char buf[1024];
sprintf(buf, "{\"frequencyCenter\":%d,\"frequencySpan\":%d,\"type\":\"capture\"}", freq, _span);
std::string data = buf;
char lenBuf[16];
sprintf(lenBuf, "%d", data.size());
rqhdr.setField("Content-Length", lenBuf);
controlHttp.sendRequestHeader(rqhdr);
controlSock->sendstr(data);
net::http::ResponseHeader rshdr;
controlHttp.recvResponseHeader(rshdr, 5000);
flog::debug("Response: {}", rshdr.getStatusString());
}
void SpectranHTTPClient::worker() {
while (sock->isOpen()) {
// Get chunk header
@ -52,6 +82,26 @@ void SpectranHTTPClient::worker() {
return;
}
// Decode JSON (yes, this is hacky, but it must be extremely fast)
auto startFreqBegin = jsonData.find("\"startFrequency\":");
auto startFreqEnd = jsonData.find(',', startFreqBegin);
std::string startFreqStr = jsonData.substr(startFreqBegin + 17, startFreqEnd - startFreqBegin - 17);
int64_t startFreq = std::stoll(startFreqStr);
auto endFreqBegin = jsonData.find("\"endFrequency\":");
auto endFreqEnd = jsonData.find(',', endFreqBegin);
std::string endFreqStr = jsonData.substr(endFreqBegin + 15, endFreqEnd - endFreqBegin - 15);
int64_t endFreq = std::stoll(endFreqStr);
// Calculate and update center freq
_span = endFreq - startFreq;
int64_t centerFreq = round(((double)endFreq + (double)startFreq) / 2.0);
if (centerFreq != _centerFreq) {
flog::debug("{}, {}, {}", _span, centerFreq);
_centerFreq = centerFreq;
onCenterFrequencyChanged(centerFreq);
}
// Read (and check for) record separator
uint8_t rs;
int rslen = sock->recv(&rs, 1, true, 5000);
@ -72,10 +122,11 @@ void SpectranHTTPClient::worker() {
i += read;
sampLen += read;
}
int sampCount = sampLen / 8;
// Swap to stream
if (streamingEnabled) {
if (!stream->swap(sampLen / 8)) { return; }
if (!stream->swap(sampCount)) { return; }
}
// Read trailing CRLF

Wyświetl plik

@ -4,22 +4,34 @@
#include <string>
#include <thread>
#include <utils/proto/http.h>
#include <utils/new_event.h>
#include <stdint.h>
class SpectranHTTPClient {
public:
SpectranHTTPClient(std::string host, int port, dsp::stream<dsp::complex_t>* stream);
void startWorker();
void streaming(bool enabled);
bool isOpen();
void close();
void setCenterFrequency(uint64_t freq);
NewEvent<uint64_t> onCenterFrequencyChanged;
private:
void worker();
std::string host;
int port;
std::shared_ptr<net::Socket> sock;
net::http::Client http;
dsp::stream<dsp::complex_t>* stream;
std::thread workerThread;
bool streamingEnabled = false;
int64_t _centerFreq = 0;
uint64_t _span = 5000000;
};