Files
Pluto-SDR/src/frame_tx.c

101 lines
4.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.

// frame_tx.c — реализация phy_tx_frame (вынесено из transmitter.c, этап 0
// roadmap §10 п.7: общий путь кодирования нужен и обратному каналу).
#include "frame_tx.h"
#include "group_fec.h"
void phy_tx_frame(ofdmflexframegen fg, struct iio_buffer *buf, int buf_samples,
fec enc, const uint8_t sig[2], uint32_t seq, uint8_t hdr11,
const uint8_t *pl, size_t n, float amp, int pause_us) {
uint8_t *tx_payload = NULL;
size_t tx_len = 0;
uint8_t hdr[HDR_SIZE] = {0};
if (enc) {
// CRC32 поверх исходных данных ДО RS (техдолг #3). framed[] вмещает
// самый большой легитимный payload — паритетный кадр GF_PAR_PAY.
uint8_t framed[GF_PAR_PAY + 4];
memcpy(framed, pl, n);
// liquid crc_generate_key() не помечает вход const (API-огрех), хотя
// только читает буфер — снимаем const кастом, чтобы -Wextra был чист.
unsigned int crc = crc_generate_key(LIQUID_CRC_32, (unsigned char *)pl, n);
framed[n] = (crc >> 24) & 0xFF;
framed[n + 1] = (crc >> 16) & 0xFF;
framed[n + 2] = (crc >> 8) & 0xFF;
framed[n + 3] = crc & 0xFF;
size_t framed_n = n + 4;
size_t total_blocks = (framed_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) ? framed_n - b * RS_DATA : RS_DATA;
memcpy(blk, framed + b * RS_DATA, bytes);
fec_encode(enc, RS_DATA, blk, tx_payload + b * RS_ENC);
}
hdr[8] = (total_blocks >> 8) & 0xFF; hdr[9] = total_blocks & 0xFF;
hdr[10] = framed_n % RS_DATA;
} else {
tx_len = n;
tx_payload = malloc(tx_len);
memcpy(tx_payload, pl, n);
}
hdr[0] = sig[0]; hdr[1] = sig[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[11] = hdr11; // group-FEC флаги (0 = legacy)
ofdmflexframegen_assemble(fg, hdr, tx_payload, tx_len);
free(tx_payload);
int16_t *out = (int16_t *)iio_buffer_start(buf);
memset(out, 0, (size_t)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++;
}
}
// Только фактически заполненные idx сэмплов (техдолг #5): иначе мёртвый эфир
// и сбитый межкадровый тайминг. push_partial даёт ту же длину, что write.
if (idx > 0) iio_buffer_push_partial(buf, idx);
if (pause_us > 0) usleep(pause_us);
}
int phy_rx_decode(const uint8_t *hdr, const uint8_t *pay, unsigned pay_len,
fec dec, uint8_t *out, size_t out_cap, size_t *out_len) {
if (!dec || pay_len < RS_ENC) return 0;
size_t nblocks = pay_len / RS_ENC;
if (nblocks == 0 || nblocks * RS_DATA > out_cap) return 0;
for (size_t b = 0; b < nblocks; b++)
// fec_decode() liquid не const-correct и «всегда успешен» — код возврата
// бесполезен, целостность проверяем CRC ниже (техдолг #3).
fec_decode(dec, RS_DATA, (unsigned char *)pay + b * RS_ENC,
out + b * RS_DATA);
uint16_t original_len = (uint16_t)((hdr[6] << 8) | hdr[7]);
uint8_t last_block_bytes = hdr[10];
size_t framed_len = (nblocks - 1) * RS_DATA +
(last_block_bytes > 0 ? last_block_bytes : RS_DATA);
if (framed_len > nblocks * RS_DATA) framed_len = nblocks * RS_DATA;
if (original_len == 0 || (size_t)original_len + 4 > framed_len) return 0;
unsigned int rx_crc = crc_generate_key(LIQUID_CRC_32, out, original_len);
unsigned int tx_crc = ((uint32_t)out[original_len] << 24) |
((uint32_t)out[original_len + 1] << 16) |
((uint32_t)out[original_len + 2] << 8) |
(uint32_t)out[original_len + 3];
if (rx_crc != tx_crc) return 0;
*out_len = original_len;
return 1;
}