mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-06-25 12:07:49 +02:00
Switched to new cleaner argument system
This commit is contained in:
@ -4,7 +4,6 @@
|
||||
#include <gui/style.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <module.h>
|
||||
#include <options.h>
|
||||
#include <gui/gui.h>
|
||||
#include <dsp/pll.h>
|
||||
#include <dsp/stream.h>
|
||||
|
21
decoder_modules/kg_sstv_decoder/CMakeLists.txt
Normal file
21
decoder_modules/kg_sstv_decoder/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(kg_sstv_decoder)
|
||||
|
||||
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
|
||||
|
||||
add_library(kg_sstv_decoder SHARED ${SRC})
|
||||
target_link_libraries(kg_sstv_decoder PRIVATE sdrpp_core)
|
||||
set_target_properties(kg_sstv_decoder PROPERTIES PREFIX "")
|
||||
|
||||
target_include_directories(kg_sstv_decoder PRIVATE "src/")
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(kg_sstv_decoder PRIVATE /O2 /Ob2 /std:c++17 /EHsc)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(kg_sstv_decoder PRIVATE -O3 -std=c++17 -Wno-unused-command-line-argument -undefined dynamic_lookup)
|
||||
else ()
|
||||
target_compile_options(kg_sstv_decoder PRIVATE -O3 -std=c++17)
|
||||
endif ()
|
||||
|
||||
# Install directives
|
||||
install(TARGETS kg_sstv_decoder DESTINATION lib/sdrpp/plugins)
|
133
decoder_modules/kg_sstv_decoder/protocol_translated.txt
Normal file
133
decoder_modules/kg_sstv_decoder/protocol_translated.txt
Normal file
@ -0,0 +1,133 @@
|
||||
○ Transmission by MSK and 4L-FSK
|
||||
MSK is a type of FSK method that is a modulation method for digital signals, and is the mark frequency of FSK.
|
||||
Minimize the frequency between the number and the space frequency (Minimum Shift Keying)
|
||||
4L-FSK is a 4-value FSK, and 4 modulation frequencies that can be taken with a type of FSK are provided.
|
||||
This makes it possible to obtain twice the transmission speed compared to MSK.
|
||||
4L-FSK is more susceptible to noise because the frequency interval is narrower than MSK.
|
||||
It also becomes more susceptible to deterioration of transmission line characteristics.
|
||||
There are two types of choices, but when the line condition such as FM is good, the image will be sent quickly, so
|
||||
Or I think you should select 4L-FSK to send high quality images. wireless
|
||||
If the SSB transmission in HF where the line condition is unstable is set to MSK, the data will be as it is.
|
||||
I think it will be.
|
||||
The first pull-down menu from the top of the pull-down menu on the right side of Send Image
|
||||
You can select MSK or 4L-FSK in the new.
|
||||
|
||||
○ Transmission in convolutional code mode
|
||||
The second pull-down menu from the top of the pull-down menu on the right side of Send Image
|
||||
New is the choice of code processing. Here no code processing (NORM) or convolutional code processing
|
||||
Set whether to perform (CONV).
|
||||
When convolutional code processing is performed, it becomes stronger against noise, but the same data is sent.
|
||||
It takes about twice as long to complete.
|
||||
Please select the code processing on a case-by-case basis while checking the transmission status.
|
||||
This setting can be changed even during transmission.
|
||||
|
||||
○ Sending and receiving text messages
|
||||
With KG-STV, a maximum of 510 half-width characters (255 full-width characters) text message can be sent once.
|
||||
You can send sage.
|
||||
To send a text message, text in the input box under Resp BSR
|
||||
And click Send Text on the right.
|
||||
When you receive a text message, the text will be displayed in the box below.
|
||||
|
||||
○ KG-STV transmission standard
|
||||
Modulation format: MSK or composite modulation of MSK and 4-value FSK
|
||||
Modulation speed: 1200baud
|
||||
Modulation frequency: MSK …… Space frequency 1200Hz Mark frequency 1800Hz
|
||||
|
||||
4L-FSK ...
|
||||
'00' 1200Hz
|
||||
'01' 1400Hz
|
||||
'10' 1600Hz
|
||||
'11' 1800Hz
|
||||
|
||||
Bandwidth: 500-2500Hz
|
||||
Error correction: None or Viterbi code (NASA standard K = 7, R=1/2, P=[109, 79] code)
|
||||
Whitening: Yes (add M-sequence code with a period of 127 bits to each bit)
|
||||
Interleaver: None
|
||||
Header: 01 repeat signal is 256 bits
|
||||
Basic code configuration: Synchronous code + 54-bit length information chunk + arbitrary length data chunk
|
||||
Error detection: Yes (CRC 16 CCITT)
|
||||
Synchronous bit: 63-bit M-sequence code
|
||||
Image compression: JPEG compatible (16x16 pixels, thinning 4: 1: 1)
|
||||
Character code: Shift JIS compatible
|
||||
Radio format: F1D (operation in SSB mode)
|
||||
F2D (operation in FM mode)
|
||||
|
||||
Information chunk configuration (system code version '0')
|
||||
|
||||
┌─────┬─────┬───┬───┬───┬───┬────┬──────┬─────┐
|
||||
│ sys │ com │ c │ m │ x │ y │ sc │ size │ CRC │
|
||||
└─────┴─────┴───┴───┴───┴───┴────┴──────┴─────┘
|
||||
0 4 8 9 10 16 22 26 38 54bit
|
||||
|
||||
Sys: system code
|
||||
Com: command code
|
||||
C: sign mode
|
||||
M: Modulation mode
|
||||
X: Image block position (X)
|
||||
Y: Image block position (Y)
|
||||
Sc: JPEG scale size
|
||||
Size: data size
|
||||
CRC: Error detection code
|
||||
|
||||
* Information chunks always perform MSK modulation + convolution processing.
|
||||
|
||||
Data chunk structure (system code version '0')
|
||||
|
||||
┌──────┬─────┐
|
||||
│ data │ CRC │
|
||||
└──────┴─────┘
|
||||
|
||||
* Data chunks are transmitted following the CRC code of the information chunks.
|
||||
|
||||
Command table (system code version '0')
|
||||
┌─────┬────────┐
|
||||
│ Command value │ Operation │ │
|
||||
├─────┼────────┤
|
||||
│ 0 │ text transmission │
|
||||
├─────┼────────┤
|
||||
│ 1 │ Image transmission │ │
|
||||
├─────┼────────┤
|
||||
│ 2 │ BSR response │ │
|
||||
├─────┼────────┤
|
||||
│ │ 3 │ end │ │
|
||||
├─────┼────────┤
|
||||
│ │ 4 │ BSR request │ │
|
||||
├─────┼────────┤
|
||||
│ 5 │ Canceled (suspended) │
|
||||
├─────┼────────┤
|
||||
│ 6 │ call sign │
|
||||
└─────┴────────┘
|
||||
|
||||
* When starting transmission, the header code of 01 shall be transmitted first.
|
||||
* One data format (code configuration) is
|
||||
Synchronous code + information chunk + data chunk
|
||||
It will be. However, the end signal, stop signal, and BSR signal do not include data chunks.
|
||||
stomach.
|
||||
* In the case of image data, this data format is continuous for the number of image blocks.
|
||||
It shall be sent.
|
||||
* In the case of text transmission, it shall be completed in one data format.
|
||||
* When the transmission is completed normally, the end signal shall be transmitted three times at the end.
|
||||
* When the transmission is canceled, the cancellation signal shall be transmitted three times at the end.
|
||||
|
||||
Synchronous code
|
||||
000011100001001000110110010110101110111100110001010100111111010
|
||||
|
||||
Whitening code
|
||||
1110110011000100100111001111100100000100011010101001101101001010000101100001100101111111010110111011110001110100010101110000001
|
||||
|
||||
○ KG-STV needs more experiments
|
||||
KG-STV was born from the creator's own interest in digital image communication.
|
||||
However, there is a lack of practical experience due to the ability of the person himself / herself.
|
||||
Therefore, the actual luck is that the transmission time is slow, the image quality is poor, and it is difficult to receive.
|
||||
I think there are many situations where it is not practical in terms of use.
|
||||
In such a case, I would like to research as a new issue, so by all means
|
||||
We hope that many people will use it and give us their impressions.
|
||||
Inconvenience such as bugs and operational problems until the degree of completion is high after receiving your opinions
|
||||
We apologize for the inconvenience, but thank you for your cooperation.
|
||||
|
||||
Creator: K.G (JJ0OBZ Myoko City, Niigata Prefecture)
|
||||
|
||||
-------------------------------------------------- -------------------------------------------------- --------------------
|
||||
Created and written by K.G k.g8956@ymail.plala.or.jp
|
||||
Today also from the day of the plane http://www2.plala.or.jp/hikokibiyori/
|
||||
-------------------------------------------------- -------------------------------------------------- --------------------
|
280
decoder_modules/kg_sstv_decoder/src/kg_sstv_dsp.h
Normal file
280
decoder_modules/kg_sstv_decoder/src/kg_sstv_dsp.h
Normal file
@ -0,0 +1,280 @@
|
||||
#pragma once
|
||||
#include <dsp/block.h>
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/types.h>
|
||||
#include <dsp/routing.h>
|
||||
#include <dsp/demodulator.h>
|
||||
#include <dsp/sink.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
extern "C" {
|
||||
#include <correct.h>
|
||||
}
|
||||
|
||||
#define KGSSTV_DEVIATION 300
|
||||
#define KGSSTV_BAUDRATE 1200
|
||||
#define KGSSTV_RRC_ALPHA 0.7f
|
||||
#define KGSSTV_4FSK_HIGH_CUT 0.5f
|
||||
|
||||
// const uint8_t KGSSTV_SYNC_WORD[] = {
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
// 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
|
||||
// 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0,
|
||||
// 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0,
|
||||
// 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
// 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
// 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
// 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0
|
||||
// };
|
||||
|
||||
const uint8_t KGSSTV_SYNC_WORD[] = {
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0,
|
||||
1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0
|
||||
};
|
||||
|
||||
const uint8_t KGSSTV_SCRAMBLING[] = {
|
||||
1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
const uint8_t KGSSTV_SCRAMBLING_BYTES[] = {
|
||||
0b11101100, 0b11000100, 0b10011100, 0b11111001, 0b00000100,
|
||||
0b01101010, 0b10011011, 0b01001010, 0b00010110, 0b00011001,
|
||||
0b01111111, 0b01011011, 0b10111100, 0b01110100, 0b01010111,
|
||||
0b00000010
|
||||
};
|
||||
|
||||
static const correct_convolutional_polynomial_t kgsstv_polynomial[] = {0155, 0117};
|
||||
|
||||
#define KGSSTV_SYNC_WORD_SIZE sizeof(KGSSTV_SYNC_WORD)
|
||||
#define KGSSTV_SYNC_SCRAMBLING_SIZE sizeof(KGSSTV_SCRAMBLING)
|
||||
|
||||
namespace kgsstv {
|
||||
// class Slice4FSK : public dsp::generic_block<Slice4FSK> {
|
||||
// public:
|
||||
// Slice4FSK() {}
|
||||
|
||||
// Slice4FSK(dsp::stream<float>* in) { init(in); }
|
||||
|
||||
// void init(dsp::stream<float>* in) {
|
||||
// _in = in;
|
||||
// dsp::generic_block<Slice4FSK>::registerInput(_in);
|
||||
// dsp::generic_block<Slice4FSK>::registerOutput(&out);
|
||||
// dsp::generic_block<Slice4FSK>::_block_init = true;
|
||||
// }
|
||||
|
||||
// void setInput(dsp::stream<float>* in) {
|
||||
// assert(dsp::generic_block<Slice4FSK>::_block_init);
|
||||
// std::lock_guard<std::mutex> lck(dsp::generic_block<Slice4FSK>::ctrlMtx);
|
||||
// dsp::generic_block<Slice4FSK>::tempStop();
|
||||
// dsp::generic_block<Slice4FSK>::unregisterInput(_in);
|
||||
// _in = in;
|
||||
// dsp::generic_block<Slice4FSK>::registerInput(_in);
|
||||
// dsp::generic_block<Slice4FSK>::tempStart();
|
||||
// }
|
||||
|
||||
// int run() {
|
||||
// int count = _in->read();
|
||||
// if (count < 0) { return -1; }
|
||||
|
||||
// float val;
|
||||
// for (int i = 0; i < count; i++) {
|
||||
// val = _in->readBuf[i];
|
||||
|
||||
// out.writeBuf[i * 2] = (val > 0.0f);
|
||||
// if (val > 0.0f) {
|
||||
// out.writeBuf[(i * 2) + 1] = (val > KGSSTV_4FSK_HIGH_CUT);
|
||||
// }
|
||||
// else {
|
||||
// out.writeBuf[(i * 2) + 1] = (val > -KGSSTV_4FSK_HIGH_CUT);
|
||||
// }
|
||||
// }
|
||||
|
||||
// _in->flush();
|
||||
|
||||
// if (!out.swap(count * 2)) { return -1; }
|
||||
// return count;
|
||||
// }
|
||||
|
||||
// dsp::stream<uint8_t> out;
|
||||
|
||||
// private:
|
||||
// dsp::stream<float>* _in;
|
||||
// };
|
||||
|
||||
class Deframer : public dsp::generic_block<Deframer> {
|
||||
public:
|
||||
Deframer() {}
|
||||
|
||||
Deframer(dsp::stream<float>* in) { init(in); }
|
||||
|
||||
void init(dsp::stream<float>* in) {
|
||||
_in = in;
|
||||
|
||||
// TODO: Destroy
|
||||
conv = correct_convolutional_create(2, 7, kgsstv_polynomial);
|
||||
memset(convTmp, 0x00, 1024);
|
||||
|
||||
dsp::generic_block<Deframer>::registerInput(_in);
|
||||
dsp::generic_block<Deframer>::registerOutput(&out);
|
||||
dsp::generic_block<Deframer>::_block_init = true;
|
||||
}
|
||||
|
||||
void setInput(dsp::stream<float>* in) {
|
||||
assert(dsp::generic_block<Deframer>::_block_init);
|
||||
std::lock_guard<std::mutex> lck(dsp::generic_block<Deframer>::ctrlMtx);
|
||||
dsp::generic_block<Deframer>::tempStop();
|
||||
dsp::generic_block<Deframer>::unregisterInput(_in);
|
||||
_in = in;
|
||||
dsp::generic_block<Deframer>::registerInput(_in);
|
||||
dsp::generic_block<Deframer>::tempStart();
|
||||
}
|
||||
|
||||
int run() {
|
||||
int count = _in->read();
|
||||
if (count < 0) { return -1; }
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (syncing) {
|
||||
// If sync broken, reset sync
|
||||
if ((_in->readBuf[i] > 0.0f) && !KGSSTV_SYNC_WORD[match]) {
|
||||
if (++err > 4) {
|
||||
i -= match - 1;
|
||||
match = 0;
|
||||
err = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If full syncword was detected, switch to read mode
|
||||
if (++match == KGSSTV_SYNC_WORD_SIZE) {
|
||||
spdlog::warn("Frame detected");
|
||||
syncing = false;
|
||||
readCount = 0;
|
||||
writeCount = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// // Process symbol
|
||||
// if (!(readCount % 2)) {
|
||||
// int bitOffset = writeCount & 0b111;
|
||||
// int byteOffset = writeCount >> 3;
|
||||
// if (!bitOffset) { convTmp[byteOffset] = 0; }
|
||||
// convTmp[byteOffset] |= _in->readBuf[i] << (7 - bitOffset);
|
||||
// writeCount++;
|
||||
// }
|
||||
|
||||
// Process symbol
|
||||
convTmp[readCount] = std::clamp<int>((_in->readBuf[i] + 1.0f) * 128.0f, 0, 255);
|
||||
|
||||
// When info was read, write data and get back to
|
||||
if (++readCount == 108) {
|
||||
match = 0;
|
||||
err = 0;
|
||||
syncing = true;
|
||||
|
||||
// Descramble
|
||||
for (int j = 0; j < 108; j++) {
|
||||
if (KGSSTV_SCRAMBLING[j]) {
|
||||
convTmp[j] = 255 - convTmp[j];
|
||||
}
|
||||
|
||||
//convTmp[j >> 3] ^= KGSSTV_SCRAMBLING[j] << (7 - (j & 0b111));
|
||||
}
|
||||
|
||||
// Decode convolutional code
|
||||
int convOutCount = correct_convolutional_decode_soft(conv, convTmp, 124, out.writeBuf);
|
||||
|
||||
spdlog::warn("Frames written: {0}, frameBytes: {1}", ++framesWritten, convOutCount);
|
||||
if (!out.swap(7)) {
|
||||
_in->flush();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_in->flush();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
dsp::stream<uint8_t> out;
|
||||
|
||||
private:
|
||||
dsp::stream<float>* _in;
|
||||
correct_convolutional* conv = NULL;
|
||||
uint8_t convTmp[1024];
|
||||
|
||||
int match = 0;
|
||||
int err = 0;
|
||||
int readCount = 0;
|
||||
int writeCount = 0;
|
||||
bool syncing = true;
|
||||
|
||||
int framesWritten = 0;
|
||||
};
|
||||
|
||||
class Decoder : public dsp::generic_hier_block<Decoder> {
|
||||
public:
|
||||
Decoder() {}
|
||||
|
||||
Decoder(dsp::stream<dsp::complex_t>* input, float sampleRate) {
|
||||
init(input, sampleRate);
|
||||
}
|
||||
|
||||
void init(dsp::stream<dsp::complex_t>* input, float sampleRate) {
|
||||
_sampleRate = sampleRate;
|
||||
|
||||
demod.init(input, _sampleRate, KGSSTV_DEVIATION);
|
||||
rrc.init(31, _sampleRate, KGSSTV_BAUDRATE, KGSSTV_RRC_ALPHA);
|
||||
fir.init(&demod.out, &rrc);
|
||||
recov.init(&fir.out, _sampleRate / KGSSTV_BAUDRATE, 1e-6f, 0.01f, 0.01f);
|
||||
doubler.init(&recov.out);
|
||||
|
||||
//slicer.init(&doubler.outA);
|
||||
deframer.init(&doubler.outA);
|
||||
ns2.init(&deframer.out, "kgsstv_out.bin");
|
||||
diagOut = &doubler.outB;
|
||||
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&demod);
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&fir);
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&recov);
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&doubler);
|
||||
//dsp::generic_hier_block<Decoder>::registerBlock(&slicer);
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&deframer);
|
||||
dsp::generic_hier_block<Decoder>::registerBlock(&ns2);
|
||||
|
||||
dsp::generic_hier_block<Decoder>::_block_init = true;
|
||||
}
|
||||
|
||||
void setInput(dsp::stream<dsp::complex_t>* input) {
|
||||
assert(dsp::generic_hier_block<Decoder>::_block_init);
|
||||
demod.setInput(input);
|
||||
}
|
||||
|
||||
dsp::stream<float>* diagOut = NULL;
|
||||
|
||||
private:
|
||||
dsp::FloatFMDemod demod;
|
||||
dsp::RRCTaps rrc;
|
||||
dsp::FIR<float> fir;
|
||||
dsp::MMClockRecovery<float> recov;
|
||||
dsp::StreamDoubler<float> doubler;
|
||||
|
||||
// Slice4FSK slicer;
|
||||
Deframer deframer;
|
||||
dsp::FileSink<uint8_t> ns2;
|
||||
|
||||
|
||||
float _sampleRate;
|
||||
};
|
||||
}
|
193
decoder_modules/kg_sstv_decoder/src/main.cpp
Normal file
193
decoder_modules/kg_sstv_decoder/src/main.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include <imgui.h>
|
||||
#include <config.h>
|
||||
#include <core.h>
|
||||
#include <gui/style.h>
|
||||
#include <gui/gui.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <module.h>
|
||||
#include <filesystem>
|
||||
#include <dsp/pll.h>
|
||||
#include <dsp/stream.h>
|
||||
#include <dsp/demodulator.h>
|
||||
#include <dsp/window.h>
|
||||
#include <dsp/resampling.h>
|
||||
#include <dsp/processing.h>
|
||||
#include <dsp/routing.h>
|
||||
#include <dsp/sink.h>
|
||||
#include <gui/widgets/folder_select.h>
|
||||
#include <gui/widgets/symbol_diagram.h>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include "kg_sstv_dsp.h"
|
||||
|
||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||
|
||||
SDRPP_MOD_INFO{
|
||||
/* Name: */ "kg_sstv_decoder",
|
||||
/* Description: */ "KG-SSTV Digital SSTV Decoder for SDR++",
|
||||
/* Author: */ "Ryzerth",
|
||||
/* Version: */ 0, 1, 0,
|
||||
/* Max instances */ -1
|
||||
};
|
||||
|
||||
ConfigManager config;
|
||||
|
||||
#define INPUT_SAMPLE_RATE 6000
|
||||
|
||||
class M17DecoderModule : public ModuleManager::Instance {
|
||||
public:
|
||||
M17DecoderModule(std::string name) : diag(0.8, 480) {
|
||||
this->name = name;
|
||||
|
||||
// Load config
|
||||
config.acquire();
|
||||
if (!config.conf.contains(name)) {
|
||||
config.conf[name]["showLines"] = false;
|
||||
}
|
||||
showLines = config.conf[name]["showLines"];
|
||||
if (showLines) {
|
||||
diag.lines.push_back(-0.75f);
|
||||
diag.lines.push_back(-0.25f);
|
||||
diag.lines.push_back(0.25f);
|
||||
diag.lines.push_back(0.75f);
|
||||
}
|
||||
config.release(true);
|
||||
|
||||
|
||||
// Initialize VFO
|
||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 3000, INPUT_SAMPLE_RATE, 3000, 3000, true);
|
||||
vfo->setSnapInterval(250);
|
||||
|
||||
// Initialize DSP here
|
||||
decoder.init(vfo->output, INPUT_SAMPLE_RATE);
|
||||
|
||||
reshape.init(decoder.diagOut, 480, 0);
|
||||
diagHandler.init(&reshape.out, _diagHandler, this);
|
||||
|
||||
// Start DSO Here
|
||||
decoder.start();
|
||||
reshape.start();
|
||||
diagHandler.start();
|
||||
|
||||
//stream.start();
|
||||
|
||||
gui::menu.registerEntry(name, menuHandler, this, this);
|
||||
}
|
||||
|
||||
~M17DecoderModule() {
|
||||
gui::menu.removeEntry(name);
|
||||
// Stop DSP Here
|
||||
if (enabled) {
|
||||
decoder.stop();
|
||||
reshape.stop();
|
||||
diagHandler.stop();
|
||||
sigpath::vfoManager.deleteVFO(vfo);
|
||||
}
|
||||
|
||||
sigpath::sinkManager.unregisterStream(name);
|
||||
}
|
||||
|
||||
void postInit() {}
|
||||
|
||||
void enable() {
|
||||
double bw = gui::waterfall.getBandwidth();
|
||||
vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, std::clamp<double>(0, -bw / 2.0, bw / 2.0), 9600, INPUT_SAMPLE_RATE, 9600, 9600, true);
|
||||
vfo->setSnapInterval(250);
|
||||
|
||||
// Set Input of demod here
|
||||
decoder.setInput(vfo->output);
|
||||
|
||||
// Start DSP here
|
||||
decoder.start();
|
||||
reshape.start();
|
||||
diagHandler.start();
|
||||
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
// Stop DSP here
|
||||
decoder.stop();
|
||||
reshape.stop();
|
||||
diagHandler.stop();
|
||||
|
||||
sigpath::vfoManager.deleteVFO(vfo);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
bool isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private:
|
||||
static void menuHandler(void* ctx) {
|
||||
M17DecoderModule* _this = (M17DecoderModule*)ctx;
|
||||
|
||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
if (!_this->enabled) { style::beginDisabled(); }
|
||||
|
||||
ImGui::SetNextItemWidth(menuWidth);
|
||||
_this->diag.draw();
|
||||
|
||||
if (ImGui::Checkbox(CONCAT("Show Reference Lines##m17_showlines_", _this->name), &_this->showLines)) {
|
||||
if (_this->showLines) {
|
||||
_this->diag.lines.push_back(-0.75f);
|
||||
_this->diag.lines.push_back(-0.25f);
|
||||
_this->diag.lines.push_back(0.25f);
|
||||
_this->diag.lines.push_back(0.75f);
|
||||
}
|
||||
else {
|
||||
_this->diag.lines.clear();
|
||||
}
|
||||
config.acquire();
|
||||
config.conf[_this->name]["showLines"] = _this->showLines;
|
||||
config.release(true);
|
||||
}
|
||||
|
||||
if (!_this->enabled) { style::endDisabled(); }
|
||||
}
|
||||
|
||||
static void _diagHandler(float* data, int count, void* ctx) {
|
||||
M17DecoderModule* _this = (M17DecoderModule*)ctx;
|
||||
float* buf = _this->diag.acquireBuffer();
|
||||
memcpy(buf, data, count * sizeof(float));
|
||||
_this->diag.releaseBuffer();
|
||||
}
|
||||
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
|
||||
// DSP Chain
|
||||
VFOManager::VFO* vfo;
|
||||
kgsstv::Decoder decoder;
|
||||
|
||||
dsp::Reshaper<float> reshape;
|
||||
dsp::HandlerSink<float> diagHandler;
|
||||
dsp::stream<float> dummy;
|
||||
|
||||
ImGui::SymbolDiagram diag;
|
||||
|
||||
bool showLines = false;
|
||||
};
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
// Create default recording directory
|
||||
json def = json({});
|
||||
config.setPath(core::args["root"].s() + "/kg_sstv_decoder_config.json");
|
||||
config.load(def);
|
||||
config.enableAutoSave();
|
||||
}
|
||||
|
||||
MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) {
|
||||
return new M17DecoderModule(name);
|
||||
}
|
||||
|
||||
MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
|
||||
delete (M17DecoderModule*)instance;
|
||||
}
|
||||
|
||||
MOD_EXPORT void _END_() {
|
||||
config.disableAutoSave();
|
||||
config.save();
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <module.h>
|
||||
#include <options.h>
|
||||
#include <filesystem>
|
||||
#include <dsp/pll.h>
|
||||
#include <dsp/stream.h>
|
||||
@ -296,7 +295,7 @@ private:
|
||||
MOD_EXPORT void _INIT_() {
|
||||
// Create default recording directory
|
||||
json def = json({});
|
||||
config.setPath(options::opts.root + "/m17_decoder_config.json");
|
||||
config.setPath(core::args["root"].s() + "/m17_decoder_config.json");
|
||||
config.load(def);
|
||||
config.enableAutoSave();
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <module.h>
|
||||
#include <options.h>
|
||||
#include <filesystem>
|
||||
#include <dsp/pll.h>
|
||||
#include <dsp/stream.h>
|
||||
@ -244,14 +243,15 @@ private:
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
// Create default recording directory
|
||||
if (!std::filesystem::exists(options::opts.root + "/recordings")) {
|
||||
std::string root = core::args["root"];
|
||||
if (!std::filesystem::exists(root + "/recordings")) {
|
||||
spdlog::warn("Recordings directory does not exist, creating it");
|
||||
if (!std::filesystem::create_directory(options::opts.root + "/recordings")) {
|
||||
if (!std::filesystem::create_directory(root + "/recordings")) {
|
||||
spdlog::error("Could not create recordings directory");
|
||||
}
|
||||
}
|
||||
json def = json({});
|
||||
config.setPath(options::opts.root + "/meteor_demodulator_config.json");
|
||||
config.setPath(root + "/meteor_demodulator_config.json");
|
||||
config.load(def);
|
||||
config.enableAutoSave();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "radio_module.h"
|
||||
#include <options.h>
|
||||
|
||||
SDRPP_MOD_INFO{
|
||||
/* Name: */ "radio",
|
||||
@ -11,7 +10,7 @@ SDRPP_MOD_INFO{
|
||||
|
||||
MOD_EXPORT void _INIT_() {
|
||||
json def = json({});
|
||||
config.setPath(options::opts.root + "/radio_config.json");
|
||||
config.setPath(core::args["root"].s() + "/radio_config.json");
|
||||
config.load(def);
|
||||
config.enableAutoSave();
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <gui/gui.h>
|
||||
#include <signal_path/signal_path.h>
|
||||
#include <module.h>
|
||||
#include <options.h>
|
||||
|
||||
#include <dsp/pll.h>
|
||||
#include <dsp/stream.h>
|
||||
|
Reference in New Issue
Block a user