Skip to content

Commit ef42ea0

Browse files
add flex decoder menu entry and fix pocsag decoding
1 parent 3fc8935 commit ef42ea0

File tree

4 files changed

+142
-143
lines changed

4 files changed

+142
-143
lines changed
+6-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#pragma once
2+
#include <signal_path/vfo_manager.h>
23

34
class Decoder {
45
public:
5-
6-
virtual void showMenu();
7-
6+
virtual ~Decoder() {}
7+
virtual void showMenu() {};
8+
virtual void setVFO(VFOManager::VFO* vfo) = 0;
9+
virtual void start() = 0;
10+
virtual void stop() = 0;
811
};

decoder_modules/pager_decoder/src/main.cpp

+54-137
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,11 @@
55
#include <gui/gui.h>
66
#include <signal_path/signal_path.h>
77
#include <module.h>
8-
#include <filesystem>
9-
#include <dsp/stream.h>
10-
#include <dsp/buffer/reshaper.h>
11-
#include <dsp/multirate/rational_resampler.h>
12-
#include <dsp/sink/handler_sink.h>
138
#include <gui/widgets/folder_select.h>
14-
#include <gui/widgets/symbol_diagram.h>
15-
#include <fstream>
16-
#include <chrono>
17-
#include <dsp/demod/quadrature.h>
18-
#include <dsp/clock_recovery/mm.h>
19-
#include <dsp/taps/root_raised_cosine.h>
20-
#include <dsp/correction/dc_blocker.h>
21-
#include <dsp/loop/fast_agc.h>
229
#include <utils/optionlist.h>
23-
#include <dsp/digital/binary_slicer.h>
24-
#include <dsp/routing/doubler.h>
25-
#include "pocsag/pocsag.h"
10+
#include "decoder.h"
11+
#include "pocsag/decoder.h"
12+
#include "flex/decoder.h"
2613

2714
#define CONCAT(a, b) ((std::string(a) + b).c_str())
2815

@@ -34,77 +21,29 @@ SDRPP_MOD_INFO{
3421
/* Max instances */ -1
3522
};
3623

37-
const char* msgTypes[] = {
38-
"Numeric",
39-
"Unknown (0b01)",
40-
"Unknown (0b10)",
41-
"Alphanumeric",
42-
};
43-
4424
ConfigManager config;
4525

46-
#define INPUT_SAMPLE_RATE 24000.0
47-
#define INPUT_BANDWIDTH 12500.0
48-
#define INPUT_BAUD_RATE 2400.0
49-
5026
enum Protocol {
27+
PROTOCOL_INVALID = -1,
5128
PROTOCOL_POCSAG,
5229
PROTOCOL_FLEX
5330
};
5431

