Skip to content

Commit 554ba2f

Browse files
add ryfi decoder module
1 parent 949fde0 commit 554ba2f

File tree

17 files changed

+1568
-0
lines changed

17 files changed

+1568
-0
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ option(OPT_BUILD_M17_DECODER "Build the M17 decoder module (Dependencies: codec2
4848
option(OPT_BUILD_METEOR_DEMODULATOR "Build the meteor demodulator module (no dependencies required)" ON)
4949
option(OPT_BUILD_PAGER_DECODER "Build the pager decoder module (no dependencies required)" ON)
5050
option(OPT_BUILD_RADIO "Main audio modulation decoder (AM, FM, SSB, etc...)" ON)
51+
option(OPT_BUILD_RYFI_DECODER "RyFi data link decoder" OFF)
5152
option(OPT_BUILD_WEATHER_SAT_DECODER "Build the HRPT decoder module (no dependencies required)" OFF)
5253

5354
# Misc
@@ -260,6 +261,10 @@ if (OPT_BUILD_RADIO)
260261
add_subdirectory("decoder_modules/radio")
261262
endif (OPT_BUILD_RADIO)
262263

264+
if (OPT_BUILD_RYFI_DECODER)
265+
add_subdirectory("decoder_modules/ryfi_decoder")
266+
endif (OPT_BUILD_RYFI_DECODER)
267+
263268
if (OPT_BUILD_WEATHER_SAT_DECODER)
264269
add_subdirectory("decoder_modules/weather_sat_decoder")
265270
endif (OPT_BUILD_WEATHER_SAT_DECODER)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
cmake_minimum_required(VERSION 3.13)
2+
project(ryfi_decoder)
3+
4+
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
5+
6+
include(${SDRPP_MODULE_CMAKE})
7+
8+
target_include_directories(ryfi_decoder PRIVATE "src/")
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include <imgui.h>
2+
#include <config.h>
3+
#include <core.h>
4+
#include <gui/style.h>
5+
#include <gui/gui.h>
6+
#include <signal_path/signal_path.h>
7+
#include <module.h>
8+
#include <filesystem>
9+
#include <dsp/routing/splitter.h>
10+
#include <dsp/buffer/reshaper.h>
11+
#include <dsp/sink/handler_sink.h>
12+
#include <gui/widgets/folder_select.h>
13+
#include <gui/widgets/constellation_diagram.h>
14+
#include "ryfi/receiver.h"
15+
16+
#define CONCAT(a, b) ((std::string(a) + b).c_str())
17+
18+
SDRPP_MOD_INFO{
19+
/* Name: */ "ryfi_decoder",
20+
/* Description: */ "RyFi decoder for SDR++",
21+
/* Author: */ "Ryzerth",
22+
/* Version: */ 0, 1, 0,
23+
/* Max instances */ -1
24+
};
25+
26+
#define INPUT_BANDWIDTH 800000
27+
#define INPUT_SAMPLE_RATE 1500000
28+
#define INPUT_BAUDRATE 720000
29+
30+
#define SYMBOL_DIAG_RATE 30
31+
#define SYMBOL_DIAG_COUNT 1024
32+
33+
class RyFiDecoderModule : public ModuleManager::Instance {
34+
public:
35+
RyFiDecoderModule(std::string name) {
36+
this->name = name;
37+
38+
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, INPUT_BANDWIDTH, INPUT_SAMPLE_RATE, INPUT_BANDWIDTH, INPUT_BANDWIDTH, true);
39+
rx.init(vfo->output, INPUT_BAUDRATE, INPUT_SAMPLE_RATE);
40+
reshape.init(rx.softOut, SYMBOL_DIAG_COUNT, (INPUT_BAUDRATE / SYMBOL_DIAG_RATE) - SYMBOL_DIAG_COUNT);
41+
symSink.init(&reshape.out, symSinkHandler, this);
42+
rx.onPacket.bind(&RyFiDecoderModule::packetHandler, this);
43+
44+
rx.start();
45+
reshape.start();
46+
symSink.start();
47+
48+
gui::menu.registerEntry(name, menuHandler, this, this);
49+
}
50+
51+
~RyFiDecoderModule() {
52+
rx.stop();
53+
reshape.stop();
54+
symSink.stop();
55+
sigpath::vfoManager.deleteVFO(vfo);
56+
gui::menu.removeEntry(name);
57+
}
58+
59+
void postInit() {}
60+
61+
void enable() {
62+
double bw = gui::waterfall.getBandwidth();
63+
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);
64+
65+
rx.setInput(vfo->output);
66+
67+
rx.start();
68+
reshape.start();
69+
symSink.start();
70+
71+
enabled = true;
72+
}
73+
74+
void disable() {
75+
rx.stop();
76+
reshape.stop();
77+
symSink.stop();
78+
79+
sigpath::vfoManager.deleteVFO(vfo);
80+
enabled = false;
81+
}
82+
83+
bool isEnabled() {
84+
return enabled;
85+
}
86+
87+
private:
88+
void packetHandler(ryfi::Packet pkt) {
89+
flog::debug("Got a {} byte packet!", pkt.size());
90+
}
91+
92+
static void menuHandler(void* ctx) {
93+
RyFiDecoderModule* _this = (RyFiDecoderModule*)ctx;
94+
95+
float menuWidth = ImGui::GetContentRegionAvail().x;
96+
97+
if (!_this->enabled) { style::beginDisabled(); }
98+
99+
ImGui::SetNextItemWidth(menuWidth);
100+
_this->constDiagram.draw();
101+
102+
if (!_this->enabled) { style::endDisabled(); }
103+
}
104+
105+
static void symSinkHandler(dsp::complex_t* data, int count, void* ctx) {
106+
RyFiDecoderModule* _this = (RyFiDecoderModule*)ctx;
107+
108+
dsp::complex_t* buf = _this->constDiagram.acquireBuffer();
109+
memcpy(buf, data, 1024 * sizeof(dsp::complex_t));
110+
_this->constDiagram.releaseBuffer();
111+
}
112+
113+
std::string name;
114+
bool enabled = true;
115+
116+
// DSP Chain
117+
VFOManager::VFO* vfo;
118+
ryfi::Receiver rx;
119+
dsp::buffer::Reshaper<dsp::complex_t> reshape;
120+
dsp::sink::Handler<dsp::complex_t> symSink;
121+
122+
ImGui::ConstellationDiagram constDiagram;
123+
};
124+
125+
MOD_EXPORT void _INIT_() {
126+
127+
}
128+
129+
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
130+
return new RyFiDecoderModule(name);
131+
}
132+
133+
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
134+
delete (RyFiDecoderModule*)instance;
135+
}
136+
137+
MOD_EXPORT void _END_() {
138+
139+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "conv_codec.h"
2+
3+
namespace ryfi {
4+
ConvEncoder::ConvEncoder(dsp::stream<uint8_t>* in) {
5+
// Create the convolutional encoder instance
6+
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
7+
8+
// Init the base class
9+
base_type::init(in);
10+
}
11+
12+
ConvEncoder::~ConvEncoder() {
13+
// Destroy the convolutional encoder instance
14+
correct_convolutional_destroy(conv);
15+
}
16+
17+
int ConvEncoder::encode(const uint8_t* in, uint8_t* out, int count) {
18+
// Run convolutional encoder on the data
19+
return correct_convolutional_encode(conv, in, count, out);
20+
}
21+
22+
int ConvEncoder::run() {
23+
int count = base_type::_in->read();
24+
if (count < 0) { return -1; }
25+
26+
count = encode(base_type::_in->readBuf, base_type::out.writeBuf, count);
27+
28+
base_type::_in->flush();
29+
if (!out.swap(count)) { return -1; }
30+
return count;
31+
}
32+
33+
ConvDecoder::ConvDecoder(dsp::stream<dsp::complex_t>* in) {
34+
// Create the convolutional encoder instance
35+
conv = correct_convolutional_create(2, 7, correct_conv_r12_7_polynomial);
36+
37+
// Allocate the soft symbol buffer
38+
soft = dsp::buffer::alloc<uint8_t>(STREAM_BUFFER_SIZE);
39+
40+
// Init the base class
41+
base_type::init(in);
42+
}
43+
44+
ConvDecoder::~ConvDecoder() {
45+
// Destroy the convolutional encoder instance
46+
correct_convolutional_destroy(conv);
47+
48+
// Free the soft symbol buffer
49+
dsp::buffer::free(soft);
50+
}
51+
52+
int ConvDecoder::decode(const dsp::complex_t* in, uint8_t* out, int count) {
53+
// Convert to uint8
54+
const float* _in = (const float*)in;
55+
count *= 2;
56+
for (int i = 0; i < count; i++) {
57+
soft[i] = std::clamp<int>((_in[i] * 127.0f) + 128.0f, 0, 255);
58+
}
59+
60+
// Run convolutional decoder on the data
61+
return correct_convolutional_decode_soft(conv, soft, count, out);
62+
}
63+
64+
int ConvDecoder::run() {
65+
int count = base_type::_in->read();
66+
if (count < 0) { return -1; }
67+
68+
count = decode(base_type::_in->readBuf, base_type::out.writeBuf, count);
69+
70+
base_type::_in->flush();
71+
if (!out.swap(count)) { return -1; }
72+
return count;
73+
}
74+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#pragma once
2+
#include <stdint.h>
3+
#include "dsp/processor.h"
4+
5+
extern "C" {
6+
#include "correct.h"
7+
}
8+
9+
namespace ryfi {
10+
/**
11+
* RyFi Convolutional Encoder.
12+
*/
13+
class ConvEncoder : public dsp::Processor<uint8_t, uint8_t> {
14+
using base_type = dsp::Processor<uint8_t, uint8_t>;
15+
public:
16+
/**
17+
* Create a convolutional encoder specifying an input stream.
18+
* @param in Input stream.
19+
*/
20+
ConvEncoder(dsp::stream<uint8_t>* in = NULL);
21+
22+
// Destructor
23+
~ConvEncoder();
24+
25+
/**
26+
* Encode data.
27+
* @param in Input bytes.
28+
* @param out Output bits.
29+
* @param count Number of input bytes.
30+
* @return Number of output bits.
31+
*/
32+
int encode(const uint8_t* in, uint8_t* out, int count);
33+
34+
private:
35+
int run();
36+
37+
correct_convolutional* conv;
38+
};
39+
40+
/**
41+
* RyFi Convolutional Decoder.
42+
*/
43+
class ConvDecoder : public dsp::Processor<dsp::complex_t, uint8_t> {
44+
using base_type = dsp::Processor<dsp::complex_t, uint8_t>;
45+
public:
46+
/**
47+
* Create a convolutional encoder specifying an input stream.
48+
* @param in Input stream.
49+
*/
50+
ConvDecoder(dsp::stream<dsp::complex_t>* in = NULL);
51+
52+
// Destructor
53+
~ConvDecoder();
54+
55+
/**
56+
* Decode soft symbols.
57+
* @param in Input soft symbols.
58+
* @param out Output bytes.
59+
* @param count Number of input bytes.
60+
* @return Number of output bits.
61+
*/
62+
int decode(const dsp::complex_t* in, uint8_t* out, int count);
63+
64+
private:
65+
int run();
66+
67+
correct_convolutional* conv;
68+
uint8_t* soft = NULL;
69+
};
70+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "frame.h"
2+
3+
namespace ryfi {
4+
int Frame::serialize(uint8_t* bytes) const {
5+
// Write the counter
6+
bytes[0] = (counter >> 8) & 0xFF;
7+
bytes[1] = counter & 0xFF;
8+
9+
// Write the first packet pointer
10+
bytes[2] = (firstPacket >> 8) & 0xFF;
11+
bytes[3] = firstPacket & 0xFF;
12+
13+
// Write the last packet pointer
14+
bytes[4] = (lastPacket >> 8) & 0xFF;
15+
bytes[5] = lastPacket & 0xFF;
16+
17+
// Write the data
18+
memcpy(&bytes[6], content, FRAME_DATA_SIZE);
19+
20+
// Return the length of a serialized frame
21+
return FRAME_SIZE;
22+
}
23+
24+
void Frame::deserialize(const uint8_t* bytes, Frame& frame) {
25+
// Read the counter
26+
frame.counter = (((uint16_t)bytes[0]) << 8) | ((uint16_t)bytes[1]);
27+
28+
// Read the first packet pointer
29+
frame.firstPacket = (((uint16_t)bytes[2]) << 8) | ((uint16_t)bytes[3]);
30+
31+
// Read the last packet pointer
32+
frame.lastPacket = (((uint16_t)bytes[4]) << 8) | ((uint16_t)bytes[5]);
33+
34+
// Read the data
35+
memcpy(frame.content, &bytes[6], FRAME_DATA_SIZE);
36+
}
37+
}

0 commit comments

Comments
 (0)