Доработка. Поменял частоты и добавленение FIR-фильтр, его штатно генерирует и грузит ad9361_set_bb_rate()
This commit is contained in:
5
makefile
5
makefile
@@ -25,10 +25,10 @@ $(BIN):
|
||||
mkdir -p $(BIN)
|
||||
|
||||
$(BIN)/transmitter: $(SRC)/transmitter.c $(SRC)/common.c $(SRC)/common.h | $(BIN)
|
||||
$(CC) $(CFLAGS) $(SRC)/transmitter.c $(SRC)/common.c -o $@ $(LDFLAGS) -liio $(LDLIBS)
|
||||
$(CC) $(CFLAGS) $(SRC)/transmitter.c $(SRC)/common.c -o $@ $(LDFLAGS) -lad9361 -liio $(LDLIBS)
|
||||
|
||||
$(BIN)/receiver: $(SRC)/receiver.c $(SRC)/common.c $(SRC)/common.h | $(BIN)
|
||||
$(CC) $(CFLAGS) $(SRC)/receiver.c $(SRC)/common.c -o $@ $(LDFLAGS) -liio $(LDLIBS)
|
||||
$(CC) $(CFLAGS) $(SRC)/receiver.c $(SRC)/common.c -o $@ $(LDFLAGS) -lad9361 -liio $(LDLIBS)
|
||||
|
||||
$(BIN)/ofdm_bench: $(SRC)/ofdm_bench.c | $(BIN)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) $(LDLIBS)
|
||||
@@ -49,6 +49,7 @@ check-env:
|
||||
@which $(CC) >/dev/null || { echo "нет $(CC): sudo apt install gcc-arm-linux-gnueabihf"; exit 1; }
|
||||
@test -f $(XARM)/lib/libliquid.a || { echo "нет libliquid.a: запусти scripts/build_deps.sh"; exit 1; }
|
||||
@test -f $(XARM)/lib/libfftw3f.a || { echo "нет libfftw3f.a: запусти scripts/build_deps.sh"; exit 1; }
|
||||
@test -f $(XARM)/lib/libad9361.a || { echo "нет libad9361.a: запусти scripts/build_deps.sh"; exit 1; }
|
||||
@echo "OK: тулчейн и зависимости на месте"
|
||||
|
||||
clean:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# build_deps.sh — кросс-сборка статических armhf-зависимостей в $XARM
|
||||
# Собирает: FFTW 3.3.10 (single+NEON), liquid-dsp 1.8.0, libiio (local backend)
|
||||
# Собирает: FFTW 3.3.10 (single+NEON), liquid-dsp 1.8.0, libiio (local backend),
|
||||
# libad9361-iio (FIR-фильтр для sample rate < 2.083 MSPS)
|
||||
# Запуск: scripts/build_deps.sh (один раз, ~15-20 мин на RPi4)
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../toolchain.env"
|
||||
@@ -50,11 +51,15 @@ else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [3/4] libiio v0.25 (static, только local backend) ==="
|
||||
echo "=== [3/5] libiio v0.25 (static, только local backend) ==="
|
||||
if [ ! -f "$XARM/lib/libiio.a" ]; then
|
||||
[ -d libiio ] || git clone --depth 1 --branch v0.25 \
|
||||
https://github.com/analogdevicesinc/libiio.git
|
||||
cd libiio
|
||||
|
||||
# ХАК: Полностью перезаписываем статус Threads, чтобы CMake даже не заходил в модуль проверки
|
||||
sed -i '/find_package(Threads/c\set(Threads_FOUND ON)\nset(CMAKE_THREAD_LIBS_INIT "-lpthread")\nset(CMAKE_HAVE_PTHREADS_CREATE ON)\nadd_library(Threads::Threads INTERFACE IMPORTED)\nset_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-lpthread")' CMakeLists.txt
|
||||
|
||||
cat > toolchain-armhf.cmake <<EOF
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
@@ -69,7 +74,9 @@ EOF
|
||||
-DWITH_USB_BACKEND=OFF -DWITH_SERIAL_BACKEND=OFF \
|
||||
-DWITH_XML_BACKEND=OFF -DHAVE_DNS_SD=OFF \
|
||||
-DWITH_TESTS=OFF -DWITH_EXAMPLES=OFF -DWITH_DOC=OFF \
|
||||
-DCSHARP_BINDINGS=OFF -DPYTHON_BINDINGS=OFF
|
||||
-DCSHARP_BINDINGS=OFF -DPYTHON_BINDINGS=OFF \
|
||||
-DWITH_IIOD=OFF -DWITH_LOCAL_CONFIG=OFF -DWITH_ZSTD=OFF \
|
||||
-DTHREADS_PREFER_PTHREAD_FLAG=ON
|
||||
cmake --build build-armhf -j"$(nproc)"
|
||||
cmake --install build-armhf
|
||||
cd "$WORK"
|
||||
@@ -80,6 +87,37 @@ else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [4/4] Итог ==="
|
||||
ls -la "$XARM/lib/" | grep -E "libfftw3f|libliquid|libiio" || true
|
||||
echo "=== [4/5] libad9361-iio (static, FIR для sample rate < 2.083 MSPS) ==="
|
||||
# AD9361 без FIR не принимает rate ниже ~2.083 MSPS (EINVAL). Наш rate 1.92 MSPS
|
||||
# требует загрузки FIR, что делает ad9361_set_bb_rate() из этой библиотеки.
|
||||
if [ ! -f "$XARM/lib/libad9361.a" ]; then
|
||||
[ -d libad9361-iio ] || git clone --depth 1 \
|
||||
https://github.com/analogdevicesinc/libad9361-iio.git
|
||||
cd libad9361-iio
|
||||
|
||||
# Тот же обход кросс-проблемы FindThreads, что и для libiio выше
|
||||
sed -i '/find_package(Threads/c\set(Threads_FOUND ON)\nset(CMAKE_THREAD_LIBS_INIT "-lpthread")\nset(CMAKE_HAVE_PTHREADS_CREATE ON)\nadd_library(Threads::Threads INTERFACE IMPORTED)\nset_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-lpthread")' CMakeLists.txt || true
|
||||
|
||||
cat > toolchain-armhf.cmake <<EOF
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_C_COMPILER ${CROSS}gcc)
|
||||
set(CMAKE_C_FLAGS_INIT "$XCFLAGS")
|
||||
set(CMAKE_FIND_ROOT_PATH $XARM)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
EOF
|
||||
cmake -B build-armhf -DCMAKE_TOOLCHAIN_FILE=toolchain-armhf.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX="$XARM" -DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF -DCMAKE_PREFIX_PATH="$XARM"
|
||||
cmake --build build-armhf -j"$(nproc)"
|
||||
cmake --install build-armhf
|
||||
cd "$WORK"
|
||||
else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [5/5] Итог ==="
|
||||
ls -la "$XARM/lib/" | grep -E "libfftw3f|libliquid|libiio|libad9361" || true
|
||||
echo "Готово. Дальше: make check-env && make"
|
||||
74
src/common.c
74
src/common.c
@@ -63,44 +63,42 @@ int pluto_init(const char *uri, struct iio_context **ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pluto_configure(struct iio_device *phy, long long freq, long long rate,
|
||||
int pluto_configure(struct iio_device *phy, long long freq, long long rate,
|
||||
long long bw, double gain, int is_tx) {
|
||||
if (is_tx) {
|
||||
// Настройка передатчика
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "altvoltage1", true),
|
||||
"frequency", freq);
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "voltage0", true),
|
||||
"sampling_frequency", rate);
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "voltage0", true),
|
||||
"rf_bandwidth", bw);
|
||||
iio_channel_attr_write(
|
||||
iio_device_find_channel(phy, "voltage0", true),
|
||||
"rf_port_select", "A");
|
||||
iio_channel_attr_write_double(
|
||||
iio_device_find_channel(phy, "voltage0", true),
|
||||
"hardwaregain", gain);
|
||||
} else {
|
||||
// Настройка приёмника
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "altvoltage0", true),
|
||||
"frequency", freq);
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "voltage0", false),
|
||||
"sampling_frequency", rate);
|
||||
iio_channel_attr_write_longlong(
|
||||
iio_device_find_channel(phy, "voltage0", false),
|
||||
"rf_bandwidth", bw);
|
||||
iio_channel_attr_write(
|
||||
iio_device_find_channel(phy, "voltage0", false),
|
||||
"gain_control_mode", "manual");
|
||||
iio_channel_attr_write_double(
|
||||
iio_device_find_channel(phy, "voltage0", false),
|
||||
"hardwaregain", gain);
|
||||
iio_channel_attr_write(
|
||||
iio_device_find_channel(phy, "voltage0", false),
|
||||
"rf_port_select", "A_BALANCED");
|
||||
// Частота дискретизации через libad9361: функция сама рассчитывает и
|
||||
// грузит FIR-фильтр. БЕЗ него AD9361 отвергает rate < ~2.083 MSPS с
|
||||
// EINVAL, и чип молча остаётся на 30.72 MSPS — тракт разваливается.
|
||||
if (ad9361_set_bb_rate(phy, (unsigned long)rate) != 0) {
|
||||
LOG_ERROR("ad9361_set_bb_rate(%lld) не удалась (нужен FIR/libad9361)", rate);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Каналы: LO (altvoltageN) и данные (voltage0). Направление у altvoltage
|
||||
// всегда output=true; у voltage0 совпадает с is_tx.
|
||||
struct iio_channel *lo = iio_device_find_channel(
|
||||
phy, is_tx ? "altvoltage1" : "altvoltage0", true);
|
||||
struct iio_channel *ch = iio_device_find_channel(phy, "voltage0", is_tx);
|
||||
if (!lo || !ch) {
|
||||
LOG_ERROR("Каналы ad9361-phy не найдены");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Несущая (LO) — критично, при отказе выходим
|
||||
if (iio_channel_attr_write_longlong(lo, "frequency", freq) < 0) {
|
||||
LOG_ERROR("Установка LO %lld Гц не удалась", freq);
|
||||
return -1;
|
||||
}
|
||||
// Полоса — при отказе предупреждаем, но продолжаем
|
||||
if (iio_channel_attr_write_longlong(ch, "rf_bandwidth", bw) < 0)
|
||||
LOG_ERROR("rf_bandwidth %lld не принят (продолжаю)", bw);
|
||||
|
||||
if (is_tx) {
|
||||
iio_channel_attr_write_double(ch, "hardwaregain", gain);
|
||||
iio_channel_attr_write(ch, "rf_port_select", "A");
|
||||
} else {
|
||||
iio_channel_attr_write(ch, "gain_control_mode", "manual");
|
||||
iio_channel_attr_write_double(ch, "hardwaregain", gain);
|
||||
iio_channel_attr_write(ch, "rf_port_select", "A_BALANCED");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
18
src/common.h
18
src/common.h
@@ -16,6 +16,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <iio.h>
|
||||
#include <ad9361.h>
|
||||
#include <liquid/liquid.h>
|
||||
|
||||
// Параметры OFDM-модуляции
|
||||
@@ -27,14 +28,15 @@
|
||||
#define RS_DATA 223
|
||||
#define RS_ENC 255
|
||||
|
||||
// Параметры радиотракта по умолчанию
|
||||
#define DEFAULT_FREQ 1265000000LL
|
||||
#define DEFAULT_RATE 3840000LL
|
||||
#define DEFAULT_BW 3000000LL
|
||||
// Параметры радиотракта по умолчанию (согласовано с CLAUDE.md/README §6)
|
||||
#define DEFAULT_FREQ 915000000LL
|
||||
#define DEFAULT_RATE 1920000LL // НЕ поднимать: бюджет CPU
|
||||
#define DEFAULT_BW 1500000LL
|
||||
|
||||
// Адреса PlutoSDR
|
||||
#define TX_URI_DEFAULT "ip:192.168.3.1" // адрес Pluto передатчика
|
||||
#define RX_URI_DEFAULT "ip:192.168.2.1" // адрес Pluto приемника
|
||||
// URI PlutoSDR: код исполняется НА плате → контекст local:
|
||||
// (сетевой ip: в статических бинарях недоступен — libiio без network backend)
|
||||
#define TX_URI_DEFAULT "local:"
|
||||
#define RX_URI_DEFAULT "local:"
|
||||
|
||||
// Формат заголовка кадра
|
||||
#define HDR_SIGNATURE_0 0xF0
|
||||
@@ -55,7 +57,7 @@ void print_config(const char *mode, long long freq, long long rate,
|
||||
long long bw, int fec_on);
|
||||
int pluto_init(const char *uri, struct iio_context **ctx,
|
||||
struct iio_device **phy, struct iio_device **dev, int is_tx);
|
||||
void pluto_configure(struct iio_device *phy, long long freq, long long rate,
|
||||
int pluto_configure(struct iio_device *phy, long long freq, long long rate,
|
||||
long long bw, double gain, int is_tx);
|
||||
|
||||
#endif
|
||||
@@ -44,7 +44,9 @@ static int callback(unsigned char *hdr, int hdr_valid,
|
||||
|
||||
if (fec_on && decoder && pay_len >= RS_ENC) {
|
||||
size_t nblocks = pay_len / RS_ENC;
|
||||
if (nblocks == 0 || nblocks > 100) return 0;
|
||||
// recovered[4096] вмещает 4096/RS_DATA = 18 блоков. Битый/чужой кадр
|
||||
// с большим pay_len иначе переполнил бы стек (техдолг #2).
|
||||
if (nblocks == 0 || nblocks > 4096 / RS_DATA) return 0;
|
||||
|
||||
uint8_t recovered[4096];
|
||||
int rs_ok = 1;
|
||||
@@ -115,7 +117,11 @@ int main(int argc, char *argv[]) {
|
||||
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);
|
||||
if (pluto_configure(phy, freq, rate, bw, RX_GAIN, 0) != 0) {
|
||||
LOG_ERROR("Настройка радиотракта не удалась");
|
||||
iio_context_destroy(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
iio_channel_enable(iio_device_find_channel(rx, "voltage0", false));
|
||||
iio_channel_enable(iio_device_find_channel(rx, "voltage1", false));
|
||||
@@ -153,6 +159,8 @@ int main(int argc, char *argv[]) {
|
||||
iio_context_destroy(ctx);
|
||||
return 1;
|
||||
}
|
||||
// Тот же 12-байтовый заголовок, что и на TX (иначе байты 8..11 — мусор)
|
||||
ofdmflexframesync_set_header_len(fs, HDR_SIZE);
|
||||
|
||||
fprintf(stderr, "Приёмник готов. Ожидание сигнала...\n\n");
|
||||
fprintf(stderr, "Кадры | Загол. | CRC | RS испр | Вывод | RSSI | EVM | CFO\n");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* 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
|
||||
* ОПТИМАЛЬНАЯ КОМАНДА ЗАПУСКА (кабель + аттенюатор):
|
||||
* cat test.bin | ./transmitter -f 915000000 -r 1920000 -b 1500000 -g -40 -a 0.2 -p 0 -c rs8 -u local:
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@@ -68,7 +68,11 @@ int main(int argc, char *argv[]) {
|
||||
if (pluto_init(uri, &ctx, &phy, &tx, 1) != 0) return 1;
|
||||
|
||||
// Настройка радиотракта
|
||||
pluto_configure(phy, freq, rate, bw, gain, 1);
|
||||
if (pluto_configure(phy, freq, rate, bw, gain, 1) != 0) {
|
||||
LOG_ERROR("Настройка радиотракта не удалась");
|
||||
iio_context_destroy(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Включение каналов передатчика
|
||||
iio_channel_enable(iio_device_find_channel(tx, "voltage0", true));
|
||||
@@ -89,6 +93,9 @@ int main(int argc, char *argv[]) {
|
||||
ofdmflexframegenprops_init_default(&fgp);
|
||||
fgp.check = LIQUID_CRC_32;
|
||||
ofdmflexframegen fg = ofdmflexframegen_create(OFDM_M, OFDM_CP, OFDM_TAPER, NULL, &fgp);
|
||||
// Наш заголовок 12 Б; по умолчанию liquid шлёт 8 — байты 8..11 (nblocks,
|
||||
// last_block_bytes) без этого в эфир не уходят. RX выставляет то же.
|
||||
ofdmflexframegen_set_header_len(fg, HDR_SIZE);
|
||||
|
||||
// Счётчики статистики
|
||||
uint64_t frames = 0, bytes_tx = 0;
|
||||
|
||||
Reference in New Issue
Block a user