Анализ метки Pandora DXL 4300

Попалась мне такая сигнализация под руки…  и очень часто попадаются электронные метки, безхозные. Почему бы их не использовать для своих нужд? 0
Для начала заглянем внутрь. Чип NRF24 широко известен в сообществе электронщиков. Для анализа работы системы я использовал китайский модуль NRF24 и готовую плату с процессором STM32F103C8T6.

2 1

Соединяем все это, подключаем программатор и USB конвертер для отправки сообщений в ком порт компьютера. Для работы нам понадобится еще анализатор, это ускорит время поиска канала связи, который использует радиометка.
Можно обойтись и без него, используя нерегламентируемые возможности NRF, но зачем тратить время?
Дело в том, что протокол, заложенный в NRF24 использует преамбулу для настройки приемника принимающей стороны, и выглядит она как 0x55 0xAA 0x55 0xAA…..Далее следует адрес приемной стороны который должен совпадать с адресом передающей. Он может быть от 3 до 5 байт. Еще есть настройки скорости передачи, контрольной суммы пакета, его длинны и т.д. по даташиту. НО! Если задать адрес приемной стороны 2 байт, что не оговорено производителем, и установить его как 0x55 0xAA, то мы сможем принимать все, что присутствует на частоте приемника. Это путь который мы обойдем с помощью анализатора логических шин. Можно посмотреть частотомером, в накопительном режиме, на какой частоте передает метка, простая формула переводит частоту в канал для записи в регистр NRF. Вобщем, мы уже знаем на каком канале будем принимать.
Вот пример настройки регистров


//*********************************************************
// Функция производит первоначальную настройку устройства. Возвращает 1, в случае успеха,
//0 в случае ошибки
uint8_t radio_start(void)
{
uint8_t cnt;
uint8_t self_addr[] = {0x8c,0x90,0x83,0xc0,0xc4}; // Собственный адрес
uint8_t remote_addr[] = {0x71,0x73,0x48,0x12,0x57}; // Адрес удалённой стороны
uint8_t chan = 0x75; // Номер радио-канала (в диапазоне 0 - 125)
radio_deassert_ce();
for(cnt = 100;;)
{
radio_writereg(CONFIG, (1 << EN_CRC) | (1 << CRCO) | (1 << PRIM_RX)); // Включение питания
if (radio_readreg(CONFIG) == ((1 << EN_CRC) | (1 << CRCO) | (1 << PRIM_RX)))
break;
// Если прочитано не то что записано, то значит либо радио-чип ещё инициализируется,
либо не работает.
if (!cnt--)
return 0; // Если после 100 попыток не удалось записать что нужно, то выходим с ошибкой
_delay_us(1000);
}
radio_writereg(EN_AA, (1 << ENAA_P1)); // включение автоподтверждения
radio_writereg(EN_RXADDR, (1 << ERX_P0 ));// включение каналов
radio_writereg(SETUP_AW, SETUP_AW_5BYTES_ADDRESS); // выбор длины адреса 5 байт
radio_writereg(SETUP_RETR, 0x30);
radio_writereg(RF_CH, chan); // Выбор частотного канала
radio_writereg(RF_SETUP ,0x26); //RF_SETUP_1MBPS |1 << RF_DR_LOW | RF_SETUP_0DBM); // выбор
скорости и мощности //06 (26)
radio_writereg_buf(RX_ADDR_P0, &self_addr[0], 5); //0x0A // Адрес канала 0 приёмника.
radio_writereg_buf(TX_ADDR, &self_addr[0], 5); //0x10 // Адрес удалённого устройства для
передачи
radio_writereg(DYNPD, (1 << DPL_P0)); // включение произвольной длины для каналов
radio_writereg(FEATURE,( 1 << EN_DPL) | (1 << EN_ACK_PAY));// разрешение произвольной длины
пакета данных //1D (06)
radio_writereg(CONFIG, 0x3F); //(1 << EN_CRC) | (1 << CRCO) | (1 << PWR_UP) | (1 << PRIM_RX)); //
Включение питания
return (radio_readreg(CONFIG) == 0x3F) /*((1 << EN_CRC) | (1 << CRCO) | (1 << PWR_UP) | (1 <<
PRIM_RX)))*/ ? 1 : 0;
return 1;
}
//*********************************************************

Итак, настроены регистры, включаем прием. Как только на приемник приходит пакет с нашим адресом, данные вычитываются в буфер, их выводим в терминал.


//********************************************************
void check_radio(void)
{
uint8_t status;
uint8_t protect;
uint8_t l;
if (!radio_is_interrupt()) // Если прерывания нет, то не задерживаемся
return;
status = radio_cmd(NOP);
radio_writereg(STATUS, status); // Просто запишем регистр обратно, тем самым сбросив биты прерываний
protect = 3; // В очереди FIFO не должно быть более 3 пакетов
while (((status & (7 << RX_P_NO)) != (7 << RX_P_NO)) && protect--)
{
l = radio_read_rx_payload_width(); // Узнаём длину пакета
}
Else
{
uint8_t buf[32]; // буфер для принятого пакета
radio_read_buf(R_RX_PAYLOAD, &Buf[0], l); // начитывается пакет
on_packet(&Buf[0], l); // вызываем обработчик полученного пакета
}
}
status = radio_cmd(NOP);
}
}
//********************************************************

Упростим задачу для всех заинтересовавшихся.. это лог работы метки
Вся нужная информация на рисунке.
Слева направо
1 настройка регистров передатчика метки.
2 данные для передачи-это идент со счетчиком и состоянием
3 после выброса пакета чип переключается на чтение регистра статуса, в ожидании ответа…

3

В результате видим в терминале следующую картину.
Запрос метки повторяется дважды, пауза между запросом 2 сек. Первый запрос 4 байт, 10мс ожидает ответ от базы, еще запрос-10мс ожидает ответ и засыпает. Через 2 сек повторяется цикл. В случае если база находится в зоне видимости, она тут же отвечает метке рандомным числом 8 байт, метка вычисляет ответ и отправляет свои 8 байт и уходит в сон. Через 2 сек все повторяется. Обмен идет на одном и том же частотном канале. Кроме частотного канала в чипе есть так называемые пайпы- это внутренне организованные каналы приема на заданной, одной частоте. Их 5. В нашем случае используется 0-нулевой канал. Отдельный канал используется для передачи. Немного мудрено на первый взгляд, но практично.
Можно использовать один чип для одновременной работы с несколькими абонентами.
Это очень кратко алгоритм обмена.

На рисунке запрос метки, БЕЗ базового блока по близости. 1 байт счетчик, своеобразный….. 2 и 3 байт это возможно идент метки, последний состояние батареи.

 5
Ну и видео работы всего вместе для демонстрации…

https://youtu.be/WmnUd8u50Is

Вся программа собрана в Keil5 на ядре cortex m3. Инициализация NRF24 стандартная – хардварный SPI софтовый NSS, состояние вывода IRQ является командой для процессора, что приняты данные. Читаем регистр статуса-если данные в приемном буфере есть-значит адрес наш и зачитываем размер принятых данных. Читаем буфер, и сбрасываем прерывания в чипе. Вот коротко процесс.

6

Теперь об использовании. Можно сделать устройство, которое при появлении метки в зоне приема будет открывать замки в автомобиле, или квартире, вобщем как угодно..выходим из зоны приема-буффер более не обновляется, значит «хозяин» ушел. Закрываем замки, или выключаем свет… тут дело фантазии. Я планирую управлять цз автомобиля, по CAN.

Обсуждение тут: https://phreaker.ru/forum/showthread.php?t=2361

www.phreakerclub.com
(c) genady34