5532
class PagerDecoderModule : public ModuleManager::Instance {
5633
public:
57-
PagerDecoderModule(std::string name) : diag(0.6, 2400) {
34+
PagerDecoderModule(std::string name) {
5835
this->name = name;
5936

6037
// Define protocols
6138
protocols.define("POCSAG", PROTOCOL_POCSAG);
6239
protocols.define("FLEX", PROTOCOL_FLEX);
6340

64-
// Load config
65-
config.acquire();
66-
if (!config.conf.contains(name)) {
67-
config.conf[name]["showLines"] = false;
68-
}
69-
showLines = config.conf[name]["showLines"];
70-
if (showLines) {
71-
diag.lines.push_back(-1.0);
72-
diag.lines.push_back(-1.0/3.0);
73-
diag.lines.push_back(1.0/3.0);
74-
diag.lines.push_back(1.0);
75-
}
76-
config.release(true);
77-
78-
// Initialize VFO
79-
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_BANDWIDTH, INPUT_SAMPLE_RATE, INPUT_BANDWIDTH, INPUT_BANDWIDTH, true);
41+
// Initialize VFO with default values
42+
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 12500, 24000, 12500, 12500, true);
8043
vfo->setSnapInterval(1);
8144

82-
// Initialize DSP here (negative dev to invert signal)
83-
demod.init(vfo->output, -4500.0, INPUT_SAMPLE_RATE);
84-
dcBlock.init(&demod.out, 0.001);
85-
float taps[] = { 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f };
86-
shape = dsp::taps::fromArray<float>(10, taps);
87-
fir.init(&dcBlock.out, shape);
88-
recov.init(&fir.out, INPUT_SAMPLE_RATE/INPUT_BAUD_RATE, 1e5, 0.1, 0.05);
89-
doubler.init(&recov.out);
90-
slicer.init(&doubler.outB);
91-
dataHandler.init(&slicer.out, _dataHandler, this);
92-
reshape.init(&doubler.outA, 2400.0, (INPUT_BAUD_RATE / 30.0) - 2400.0);
93-
diagHandler.init(&reshape.out, _diagHandler, this);
94-
95-
// Initialize decode
96-
decoder.onMessage.bind(&PagerDecoderModule::messageHandler, this);
97-
98-
// Start DSP Here
99-
demod.start();
100-
dcBlock.start();
101-
fir.start();
102-
recov.start();
103-
doubler.start();
104-
slicer.start();
105-
dataHandler.start();
106-
reshape.start();
107-
diagHandler.start();
45+
// Select the protocol
46+
selectProtocol(PROTOCOL_POCSAG);
10847

10948
gui::menu.registerEntry(name, menuHandler, this, this);
11049
}
@@ -113,15 +52,8 @@ class PagerDecoderModule : public ModuleManager::Instance {
11352
gui::menu.removeEntry(name);
11453
// Stop DSP
11554
if (enabled) {
116-
demod.stop();
117-
dcBlock.stop();
118-
fir.stop();
119-
recov.stop();
120-
doubler.stop();
121-
slicer.stop();
122-
dataHandler.stop();
123-
reshape.stop();
124-
diagHandler.stop();
55+
decoder->stop();
56+
decoder.reset();
12557
sigpath::vfoManager.deleteVFO(vfo);
12658
}
12759

@@ -132,36 +64,17 @@ class PagerDecoderModule : public ModuleManager::Instance {
13264

13365
void enable() {
13466
double bw = gui::waterfall.getBandwidth();
135-
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), INPUT_BANDWIDTH, INPUT_SAMPLE_RATE, INPUT_BANDWIDTH, INPUT_BANDWIDTH, true);
136-
vfo->setSnapInterval(250);
137-
138-
// Start DSP
139-
demod.start();
140-
dcBlock.start();
141-
fir.start();
142-
recov.start();
143-
doubler.start();
144-
slicer.start();
145-
dataHandler.start();
146-
reshape.start();
147-
diagHandler.start();
67+
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), 12500, 24000, 12500, 12500, true);
68+
vfo->setSnapInterval(1);
69+
70+
decoder->setVFO(vfo);
71+
decoder->start();
14872

14973
enabled = true;
15074
}
15175

15276
void disable() {
153-
demod.stop();
154-
dcBlock.stop();
155-
fir.stop();
156-
recov.stop();
157-
doubler.stop();
158-
slicer.stop();
159-
dataHandler.stop();
160-
reshape.stop();
161-
diagHandler.stop();
162-
reshape.stop();
163-
diagHandler.stop();
164-
77+
decoder->stop();
16578
sigpath::vfoManager.deleteVFO(vfo);
16679
enabled = false;
16780
}
@@ -170,6 +83,36 @@ class PagerDecoderModule : public ModuleManager::Instance {
17083
return enabled;
17184
}
17285

