
Прошлую свою заметку закончил на желании разобраться как управлять передачей на LibreSDR и организовать вывод PTT. Некоторым хитрым образом это удалось сделать. Кроме того, исследовал возможность писать на Rust для LibreSDR с использованием библиотеки libiio. Получилось сделать автономный CW маяк, работающий прям на LibreSDR без использования других компьютеров.
Обработка сигнала передачи
Начну с темы управления передачей в AD9361. У микросхемы есть отдельные выводы включения режима передачи, а кроме того, можно включить режим передачи дав команду по интерфейсу SPI. Первый режим является самым быстрым способом включения передачи и используется в требовательных к таймингам приложениях, типа передачи LTE. Асинхронный режим управления по SPI используется в большинстве случаев, когда высокая скорость переключения не нужна. Подробнее можно почитать об этом здесь.
Однако трансивер обычно работает в дуплексном режиме и, вообще говоря, говорить о включении режима передачи можно только условно. Таким образом, чтоб задействовать управление режимом передачи нужно сначала перевести микросхему в полудуплексный режим. Но интересующие меня радиолюбительские программы, прежде всего SDR Console, работают иначе. Как оказалось, вместо управления режимом передачи штатным и документированным для AD9361 способом, режим включения передачи определяется просто уровнем ослабления выходного сигнала LibreSDR. Да-да, именно ослаблением, я не оговорился. Существует управляющий параметр hardwaregain, который определяет аттенюацию выходного сигнала от примерно -90 дБ до 0 дБ (максимальная выходная мощность).
Программа SDR Console при нажатии кнопки передачи PTT устанавливает уровень аттенюации на LibreSDR в зависимости от выбора пользователя от -39 дБ до 0 дБ. А при отпускании кнопки передачи устанавливает стандартное значение -40 дБ. Так что передача на самом деле может полностью не прекращаться, просто уровень выходного сигнала устанавливается очень низкого уровня.

Этой особенностью пользуются разработчики прошивок для ADALM Pluto. Вместо того, чтоб менять драйверы AD9361, придумали шелл скрипт, который следит за изменением значения hardwaregain и в соответствие с ним устанавливает выходной сигнал PTT управления внешним усилителем. Достоинством такого подхода является простота реализации, а недостатком невозможность практически работать в режиме телеграфа и вероятность появления гонок. Надо понимать, что при доступе к переменной hardwaregain не используется какой-либо режим блокировок и синхронизации процессов, поэтому скрипт может неверно интерпретировать значение параметра.
В итоге я не стал изобретать велосипед, а просто утащил из прошивки F5OEO к себе готовый скрипт, который в моём варианте выглядит так:
#!/bin/sh
dev=0
ptton()
{
echo 1 > /sys/class/leds/led1:red/brightness
}
pttoff()
{
echo 0 > /sys/class/leds/led1:red/brightness
}
echo manual_tx_quad > /sys/bus/iio/devices/iio:device$dev/calib_mode
pttoff
while :
do
inotifywait -e modify /sys/bus/iio/devices/iio:device$dev/out_voltage0_hardwaregain
gain=$(cat /sys/bus/iio/devices/iio:device$dev/out_voltage0_hardwaregain)
gain=${gain::-4}
if [ "`echo "${gain} <= -40" | bc`" -eq 1 ]; then
echo "SdrConsole PTT OFF"
pttoff
else
if [ "$gain" = "0.00000" ] ; then
sleep 2
gain=$(cat /sys/bus/iio/devices/iio:device$dev/out_voltage0_hardwaregain)
if [ "$gain" = "0.000000 dB" ] ; then
echo "SdrConsole Power Max PTT ON"
ptton
fi
else
echo "SdrConsole PTT ON"
ptton
fi
fi
done
Скрипт использует программу inotifywait , которой нет в стандартной прошивке. Пришлось включить в настройках buildroot включение в сборку этой утилиты. Этот скрипт я поставил в автозапуск при включении LibreSDR, так что теперь есть возможность управлять внешним усилителем. Вывел сигнал PTT на GPIO2, а в devicetree обозвал этот сигнал светодиодом led1:red для простоты управления.
Собранную прошивку я разместил на гитхабе здесь в разделе релизов. Для интересующихся исходниками прошивки там же есть все файлы, которые я изменил в прошивке по сравнению с тем, что есть в варианте hz12opensource.
Радиомаяк на Rust
Одним из любимых занятий радиолюбителей, конструирующих передающую аппаратуру, является создание телеграфных радиомаяков. Такой маяк в бесконечном цикле передает на заданной частоте свой позывной. Удобная штука для определения условий прохождения сигнала, опытов с антеннами и прочих радиолюбительских развлечений. Это такой же обязательный проект как помигать светодиодом на ардуино. Поэтому у меня появилось желание сделать что-то подобное для LibreSDR. Чтоб задача не была уж совсем тривиальной, я решил написать программу на языке Rust.
Встречающиеся в интернете примеры программ для ADALM Pluto SDR, которого имитирует наш LibreSDR, написаны на C. Реже попадается код на Python, Matlab, GNU SDR и пр. Понимая, что на дворе XXI век, я в первую очередь попросил написать для меня код многочисленные клоны Chat GPT. Увы, получаемый код лишь внешне напоминал рабочий. Так что для себя я сделал вывод, что пользоваться ИИ в данном случае – тупиковый путь. Выбрал самой простой пример передачи от Analog на C и решил прямолинейно переписать его на Rust используя естественный интеллект.
Стоит отметить, что все программы приема и передачи для Pluto используют в своей основе библиотеку libiio. К моей радости, на crates.io обнаружилась одна рабочая версия такой библиотеки для Rust (industrial-io). К сожалению, это не нативная библиотека, а лишь обертка над обычной библиотекой, написанной на C. Т.е. ожидать какого-либо улучшения надежности кода не приходится. Я до этого уже работал с этой библиотекой и уверенно могу утверждать, что получить в ней неопределенное поведение и дамп ядра не составляет какого-либо труда. Это меня несколько опечалило, но не остановило.

