5G-MAG Reference Tools - MBMS Modem
RestHandler.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Modem Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
15 //
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 //#include "RestHandler.h"
21 #include "CasFrameProcessor.h"
22 
23 #include <memory>
24 #include <utility>
25 
26 #include "spdlog/spdlog.h"
27 
28 using web::json::value;
29 using web::http::methods;
30 using web::http::uri;
31 using web::http::http_request;
32 using web::http::status_codes;
33 using web::http::experimental::listener::http_listener;
34 using web::http::experimental::listener::http_listener_config;
35 
36 RestHandler::RestHandler(const libconfig::Config& cfg, const std::string& url,
37  state_t& state, SdrReader& sdr, Phy& phy,
39  : _cfg(cfg),
40  _state(state),
41  _sdr(sdr),
42  _phy(phy),
43  _set_params(std::move(set_params)) {
44 
45  http_listener_config server_config;
46  if (url.rfind("https", 0) == 0) {
47  server_config.set_ssl_context_callback(
48  [&](boost::asio::ssl::context& ctx) {
49  std::string cert_file = "/usr/share/5gmag-rt/cert.pem";
50  cfg.lookupValue("modem.restful_api.cert", cert_file);
51 
52  std::string key_file = "/usr/share/5gmag-rt/key.pem";
53  cfg.lookupValue("modem.restful_api.key", key_file);
54 
55  ctx.set_options(boost::asio::ssl::context::default_workarounds);
56  ctx.use_certificate_chain_file(cert_file);
57  ctx.use_private_key_file(key_file, boost::asio::ssl::context::pem);
58  });
59  }
60 
61  cfg.lookupValue("modem.restful_api.api_key.enabled", _require_bearer_token);
63  _api_key = "106cd60-76c8-4c37-944c-df21aa690c1e";
64  cfg.lookupValue("modem.restful_api.api_key.key", _api_key);
65  }
66 
67  _listener = std::make_unique<http_listener>(
68  url, server_config);
69 
70  _listener->support(methods::GET, std::bind(&RestHandler::get, this, std::placeholders::_1)); // NOLINT
71  _listener->support(methods::PUT, std::bind(&RestHandler::put, this, std::placeholders::_1)); // NOLINT
72 
73  //_listener->open().wait();
74 }
75 
76 RestHandler::~RestHandler() = default;
77 
78 void RestHandler::get(http_request message) {
79  spdlog::debug("Received GET request {}", message.to_string() );
80  auto paths = uri::split_path(uri::decode(message.relative_uri().path()));
82  (message.headers()["Authorization"] != "Bearer " + _api_key)) {
83  message.reply(status_codes::Unauthorized);
84  return;
85  }
86 
87  if (paths.empty()) {
88  message.reply(status_codes::NotFound);
89  } else {
90  if (paths[0] == "status") {
91  auto state = value::object();
92 
93  switch (_state) {
94  case searching:
95  state["state"] = value::string("searching");
96  break;
97  case syncing:
98  state["state"] = value::string("syncing");
99  break;
100  case processing:
101  state["state"] = value::string("synchronized");
102  break;
103  }
104 
105  if (_phy.cell().nof_prb == _phy.cell().mbsfn_prb) {
106  state["nof_prb"] = value(_phy.cell().nof_prb);
107  } else {
108  state["nof_prb"] = value(_phy.cell().mbsfn_prb);
109  }
110  state["cell_id"] = value(_phy.cell().id);
111  state["cfo"] = value(_phy.cfo());
112  state["cinr_db"] = value(cinr_db());
113  state["cinr_db_avg"] = value(cinr_db_avg());
114  state["subcarrier_spacing"] = value(_phy.mbsfn_subcarrier_spacing_khz());
115 
116  // CAS Chest params //
117  state["filter_order"] = value(_cas_processor->get_filter_order());
118  state["filter_coef"] = value(_cas_processor->get_filter_coef());
119  state["filter_type"] = value(_cas_processor->get_filter_type());
120  state["noise_alg"] = value(_cas_processor->get_noise_alg());
121  state["sync_error"] = value(_cas_processor->get_sync_error());
122  state["estimator_alg"] = value(_cas_processor->get_estimator_alg());
123  state["cfo_estimate"] = value(_cas_processor->get_cfo_estimate());
124  state["evm_meas"] = value(_cas_processor->get_evm_meas());
125 
126  // Phy params //
127  state["cfo_est_pss_find"] = value(_phy.get_ue_sync_find_cfo_pss_enable());
128  state["cfo_est_pss_track"] = value(_phy.get_ue_sync_track_cfo_pss_enable());
129  state["cfo_correct_find"] = value(_phy.get_ue_sync_find_cfo_correct_enable());
130  state["cfo_correct_track"] = value(_phy.get_ue_sync_track_cfo_correct_enable());
131  state["cfo_pss_loop_bw"] = value(_phy.get_ue_sync_cfo_loop_bw_pss());
132  state["cfo_ema_alpha_find"] = value(_phy.get_ue_sync_find_cfo_ema());
133  state["cfo_ema_alpha_track"] = value(_phy.get_ue_sync_track_cfo_ema());
134  state["pss_ema_find"] = value(_phy.get_ue_sync_pss_cfo_ema_find());
135  state["pss_ema_track"] = value(_phy.get_ue_sync_pss_cfo_ema_track());
136  state["threshold_find"] = value(_phy.get_ue_sync_threshold_find());
137  state["threshold_track"] = value(_phy.get_ue_sync_threshold_track());
138 
139 
140  message.reply(status_codes::OK, state);
141  } else if (paths[0] == "sdr_params") {
142  value sdr = value::object();
143  sdr["frequency"] = value(_sdr.get_frequency());
144  sdr["gain"] = value(_sdr.get_gain());
145  sdr["min_gain"] = value(_sdr.min_gain());
146  sdr["max_gain"] = value(_sdr.max_gain());
147  sdr["filter_bw"] = value(_sdr.get_filter_bw());
148  sdr["antenna"] = value(_sdr.get_antenna());
149  sdr["sample_rate"] = value(_sdr.get_sample_rate());
150  sdr["buffer_level"] = value(_sdr.get_buffer_level());
151  message.reply(status_codes::OK, sdr);
152  } else if (paths[0] == "ce_values") {
153  auto cestream = Concurrency::streams::bytestream::open_istream(_ce_values);
154  message.reply(status_codes::OK, cestream);
155  } else if (paths[0] == "cir_values") {
156  auto cestream = Concurrency::streams::bytestream::open_istream(_cir_values);
157  message.reply(status_codes::OK, cestream);
158  } else if (paths[0] == "cir_values_mbsfn") {
159  auto cestream = Concurrency::streams::bytestream::open_istream(_cir_values_mbsfn);
160  message.reply(status_codes::OK, cestream);
161  } else if (paths[0] == "corr_values") {
162  auto cestream = Concurrency::streams::bytestream::open_istream(_corr_values);
163  message.reply(status_codes::OK, cestream);
164  } else if (paths[0] == "corr_values_mbsfn") {
165  auto cestream = Concurrency::streams::bytestream::open_istream(_corr_values_mbsfn);
166  message.reply(status_codes::OK, cestream);
167  } else if (paths[0] == "pdsch_status") {
168  value sdr = value::object();
169  sdr["bler"] = value(static_cast<float>(_pdsch.errors) /
170  static_cast<float>(_pdsch.total));
171  sdr["ber"] = value(_pdsch.ber);
172  sdr["mcs"] = value(_pdsch.mcs);
173  sdr["present"] = 1;
174  message.reply(status_codes::OK, sdr);
175  } else if (paths[0] == "pdsch_data") {
176  auto cestream = Concurrency::streams::bytestream::open_istream(_pdsch.GetData());
177  message.reply(status_codes::OK, cestream);
178  } else if (paths[0] == "mcch_status") {
179  value sdr = value::object();
180  sdr["bler"] = value(static_cast<float>(_mcch.errors) /
181  static_cast<float>(_mcch.total));
182  sdr["ber"] = value(_mcch.ber);
183  sdr["mcs"] = value(_mcch.mcs);
184  sdr["present"] = 1;
185  message.reply(status_codes::OK, sdr);
186  } else if (paths[0] == "mcch_data") {
187  auto cestream = Concurrency::streams::bytestream::open_istream(_mcch.GetData());
188  message.reply(status_codes::OK, cestream);
189  } else if (paths[0] == "mch_info") {
190  std::vector<value> mi;
191  auto mch_info = _phy.mch_info();
192  std::for_each(std::begin(mch_info), std::end(mch_info), [&mi](Phy::mch_info_t const& mch) {
193  value m;
194  m["mcs"] = value(mch.mcs);
195  std::vector<value> mti;
196  std::for_each(std::begin(mch.mtchs), std::end(mch.mtchs), [&mti](Phy::mtch_info_t const& mtch) {
197  value mt;
198  mt["tmgi"] = value(mtch.tmgi);
199  mt["dest"] = value(mtch.dest);
200  mt["lcid"] = value(mtch.lcid);
201  mti.push_back(mt);
202  });
203  m["mtchs"] = value::array(mti);
204  mi.push_back(m);
205  });
206  message.reply(status_codes::OK, value::array(mi));
207  } else if (paths[0] == "mch_status") {
208  int idx = std::stoi(paths[1]);
209  value sdr = value::object();
210  sdr["bler"] = value(static_cast<float>(_mch[idx].errors) /
211  static_cast<float>(_mch[idx].total));
212  sdr["ber"] = value(_mch[idx].ber);
213  sdr["mcs"] = value(_mch[idx].mcs);
214  sdr["present"] = value(_mch[idx].present);
215  message.reply(status_codes::OK, sdr);
216  } else if (paths[0] == "mch_data") {
217  int idx = std::stoi(paths[1]);
218  auto cestream = Concurrency::streams::bytestream::open_istream(_mch[idx].GetData());
219  message.reply(status_codes::OK, cestream);
220  } else if (paths[0] == "log") {
221  std::string logfile = "/var/log/syslog";
222 
223  Concurrency::streams::file_stream<uint8_t>::open_istream(logfile).then(
224  [message](const Concurrency::streams::basic_istream<unsigned char>&
225  file_stream) {
226  message.reply(status_codes::OK, file_stream, "text/plain");
227  });
228  }
229  }
230 }
231 
232 void RestHandler::put(http_request message) {
233  spdlog::debug("Received PUT request {}", message.to_string() );
234 
235  if (_require_bearer_token &&
236  (message.headers()["Authorization"] != "Bearer " + _api_key)) {
237  message.reply(status_codes::Unauthorized);
238  return;
239  }
240 
241  auto paths = uri::split_path(uri::decode(message.relative_uri().path()));
242  if (paths.empty()) {
243  message.reply(status_codes::NotFound);
244  } else {
245  if (paths[0] == "sdr_params") {
246  value answer;
247 
248  auto f = _sdr.get_frequency();
249  auto g = _sdr.get_gain();
250  auto bw = _sdr.get_filter_bw();
251  auto a = _sdr.get_antenna();
252  auto sr = _sdr.get_sample_rate();
253 
254  const auto & jval = message.extract_json().get();
255  spdlog::debug("Received JSON: {}", jval.serialize());
256 
257  if (jval.has_field("antenna")) {
258  a = jval.at("antenna").as_string();
259  }
260  if (jval.has_field("frequency")) {
261  f = jval.at("frequency").as_integer();
262  }
263  if (jval.has_field("gain")) {
264  g = jval.at("gain").as_double();
265  }
266  _set_params( a, f, g, sr, bw);
267 
268  message.reply(status_codes::OK, answer);
269  } else if (paths[0] == "chest_cfg_params") {
270  value answer;
271 
272  const auto & jval = message.extract_json().get();
273  spdlog::debug("Recieved JSON: {}", jval.serialize());
274 
275  if (jval.has_field("noise_alg")) {
276  auto alg = jval.at("noise_alg").as_string();
277  spdlog::info("New alg est {}", alg);
278  _cas_processor->set_noise_alg(static_cast<srsran_chest_dl_noise_alg_t>(stoi(alg)));
279  }
280  if (jval.has_field("sync_error")) {
281  spdlog::info("New sync error value");
282 
283  bool alg = jval.at("sync_error").as_bool();
284 
285  spdlog::info("{}", alg);
287  }
288  if (jval.has_field("estimator_alg")) {
289  auto alg = jval.at("estimator_alg").as_string();
290  spdlog::info("New alg est {}", alg);
291  _cas_processor->set_estimator_alg(static_cast<srsran_chest_dl_estimator_alg_t>(stoi(alg)));
292  }
293  if (jval.has_field("filter_type")) {
294  auto type = jval.at("filter_type").as_string();
295  spdlog::info("New filter type {}", type);
296  _cas_processor->set_filter_type(static_cast<srsran_chest_filter_t>(stoi(type)));
297  }
298  if (jval.has_field("filter_order")) {
299  spdlog::info("New filter order");
300  auto order = jval.at("filter_order").as_integer();
302  }
303  if (jval.has_field("filter_coef")) {
304  spdlog::info("New filter coef");
305  auto coef = jval.at("filter_coef").as_double();
307  }
308 
309  // Phy params
310  if (jval.has_field("cfo_est_pss_find")) {
311  spdlog::info("New cfo est pss find");
312  auto toggle = jval.at("cfo_est_pss_find").as_bool();
314  }
315  if (jval.has_field("cfo_est_pss_track")) {
316  spdlog::info("New cfo est pss track");
317  auto toggle = jval.at("cfo_est_pss_track").as_bool();
319  }
320  if (jval.has_field("cfo_correct_find")) {
321  spdlog::info("New cfo correct find");
322  auto toggle = jval.at("cfo_correct_find").as_bool();
324  }
325  if (jval.has_field("cfo_correct_track")) {
326  spdlog::info("New cfo correct track");
327  auto toggle = jval.at("cfo_correct_track").as_bool();
329  }
330  if (jval.has_field("cfo_pss_loop_bw")) {
331  spdlog::info("New BW pss CFO loop");
332  auto bw = jval.at("cfo_pss_loop_bw").as_double();
334  }
335  if (jval.has_field("cfo_ema_alpha_find")) {
336  spdlog::info("New CFO ema alpha for find");
337  auto ema = jval.at("cfo_ema_alpha_find").as_double();
339  }
340  if (jval.has_field("cfo_ema_alpha_track")) {
341  spdlog::info("New CFO ema alpha for track");
342  auto ema = jval.at("cfo_ema_alpha_track").as_double();
344  }
345  if (jval.has_field("pss_ema_find")) {
346  spdlog::info("New PSS corr ema alpha for find");
347  auto ema = jval.at("pss_ema_find").as_double();
349  }
350  if (jval.has_field("pss_ema_track")) {
351  spdlog::info("New PSS corr ema alpha for track");
352  auto ema = jval.at("pss_ema_track").as_double();
354  }
355  if (jval.has_field("threshold_find")) {
356  spdlog::info("New threshold for find");
357  auto ema = jval.at("threshold_find").as_double();
359  }
360  if (jval.has_field("threshold_track")) {
361  spdlog::info("New threshold for track");
362  auto ema = jval.at("threshold_track").as_double();
364  }
365 
366  message.reply(status_codes::OK, answer);
367  }
368  }
369 }
370 
371 void RestHandler::add_cinr_value( float cinr) {
372  if (_cinr_db.size() > CINR_RAVG_CNT) {
373  _cinr_db.erase(_cinr_db.begin());
374  }
375  _cinr_db.push_back(cinr);
376 }
state_t
Definition: RestHandler.h:39
@ syncing
Definition: RestHandler.h:39
@ searching
Definition: RestHandler.h:39
@ processing
Definition: RestHandler.h:39
const int CINR_RAVG_CNT
Definition: RestHandler.h:38
void set_noise_alg(srsran_chest_dl_noise_alg_t noise_alg)
Set the noise estimation algorithm used in the channel estimation stage.
void set_sync_error(bool enable)
Enables the estimation os synchronization error.
void set_estimator_alg(srsran_chest_dl_estimator_alg_t estimator_alg)
Set the method to estimate the channel estimates of the complete resource grid from the reference sym...
void set_filter_coef(float filter_coef)
Set the coef for gauss filtering.
void set_filter_order(uint8_t filter_order)
Set the filter order used to filter the channel estimates.
void set_filter_type(srsran_chest_filter_t filter_type)
Set the filter type for chest.
The PHY component.
Definition: Phy.h:42
float get_ue_sync_threshold_track()
Definition: Phy.h:235
bool get_ue_sync_track_cfo_pss_enable()
Definition: Phy.h:185
void set_ue_sync_track_cfo_ema(float ema)
Sets the ema alpha value used for the tracking of the CFO in the trackin sync object,...
Definition: Phy.h:204
const std::vector< mch_info_t > & mch_info()
Definition: Phy.h:253
void set_ue_sync_threshold_track(float threshold)
Sets the threshold of the peak found while tracking for synchronization.
Definition: Phy.h:234
bool get_ue_sync_find_cfo_pss_enable()
Definition: Phy.h:179
float get_ue_sync_pss_cfo_ema_find()
Definition: Phy.h:223
float get_ue_sync_track_cfo_ema()
Definition: Phy.h:205
void set_ue_sync_find_cfo_ema(float ema)
Sets the ema alpha value used for the tracking of the CFO in the trackin sync object,...
Definition: Phy.h:210
srsran_cell_t cell()
Get the current cell (with params adjusted for MBSFN)
Definition: Phy.h:91
void set_ue_sync_track_cfo_pss_enable(bool enable)
Enables or disables the CFO estimation from the PSS in the tracking stage.
Definition: Phy.h:184
void set_ue_sync_pss_cfo_ema_find(float ema)
Sets the weight factor alpha for the exponential moving average of the PSS correlation output
Definition: Phy.h:222
float get_ue_sync_find_cfo_ema()
Definition: Phy.h:211
void set_ue_sync_pss_cfo_ema_track(float ema)
Sets the weight factor alpha for the exponential moving average of the PSS correlation output
Definition: Phy.h:228
void set_ue_sync_track_cfo_correct_enable(bool enable)
Enables the CFO correction while tracking the synchronization from previous estimations.
Definition: Phy.h:198
float get_ue_sync_cfo_loop_bw_pss()
Definition: Phy.h:173
float mbsfn_subcarrier_spacing_khz()
Definition: Phy.h:275
bool get_ue_sync_find_cfo_correct_enable()
Definition: Phy.h:193
void set_ue_sync_find_cfo_pss_enable(bool enable)
Enables or disables the CFO estimation from the PSS in the finding stage.
Definition: Phy.h:178
void set_ue_sync_find_cfo_correct_enable(bool enable)
Enables the CFO correction while finding the synchronization from previous estimations.
Definition: Phy.h:190
float get_ue_sync_pss_cfo_ema_track()
Definition: Phy.h:229
bool get_ue_sync_track_cfo_correct_enable()
Definition: Phy.h:199
void set_ue_sync_cfo_loop_bw_pss(float bw)
Set the factor for the PSS loopback.
Definition: Phy.h:172
float cfo()
Get the current CFO value.
Definition: Phy.h:108
void set_ue_sync_threshold_find(float threshold)
Sets the threshold of the peak found while searching for synchronization.
Definition: Phy.h:240
float get_ue_sync_threshold_find()
Definition: Phy.h:241
std::vector< uint8_t > GetData()
Definition: RestHandler.h:84
CasFrameProcessor * _cas_processor
Definition: RestHandler.h:161
SdrReader & _sdr
Definition: RestHandler.h:178
std::vector< uint8_t > _cir_values
Time domain channel impulse response of the CAS.
Definition: RestHandler.h:107
std::unique_ptr< web::http::experimental::listener::http_listener > _listener
Definition: RestHandler.h:175
float cinr_db()
Current instantaneous CINR value.
Definition: RestHandler.h:144
float cinr_db_avg()
Current average CINR value.
Definition: RestHandler.h:149
std::vector< uint8_t > _ce_values
Time domain subcarrier CE values.
Definition: RestHandler.h:102
void put(web::http::http_request message)
std::vector< uint8_t > _corr_values
Correlaton samples from the sync functions.
Definition: RestHandler.h:118
ChannelInfo _mcch
RX info for MCCH.
Definition: RestHandler.h:134
std::string _api_key
Definition: RestHandler.h:184
std::vector< float > _cinr_db
Definition: RestHandler.h:169
void add_cinr_value(float cinr)
std::map< uint32_t, ChannelInfo > _mch
RX info for MCHs.
Definition: RestHandler.h:139
std::function< void(const std::string &antenna, unsigned fcen, double gain, unsigned sample_rate, unsigned bandwidth)> set_params_t
Definition of the callback for setting new reception parameters.
Definition: RestHandler.h:52
RestHandler(const libconfig::Config &cfg, const std::string &url, state_t &state, SdrReader &sdr, Phy &phy, set_params_t set_params)
Default constructor.
Definition: RestHandler.cpp:36
void get(web::http::http_request message)
Definition: RestHandler.cpp:78
ChannelInfo _pdsch
RX info for PDSCH.
Definition: RestHandler.h:129
virtual ~RestHandler()
Default destructor.
state_t & _state
Definition: RestHandler.h:177
std::vector< uint8_t > _corr_values_mbsfn
Correlaton samples from the sync functions.
Definition: RestHandler.h:124
bool _require_bearer_token
Definition: RestHandler.h:183
set_params_t _set_params
Definition: RestHandler.h:181
std::vector< uint8_t > _cir_values_mbsfn
Time domain channel impulse response of the mbsfn subframes.
Definition: RestHandler.h:112
Interface to the SDR stick.
Definition: SdrReader.h:37
double get_frequency()
Get current center frequency.
Definition: SdrReader.h:100
double get_buffer_level()
Get current ringbuffer level (0 = empty .
Definition: SdrReader.cpp:399
unsigned get_filter_bw()
Get current filter bandwidth.
Definition: SdrReader.h:105
std::string get_antenna()
Get current antenna port.
Definition: SdrReader.h:120
double max_gain()
Definition: SdrReader.h:129
double min_gain()
Definition: SdrReader.h:127
double get_gain()
Get current gain.
Definition: SdrReader.h:110
double get_sample_rate()
Get current sample rate.
Definition: SdrReader.h:95
static Config cfg
Global configuration object.
Definition: main.cpp:172
void set_params(const std::string &ant, unsigned fc, double g, unsigned sr, unsigned bw)
Set new SDR parameters and initialize resynchronisation.
Definition: main.cpp:205
std::vector< mtch_info_t > mtchs
Definition: Phy.h:250