86+
void selectProtocol(Protocol newProto) {
87+
// Cannot change while disabled
88+
if (!enabled) { return; }
89+
90+
// If the protocol hasn't changed, no need to do anything
91+
if (newProto == proto) { return; }
92+
93+
// Delete current decoder
94+
decoder.reset();
95+
96+
// Create a new decoder
97+
switch (newProto) {
98+
case PROTOCOL_POCSAG:
99+
decoder = std::make_unique<POCSAGDecoder>(name, vfo);
100+
break;
101+
case PROTOCOL_FLEX:
102+
decoder = std::make_unique<FLEXDecoder>(name, vfo);
103+
break;
104+
default:
105+
flog::error("Tried to select unknown pager protocol");
106+
return;
107+
}
108+
109+
// Start the new decoder
110+
decoder->start();
111+
112+
// Save selected protocol
113+
proto = newProto;
114+
}
115+
173116
private:
174117
static void menuHandler(void* ctx) {
175118
PagerDecoderModule* _this = (PagerDecoderModule*)ctx;
@@ -181,54 +124,28 @@ class PagerDecoderModule : public ModuleManager::Instance {
181124
ImGui::LeftLabel("Protocol");
182125
ImGui::FillWidth();
183126
if (ImGui::Combo(("##pager_decoder_proto_" + _this->name).c_str(), &_this->protoId, _this->protocols.txt)) {
184-
// TODO
127+
_this->selectProtocol(_this->protocols.value(_this->protoId));
185128
}
186129

187-
ImGui::SetNextItemWidth(menuWidth);
188-
_this->diag.draw();
189-
190-
if (!_this->enabled) { style::endDisabled(); }
191-
}
192-
193-
static void _dataHandler(uint8_t* data, int count, void* ctx) {
194-
PagerDecoderModule* _this = (PagerDecoderModule*)ctx;
195-
_this->decoder.process(data, count);
196-
}
130+
if (_this->decoder) { _this->decoder->showMenu(); }
197131

198-
static void _diagHandler(float* data, int count, void* ctx) {
199-
PagerDecoderModule* _this = (PagerDecoderModule*)ctx;
200-
float* buf = _this->diag.acquireBuffer();
201-
memcpy(buf, data, count * sizeof(float));
202-
_this->diag.releaseBuffer();
203-
}
132+
ImGui::Button(("Record##pager_decoder_show_" + _this->name).c_str(), ImVec2(menuWidth, 0));
133+
ImGui::Button(("Show Messages##pager_decoder_show_" + _this->name).c_str(), ImVec2(menuWidth, 0));
204134

205-
void messageHandler(pocsag::Address addr, pocsag::MessageType type, const std::string& msg) {
206-
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
135+
if (!_this->enabled) { style::endDisabled(); }
207136
}
208137

209138
std::string name;
210139
bool enabled = true;
211140

141+
Protocol proto = PROTOCOL_INVALID;
212142
int protoId = 0;
213143

214144
OptionList<std::string, Protocol> protocols;
215145

216-
pocsag::Decoder decoder;
217-
218146
// DSP Chain
219147
VFOManager::VFO* vfo;
220-
dsp::demod::Quadrature demod;
221-
dsp::correction::DCBlocker<float> dcBlock;
222-
dsp::tap<float> shape;
223-
dsp::filter::FIR<float, float> fir;
224-
dsp::clock_recovery::MM<float> recov;
225-
dsp::routing::Doubler<float> doubler;
226-
dsp::digital::BinarySlicer slicer;
227-
dsp::buffer::Reshaper<float> reshape;
228-
dsp::sink::Handler<uint8_t> dataHandler;
229-
dsp::sink::Handler<float> diagHandler;
230-
231-
ImGui::SymbolDiagram diag;
148+
std::unique_ptr<Decoder> decoder;
232149

233150
bool showLines = false;
234151
};

decoder_modules/pager_decoder/src/pocsag/decoder.h

