Изучаем сигналы NRF24L01 с помощью LimeSDR

23 октября 2017

Помните, как мы удаленно мигали светодиодом при помощи NRF24L01, а затем использовали этот же беспроводной модуль для управления гусеничным роботом? В этих заметках модуль мы использовали по принципу «подключаем к таким-то пинам, берем готовую библиотеку, пишем пару строк кода и все работает, магия». Так вот, мне не нравится магия. Я программист, а не колдун, и потому хочу знать точно, что там и в каком виде передается в эфире. К счастью, Software Defined Radio позволяет с легкостью это увидеть.

Итак, первым делом я залил в Arduino следующий скетч:

#include <Arduino.h>
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9, 10);

void setup(void)
{
  radio.begin();
  radio.setChannel(108);
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(0xA1B2C3D4E5);
}

void loop(void)
{
  uint8_t state[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
  delay(100);
  radio.write( &state, sizeof(state) );
}

Как видите, он просто передает раз в 100 мс довольно бессмысленный пакет размером 8 байт на 108-м канале. С помощью LimeSDR и Gqrx несложно увидеть, что сигнал, в соответствии с нашими ожиданиями, передается на частоте 2508 МГц (2400 + номер канала). Также Gqrx позволяет записать сигнал в файл, чтобы сигнал этот можно было, например, лучше рассмотреть в Inspectrum:

Сигнал NRF24L01 в Inspectrum

Каждый вызов radio.write сопровождается посылкой 16-и пакетов (см верхнюю часть картинки). Забегая немного вперед отмечу, что пакеты абсолютно идентичны и посылаются повторно исключительно для избыточности. Если приблизить один из этих пакетов (см нижнюю часть картинки), можно фактически увидеть единички и нолики, передаваемые при помощи изменения частоты сигнала. Как нам уже известно, NRF24L01 использует модуляцию GFSK, поэтому такой результат был вполне ожидаем. В сигнале можно заметить длинную последовательность нулей. Это тоже вполне объяснимо, если вспомнить, что максимальный размер пакета у NRF24L01 составляет 32 байта, из которых мы использовали только 8.

Декодировать GFSK можно при помощи такого проекта в GNU Radio:

Проект в GNU Radio для декодирования GFSK

Изучать получившийся в итоге сигнал можно, конечно, и в Scope Sink, но на практике это не очень-то удобно. Scope Sink подходит разве что для визуального определения, что что-то действительно декодировалось. Для просмотра получившегося сигнала лучше подходит утилита под названием baudline. Открываем файл, указав sample rate, использованный при записи (в моем случае это 5000000), а также формат 32 bit float, little endian. Открываем окно waveform и ищем что-то вроде:

Декодированный GFSK-сигнал в baudline

Фактически, это уже единички и нолики в чистом виде. Как не видите единичек и ноликов? Да вот же они:

Сигнал NRF24L01, нарезанный на единички и нолики

Здесь красная полоска означает границу бита, а синяя полоска — границу байта. Аккуратно выписав единички и нолики, получаем:

10101010  AA <- преамбула
10100001  A1 <- 5 байт адреса
10110010  B2  
11000011  C3  
11010100  D4  
11100101  E5  
11001101  CD <- видимо, флаги
00000000  00 <- данные
00010001  11  
00100010  22  
00110011  33  
01000100  44  
...

То есть, при сильном желании теперь мы можем написать софтверный декодер пакетов. Только польза от такого проекта, на мой взгляд, будет несколько сомнительной. Во-первых, потому что такой проект уже есть, и, возможно, не один. А во-вторых, потому что пакеты намного проще декодировать при помощи самого NRF24L01 и Arduino. Может понадобиться разве что знать адрес передающего устройства, но мы только что выяснили, как его определить. Впрочем, если рассматривать задачу исключительно как code kata на выходные, то почему бы и нет.

Все исходники к посту, как обычно, вы найдете на GitHub.

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.