Files
go-service/SDR/reciever.c
2026-06-03 14:23:30 +03:00

206 lines
7.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* receiver.c — OFDM-приёмник с RS(255,223) FEC и частотной коррекцией
*/
#include "common.h"
#define BUF_SAMPLES 32768
#define MAX_FRAME_SAMPLES (1 << 16)
#define RX_GAIN 50.0
#define CFO_FILTER_ALPHA 0.95f
#define CFO_MAX_VALID 0.5f
extern volatile sig_atomic_t stop;
static uint64_t calls = 0, hdr_ok = 0, crc_raw = 0;
static uint64_t rs_saved = 0, crc_final = 0, total_bytes = 0;
static float rssi = -100, evm = 0;
static float cfo_est = 0.0f;
static nco_crcf nco = NULL;
static fec decoder = NULL;
static int fec_on = 0;
static liquid_float_complex frame[MAX_FRAME_SAMPLES];
static int callback(unsigned char *hdr, int hdr_valid,
unsigned char *pay, unsigned int pay_len,
int pay_valid, framesyncstats_s stats,
void *user) {
(void)user;
calls++;
rssi = stats.rssi;
evm = stats.evm;
// Обновляем CFO только если NCO инициализирован
if (nco && fabsf(stats.cfo) < CFO_MAX_VALID) {
cfo_est = CFO_FILTER_ALPHA * cfo_est + (1.0f - CFO_FILTER_ALPHA) * stats.cfo;
nco_crcf_set_frequency(nco, cfo_est);
}
if (!hdr_valid) return 0;
hdr_ok++;
if (pay_valid) crc_raw++;
uint16_t original_len = (hdr[6] << 8) | hdr[7];
uint8_t last_block_bytes = hdr[10];
if (fec_on && decoder && pay_len >= RS_ENC) {
size_t nblocks = pay_len / RS_ENC;
if (nblocks == 0 || nblocks > 100) return 0;
uint8_t recovered[4096];
int rs_ok = 1;
for (size_t b = 0; b < nblocks; b++) {
if (fec_decode(decoder, RS_DATA, pay + b * RS_ENC,
recovered + b * RS_DATA) != 0) {
rs_ok = 0; break;
}
}
if (rs_ok) {
if (!pay_valid) rs_saved++;
size_t out_len = (nblocks - 1) * RS_DATA +
(last_block_bytes > 0 ? last_block_bytes : RS_DATA);
if (out_len > nblocks * RS_DATA) out_len = nblocks * RS_DATA;
if (out_len > original_len) out_len = original_len;
if (out_len > 0) {
fwrite(recovered, 1, out_len, stdout);
fflush(stdout);
total_bytes += out_len;
crc_final++;
}
}
} else if (pay_valid && original_len > 0 && original_len <= pay_len) {
fwrite(pay, 1, original_len, stdout);
fflush(stdout);
total_bytes += original_len;
crc_final++;
}
return 0;
}
int main(int argc, char *argv[]) {
long long freq = DEFAULT_FREQ, rate = DEFAULT_RATE, bw = DEFAULT_BW;
const char *uri = RX_URI_DEFAULT;
const char *fec_opt = "rs8";
int opt;
while ((opt = getopt(argc, argv, "f:r:b:u:c:h")) != -1) {
switch (opt) {
case 'f': freq = atoll(optarg); break;
case 'r': rate = atoll(optarg); break;
case 'b': bw = atoll(optarg); break;
case 'u': uri = optarg; break;
case 'c': fec_opt = optarg; break;
case 'h':
print_usage(argv[0], "ПРИЁМНИК");
fprintf(stderr, "\nСПЕЦИФИЧНЫЕ ОПЦИИ RX:\n");
fprintf(stderr, " Усиление фиксированное: %.0f дБ\n", RX_GAIN);
fprintf(stderr, " Частотная коррекция: адаптивная (α=%.2f)\n", CFO_FILTER_ALPHA);
fprintf(stderr, "\nОПТИМАЛЬНЫЙ ЗАПУСК:\n");
fprintf(stderr, " %s -f %lld -r %lld -b %lld -c rs8 > output.bin\n",
argv[0], DEFAULT_FREQ, DEFAULT_RATE, DEFAULT_BW);
return 0;
default: return 1;
}
}
fec_on = !strcmp(fec_opt, "rs8");
setup_signal_handlers();
print_config("ПРИЁМНИК", freq, rate, bw, fec_on);
fprintf(stderr, "Усиление: %.0f дБ (ручное)\n", RX_GAIN);
fprintf(stderr, "CFO фильтр: α=%.2f\n", CFO_FILTER_ALPHA);
fprintf(stderr, "URI: %s\n", uri);
fprintf(stderr, "═══════════════════════════════════════════════════\n");
struct iio_context *ctx = NULL;
struct iio_device *phy = NULL, *rx = NULL;
if (pluto_init(uri, &ctx, &phy, &rx, 0) != 0) return 1;
pluto_configure(phy, freq, rate, bw, RX_GAIN, 0);
iio_channel_enable(iio_device_find_channel(rx, "voltage0", false));
iio_channel_enable(iio_device_find_channel(rx, "voltage1", false));
struct iio_buffer *buf = iio_device_create_buffer(rx, BUF_SAMPLES, false);
if (!buf) {
fprintf(stderr, "Ошибка создания буфера приёма\n");
iio_context_destroy(ctx);
return 1;
}
// Инициализация FEC
if (fec_on) {
decoder = fec_create(LIQUID_FEC_RS_M8, NULL);
if (!decoder) {
fprintf(stderr, "Ошибка создания FEC-декодера\n");
}
}
// Инициализация NCO для частотной коррекции
nco = nco_crcf_create(LIQUID_NCO);
if (!nco) {
fprintf(stderr, "Ошибка создания NCO\n");
} else {
nco_crcf_set_frequency(nco, 0.0f);
}
ofdmflexframesync fs = ofdmflexframesync_create(
OFDM_M, OFDM_CP, OFDM_TAPER, NULL, callback, NULL);
if (!fs) {
fprintf(stderr, "Ошибка создания OFDM-синхронизатора\n");
if (decoder) fec_destroy(decoder);
if (nco) nco_crcf_destroy(nco);
iio_buffer_destroy(buf);
iio_context_destroy(ctx);
return 1;
}
fprintf(stderr, "Приёмник готов. Ожидание сигнала...\n\n");
fprintf(stderr, "Кадры | Загол. | CRC | RS испр | Вывод | RSSI | EVM | CFO\n");
fprintf(stderr, "--------+--------+------+---------+--------+-------+-------+----------\n");
time_t last = time(NULL);
while (!stop) {
ssize_t n = iio_buffer_refill(buf);
if (n < 0) { usleep(500); continue; }
int16_t *bb = (int16_t *)iio_buffer_start(buf);
int ns = (iio_buffer_end(buf) - iio_buffer_start(buf)) / sizeof(int16_t) / 2;
if (ns > MAX_FRAME_SAMPLES) ns = MAX_FRAME_SAMPLES;
for (int i = 0; i < ns; i++) {
frame[i] = ((float)bb[2*i] / 2048.0f) +
((float)bb[2*i+1] / 2048.0f) * _Complex_I;
if (nco) {
nco_crcf_mix_down(nco, frame[i], &frame[i]);
nco_crcf_step(nco);
}
}
if (nco) nco_crcf_set_phase(nco, 0.0f);
ofdmflexframesync_execute(fs, frame, ns);
if (time(NULL) > last) {
fprintf(stderr, "\r%6llu | %5llu | %4llu | %6llu | %6llu | %+5.0f | %+5.1f | %+8.4f",
(unsigned long long)calls, (unsigned long long)hdr_ok,
(unsigned long long)crc_raw, (unsigned long long)rs_saved,
(unsigned long long)crc_final, rssi, evm, cfo_est);
fflush(stderr);
last = time(NULL);
}
}
fprintf(stderr, "\n\nПРИЁМ ЗАВЕРШЁН\n");
fprintf(stderr, "Кадров: %llu | Заголовков: %llu | CRC: %llu | RS испр: %llu | Вывод: %llu | Байт: %llu\n",
(unsigned long long)calls, (unsigned long long)hdr_ok,
(unsigned long long)crc_raw, (unsigned long long)rs_saved,
(unsigned long long)crc_final, (unsigned long long)total_bytes);
if (decoder) fec_destroy(decoder);
if (nco) nco_crcf_destroy(nco);
ofdmflexframesync_destroy(fs);
iio_buffer_destroy(buf);
iio_context_destroy(ctx);
return 0;
}