+81-2
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,107 @@
11
#pragma once
22
#include "../decoder.h"
3+
#include <signal_path/vfo_manager.h>
34
#include <utils/optionlist.h>
45
#include <gui/widgets/symbol_diagram.h>
56
#include <gui/style.h>
7+
#include <dsp/sink/handler_sink.h>
8+
#include "dsp.h"
9+
#include "pocsag.h"
10+
11+
const char* msgTypes[] = {
12+
"Numeric",
13+
"Unknown (0b01)",
14+
"Unknown (0b10)",
15+
"Alphanumeric",
16+
};
617

718
class POCSAGDecoder : public Decoder {
819
public:
9-
POCSAGDecoder() : diag(0.6, 2400) {
20+
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 2400) {
21+
this->name = name;
22+
this->vfo = vfo;
23+
1024
// Define baudrate options
1125
baudrates.define(512, "512 Baud", 512);
1226
baudrates.define(1200, "1200 Baud", 1200);
1327
baudrates.define(2400, "2400 Baud", 2400);
28+
29+
// Init DSP
30+
vfo->setBandwidthLimits(12500, 12500, true);
31+
vfo->setSampleRate(24000, 12500);
32+
dsp.init(vfo->output, 24000, 2400);
33+
reshape.init(&dsp.soft, 2400.0, (2400 / 30.0) - 2400.0);
34+
dataHandler.init(&dsp.out, _dataHandler, this);
35+
diagHandler.init(&reshape.out, _diagHandler, this);
36+
37+
// Init decoder
38+
decoder.onMessage.bind(&POCSAGDecoder::messageHandler, this);
39+
}
40+
41+
~POCSAGDecoder() {
42+
stop();
1443
}
1544

1645
void showMenu() {
1746
ImGui::LeftLabel("Baudrate");
1847
ImGui::FillWidth();
19-
if (ImGui::Combo(("##pager_decoder_proto_" + name).c_str(), &brId, baudrates.txt)) {
48+
if (ImGui::Combo(("##pager_decoder_pocsag_br_" + name).c_str(), &brId, baudrates.txt)) {
2049
// TODO
2150
}
51+
52+
ImGui::FillWidth();
53+
diag.draw();
54+
}
55+
56+
void setVFO(VFOManager::VFO* vfo) {
57+
this->vfo = vfo;
58+
vfo->setBandwidthLimits(12500, 12500, true);
59+
vfo->setSampleRate(24000, 12500);
60+
dsp.setInput(vfo->output);
61+
}
62+
63+
void start() {
64+
flog::debug("POCSAG start");
65+
dsp.start();
66+
reshape.start();
67+
dataHandler.start();
68+
diagHandler.start();
69+
}
70+
71+
void stop() {
72+
flog::debug("POCSAG stop");
73+
dsp.stop();
74+
reshape.stop();
75+
dataHandler.stop();
76+
diagHandler.stop();
2277
}
2378

2479
private:
80+
static void _dataHandler(uint8_t* data, int count, void* ctx) {
81+
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
82+
_this->decoder.process(data, count);
83+
}
84+
85+
static void _diagHandler(float* data, int count, void* ctx) {
86+
POCSAGDecoder* _this = (POCSAGDecoder*)ctx;
87+
float* buf = _this->diag.acquireBuffer();
88+
memcpy(buf, data, count * sizeof(float));
89+
_this->diag.releaseBuffer();
90+
}
91+
92+
void messageHandler(pocsag::Address addr, pocsag::MessageType type, const std::string& msg) {
93+
flog::debug("[{}]: '{}'", (uint32_t)addr, msg);
94+
}
95+
2596
std::string name;
97+
VFOManager::VFO* vfo;
98+
99+
POCSAGDSP dsp;
100+
dsp::buffer::Reshaper<float> reshape;
101+
dsp::sink::Handler<uint8_t> dataHandler;
102+
dsp::sink::Handler<float> diagHandler;
103+
104+
pocsag::Decoder decoder;
26105

27106
ImGui::SymbolDiagram diag;
28107

0 commit comments

Comments
 (0)