Skip to content

Commit 5d7d2a3

Browse files
committed
update r09-receiver to allow for scraping the prometheus data
1 parent 50ab0f6 commit 5d7d2a3

File tree

9 files changed

+187
-6
lines changed

9 files changed

+187
-6
lines changed

CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
cmake_minimum_required(VERSION 3.22)
22

33
add_executable(r09-receiver
4-
src/main.cpp
54
src/correlate_access_code_bb_ts_fl_impl.cpp
5+
src/prometheus.cpp
6+
src/prometheus_gauge_populator.cpp
7+
src/r09-receiver.cpp
68
src/rational_resampler_impl.cc)
79

810
target_compile_options(r09-receiver PUBLIC -std=c++17 -Wall)
@@ -13,11 +15,12 @@ find_package(Gnuradio "3.8" REQUIRED)
1315
find_package(Boost REQUIRED)
1416
find_package(Volk REQUIRED)
1517
find_package(libenvpp REQUIRED)
18+
find_package(prometheus-cpp CONFIG REQUIRED)
1619

1720
include(${OSMOSDR_DIR}/lib/cmake/osmosdr/gnuradio-osmosdrConfig.cmake)
1821

1922
include_directories(${GNURADIO_ALL_INCLUDE_DIRS})
2023

21-
target_link_libraries(r09-receiver log4cpp gnuradio-digital gnuradio-analog gnuradio-filter gnuradio-blocks gnuradio-fft gnuradio-runtime gnuradio-pmt volk gnuradio-osmosdr libenvpp::libenvpp)
24+
target_link_libraries(r09-receiver log4cpp gnuradio-digital gnuradio-analog gnuradio-filter gnuradio-blocks gnuradio-fft gnuradio-runtime gnuradio-pmt volk gnuradio-osmosdr libenvpp::libenvpp prometheus-cpp::pull)
2225

2326
install(TARGETS r09-receiver DESTINATION bin)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ DECODER\_RF | int of RF value for SDR
1616
DECODER\_IF | int of IF value for SDR
1717
DECODER\_BB | int of BB value for SDR
1818
DECODER\_DEVICE\_STRING | device string for osmosdr
19+
DECODER\_PROMETHEUS\_ADDRESS | the address where the appliaction is listening on for prometheus metric extraction (Format is host:port)
1920

2021
## building with nix flakes
2122

nixos-module/default.nix

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ in
4040
default = 42;
4141
description = "";
4242
};
43+
PrometheusHost = mkOption {
44+
type = types.str;
45+
default = "localhost";
46+
description = ''The host of the prometheus exporter for the R09-receiver'';
47+
};
48+
PrometheusPort = mkOption {
49+
type = types.port;
50+
default = 9020;
51+
description = ''The port of the prometheus exporter for the R09-receiver'';
52+
};
4353
user = mkOption {
4454
type = types.str;
4555
default = "r09-receiver";
@@ -52,6 +62,16 @@ in
5262
};
5363
};
5464

65+
options.services.prometheus.exporters.r09-receiver = with lib; {
66+
port = mkOption {
67+
type = types.port;
68+
default = 9020;
69+
description = lib.mdDoc ''
70+
Port to listen on.
71+
'';
72+
};
73+
};
74+
5575
config = lib.mkIf cfg.enable {
5676

5777
hardware = {
@@ -74,6 +94,7 @@ in
7494
"DECODER_IF" = toString IF;
7595
"DECODER_BB" = toString BB;
7696
"DECODER_DEVICE_STRING" = device;
97+
"DECODER_PROMETHEUS_ADDRESS" = "${PrometheusHost}:${toString PrometheusPort}";
7798
};
7899

79100
serviceConfig = {
@@ -85,6 +106,9 @@ in
85106
};
86107
};
87108

109+
# provide the prometheus exporter information for scraping
110+
services.prometheus.exporters.r09-receiver.port = cfg.PrometheusPort;
111+
88112
users.groups."${cfg.group}" = { };
89113
users.users."${cfg.user}" = {
90114
name = cfg.user;

pkgs/r09-receiver.nix

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
, fftwFloat
1414
, patchelf
1515
, libenvpp
16+
, prometheus-cpp
17+
, zlib
18+
, curlFull
1619
}:
1720
let
1821
decoder-dependencies = stdenv.mkDerivation {
@@ -82,7 +85,7 @@ let
8285
src = ./..;
8386

8487
nativeBuildInputs = [ cmake pkg-config gnuradio_unwrapped osmosdr ];
85-
buildInputs = [ log4cpp mpir gnuradio_unwrapped.boost.dev gmpxx.dev gnuradio_unwrapped.volk libenvpp ];
88+
buildInputs = [ log4cpp mpir gnuradio_unwrapped.boost.dev gmpxx.dev gnuradio_unwrapped.volk libenvpp prometheus-cpp zlib curlFull ];
8689

8790
cmakeFlags = [ "-DOSMOSDR_DIR=${osmosdr}" ];
8891
};

