Flipper на минималках. Как мы делаем устройство для чтения и эмуляции ключей от домофонов…

Мне понравилась идея Flipper Zero в хранении и эмуляции электронных ключей. Это довольно удобно, можно избавится от половины моей связки со всеми ключами, плюс те ключи, которые я обычно даже не ношу, будут под рукой, в том числе универсальные. Но не понравились его габариты. К тому же, весь остальной функционал хоть мне и интересен, для этой задачи излишен, а за него тоже надо платить. В этот момент появилась идея и, что самое главное, желание самостоятельно реализовать такую штуку.

Я работаю в центре поддержки одаренных школьников, поэтому сначала дал эту тему одному своему самому продвинутому ученику в качестве проекта. Но потом сам погрузился в этот проект : D

Конечная идея была в эмуляции ключей стандартов TouchMemory, Em-Marine и Mifare classic в одном устройстве. Хочется, чтобы это устройство было максимально компактным, в идеале вообще помещалось на связку ключей.

Текущие прототипы устройства

Текущие прототипы устройства

Давайте для начала расскажу, что это за стандарты такие.

Распространенные стандарты ключей

Em-Marine и Mifare classic — это бесконтактные ключи, которые работают по беспроводным протоколам на частоте 125кГц для Em-Marine и 13.56 для mifare classic.

Em-Marine — это старые, довольно глупые ключи, которые хранят только свой id, и в основном используются на турникетах и домофонах (если их ещё не заменили на Mifare classic).

Mifare classic работает на частотах nfc, и, соответственно, его без проблем можно прочитать современным телефоном, скопировать (к сожалению с ограничениями), и даже иногда эмулировать (далеко не на всех устройствах, часто только с root правами и т.д.).

Не буду сильно вдаваться в этот стандарт, до работы с ним мы ещё не добрались.

TouchMemory — класс электронных устройств, имеющих однопроводный протокол обмена информацией (1-Wire, но не всегда) и помещённых в стандартный металлический корпус (обычно имеющий вид таблетки).

Это те самые ключи-таблетки, которые вы прислоняете к домофону, чтобы зайти.

Про ключи TouchMemory

В основном стандарт представлен в виде ключей dallas и русских-народных Cyfral и Metacom.

Соответственно, с этих ключей мы и решили начать, т.к. они показались нам самыми простыми. Проектировать это устройство решили на всеми любимой arduino, и кодить естественно в её среде.

Для начала решили разобраться с dallas, все-таки это самые распространённые ключи. И обычно поддерживаются любым домофоном, даже cyfral и metacom. Эти ключи работают на протоколе 1-wire, сам ключ является умным, умеет принимать и обрабатывать несколько стандартных команд, и хранит только свой уникальный ID из 8 байт.

Протокол 1-wire

Протокол 1-wire

Протокол 1-wire работает по модели Master-Slave. В этой топологии устройство Master всегда инициирует общение, а Slave следует его указаниям. При контакте ключа (Slave) с домофоном (Master), ключ получает питание, чип внутри ключа включается, происходит инициализация ключа, после чего домофон запрашивает ID ключа.

Домофон считывает из iButton 8 байт (64 бита) информации, чтобы решить, открывать дверь или нет. Первый байт это family code. У ds1990 это всегда 01, по нему можно понять, что это за ключ (например, у cyfral и metacom мы сюда будем писать уже их коды 10 и 20, в статьях про них объясню, почему так). Далее 6 байт самого ключа и последний байт — контрольная сумма. Иногда код ключа записывают в перевернутом виде, как на схеме:

9d97aa9b66b9b02248ecc67982b424dd.jpg

Подключаем Arduino

Для работы с этим протоколом для ардуины есть шикарная библиотека OneWire, которая позволяет работать ардуино как Master устройство, и на ней написаны прошивки практически всех дубликаторов ключей на ардуино. Проблема в том, что эта библиотека не умеет работать как slave устройство, и, соответственно, написать эмуляцию на ней не получится.

Но для начала было бы неплохо хотя бы прочитать какой-нибудь ключ…

Чтобы обеспечить ключ питанием, достаточно притянуть центральный контакт на 5в через резистор и боковой на gnd. Обычно советуют использовать 2.2кОм, но, как показала практика, можно использовать любой от 500ом до 5кОм, и даже напряжения достаточно 3.3в

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

Этой схемы уже достаточно, чтобы читать и эмулировать ключи протокола OneWire

Этой схемы уже достаточно, чтобы читать и эмулировать ключи протокола OneWire

Само чтение происходит всего в одну строчку кода:

#include 
#define iButtonPort 2

byte addr[8];
OneWire ibutton(iButtonPort);
void setup() {
  Serial.begin(115200);
}

void loop() {
  readKey();
}
void readKey() {
  if (ibutton.search(addr)) {       // Если устройство подключено - считываем
    for (int i = 7; i > -1; i--) {  // Запускаем цикл печати данных из массива
      Serial.print(addr[i], HEX);   // Печатаем нужный байт в шестнадцатиричном виде
      Serial.print(" ");
    }
    Serial.println();        // В конце цикла переводим строку
    ibutton.reset_search();  // Сбрасываем устройство
  }
}

Давайте вернемся к эмуляции