Помимо просто передачи маяку нужно как-то формировать сигналы в соответствии с азбукой Морзе. Опять же, на crates.io нашлось немало библиотек, декларирующих способность к обработке морзянки. Из них я выбрал morse-codec. Эта библиотека умеет транслировать цифробуквенные строки в последовательность кода Морзе, а еще формировать сигналы включения передачи с нужными интервалами. В примерах к библиотеке есть программа передачи с помощью мигания светодиодом, так что не составило труда переделать пример на включение передатчика LibreSDR вместо светодиода.
Я хотел чтоб моя программа могла работать непосредственно на LibreSDR, например, можно её запускать автостартом с SD карты. Оказалось очень удобным при использовании библиотеки libiio, что программу можно написать и отладить на обычной персоналке (я использую Ubuntu WSL), при этом доступ к LibreSDR идет через сеть. А после окончания разработки можно проект с помощью кросс компиляции собрать без каких-либо доработок под ARM и полученный бинарник уже запускать на LibreSDR.
Несколько слов о кросс компиляции Rust. Нужно сначала установить нужную целевую платформу и стандартную библиотеку.
rustup target add armv7-unknown-linux-gnueabihf
В папке проекта сделать каталог .cargo и в нем создать файл cargo.toml следующего содержания:
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
Далее, при компиляции программы указать в командной строке компилятору для какой платформы будет сборка:
cargo build --target=armv7-unknown-linux-gnueabihf –release
В результате получится исполняемый файл для LibreSDR. Надо сказать, что нужно указывать в качестве arm-linux-gnueabihf-gcc линкер, который совместим с версией линукс, установленной на LibreSDR. Я сперва установил самую свежую версию тулчейна и в результате полученный бинарник не запускался – жаловался на несовместимую версию libc. Пришлось свежую версию тулчейна удалить и настроить пути на linaro-toolchain, который я использовал при сборке линукса для LibreSDR. После этого проблемы совместимости оказались устранены.
Проект радиомаяка я разместил на гитхабе здесь. Можете попробовать как он работает. У маяка есть несколько параметров командной строки для выбора позывного, частоты и способа подключения к LibreSDR. Кроме того, есть возможность отключить передачу позывного. В этом случае будет передаваться просто несущая частота. В таком режиме можно использовать LibreSDR как генератор сигнала на любую частоту от 70 МГц до 6 ГГц. Тоже может быть полезно.
На этом всё. Желаю всем интересных экспериментов с SDR!
Автор: lesha108