src/prometheus.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "prometheus.h"
2+
3+
PrometheusExporter::PrometheusExporter(
4+
const std::string &prometheus_host) noexcept {
5+
exposer_ = std::make_unique<prometheus::Exposer>(prometheus_host);
6+
registry_ = std::make_shared<prometheus::Registry>();
7+
8+
exposer_->RegisterCollectable(registry_);
9+
}
10+
11+
auto PrometheusExporter::signal_strength() noexcept
12+
-> prometheus::Family<prometheus::Gauge> & {
13+
return prometheus::BuildGauge()
14+
.Name("signal_strength")
15+
.Help("Current Signal Strength")
16+
.Register(*registry_);
17+
}

src/prometheus.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef PROMETHEUS_H
2+
#define PROMETHEUS_H
3+
4+
#include <memory>
5+
6+
#include <prometheus/counter.h>
7+
#include <prometheus/exposer.h>
8+
#include <prometheus/registry.h>
9+
10+
class PrometheusExporter {
11+
private:
12+
std::shared_ptr<prometheus::Registry> registry_;
13+
std::unique_ptr<prometheus::Exposer> exposer_;
14+
15+
public:
16+
PrometheusExporter(const std::string &host) noexcept;
17+
~PrometheusExporter() noexcept = default;
18+
19+
auto signal_strength() noexcept -> prometheus::Family<prometheus::Gauge> &;
20+
};
21+
22+
#endif // PROMETHEUS_H

src/prometheus_gauge_populator.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <gnuradio/io_signature.h>
2+
3+
#include "prometheus_gauge_populator.h"
4+
5+
namespace gr::prometheus {
6+
7+
PrometheusGaugePopulator::sptr
8+
PrometheusGaugePopulator::make(::prometheus::Gauge &gauge) {
9+
return gnuradio::get_initial_sptr(new PrometheusGaugePopulator(gauge));
10+
}
11+
12+
PrometheusGaugePopulator::PrometheusGaugePopulator(::prometheus::Gauge &gauge)
13+
: block(
14+
/*name=*/"PrometheusGaugePopulator",
15+
/*input_signature=*/
16+
io_signature::make(/*min_streams=*/1, /*max_streams=*/1,
17+
/*sizeof_stream_items=*/sizeof(float)),
18+
/*output_signature=*/
19+
io_signature::make(/*min_streams=*/0, /*max_streams=*/0,
20+
/*sizeof_stream_items=*/0)),
21+
gauge_(gauge) {}
22+
23+
auto PrometheusGaugePopulator::general_work(
24+
const int, gr_vector_int &, gr_vector_const_void_star &input_items,
25+
gr_vector_void_star &) -> int {
26+
const auto *in = (const float *)input_items[0];
27+
28+
// Consume one and write it to the gauge.
29+
const auto item = *in;
30+
consume_each(1);
31+
32+
gauge_.Set(item);
33+
34+
// We do not produce any items.
35+
return 0;
36+
}
37+
38+
} // namespace gr::prometheus

src/prometheus_gauge_populator.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef PROMETHEUS_GAUGE_POPULATOR_H
2+
#define PROMETHEUS_GAUGE_POPULATOR_H
3+
4+
#include <gnuradio/block.h>
5+
#include <gnuradio/blocks/api.h>
6+
7+
#include <prometheus/gauge.h>
8+
9+
namespace gr::prometheus {
10+
11+
/// This block takes a float as an input and writes in into a prometheus gauge
12+
class PrometheusGaugePopulator : virtual public block {
13+
private:
14+
/// the prometheus gauge we are populating with this block
15+
::prometheus::Gauge &gauge_;
16+
17+
public:
18+
using sptr = boost::shared_ptr<PrometheusGaugePopulator>;
19+
20+
PrometheusGaugePopulator() = delete;
21+
22+
explicit PrometheusGaugePopulator(::prometheus::Gauge &gauge);
23+
24+
static auto make(::prometheus::Gauge &gauge) -> sptr;
25+
26+
auto general_work(int noutput_items, gr_vector_int &ninput_items,
27+
gr_vector_const_void_star &input_items,
28+
gr_vector_void_star &output_items) -> int override;
29+
};
30+
31+
} // namespace gr::prometheus
32+
33+
#endif // PROMETHEUS_GAUGE_POPULATOR_H

src/main.cpp renamed to src/r09-receiver.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <gnuradio/analog/pwr_squelch_cc.h>
99
#include <gnuradio/analog/quadrature_demod_cf.h>
1010
#include <gnuradio/blocks/add_const_ff.h>
11+
#include <gnuradio/blocks/complex_to_mag_squared.h>
1112
#include <gnuradio/blocks/multiply_const.h>
1213
#include <gnuradio/blocks/socket_pdu.h>
1314
#include <gnuradio/blocks/tagged_stream_to_pdu.h>
@@ -27,6 +28,8 @@
2728
#include <osmosdr/source.h>
2829

