SatDump 2.0.0-alpha-520736c72
Loading...
Searching...
No Matches
rec_backend.h
1#pragma once
2
3#include "base/remote_handler_backend.h"
4#include "core/config.h"
5#include "core/exception.h"
6#include "dsp/device/dev.h"
7#include "dsp/fft/fft_pan.h"
8#include "dsp/io/iq_sink.h"
9#include "dsp/io/iq_types.h"
10#include "dsp/path/splitter.h"
11#include "nlohmann/json.hpp"
12#include "utils/time.h"
13#include <chrono>
14#include <cstddef>
15#include <cstdint>
16#include <string>
17#include <thread>
18
19namespace satdump
20{
21 namespace handlers
22 {
23 class RecBackend : public RemoteHandlerBackend
24 {
25 private:
26 std::vector<ndsp::DeviceInfo> available_devices;
27 ndsp::DeviceInfo current_device;
28
29 bool is_started = false;
30
31 private:
32 std::shared_ptr<ndsp::DeviceBlock> dev_blk;
33
34 std::shared_ptr<ndsp::SplitterBlock<complex_t>> splitter;
35
36 std::shared_ptr<ndsp::FFTPanBlock> fftp;
37
38 int fft_size = 65536;
39 int fft_rate = 30;
40
41 // Recording
42 bool recording = false;
43 ndsp::IQType rec_type;
44 std::shared_ptr<ndsp::IQSinkBlock> iq_sink;
45
46 private:
47 std::thread metaThread;
48 bool metaThread_r = true;
49 void metaThread_f()
50 {
51 while (metaThread_r)
52 {
53 if (is_started)
54 {
55 float buffer_usage = getRatio();
56 push_stream_data("buffer_usage", (uint8_t *)&buffer_usage, sizeof(float));
57 }
58 if (is_started && recording)
59 push_stream_data("rec_size", (uint8_t *)&iq_sink->total_written_raw, sizeof(size_t));
60
61 std::this_thread::sleep_for(std::chrono::milliseconds(100));
62 }
63 }
64
65 public:
66 RecBackend()
67 {
68 available_devices = ndsp::getDeviceList(ndsp::DeviceBlock::MODE_SINGLE_RX);
69
70 splitter = std::make_shared<ndsp::SplitterBlock<complex_t>>();
71
72 fftp = std::make_shared<ndsp::FFTPanBlock>();
73 fftp->set_input(splitter->add_output("main_fft"), 0);
74 fftp->on_fft = [this](float *p, size_t s) { push_stream_data("fft", (uint8_t *)p, s * sizeof(float)); };
75
76 iq_sink = std::make_shared<ndsp::IQSinkBlock>();
77
78 metaThread = std::thread(&RecBackend::metaThread_f, this);
79 }
80 ~RecBackend()
81 {
82 metaThread_r = false;
83 if (metaThread.joinable())
84 metaThread.join();
85 }
86
87 void start()
88 {
89 if (!dev_blk || is_started)
90 return;
91
92 fftp->set_fft_settings(fft_size, dev_blk->getStreamSamplerate(0, false), fft_rate);
93
94 splitter->link(dev_blk.get(), 0, 0, 100); // fftp->inputs[0] = dev->outputs[0];
95
96 dev_blk->start();
97 splitter->start();
98 fftp->start();
99
100 is_started = true;
101 }
102
103 void stop()
104 {
105 if (!dev_blk || !is_started)
106 return;
107
108 dev_blk->stop(true);
109 splitter->stop();
110 fftp->stop();
111
112 is_started = false;
113 }
114
115 void start_rec()
116 {
117 if (!is_started || recording)
118 return;
119
120 std::string recording_path = satdump_cfg.main_cfg["satdump_directories"]["recording_path"]["value"].get<std::string>();
121 iq_sink->set_cfg("file", recording_path);
122 iq_sink->set_cfg("autogen", true);
123 iq_sink->set_cfg("samplerate", dev_blk->getStreamSamplerate(0, false));
124 iq_sink->set_cfg("frequency", dev_blk->getStreamFrequency(0, false));
125 iq_sink->set_cfg("timestamp", getTime());
126 iq_sink->set_cfg("type", rec_type);
127 iq_sink->set_input(splitter->add_output("tmp_record", false), 0);
128 iq_sink->start();
129
130 recording = true;
131 }
132
133 void stop_rec()
134 {
135 if (!recording)
136 return;
137
138 splitter->del_output("tmp_record", true);
139 iq_sink->stop();
140
141 recording = false;
142 }
143
144 float getRatio()
145 {
146 if (dev_blk)
147 return (float)dev_blk->get_outputs()[0].fifo->size_approx() / (float)dev_blk->get_outputs()[0].fifo->max_capacity();
148 else
149 return 0;
150 }
151
152 nlohmann::ordered_json _get_cfg_list()
153 {
154 nlohmann::ordered_json p;
155
156 p["available_devices"]["type"] = "json";
157 p["current_device"]["type"] = "json";
158
159 if (dev_blk)
160 {
161 p["dev/list"]["type"] = "json";
162 p["dev/cfg"]["type"] = "json";
163 }
164
165 p["started"]["type"] = "bool";
166
167 p["fft/avg_num"]["type"] = "float";
168 p["fft/size"]["type"] = "int";
169 p["fft/rate"]["type"] = "int";
170
171 p["buffer_usage"]["type"] = "float";
172
173 p["rec_type"]["type"] = "string";
174 p["recording"]["type"] = "bool";
175 p["rec_size"]["type"] = "int";
176
177 return p;
178 }
179
180 nlohmann::ordered_json _get_cfg(std::string key)
181 {
182 if (key == "available_devices")
183 return (nlohmann::json)available_devices;
184 else if (key == "current_device")
185 return (nlohmann::json)current_device;
186 else if (dev_blk && key == "dev/list")
187 return dev_blk->get_cfg_list();
188 else if (dev_blk && key == "dev/cfg")
189 return dev_blk->get_cfg();
190 else if (key == "started")
191 return is_started;
192 else if (key == "fft/avg_num")
193 return fftp->avg_num;
194 else if (key == "fft/size")
195 return fft_size;
196 else if (key == "fft/rate")
197 return fft_rate;
198 else if (key == "buffer_usage")
199 return getRatio();
200 else if (key == "rec_type")
201 return rec_type;
202 else if (key == "recording")
203 return recording;
204 else if (key == "rec_size")
205 return iq_sink->total_written_raw;
206 else
207 return nlohmann::json();
208 }
209
210 cfg_res_t _set_cfg(std::string key, nlohmann::ordered_json v)
211 {
212 if (!is_started && key == "current_device")
213 {
214 bool found = false;
215 for (auto &d : available_devices)
216 found |= nlohmann::json(d) == nlohmann::json(v);
217
218 if (!found)
219 return RES_ERR;
220
221 current_device = v;
222 dev_blk = ndsp::getDeviceInstanceFromInfo(current_device, ndsp::DeviceBlock::MODE_SINGLE_RX);
223 }
224 else if (dev_blk && key == "dev/cfg")
225 dev_blk->set_cfg(v);
226 else if (key == "started")
227 {
228 bool val = v;
229 if (!is_started && val)
230 start();
231 else if (is_started && !val)
232 stop();
233 }
234 else if (key == "fft/avg_num")
235 {
236 fftp->avg_num = v;
237 }
238 else if (key == "fft/size")
239 {
240 fft_size = v;
241
242 if (fft_size < 8)
243 fft_size = 8;
244 if (fft_size > 65536 * 8)
245 fft_size = 65536 * 8;
246
247 if (is_started)
248 fftp->set_fft_settings(fft_size, dev_blk->getStreamSamplerate(0, false), fft_rate);
249 }
250 else if (key == "fft/rate")
251 {
252 fft_rate = v;
253
254 if (fft_rate < 1)
255 fft_rate = 1;
256 if (fft_rate > 100e3)
257 fft_rate = 100e3;
258
259 if (is_started)
260 fftp->set_fft_settings(fft_size, dev_blk->getStreamSamplerate(0, false), fft_rate);
261 }
262 else if (!recording && key == "rec_type")
263 {
264 rec_type = std::string(v);
265 }
266 else if (is_started && key == "recording")
267 {
268 bool val = v;
269 if (!recording && val)
270 start_rec();
271 else if (recording && !val)
272 stop_rec();
273 }
274 else
275 throw satdump_exception("Oops");
276
277 return RES_OK;
278 }
279 };
280 } // namespace handlers
281} // namespace satdump
Definition iq_types.h:26
Definition dev.h:12
A collection of time-related utility functions.