Этап 2. Новый модуль обратного канала
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "common.h"
|
||||
#include "group_fec.h"
|
||||
#include "frame_tx.h"
|
||||
#include "feedback.h" // приём STATUS обратного канала (этап 2, §10 п.7)
|
||||
|
||||
// Параметры передатчика по умолчанию
|
||||
#define DEFAULT_GAIN -30.0 // Усиление передатчика: -30 дБ
|
||||
@@ -24,6 +25,63 @@ extern volatile sig_atomic_t stop;
|
||||
// hdr[0..1]; END/STATUS обратного канала используют другие сигнатуры, §10 п.7).
|
||||
static const uint8_t SIG_DATA[2] = { HDR_SIGNATURE_0, HDR_SIGNATURE_1 };
|
||||
|
||||
// --- Обратный канал: приём STATUS на 868 (этап 2, §10 п.7) --------------
|
||||
// Отдельный поток на ядре 1 (данные TX — ядро 0). Свой синхронизатор с
|
||||
// header_len 12 и свой RS-декодер. Пока ТОЛЬКО логирует; ARQ-реакция (ретрансмит
|
||||
// по NACK) — этап 3. Слушает rxfb — второй cf-девайс, открытый pluto_init_fdd.
|
||||
#define FB_RX_BUF_SAMPLES 16384
|
||||
|
||||
static struct iio_buffer *g_fbrx_buf = NULL;
|
||||
static ofdmflexframesync g_fbrx_fs = NULL;
|
||||
static fec g_fbrx_dec = NULL;
|
||||
static volatile sig_atomic_t fb_stop = 0;
|
||||
static uint64_t g_fb_status_rx = 0; // сколько STATUS декодировано (для итога)
|
||||
|
||||
// callback синхронизатора обратного канала: отсев по сигнатуре F0 55, RS+CRC
|
||||
// декод, распаковка и лог. Этап 2 — без действий над состоянием передачи.
|
||||
static int fb_callback(unsigned char *hdr, int hdr_valid,
|
||||
unsigned char *pay, unsigned int pay_len,
|
||||
int pay_valid, framesyncstats_s stats, void *user) {
|
||||
(void)pay_valid; (void)stats; (void)user;
|
||||
if (!hdr_valid) return 0;
|
||||
if (hdr[0] != FB_SIG_0 || hdr[1] != FB_SIG_1) return 0; // не STATUS
|
||||
|
||||
static uint8_t dec[RS_ENC * 2]; // STATUS ≤ 1 RS-блок, запас на будущее
|
||||
size_t dlen = 0;
|
||||
if (!phy_rx_decode(hdr, pay, pay_len, g_fbrx_dec, dec, sizeof(dec), &dlen))
|
||||
return 0; // RS/CRC не прошли — молча дропаем
|
||||
fb_status_t st;
|
||||
if (fb_status_unpack(dec, dlen, &st) != 0) return 0;
|
||||
|
||||
g_fb_status_rx++;
|
||||
fprintf(stderr, "\n[FB] highest=%u rx_frames=%u overruns=%u nack=%u{",
|
||||
st.highest_seq, st.rx_frames, st.overruns, st.nack_cnt);
|
||||
for (int i = 0; i < st.nack_cnt && i < 8; i++)
|
||||
fprintf(stderr, "%s%u", i ? "," : "", st.nack[i]);
|
||||
if (st.nack_cnt > 8) fprintf(stderr, ",…");
|
||||
fprintf(stderr, "}\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *fb_rx_thread(void *arg) {
|
||||
(void)arg;
|
||||
pin_to_cpu(1);
|
||||
static liquid_float_complex conv[FB_RX_BUF_SAMPLES];
|
||||
while (!fb_stop && !stop) {
|
||||
ssize_t nb = iio_buffer_refill(g_fbrx_buf);
|
||||
if (nb < 0) { if (fb_stop || stop) break; usleep(500); continue; }
|
||||
int16_t *bb = (int16_t *)iio_buffer_start(g_fbrx_buf);
|
||||
int ns = (iio_buffer_end(g_fbrx_buf) - iio_buffer_start(g_fbrx_buf))
|
||||
/ (int)sizeof(int16_t) / 2;
|
||||
if (ns > FB_RX_BUF_SAMPLES) ns = FB_RX_BUF_SAMPLES;
|
||||
for (int i = 0; i < ns; i++)
|
||||
conv[i] = ((float)bb[2*i] / 2048.0f) +
|
||||
((float)bb[2*i+1] / 2048.0f) * _Complex_I;
|
||||
ofdmflexframesync_execute(g_fbrx_fs, conv, ns);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Инициализация параметров
|
||||
long long freq = DEFAULT_FREQ, rate = DEFAULT_RATE, bw = DEFAULT_BW;
|
||||
@@ -74,7 +132,7 @@ int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "Пауза: %d мкс\n", pause_us);
|
||||
fprintf(stderr, "Group-FEC: %s\n", group_fec ? "16+2 (§10 п.6)" : "выкл");
|
||||
fprintf(stderr, "Дуплекс: %s\n", fb_freq
|
||||
? "FDD (обратный RX настроен, трафик — этап 2)" : "симплекс");
|
||||
? "FDD (обратный канал: приём STATUS на 868)" : "симплекс");
|
||||
if (fb_freq) fprintf(stderr, "Обр. RX LO: %.1f МГц\n", fb_freq / 1e6);
|
||||
fprintf(stderr, "URI: %s\n", uri);
|
||||
fprintf(stderr, "═══════════════════════════════════════════════════\n");
|
||||
@@ -122,6 +180,29 @@ int main(int argc, char *argv[]) {
|
||||
// last_block_bytes) без этого в эфир не уходят. RX выставляет то же.
|
||||
ofdmflexframegen_set_header_len(fg, HDR_SIZE);
|
||||
|
||||
// Обратный канал (этап 2): поток fb_rx слушает STATUS на 868 (rxfb). Пока
|
||||
// только логирует. Данные TX уводим на ядро 0, fb_rx — на ядро 1 (§affinity).
|
||||
pthread_t fb_tid;
|
||||
int fb_started = 0;
|
||||
if (fb_freq) {
|
||||
iio_channel_enable(iio_device_find_channel(rxfb, "voltage0", false));
|
||||
iio_channel_enable(iio_device_find_channel(rxfb, "voltage1", false));
|
||||
g_fbrx_buf = iio_device_create_buffer(rxfb, FB_RX_BUF_SAMPLES, false);
|
||||
if (!g_fbrx_buf) {
|
||||
LOG_ERROR("Буфер обратного канала не создан — STATUS не принимаются");
|
||||
} else {
|
||||
g_fbrx_fs = ofdmflexframesync_create(OFDM_M, OFDM_CP, OFDM_TAPER,
|
||||
NULL, fb_callback, NULL);
|
||||
ofdmflexframesync_set_header_len(g_fbrx_fs, HDR_SIZE);
|
||||
g_fbrx_dec = fec_create(LIQUID_FEC_RS_M8, NULL);
|
||||
pin_to_cpu(0); // TX-данные — ядро 0
|
||||
pthread_create(&fb_tid, NULL, fb_rx_thread, NULL);
|
||||
fb_started = 1;
|
||||
fprintf(stderr, "Обратный канал: слушаю STATUS на %.1f МГц (ядро 1)\n",
|
||||
fb_freq / 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
// Счётчики статистики
|
||||
uint64_t frames = 0, bytes_tx = 0;
|
||||
uint32_t seq = 0;
|
||||
@@ -207,10 +288,22 @@ int main(int argc, char *argv[]) {
|
||||
usleep(100000); // ~4 kernel-буфера при 1.92 MSPS ≈ 35 мс, с запасом
|
||||
}
|
||||
|
||||
// Остановить обратный канал: fb_rx выходит по fb_stop в течение одного
|
||||
// refill (~8.5 мс на 16384 сэмпл @ 1.92 Msps), затем join.
|
||||
if (fb_started) {
|
||||
fb_stop = 1;
|
||||
pthread_join(fb_tid, NULL);
|
||||
fprintf(stderr, "Обратный канал: принято STATUS: %llu\n",
|
||||
(unsigned long long)g_fb_status_rx);
|
||||
}
|
||||
|
||||
// Освобождение ресурсов
|
||||
if (enc) fec_destroy(enc);
|
||||
ofdmflexframegen_destroy(fg);
|
||||
iio_buffer_destroy(buf);
|
||||
if (g_fbrx_fs) ofdmflexframesync_destroy(g_fbrx_fs);
|
||||
if (g_fbrx_dec) fec_destroy(g_fbrx_dec);
|
||||
if (g_fbrx_buf) iio_buffer_destroy(g_fbrx_buf);
|
||||
iio_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user