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

185 lines
7.9 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.

/**
* transmitter.c — OFDM-передатчик с RS(255,223) FEC для PlutoSDR
*
* ОПТИМАЛЬНАЯ КОМАНДА ЗАПУСКА:
* cat test.bin | ./transmitter -f 1265000000 -r 3840000 -b 2000000 -g -20 -a 0.3 -p 0 -c rs8
*/
#include "common.h"
// Параметры передатчика по умолчанию
#define DEFAULT_GAIN -30.0 // Усиление передатчика: -30 дБ
#define DEFAULT_AMP 0.2f // Амплитуда сигнала
#define DEFAULT_PAUSE 2000 // Пауза между кадрами: 2000 мкс
#define BUF_SAMPLES 16384 // Размер буфера в отсчётах
#define MAX_PAYLOAD 1024 // Максимальный размер полезной нагрузки
// Внешняя переменная флага завершения (определена в common.c)
extern volatile sig_atomic_t stop;
int main(int argc, char *argv[]) {
// Инициализация параметров
long long freq = DEFAULT_FREQ, rate = DEFAULT_RATE, bw = DEFAULT_BW;
double gain = DEFAULT_GAIN;
float amp = DEFAULT_AMP;
const char *uri = TX_URI_DEFAULT;
int pause_us = DEFAULT_PAUSE, use_fec = 1;
// Обработка аргументов командной строки
int opt;
while ((opt = getopt(argc, argv, "f:r:b:g:a:p: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 'g': gain = atof(optarg); break;
case 'a': amp = atof(optarg); break;
case 'p': pause_us = atoi(optarg); break;
case 'u': uri = optarg; break;
case 'c': use_fec = strcmp(optarg, "none") ? 1 : 0; break;
case 'h':
print_usage(argv[0], "ПЕРЕДАТЧИК");
fprintf(stderr, "\nСПЕЦИФИЧНЫЕ ОПЦИИ TX:\n");
fprintf(stderr, " -g УСИЛЕНИЕ Усиление в дБ (по умолчанию: %.0f)\n", DEFAULT_GAIN);
fprintf(stderr, " -a АМПЛИТ. Амплитуда сигнала (по умолчанию: %.2f)\n", DEFAULT_AMP);
fprintf(stderr, " -p ПАУЗА Пауза между кадрами в мкс (по умолчанию: %d)\n", DEFAULT_PAUSE);
fprintf(stderr, "\nОПТИМАЛЬНЫЙ ЗАПУСК:\n");
fprintf(stderr, " cat test.bin | %s -f %lld -r %lld -b %lld -c rs8 > /dev/null\n",
argv[0], DEFAULT_FREQ, DEFAULT_RATE, DEFAULT_BW);
return 0;
default: return 1;
}
}
// Настройка обработчиков сигналов
setup_signal_handlers();
// Вывод конфигурации
print_config("ПЕРЕДАТЧИК", freq, rate, bw, use_fec);
fprintf(stderr, "Усиление: %.0f дБ\n", gain);
fprintf(stderr, "Амплитуда: %.2f\n", amp);
fprintf(stderr, "Пауза: %d мкс\n", pause_us);
fprintf(stderr, "URI: %s\n", uri);
fprintf(stderr, "═══════════════════════════════════════════════════\n");
// Инициализация PlutoSDR
struct iio_context *ctx = NULL;
struct iio_device *phy = NULL, *tx = NULL;
if (pluto_init(uri, &ctx, &phy, &tx, 1) != 0) return 1;
// Настройка радиотракта
pluto_configure(phy, freq, rate, bw, gain, 1);
// Включение каналов передатчика
iio_channel_enable(iio_device_find_channel(tx, "voltage0", true));
iio_channel_enable(iio_device_find_channel(tx, "voltage1", true));
// Создание буфера передачи
struct iio_buffer *buf = iio_device_create_buffer(tx, BUF_SAMPLES, false);
if (!buf) {
LOG_ERROR("Ошибка создания буфера передачи");
iio_context_destroy(ctx);
return 1;
}
// Инициализация FEC и OFDM
fec enc = use_fec ? fec_create(LIQUID_FEC_RS_M8, NULL) : NULL;
ofdmflexframegenprops_s fgp;
ofdmflexframegenprops_init_default(&fgp);
fgp.check = LIQUID_CRC_32;
ofdmflexframegen fg = ofdmflexframegen_create(OFDM_M, OFDM_CP, OFDM_TAPER, NULL, &fgp);
// Счётчики статистики
uint64_t frames = 0, bytes_tx = 0;
uint32_t seq = 0;
time_t last = time(NULL);
fprintf(stderr, " Передатчик готов. Ожидание данных...\n\n");
// Основной цикл передачи
while (!stop) {
uint8_t raw[MAX_PAYLOAD];
size_t n = fread(raw, 1, MAX_PAYLOAD, stdin);
if (!n) {
if (feof(stdin) || stop) break;
usleep(10000);
continue;
}
uint8_t *tx_payload = NULL;
size_t tx_len = 0;
uint8_t hdr[HDR_SIZE] = {0};
// Кодирование данных
if (enc) {
size_t total_blocks = (n + RS_DATA - 1) / RS_DATA;
tx_len = total_blocks * RS_ENC;
tx_payload = malloc(tx_len);
for (size_t b = 0; b < total_blocks; b++) {
uint8_t blk[RS_DATA] = {0};
size_t bytes = (b == total_blocks - 1) ? n - b * RS_DATA : RS_DATA;
memcpy(blk, raw + b * RS_DATA, bytes);
fec_encode(enc, RS_DATA, blk, tx_payload + b * RS_ENC);
}
// Формирование заголовка
hdr[0] = HDR_SIGNATURE_0; hdr[1] = HDR_SIGNATURE_1;
hdr[2] = (seq >> 24) & 0xFF; hdr[3] = (seq >> 16) & 0xFF;
hdr[4] = (seq >> 8) & 0xFF; hdr[5] = seq & 0xFF;
hdr[6] = (n >> 8) & 0xFF; hdr[7] = n & 0xFF;
hdr[8] = (total_blocks >> 8) & 0xFF; hdr[9] = total_blocks & 0xFF;
hdr[10] = n % RS_DATA; hdr[11] = 0;
} else {
tx_len = n;
tx_payload = malloc(tx_len);
memcpy(tx_payload, raw, n);
hdr[0] = HDR_SIGNATURE_0; hdr[1] = HDR_SIGNATURE_1;
hdr[2] = (seq >> 24) & 0xFF; hdr[3] = (seq >> 16) & 0xFF;
hdr[4] = (seq >> 8) & 0xFF; hdr[5] = seq & 0xFF;
hdr[6] = (n >> 8) & 0xFF; hdr[7] = n & 0xFF;
}
// Сборка OFDM-кадра
ofdmflexframegen_assemble(fg, hdr, tx_payload, tx_len);
free(tx_payload);
// Формирование выходного сигнала
int16_t *out = (int16_t *)iio_buffer_start(buf);
memset(out, 0, BUF_SAMPLES * 2 * sizeof(int16_t));
int idx = 0, done = 0;
float complex symb[OFDM_M + OFDM_CP];
while (!done && (idx + OFDM_M + OFDM_CP) <= BUF_SAMPLES) {
done = ofdmflexframegen_write(fg, symb, OFDM_M + OFDM_CP);
for (int i = 0; i < OFDM_M + OFDM_CP; i++) {
out[2 * idx] = (int16_t)(crealf(symb[i]) * 32767 * amp);
out[2 * idx + 1] = (int16_t)(cimagf(symb[i]) * 32767 * amp);
idx++;
}
}
if (idx > 0) iio_buffer_push(buf);
// Обновление статистики
frames++; bytes_tx += n; seq++;
if (time(NULL) > last) {
fprintf(stderr, "\r📤 Передано: %llu кадров, %llu байт",
(unsigned long long)frames, (unsigned long long)bytes_tx);
fflush(stderr);
last = time(NULL);
}
if (pause_us > 0) usleep(pause_us);
}
fprintf(stderr, "\nПередача завершена: %llu кадров, %llu байт\n",
(unsigned long long)frames, (unsigned long long)bytes_tx);
// Освобождение ресурсов
if (enc) fec_destroy(enc);
ofdmflexframegen_destroy(fg);
iio_buffer_destroy(buf);
iio_context_destroy(ctx);
return 0;
}