101 lines
4.7 KiB
C
101 lines
4.7 KiB
C
// 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;
|
||
}
|