2930
#include "correlate_access_code_bb_ts_fl.h"
31+
#include "prometheus.h"
32+
#include "prometheus_gauge_populator.h"
3033
#include "rational_resampler.h"
3134

3235
static auto print_gnuradio_diagnostics() -> void {
@@ -42,7 +45,8 @@ static auto print_gnuradio_diagnostics() -> void {
4245
}
4346

4447
auto receiver_main(const int frequency, const int offset, const int RF,
45-
const int IF, const int BB, const std::string &device_string)
48+
const int IF, const int BB, const std::string &device_string,
49+
std::shared_ptr<PrometheusExporter> prometheus_exporter)
4650
-> void {
4751
float samp_rate = 2000000;
4852
float bandwidth_sdr = 1000000;
@@ -117,6 +121,32 @@ auto receiver_main(const int frequency, const int offset, const int RF,
117121
tb->connect(correlate, 0, taggedStreamToPdu, 0);
118122
tb->msg_connect(taggedStreamToPdu, "pdus", udp_client, "pdus");
119123

124+
// create blocks to save the power of the current channel if prometheus
125+
// exporter is available
126+
if (prometheus_exporter) {
127+
auto &signal_strength = prometheus_exporter->signal_strength();
128+
auto &stream_signal_strength =
129+
signal_strength.Add({{"frequency", std::to_string(frequency + offset)},
130+
{"name", "R09 Receiver Average Signal Strength"}});
131+
132+
auto mag_squared = gr::blocks::complex_to_mag_squared::make();
133+
// averaging filter over one second
134+
unsigned tap_size = samp_rate / decimation;
135+
std::vector<float> averaging_filter(/*count=*/tap_size,
136+
/*alloc=*/1.0 / tap_size);
137+
// do not decimate directly to the final frequency, since there will be some
138+
// jitter
139+
unsigned decimation = tap_size / 10;
140+
auto fir = gr::filter::fir_filter_fff::make(/*decimation=*/decimation,
141+
averaging_filter);
142+
auto populator = gr::prometheus::PrometheusGaugePopulator::make(
143+
/*gauge=*/stream_signal_strength);
144+
145+
tb->connect(xlat, 0, mag_squared, 0);
146+
tb->connect(mag_squared, 0, fir, 0);
147+
tb->connect(fir, 0, populator, 0);
148+
}
149+
120150
print_gnuradio_diagnostics();
121151

122152
tb->start();
@@ -130,7 +160,7 @@ auto main(int argc, char **argv) -> int {
130160
float frequency;
131161
float offset;
132162
int RF, IF, BB;
133-
std::string device_string;
163+
std::string device_string, prometheus_addr;
134164

135165
const auto frequency_id = pre.register_required_variable<float>("FREQUENCY");
136166
const auto offset_id = pre.register_required_variable<float>("OFFSET");
@@ -139,6 +169,8 @@ auto main(int argc, char **argv) -> int {
139169
const auto BB_id = pre.register_variable<int>("BB");
140170
const auto device_string_id =
141171
pre.register_variable<std::string>("DEVICE_STRING");
172+
const auto prometheus_addr_id =
173+
pre.register_variable<std::string>("PROMETHEUS_ADDRESS");
142174

143175
const auto parsed_and_validated_pre = pre.parse_and_validate();
144176

@@ -149,15 +181,23 @@ auto main(int argc, char **argv) -> int {
149181
IF = parsed_and_validated_pre.get_or(IF_id, 0);
150182
BB = parsed_and_validated_pre.get_or(BB_id, 0);
151183
device_string = parsed_and_validated_pre.get_or(device_string_id, "");
184+
prometheus_addr = parsed_and_validated_pre.get_or(prometheus_addr_id, "");
152185
} else {
153186
std::cout << parsed_and_validated_pre.warning_message();
154187
std::cout << parsed_and_validated_pre.error_message();
155188

156189
return EXIT_FAILURE;
157190
}
158191

192+
std::shared_ptr<PrometheusExporter> prometheus_exporter;
193+
194+
if (!prometheus_addr.empty()) {
195+
prometheus_exporter = std::make_shared<PrometheusExporter>(prometheus_addr);
196+
}
197+
159198
try {
160-
receiver_main(frequency, offset, RF, IF, BB, device_string);
199+
receiver_main(frequency, offset, RF, IF, BB, device_string,
200+
prometheus_exporter);
161201
} catch (std::exception &e) {
162202
std::cerr << e.what() << std::endl;
163203
return EXIT_FAILURE;

0 commit comments

Comments
 (0)