IEEE802.15.4 - стандарт для беспроводных персональных сетей с низким уровнем мощности сигнала в нелицензируемых диапазонах частот.
Он определяет физический уровень и MAC уровень доступа к среде.
В этой статье рассматривается версия 2003 года и OQPSK модуляция...
ссылка на предыдущую статью : https://habr.com/ru/articles/915758/
Что нам рисует стандарт:

Bit - здесь пояснений не нужно.
Symbol - 4 bits, т.е полбайта и просто, и ясно.
Chip - самый продходящий перевод, который я нашел, это деньги. Но к сожалению к статье не имеет отношения. Здесь Chip - метод расширения спектра DSSS(direct-sequence spread spectrum). Каждый символ (4бита) отображается в 32 бита псевдошумовой последовательности:

и пока не передается.
Тип модуляции OQPSK, где четные биты(уже биты Chip) это синфазная составляющая, а нечетные квадратурная, т.е по 16 штук.
O(OQPSK) - offset. Здесь нечетные биты сдвигаются на половину периода:

Скорость стандарта 62,5 килосимволов/сек. Чтобы “прорисовать” один бит Chip последовательности нужно не менее двух отсчетов, из-за сдвига. В итоге получаем минимальную частоту дискретизации:
Sr = 65500(hz) * 16(chip) * 2(offset) = 2000000 Hz IQ отсчетов.
А сама полуволна выходит из формирующего фильтра:

На практике стараются выбрать более высокую частоту дискретизации для уменьшения шума квантования. Выбираем 4MHz ... В коде это выглядит так:
h_matched_filter[4] = {0.0f, 1.0f / M_SQRT2, 1.0f, 1.0f / M_SQRT2};
Теперь можно что-то передать.
В отличие от пассивного сканирования многочисленными USB сканерами для перехвата протоколов(что нам неинтересно) имеем возможность активного сканирования.
В протоколе предусмотрено два вида активного сканирования:
запрос маяка
сканирование “сирот”
Запрос маяка необходим для определения занятости среды передачи, наличие развернутых сетей на данной частоте в пределах досягаемости.
Сказано - сделано(редкий случай):

Ответ в маяке может быть более откровенен:

tppSmart - это электросчетчики (у меня такого нет)
0x3688:0x0 - 0x3688 PAN сеть, 0x0 - контроллер
0x53b6:0x8118 - другая PAN сеть и не контроллер (контроллер всегда 0x0)
Картинки сняты при использовании HackRF. Причем здесь HackRF?
Здесь нужно начать издалека.
Технология SDR изначально предназначалась для совмещения старых(аналоговых) и новых(цифровых) методов связи. Так гласит легенда.
Только цифровые методы, как правило, требуют жестких временных интервалов приема и передачи. А некоторые протоколы работают в режиме очень коротких сообщений - “burst mode”.
И здесь выясняется, что известное мне большинство устройств SDR, к этому не приспособлено.
Без модификаций заработало, только USRP B200.
Как ускорить PlutoSDR обходом протокола IIO через USB мы уже знаем. LimeSDR то работает, то нет - здесь пока не понятно.
Но HackRF не зря вынесен в заголовок. Здесь все “прибито гвоздями”.
В драйвере:
#define TRANSFER_BUFFER_SIZE 262144
#define DEVICE_BUFFER_SIZE 32768
т.е., если не передать 32768 отсчетов, он вообще не заводиться.
А в стандарте:
8 символов период доступа к среде - 512 отсчетов при 4Мгц частоты дискретизации
12 символов на переключение прием-передача - 768 отсчетов при 4Мгц частоты дискретизации
И это, документ между прочим...
В интернете редкие жалобы на медлительность управления машинками, невозможность ретрансляции и т.д. Решений нет, есть намек - изменить значение буфера, но не сказано как.
Поэтому поступим просто:
Правим файл usb_api_transceiver.c в firmware:
с 50 строки
//#define USB_TRANSFER_SIZE 0x4000
#define USB_TRANSFER_SIZE 0x400
здесь 0x400 наши 512 символов
с 450 строки
while (transceiver_request.seq == seq) {
// if (!started && (m0_state.m4_count == USB_BULK_BUFFER_SIZE)) {
if (!started && (m0_state.m4_count == USB_TRANSFER_SIZE)) {
// Buffer is now full, start streaming.
baseband_streaming_enable(&sgpio_config);
started = true;
}
if ((usb_count - m0_state.m0_count) <= USB_TRANSFER_SIZE) {
usb_transfer_schedule_block(
&usb_endpoint_bulk_out,
&usb_bulk_buffer[usb_count & USB_BULK_BUFFER_MASK],
USB_TRANSFER_SIZE,
transceiver_bulk_transfer_complete,
NULL);
usb_count += USB_TRANSFER_SIZE;
}
}
компилируем firmware строго по инструкции и загружаем в командной строке:
hackrf_spiflash -w hackrf_usb.bin
Что там теперь твориться в “машинном отделении” не знаю, но это работает.
Далее избавляемся от асинхронного режима (API драйвера) USB и пишем свой , с короткими транзакциями.
Вытаскиваем из драйвера конечные точки USB
#define RX_ENDPOINT_ADDRESS (LIBUSB_ENDPOINT_IN | 1)
#define HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE 1
#define HACKRF_TRANSCEIVER_MODE_RECEIVE 1
#define HACKRF_TRANSCEIVER_MODE_OFF 0
#define TX_ENDPOINT_ADDRESS (LIBUSB_ENDPOINT_OUT | 2)
#define HACKRF_TRANSCEIVER_MODE_TRANSMIT 2
и работаем с libusb-1.0 стандартным методом.
Сам проект можно посмотреть здесь:
https://github.com/Oleg-Malyutin/SDR_ieee802.15.4_PHY