Поиски библиотеки для эмуляции были долгими, первой нашлась статья на RoboCraft: Arduino/CraftDuino и эмулятор iButton с недописанным кодом, и следом библиотека OneWireSlave, которая до сих пор не может эмулировать ds1990:(

Было желание на все плюнуть и написать свою библиотеку, но моя лень и упорство вывели меня на библиотеку OneWireHub, которая основана как раз на OneWireSlave: D. Вот она заработала отлично.

К этому моменту была собрана первая тестовая железка

К этому моменту была собрана первая тестовая железка

Первое удачное испытание

Первое удачное испытание

В этой библиотеке есть пример эмуляции, но для кучи устройств в одном скетче. Я, пожалуй, приведу в пример скетч только с эмуляцией ключа.

#include "OneWireHub.h"
#include "DS2401.h"  // Serial Number
#define iButtonPort 2

auto hub = OneWireHub(iButtonPort);
byte Key[8] = { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F };               //универсальный ключ
auto ds1990A = DS2401(Key[0], Key[1], Key[2], Key[3], Key[4], Key[5], Key[6]);  //crc считается автоматически

void setup() {
  hub.attach(ds1990A);  // всегда онлайн
}

void loop() {
  hub.poll();  // необходимо периодически вызывать следующую функцию
}

Как видите, ничего сложного. Но на этом этапе уже появились проблемы с нехваткой ресурсов ардуины. Оказывается, у atmega328p всего 2 кб оперативной (если точнее SRAM) памяти, а буфер для работы с oled 128×64, который мы решили использовать, занимает смело половину.
В принципе, можно было бы оптимизировать прошивку, повозиться с дисплеем, но для работы с Mifare Classic (хотя до него еще и далеко) памяти уже бы точно не хватило, да и хотелось писать код попроще. Поэтому было решено перейти на более производительный контроллер.

Переходим на ESP8266

И тут выбор встал между stm32f103 (или чем-то подобным) и esp8266. По сути, stm больше подходит к этому проекту, в ней и портов побольше, и полезные аппаратные фишки есть, но stm32 все еще плохо совместима с arduino кодом, поэтому выбор пока остановился на esp8266.

В esp8266 уже 82 кБ SRAM памяти и до 160Мгц частота ядра, что даже больше, чем у stm32f103. Поэтому можно ни в чем себе не отказывать, хоть картины рисовать : D

И вот готов третий тестовый образец на отладочной плате NodeMCU (esp8266)

И вот готов третий тестовый образец на отладочной плате NodeMCU (esp8266)

Эта железка уже умела читать, писать и эмулировать ключи dallas, а также хранить их в памяти. Также я, естественно, забил в быстрый доступ десять универсальных и часто используемых ключей :)
Но получилось не очень компактно :(

1bf776a9149bf6ae94425bc46b27242b.jpg

Следующий вариант был собран на vemosMini v4, это уже более компактная плата на базе esp8266. Существенно меньше девайс не стал, т.к. экран все равно остался довольно большим.

Зато появился аккумулятор с платой зарядки и стильный фиолетовый корпус!

62bf7dea6d5d1dd2197680a805affe06.jpg

Следующим этапом был переход на более маленький oled 1106_128×64. Для него не надо выводить отдельные контакты, т.к. он подключается в стандартный i2c разъем на vemosMini v4 по проводу. И вот с ним удалось добиться хоть какой-то компактности.

cb8c60fcc3f2060565adc11719abe1f0.jpg

Бонусом оказалось, что GPIO2 на vemosMini, как и на nodeMCU, уже подтянуты через резистор к 3.3v. Поэтому схема устройства ещё сильнее упростилась. Правда, не на всех платах хватает этой подтяжки, иногда надо добавить резистор 1кОм на 3.3v.

Схема устройства на vemosMini, сверху кнопки управления. Экран подключен по проводу

Схема устройства на vemosMini, сверху кнопки управления. Экран подключен по проводу

Спустя некоторое время появился и корпус. Кривой, конечно, но пока и такой пойдет.

9be695d545ad66288a2b8de09e3c5593.jpgf74d7e8110d1338b233159710fa7b6db.jpgd0ca09e0f4759e5e5aee40d150cf80d6.png

Да, забыл упомянуть про контактную площадку. Мы перебрали кучу вариантов и остановились на форме, которая позволяет удобно читать ключ и имеет надежный и удобный контакт с домофоном. В будущем она, скорее всего, будет изменена, но на данный момент это наиболее удобный вариант.

04e6332b1d4932d3dea21b90430509fa.jpg

Для достижения максимальной компактности, естественно, надо собирать эту штуку на печатной плате, но схема устройства пока всё время меняется, и печатка перерисовывается. Думаю, после победы над контактными ключами попробуем собрать небольшую партию устройств на печатных платах.

Модель устройства на печатной плате

Модель устройства на печатной плате

Что уже получилось

Следующим этапом были ключи Cyfral и Metacom.
Спойлер! С метакомом все получилось, можно читать, перекодировать и писать на болванки ds1990, писать на специализированные болванки и даже эмулировать оригинальный ключ! С Cyflal все похуже, можно читать и писать на спец. болванки, но эмулированный ключ домофон так и не воспринимает. Также получилось прочитать, записать и эмулировать EM-Marine. Но про все это в следующих статьях.

© Habrahabr.ru