Как подружить PLUTO и HDSDR

dxvl5cuxvc4qn7duv1lossoiz2c.jpeg

Не так давно импульсивно купил симпатичный SDR трансивер для детей и юношества — ADALM PLUTO. К моему сожалению он работает с кучей софта под LINUX, а вот мой любимый HDSDR его не поддерживает. Недолго думая стал разбираться с этой проблемой и вот что из этого получилось:

Analog Devices адресует свой PLUTO студентам. Весь софт для PLUTO открытый и находится в свободном доступе. На сайте компании есть страничка, на которой можно найти почти всю необходимую информацию о функционировании PLUTO. Большая часть софта написана под Linux и студентам рекомендуют пользоваться GNU Radio, MATLAB и т.п.

У меня же чисто радиолюбительский интерес к PLUTO. SDR с диапазоном от 70МГц до 6ГГц (после раскрытия) всего за 150 американских денег — это чудо. Сколько всяких экспериментов можно провести! Посмотрите как много там всего интегрировано:

aowgmnuvpv1nj7kzloexjef5-fy.jpeg

По всей видимости AD считает, что радиолюбители сами должны писать драйвера для популярных программ, поэтому до недавнего времени даже SDR# не поддерживался. Но меня SDR# не устраивает, поскольку мне нужна хорошая поддержка CAT в программе для синхронизации частоты с трансивером. HDSDR же хочется попробовать использовать в качестве панорамного приёмника, подключив его к первой промежуточной частоте трансивера. Итак, выход один — интегрировать HDSDR и PLUTO самому.

С помощью гугла я довольно быстро выяснил, что для решения моей задачи нужно создать специальную ExtIO_.dll библиотеку в формате Winrad. Эта библиотека служит программным мостом между HDSDR и желаемым SDR приёмником. К счастью, интерфейс библиотеки неплохо документирован. Кроме того, на github довольно много готовых реализаций библиотек для различных приёмников: RTL_SDR, LimeSDR и пр. Было где подсмотреть как надо писать код. Сама же библиотека совсем олдскульная, никаких новых технологий, чистый C89, как писали лет 20 лет назад. По крайней мере не надо учить новый язык программирования, что уже вселяло надежду на успех.

По сути в ExtIO_.dll нужно реализовать с десяток функций, которые позволяют инициализировать оборудование SDR, запускать и останавливать приём сигнала, сохранять и восстанавливать заданные настройки. Для меня самым непонятным моментом явился формат обмена потоковыми данными между приёмником и HDSDR, но об этом чуть ниже.

Теперь возник вопрос как управлять PLUTO программным способом. На самом деле есть несколько вариантов управления. Я нашёл минимум два: напрямую чипом через библиотеку libad9361.dll, либо через библиотеку IIO. Последний вариант мне показался более простым и хорошо описанным, поэтому остановился на нём. В этой библиотеке все настройки оборудования доступны в виде какого-то подобия XML структуры, обращение к отдельному элементу идёт по текстовому названию свойства, что довольно удобно. Подробнее описание библиотеки можно посмотреть здесь. Огромным преимуществом библиотеки является то, что она поставляется с утилитами командной строки, с помощью которых всегда можно быстро поменять нужную настройку приёмника. Таким образом, не нужно реализовывать все настройки SDR в интерфейсе HDSDR, можно обойтись необходимым минимумом. А загрузку какого-нибудь экзотического FIR фильтра можно сделать из командной строки, если вообще когда-нибудь такая необходимость появится. Потоки данных в IIO:

cedzbhmsy9z56vdehgcoaas5hmk.png

Программно научиться управлять PLUTO из HDSDR получилось довольно быстро и просто. Несколько сложнее было получить удовлетворительный результат по передаче потоковых данных, тем более ранее опыта работы с SDR у меня не было. Тут надо понимать, что данные поступают из SDR приёмника в виде потока I/Q/I/Q… I /Q сэмплов. Каждый сэмпл это без знаковое 16 битное целое число, из которого только 12 младших бит имеют значение. В то же время у HDSDR есть с десяток вариантов принимаемых потоков данных. Какой из них удобнее и лучше не совсем мне понятно. В результате я остановился на варианте, который в ExtIO называется exthwUSBdata16, т.е. фактически один в один как отдаёт данные библиотека IIO.
Следующей проблемой стала передача данных между буферами приёма IIO и HDSDR. Последний принимает данные блоками, кратными 512 байтам, а IIO в таком формате выдавать данные не может. Пришлось сделать промежуточный буфер и передавать поток через него. Код передачи показан ниже.

DWORD WINAPI GeneratorThreadProc( __in  LPVOID lpParameter )
{
        int16_t iqbuf[EXT_BLOCKLEN * 2];
        ssize_t nbytes_rx;
        char    *p_dat, *p_end;
        ptrdiff_t       p_inc;

        int     iqcnt = 0; // pointer to sample in iqbuf
        
        while ( !gbExitThread )
        {
                nbytes_rx = iio_buffer_refill(rxbuf);
                p_inc = iio_buffer_step(rxbuf);
                p_end = (char *)iio_buffer_end(rxbuf);
                for (p_dat = (char *)iio_buffer_first(rxbuf, rx0_i); p_dat < p_end; p_dat += p_inc) {

                        iqbuf[iqcnt++] = ((int16_t*)p_dat)[0];
                        iqbuf[iqcnt++] = ((int16_t*)p_dat)[1];

                        if (iqcnt == EXT_BLOCKLEN * 2) { // buffer full
                                iqcnt = 0;
                                pfnCallback(EXT_BLOCKLEN, 0, 0.0F, &iqbuf[0]);
                        }
                }
        }
        gbExitThread = false;
        gbThreadRunning = false;
        return 0;
}

Используя указанный цикл удалось достичь передачи потока в 4 MS/s, выше этого значения данные не успевают передаваться и приём сигнала идёт с заиканиями, хотя железо вроде способно отдавать и 20 MS/s и даже выше. Увеличил приоритет потока, в котором крутится цикл до THREAD_PRIORITY_TIME_CRITICAL, увеличивал размер буферов. Без результата. Причём при увеличении буфера до 1 МБ, нормальный приём был невозможен и на минимальной скорости потока. Больше тут не значит лучше. Если есть идеи как повысить скорость, прошу поделиться в комментариях.

Надо сказать, что 4 MS/s для моих целей вполне достаточно, полоса с лихвой перекрывает любой радиолюбительский КВ диапазон. Да и на УКВ и СВЧ полосы хватит для большинства задач. В результате библиотека написана, окно HDSDR с включенным на приём PLUTO выглядит примерно так:

bzsdhbg83dfjqv9iokbtcpwltbi.jpeg

Весь код библиотеки доступен на github здесь. Можете смело использовать его для своих экспериментов с ADALM PLUTO.

73 de R2AJP

© Habrahabr.ru