Я купил свой Sphero R2D2 два года назад, это была классная игрушка для таких фанатов Звездных войн, как я, и отличный друг для моей кошки ... в любом случае, через некоторое время я задумал сделать какой-нибудь программный проект с этим прекрасным кластером электроники. ! Я хотел найти способ написать сценарий своего робота, но не нашел ничего хорошо документированного и поддерживаемого.

Единственное, что я знал о R2D2, это то, что он работает с использованием технологии BLE, и вы можете управлять им с помощью официального приложения Sphero Droids. После некоторого поиска я нашел только эту статью, хорошую отправную точку и некоторую документацию по протоколу связи… Этого было недостаточно, статья и прикрепленный скрипт выглядели незаконченными, а официальная документация не содержала спецификации сообщений, которые создают R2D2. движение и танцы.

Вот почему я решил написать код Javascript, чтобы узнать, как общаться с R2D2! В этой статье я покажу вам свой личный опыт реверс-инжиниринга этого дроида: вы можете использовать этот подход к любому устройству BLE, которое хотите взломать.

TL;DR

Используя телефон Android, Wireshark и документацию по протоколу, я обнаружил, как приложение взаимодействует с R2D2, и написал драйвер с помощью Node: вы можете перейти в этот репозиторий и использовать код для связи с R2D2. Окончательный результат на этом видео 📺

Настраивать

Для этого эксперимента необходимо:

  • Базовые знания протокола BLE (учебник для новичков)
  • Компьютер с поддержкой BLE (я использую MacBook Pro)
  • Телефон Android (я использую старую Motorola с Android 6)
  • Дроид Sphero R2D2! (Амазонка 📦)

Первое, что нужно сделать, это установить на ПК инструменты Wireshark и Android Developer:

  • Wireshark - это анализатор сетевых протоколов, полезный для проверки сообщений Bluetooth, который можно скачать с официального сайта.
  • Инструменты разработчика Android содержат исполняемый файл adb для связи с вашим телефоном Android с ПК. Посетите официальный сайт для получения дополнительной информации.

На телефоне Android установите Приложение Sphero Droids и включите функцию Bluetooth HCI Spoofing в разделе Параметры разработчика.

Используя эту функцию, я могу получить файл со всеми пакетами связи Bluetooth, отправленными и полученными между устройствами.

Сбор данных

Теперь, когда включен BLE HCI Spoofing, откройте приложение Sphero Droids, подключите R2D2 и поиграйте с ним некоторое время.

После этого закройте приложение и загрузите файл, созданный на вашем диске, с помощью adb.

adb pull /sdcard/btsnoop_hci.log / dest / путь

Этот файл обычно сохраняется в папке /sdcard/btsnoop_hci.log и может быть открыт с помощью Wireshark.

Проверка Wireshark

Это самая интересная часть проекта: открытие файла с помощью Wireshark раскрывает много полезной информации для обратного проектирования дроида. Вот что я получил после первого сеанса: между устройством Android (localhost) и дроидом (мое помечено адресом d7: 1b: 52: 17: 7b: d6) и после некоторой прокрутки появляется первый запрос записи!

Как вы можете видеть в инспекторе байтов, полезная нагрузка весьма красноречива: «usetheforce. ..band ». Звучит отлично :)

Еще одна полезная информация - это UUID службы и Характерный UUID (дескриптор 0x0015), аннотируйте их, чтобы знать, куда отправлять «usetheforce». ..band »сообщение!

Пришло время прочитать некоторую документацию, начиная со структуры пакета. Это структура пакета в протоколе Sphero:

Каждый пакет имеет байт SOP (начало пакета) и байт EOP (конец пакета), оба равны 0x8D и 0xD8, поэтому необходимо искать все эти пакеты, начиная с SOP и заканчивая EOP.

Другие интересные байты:

SEQ (порядковый номер): токен, используемый для связывания команд с ответами
DATA (данные сообщения): ноль или более байтов данных полезной нагрузки
CHK (контрольная сумма): сумма всех байтов (исключая SOP и EOP) по модулю 256, инвертированный бит

Первый пакет, отправленный из приложения, следующий:

0x8D 0x0A 0x13 0x0D 0x00 0xD5 0xD8

Байт SEQ здесь равен 0x00 в соответствии со схемой структуры пакета: это первый пакет, который приложение отправляет дроиду! Назовем его пакет инициализации.

Как видите, есть другой UUID службы и другой UUID характеристики (дескриптор 0x001c), которые будут получать следующие сообщения.

Еще одно полезное сообщение, которое нужно получить, - это последнее сообщение в конце файла журнала, отправленное из приложения перед закрытием, пакет для выключения дроида:

0x8D 0x0A 0x13 0x01 0x20 0xC1 0xD8

Пришло время аннотировать службы, характеристики и сообщения (без SOP, EOP и других байтов) в некоторых константах.

Напишем код

Окончательный сценарий будет составлен из:

  • функция для создания пакета
  • функция для подключения дроида R2D2
  • функция для записи пакетов и ожидания ответа
  • функция для выключения дроида

Сборка пакета

Создать пакет очень просто, потому что это всего лишь массив байтов, начиная с байта SOP и заканчивая байтом EOP. Во время выполнения необходимо сгенерировать два байта:

  • SEQ byte: это просто переменная, инициализируемая значением 0x00 и увеличивающаяся на 1 каждый раз при создании пакета.
  • Байт CHK: согласно документации, байт CHK - это сумма всех байтов (исключая SOP и EOP) по модулю 256, с инвертированием битов, очень легко сгенерировать:

Помимо SOP и EOP для связи используются и другие специальные байты:

Когда в полезной нагрузке требуются байты ESC, SOP или EOP, они кодируются в двухбайтовые управляющие последовательности следующим образом:

Это последний код для создания действительного пакета для R2D2:

Подключаем нашего дроида

В этом примере для подключения R2D2 к ПК по технологии BLE я использую Библиотеку Noble. Я установил специальную вилку, чтобы Noble работала на MacOS Catalina.

пряжа добавить git: //github.com/lzever/noble.git

В Noble действительно легко реализовать функцию, позволяющую получить основные характеристики, используемые для связи с дроидом.

Этот сценарий запускает сканирование всех устройств вокруг и выбирает устройство с указанным адресом, получает службу подключения и отправляет usetheforce. ..band » (MSG_CONNECTION) к его характеристике (CONNECT_CHAR). После этого пора получить «Основную характеристику» для отправки команд дроиду! Для этого лучше создать код для записи и чтения, потому что мне нужно дождаться ответов.

Записывать пакеты и читать ответы

Это основная часть эксперимента: создать функцию для записи команд и… дождаться ответа, чтобы прочитать! Когда приложение отправляет сообщение дроиду, оно получает один или несколько пакетов ответа, как вы можете видеть из журналов и / или читать из документации:

Ответы повторяют DID, CID и SEQ, чтобы помочь отправителю полностью идентифицировать соответствующий пакет команд.

Если байт ERR равен 0x00, во время выполнения команды ошибок не произошло, иначе вам нужно проверить эту ссылку, чтобы узнать, что произошло.

Просматривая журнал Wireshark, вы можете увидеть, что есть некоторые команды, которые получают другой ответ после эхо-ответа, и другие команды, для которых требуется тайм-аут (например, трансформация сошки / штатива).

Чтобы удовлетворить все эти случаи, последняя функция записи должна работать следующим образом:

  • Получает характеристический объект, команду для выполнения, логическое значение, чтобы указать, нужно ли ждать другого ответа после эха и тайм-аута.
  • Отправляет команду характеристике
  • Ожидает ответа, проверяет, есть ли ошибки, а затем разрешает обещание (через некоторое время, если таймаут больше 0)

Чтобы включить обработчик получения ‘data’, функция должна подписаться на основную характеристику и читать из нее. Пакет данных имеет ту же структуру, что и пакет, используемый для отправки команд, но теперь мы должны проверить, нет ли ошибок в байте ошибки.

Поддерживаемые типы данных полезной нагрузки

Следуя тому же процессу, я попытался узнать, как повернуть верх. Есть много похожих сообщений, чтобы верхняя часть вращалась, начиная с 0x0A 0x17 0x0F.

Я попытался повернуть верх почти на 90 градусов и получил 32 бита полезной нагрузки (0x42 0xb2 0x31 0x98, для простоты 0x42b23198) без значения, близкого к 90, поэтому ... это число не должно быть представлено с целое число! К счастью, в протоколе дроидов нет специального секретного кода, согласно документации существуют другие типы, поддерживаемые для данных полезной нагрузки.

32-битная полезная нагрузка 0x42b23198 очень похожа на число, закодированное с помощью IEEE754! Преобразуя это значение с помощью онлайн-инструмента, я получаю 89.09686.

Добавив простую функцию для преобразования градусов в шестнадцатеричный, это последний код для поворота вершины R2D2:

Я попытался полностью повернуть верх, но это не удалось, дроид отвечает с ошибкой 0x07 (неверный параметр данных).

В следующем эпизоде ​​я попытаюсь переместить R2D2, пока вы можете проверить этот репозиторий, содержащий некоторые другие функции, такие как анимация и трансформации сошек / штатива.

В последнем эпизоде ​​я попытаюсь написать настоящую библиотеку, переписав код (может быть, используя какую-то очередь?) И добавив поддержку других дроидов 🤖 Следите за обновлениями!

Это все, ребята 👋