-
Добрый день! Есть модуль RС522, хочу использовать его для системы доступа, но во всех примерах которые есть в сети используют только UID карты, Слышал что это не совсем безопасно, поэтому хочу сменить на карте ключ (допустим ключ B) чтобы можно было записывать и считывать с карты информацию для идентификации только по этому ключу. В сети внятной информации не нашел. Может кто подскажет как это делать?
-
Не совсем понятно что Вам надо? На русскийпереведите? Вы хотите карты клонировать? Чем UID небезопасен?
-
Наоборот, хочу защититься от возможного клонирования.
Ну, утверждают что можно незаметно прочитать карту и узнать UID. Поэтому рекомендуют в имеющийся на карте блок записать дополнительный код и закрыть считывание из этого блока ключом. Установленные на этих картах по умолчанию ключи всем известны. Вот я и хочу узнать как можно изменить хотя бы один из двух ключей и защитить блок с записанной информацией этим ключом.
-
Скажи проще — есть академический интерес. А клонировать…кому надо, тот клонирует. Выбор защитного ключа — это тоже целая история.
mifar и Airbus нравится это.
-
Не давать карту в чужие руки. Считывает максимум с 2—3 сантиметров. Если в кожанном чехле то только при касании.Прочитать карту незаметно нельзя от слова совсем. Это уже Паранойя. Даже в банках идентификация сотрудников и операций обычными rfid метками 125 кгц. Других вариантов не знаю хотя вопросом клонирования карт/симок/кодов занимался. Посмотрите на сайте фрикерклуб.ру может там чтото новое за год появилось? Если Вы хотите закрыть считывание то как будете проходить?
-
Я это уже заметил. И поэтому все больше склоняюсь что ну его нафиг этот геморрой со сменой ключей.
Но для себя все-таки разобраться хотелось бы как это работает. Вдруг когда-нибудь пригодится.
-
Тогда изучайте протоколы, принцип работы все есть в сети. Я копировал симки, карты с магнитной полосой, ключи но все это требует физического доступа к носителю. До сих пор есть мультисим и парочка клонов электронных пропусков на rfid картах.А устройства можно купить а можно сделать.Вот чувак сделал прикольный копир на Ардуино.
-
Я в сети натыкался на статью с описанием, как это сделать. Так с ходу не найду.
Как по мне, вот такое выглядит куда более цивильно:
-
Для майфер классика у NXP есть (и был с принятия стандарта) в открытом доступе MIFARE Classic EV1 1K
Карта разделена размечена на сектора, каждый сектор поделен на блоки данных и один служебный блок, т.н. sector trailer, который содержит два ключа A, B и access bits — биты определяющие на каком ключе (A или B) разрешены операции чтения/записи/увеличения/уменьшения для блока сектора.Пример для использовании карты (карт) для контроля доступа и учета количества проходов:
При персонализации кары разрешаем чтение и уменьшение значения блока на ключе A или B, а запись и увеличение только на ключе B.
Валидатору отдаем ключ А, он может только считать значение, либо уменьшить на единицу (списать проход). -
Мне бы конкретный пример, допустим, как сменить заводской ключ 0xFF на 0х11, в трейлер первого сектора установить биты разрешающие запись/чтение данных только в первом блоке этого сектора и только на ключе В. А то тем что удалось найти боюсь запороть карту.
-
В контроле доступа это не применяется и никогда не будет применяться. Весь учёт только внешний.
-
Полагаю речь идет о хакинге карты Метро? Или не только Метро?
-
На эмиссии в миллионы карт (контроль доступа на общественном транспорте) обеспечить онлайн контроль для десятков тысяч валидаторов — чрезвычайно дорогое решение,
дешевле «заряжать» карты прописывая количество проходов на карту.
Сначала платим либо кассиру либо удаленно через интернеты, после либо кассир либо сами прикладываем карту к считывателю и активируем пополнение.Если «Весь учёт только внешний» то никаких активаций не требовалось бы однако.
-
Второй раз повторяю — никакого хакинга. Этим вопросом заинтересовался когда увидел совет b707 Где то на этом ресурсе попадалось аналогичное высказывание, но не найду, столько перелопатил что уже не помню в какой теме и от кого.
Вот конкретно пример реализации чего я хотел бы найти
Последнее редактирование: 6 янв 2021
-
Можно запороть установив для аксесс биты для трейлера запрещающие перезапись самих аксесс битов, остальное, если вы ключи не забыли, не страшно.
Для расчета можно воспользоваться калькулятором, перед записью трейлера ещё раз проверяем аксесс биты что записываем по спеке производителя, калькулятор хорошо, но проверить не помешает. -
Это разновидность платёжной системы, причём не очень удачной. Но учёт то ведётся.
Автор: Nich1con
Технология RFID (Радиочастотная идентификация) позволяет при помощи радиосигнала быстро и безопасно передавать данные между специальными “считывателями” и “метками” – карточками, брелоками, браслетами и т.д. на небольшом расстоянии.
Одно из широко известных развитий технологии – NFC, при помощи которого можно оплачивать покупки или подключать устройства бесконтактно. Нам же доступны менее сложные, но не менее полезные и интересные применения, о которых будет сказано ниже.
Применение
Комплект RFID модуль + метки может быть использован:
- Как часть самодельных охранных систем
- При создании простых электронных замков (метка является ключом)
- В системах контроля доступа (однократный, многократный пропуск)
- В качестве электронного “кошелька” внутри собственного предприятия
- В роли интерактивного предмета в квестах и т.д.
Железо
RFID работает в нескольких частотных диапазонах, в свою очередь RFID модули и метки можно поделить на низкочастотные “LF” (125 кгц) и высокочастотные “HF” (13,56 MHz), существуют так же и ультравысокочастотные “UHF”, но они нас не интересуют.
Наиболее распространенные RFID Arduino-модули основаны на микросхеме MFRC522, работающей с HF метками 13,56 МГц. Поиск модулей и библиотек производится по этому же имени.
Существует два типа модулей MFRC522, с которыми вы скорее всего столкнетесь:
Отвечая на главный вопрос – не смотря на значительную разницу в размере, ощутимой разницы в работе модулей нет, можно брать любой. В комплекте к модулю как правило уже идет несколько меток.
Библиотеки
Для работы с модулем MFRC522 понадобится библиотека https://github.com/miguelbalboa/rfid. Библиотека тяжелая, индусская и имеет немало проблем, но достойных альтернатив просто нет – несколько других “облегченных” библиотек значительно уступают в функциональности и удобстве использования.
Подключение
Модуль MFRC522 подключается по аппаратному интерфейсу SPI, выбранная библиотека предоставляет следующую таблицу подключения к Arduino:
Сигнал | Модуль MFRC522 | UNO/NANO | Leonardo | Pro micro | Mega |
Reset | RST | D9 | RST/ISCP-5 | RST | D5 |
Chip select | SDA (SS) | D10 | D10 | D10 | D53 |
MOSI | MOSI | D11 | ISCP-4 | D16 | D51 |
MISO | MISO | D12 | ISCP-1 | D14 | D50 |
SCK | SCK | D13 | ISCP-3 | D15 | D52 |
- Контакты модуля RST и SDA (SS) указываются в скетче – можно использовать любые.
- У Leonardo подключение производится к 6-ти контактному ICSP разъему программатора.
Пример подключения модуля к Arduino Nano:
О RFID метках
Прежде всего самая сложная для понимания, но и самая важная часть – работа с RFID метками. В комплекте с модулем идут пара меток MIFARE Classic 1K, как понятно из названия – на 1 килобайт (на самом деле меньше, но об этом позже).
Чтобы изучить организацию памяти такой метки, можно воспользоваться примером из библиотеки, открыв Примеры > MFRC522 > DumpInfo. Однако для вашего удобства я подготовил вот такую карту:
Обратите внимание – память организована в виде 16-ти секторов, по 4 блока каждый. Итого – 64 блока по 16 Байт, как раз набегает 1 Килобайт. Деление по секторам носит скорее условный характер, так как адресация в памяти будет производиться по блокам.
Все сектора кроме нулевого имеют одинаковое строение – 3 блока данных + 1 блок безопасности, так называемый sector trailer. Каждый из этих блоков может быть прочитан и перезаписан (при соблюдении условий), исключение составляет нулевой блок (сектор 0).
Нулевой блок хранит в себе уникальный ID “UID”, тип метки и прочую информацию, записанную заводом-изготовителем. Нулевой сектор не может быть перезаписан, если речь идет о “классических” метках, к которым относятся комплектные с модулем. Таким образом UID позволяет отличить две с виду идентичные метки. UID как правило состоит из 4х байт, свободно считываемых из метки. Важно: китайский рынок может предложить вам “перезаписываемые” метки, UID в которых можно менять, путем перезаписи нулевого блока. Если в вашей системе используется только UID – учтите возможность очень простого копирования UID в метки-болванки (в том числе злоумышленниками).
Блоком безопасности является каждый 4й блок, каждый блок безопасности отвечает за свой сектор (предыдущие 3 блока данных) – он хранит 2 ключа доступа по 6 байт (ключи A и B), а также специальные “Access bits” (Биты доступа), грубо говоря настройки доступа. Ключи A и B могут быть использованы для аутентификации и последующего доступа к блокам данных в пределах сектора. То есть да, для того чтобы получить доступ к любому из блоков внутри сектора необходимо “разблокировать” этот сектор, при помощи одного из ключей.
Поэтому будьте уверены, если производитель позаботился о смене секретных ключей в своих RFID метках – скопировать или как-нибудь изменить содержимое штатными средствами вы уже не сможете, а ведь так хотелось? Идем дальше.
Биты доступа позволяют настроить условия доступа и возможности работы каждого блока в отдельности (каждого блока данных + блока безопасности). Наилучшим инструментом в работе с метками MIFARE Classic 1K является вот этот онлайн-калькулятор http://calc.gmss.ru/Mifare1k/. Если хотите разобраться чуть глубже – обязательно полистайте и опробуйте.
Я же хочу сэкономить ваше время, поэтому сразу уточню, что наиболее удачным решением в большинстве ситуаций будет оставить блоки данных в состоянии transport configuration, то есть по умолчанию.
Однако есть возможность настроить блоки на некоторые интересные сценарии, например защитить от записи (конфигурация 1-0-1 или 0-1-0). Или же сделать так, что прочитать блок можно при помощи как ключа A, так и ключа B, а вот для записи обязательно понадобится ключ B (конфигурация 1-0-0), в таком случае можно ограничить права некоторого оборудования и сделать систему безопаснее. И да, конфигурация 1-1-1 превращает блок в кирпич (обратимо).
В примерах ниже мы будем использовать конфигурацию блоков данных по умолчанию (0-0-0) и следующие принципы:
- Создаем ключ B, значение которого знаем только мы, длина ключа – 6 Байт.
- Ключ A будет полностью аналогичен ключу B, однако он не будет использоваться.
- Биты доступа для блоков безопасности будем использовать в конфигурации 0-1-1
Таким образом для всех операций с меткой применяется только ключ B, который невозможно считать из метки (впрочем, как и ключ A), даже если сектор предварительно разблокирован. Если хотите намертво зашить ключи A и B в блок безопасности – подойдет конфигурация 1-0-1, поменять будет уже невозможно. Ну а последняя 1-1-1 конфигурация блока безопасности заблокирует еще и настройки доступа к блокам данных!
Некоторые варианты необратимы, но не переживайте – у вас есть целых 16 попыток! По одной на каждый сектор.
В итоге 3 байта настроек доступа приняли следующие значения: 0x7F 0x07 0x88, байт USER может быть любой.
Важно: изначально ключи A и B от всех секторов метки содержат значение 0xFFFFFFFFFFFF, так что если хотите защитить данные в ваших метках, не забывайте сменить оба ключа! Кстати, нулевой блок и соответственно UID свободно читаются из метки, даже если нулевой сектор был заблокирован секретными ключами.
Ну и последнее, что касается меток – реальный объем пользовательской памяти. Если не создавать костыли, а использовать только блоки для хранения данных – (по 3 блока в 15-ти секторах, и 2 блока в нулевом секторе) получаем 47 доступных блоков по 16 байт или 752 байта, что тоже неплохо.
Начало работы
Подключили модуль, распаковали свежие метки – начинаем работать!
Прежде всего создаем необходимые объекты, инициализируем интерфейс SPI и MFRC522, не забываем про ключ доступа. Изначально все ключи состоят из FF-ок, так что “наполняем” ключ.
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() {}
Работу с RFID модулем удобнее всего производить в конце главного цикла программы, сейчас поймете почему. Для отслеживания поднесенной метки библиотека предлагает использовать пару методов с замысловатыми названиями:
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop
Если поднесенная метка успешно считана – программа идет дальше, в противном случае происходит возврат в начало главного цикла, а весь блок кода связанный с RFID пропускается.
В итоге наш скетч имеет следующую структуру:
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop // Работаем с RFID }
Теперь давайте идти по порядку, осваивая основные методы для работы с RFID.
Обратите внимание: примеры ниже содержат специальные блоки кода, повышающие стабильность работы, о них подробно сказано в конце статьи.
Чтение UID
Самое простое, что можно сделать с RFID меткой – прочитать UID, в некоторых системах уже этого функционала вполне достаточно, например – в простых электронных замках. Как уже сказано ранее, некоторые метки позволяют сменить UID, в свою очередь запретить считать UID из ваших меток не получится – учтите это при разработке.
Так или иначе пример чтения UID и вывод в порт приведен ниже:
Чтение UID
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop Serial.print("UID: "); for (uint8_t i = 0; i < 4; i++) { // Цикл на 4 итерации Serial.print("0x"); // В формате HEX Serial.print(rfid.uid.uidByte[i], HEX); // Выводим UID по байтам Serial.print(", "); } Serial.println(""); }
После успешного чтения метки, ее UID появляется в массиве rfid.uid.uidByte[]
который можно прочитать и использовать.
Чтение блока
Если чтением UID ваш интерес не ограничился – давайте узнаем, как читать блок данных из метки. Прежде чем что-либо читать или писать, необходимо аутентифицировать (разблокировать) сектор, в котором находится интересующий нас блок.
В примерах ниже будем работать с блоком под номером 6 (сектор 1), за первый сектор и соответственно блоки 4, 5 и 6 отвечает блок безопасности под номером 7. То есть запомнили – блок данных 6, блок безопасности 7.
Аутентификацию сектора производит метод PCD_Authenticate()
, по умолчанию все манипуляции с меткой возможны при помощи ключа A, а сам процесс аутентификации выглядит следующим образом:
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; }
Обратите внимание на …KEY_A в первом аргументе и цифру 7 вторым аргументом – это и есть номер блока безопасности. Отслеживать статус не обязательно, но крайне желательно.
После успешной аутентификации можно свободно манипулировать разблокированным сектором, в нашем случае будем читать содержимое методом MIFARE_Read()
. Читать нужно в байтовый массив, размером 18 (!) байт, чтение происходит из блока 6 (первый аргумент) и выглядит так:
uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Read error"); // Выводим ошибку return; }
Важно: Не смотря на то, что блоки имеют размер 16 байт, буферный массив создается на 18 байт, а количество байт на чтение передается именно в виде указателя на переменную. В противном случае чтение закончится ошибкой, примите это как факт.
В случае успешного чтения, выведем содержимое блока 6 в монитор порта, все как обычно:
Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) { Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); } Serial.println("");
А завершать работу с меткой нужно при помощи еще двух замысловатых методов:
rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1();
В итоге полный скетч для чтения блока 6 из новой метки со стандартными ключами выглядит так:
Чтение блока
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; } /* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Read error"); // Выводим ошибку return; } /* Выводим содержимое блока в Serial */ Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) { Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); } Serial.println(""); rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); }
После поднесения метки в мониторе порта должны отобразиться 16 байт – содержимое прочитанного блока.
Запись блока
При записи все 16 байт записываются в блок единовременно, для чего должен быть заранее подготовлен байтовый массив на 16 Байт, например такой:
uint8_t dataToWrite[16] = { 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 };
Как в случае и с чтением, сектор в котором находится нужный блок 6 нужно предварительно аутентифицировать, об этом уже сказано выше, так что переходим непосредственно к записи. Запись производится методом MIFARE_Write()
, в отличии от MIFARE_Read()
тут все несколько проще – указываем записываемый блок, массив и число 16 (количество байт на запись):
status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; }
Итоговый скетч записи массива в блок 6 выглядит так:
Запись блока
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; } /* Запись блока, указываем блок данных #6 */ uint8_t dataToWrite[16] = { // Массив на запись в блок 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 }; status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; } Serial.println("Write OK"); // Завершаем работу с меткой rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); }
После поднесения метки в мониторе порта должно отобразиться сообщение “Write OK“.
К слову ничто не мешает нам объеденить запись и чтение в одном скетче:
Запись + чтение блока
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; } /* Запись блока, указываем блок данных #6 */ uint8_t dataToWrite[16] = { // Массив на запись в блок 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 }; status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; } /* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Read error"); // Выводим ошибку return; } Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) { Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); } Serial.println(""); rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); }
Смена ключей безопасности и настройка блоков
Если вы хотите не только уметь читать и писать данные в метки, но и защить хранящуюся там информацию от стороннего вмешательства – необходимо сменить ключи доступа как минимум от тех секторов, в которых вы собираетесь хранить данные, однако в идеале установить новые ключи для всех секторов, чтобы усложнить задачу потенциальным взломащикам.
Для того, чтобы изменить ключи доступа к сектору, необходимо перезаписать блок безопасности, ответственный за данный сектор. В наших примерах фигурировал блок данных под номером 6 и соответственно блок безопасности под номером 7. Задача по смене ключей безопасности сводится к следующим шагам:
- Создать байтовый массив на 16 ячеек, включающий:
- Ключ A
- Байты настроек доступа
- Ключ B
- Провести аутентификацию выбранного сектора, пока что используя стандартный ключ 0xFFFFFFFFFFFF
- Произвести запись подготовленного массива в блок безопасности, в точности так же, как в случае с обычным блоком.
После этого ключи безопасности будут изменены, а мы сможем безопасно хранить данные в одном или нескольких блоках выбранного сектора! Сейчас покажу по шагам.
- Для создания образа блока безопасности (содержимого массива) придется вернуться вверх по тексту и вспомнить, что при выбранных нами настройках сектора, байты доступа получили значения 0x7F 0x07 0x88. Осталось придумать ключи доступа, имеющие длину 6 байт. Я буду использовать ключ 0xABABABABABAB, данный ключ не является безопасным и подходит исключительно для демонстрации! Так же напоминаю, что ключи A и B будут идентичны, однако использоваться будет только ключ B.
- 1 После того, как мы определились с настройками сектора (“Access Bits“) и ключами безопасности – создаем нужный байтовый массив:
uint8_t secBlockDump[16] = { // Дамп блока безопасности 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, // < Ключ A 0x7F, 0x07, 0x88, // < Access Bits 0xFF, // < User байт (любой) 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB // < Ключ B };
Думаю по структуре массива все понятно и вполне наглядно.
- Производим аутентификацию сектора, как и раньше. Напомнинаю, что для этого используется блок безопасности 7:
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; }
- После чего записываем дамп, в тот же блок безопасности – под номером 7:
status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; }
Итоговый скетч записи новых ключей и настроек доступа:
Запись блока безопасности
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; } /* Запись блока, указываем блок безопасности #7 */ uint8_t secBlockDump[16] = { // Дамп блока безопасности 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, // < Ключ A 0x7F, 0x07, 0x88, // < Access Bits 0xFF, // < User байт (любой) 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB // < Ключ B }; status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 7 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; } Serial.println("Write OK"); // Завершаем работу с меткой rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); }
Важно: при повторном поднесении метки мы неизбежно получим ошибку аутентификации, это связано с тем, что стандартный ключ больше не подходит к перенастроенному сектору!
Не забываем сменить “наполнение” ключа в void setup(){}
:
for (byte i = 0; i < 6; i++) { // Наполняем ключ key.keyByte[i] = 0xAB; // Пишем свой ключ }
Так же напоминаю, что отныне для сектора 1 (блоков 4…7) мы используем только ключ B, соответственно и команда аутентификации отныне выглядит чуть иначе:
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; }
Работа с защищенным сектором
Теперь, после того как мы сменили ключи безопасности от сектора 1, в качестве примера будем выводить количество поднесений метки к считывателю в последовательный порт. Количество поднесений хранится в нулевом байте защищенного блока 6 и увеличивается при каждом поднесении:
Инкремент при поднесении
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() { Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) { // Наполняем ключ B key.keyByte[i] = 0xAB; // Пишем свой ключ } } void loop() { // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного } if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ B */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; } /* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Read error"); // Выводим ошибку return; } /* Выводим количество поднесений метки */ Serial.print("Count: "); // Выводим количество Serial.println(dataBlock[0]); // Хранится в нулевом байте массива dataBlock[0]++; // Инкремент /* Запись блока, указываем блок данных #6 */ status = rfid.MIFARE_Write(6, dataBlock, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) { // Если не окэй Serial.println("Write error"); // Выводим ошибку return; } rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); }
Количество поднесений ограничено 255, потому что используется лишь 1 Байт, но для примера это и не важно.
Инкремент и декремент
Наболее продвинутые могут обратить внимание на то, что пример выше не имеет смысла, поскольку метки уже имеют функционал инкремента и декремента, позволяющего использовать защищенный блок в качестве электронного кошелька.
Для реализации данного функционала библиотека имеет методы MIFARE_Increment()
и MIFARE_Decrement()
, однако независимо от установленных байтов доступа данный функционал не показал работоспособность на десятке меток и нескольких модулях. Возможно всему виной поддельные чипы MFRC522, установленные в модули. В любом случае перечисленные методы возвращают ошибку при поднесении метки, а потому и пример для работы не привожу.
Особенности и костыли
Несмотря на то, что данные модули выпускаются много лет, в течение которых дорабатывалась и библиотека, пара модуль + библиотека имеют критическую проблему зависания (!). Через случайный промежуток времени система просто перестает считывать поднесенные метки – помогает только перезагрузка микроконтроллера. Этот критический баг может сыграть злую шутку, при использовании данного комплекта в электронных замках. Что является причиной? На данный момент достоверного ответа нет… однако есть кое-какие решения!
- Периодическая перезагрузка и повторная инициализация. В главный цикл программы добавляется таймер на millis() с периодом 500…3000 мс, внутри которого производится принудительный сброс и инициализация модуля. Данный код располагается в начале главного цикла программы. Данный костыль является наиболее эффективным в борьбе с зависанием модуля.
static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) { // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного }
- Принудительная установка усиления и перезагрузка антенны. Полезность сомнительная, однако по некоторым заявлениям библиотека не всегда корректно настраивает антенну после инициализации модуля. Решается добавлением соответствующих строк помимо инициализации модуля в функции
void setup(){}
:rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну
- Повторное чтение или второй шанс. В примерах выше мы использовали следующую конструкцию для отслеживания поднесенной метки:
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop
Фокус заключается в добавлении еще одной попытке чтения метки, в случае неудачи. Таким образом наша конструкция принимает следующий вид:
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) { // Если метка не читается - пробуем еще раз if (!rfid.PICC_ReadCardSerial()) return; // Все равно не читается - вернуться в начало loop }
Наиболее эффективным и важным является первый костыль, располагайте его перед работой с модулем, желательно в начале цикла void loop(){}
, но ни в коем случае не в прерывании таймера. Однако несмотря на то, что приведенные выше хитрости действительно работают и многократно повышают стабильность работы RFID модуля – в случае с электронными замками и прочими системами контроля доступа рекомендуется иметь резервные способы входа, помимо RFID.
Есть карточка, можно на ней перезаписать, с помощью arduino и rfid522 ?
-
Вопрос заданболее трёх лет назад
-
2303 просмотра
Пригласить эксперта
От карточки зависит.
В подавляющем большинстве случаев — нельзя.
По стандарту — нельзя.
Но китайцы сказали «если нельзя, но очень хочется — то можно» и выпустили карты поддерживающие перезапись 0 блока.
Со стандартной меткой — нельзя. Но если ввести в поиске <имя_метки> white или <имя_метки> zero, то можно приобрести соответствующую метку или даже взять «за пиво» у наигравшегося.
Только не экспериментируйте в метро с Mifare Zero, ладно?;)
-
Показать ещё
Загружается…
Сбер
•
Нижний Новгород
от 220 000 ₽
10 февр. 2023, в 13:40
75000 руб./за проект
10 февр. 2023, в 13:27
2000 руб./за проект
10 февр. 2023, в 13:18
150000 руб./за проект
Минуточку внимания
Offline
Зарегистрирован: 20.05.2014
Здравствуйте!
Использую считываетль RC522 и библиотеку для него от сюда https://github.com/miguelbalboa/rfid
Подскажите как правильно изменить ключ доступа карточки с заводского FF FF FF FF FF FF на другой? В примерах это не показано а найти верную функцию в справочном файле не могу. Попробовал перезаписать ключ с помощю этого кода (с 48 строки) в 1 сектор 7 блок, после чего он перестал считыватся. Хотя по факту как я думаю записал опять же стандартынй ключ FF FF FF FF FF FF
Подскажите пожалуйста как это правильно делать?
// Библиотека RC522 взята отсюда: https://github.com/miguelbalboa/rfid #include <SPI.h> #include <MFRC522.h> #define SS_PIN 10 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. unsigned long uidDec, uidDecTemp; // Для отображения номера карточки в десятичном формате. MFRC522::MIFARE_Key keyA; void setup() { Serial.begin(9600); // Initialize serial communications with the PC SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card // Подготовьте ключ (используется как ключ A и как ключ B) // используя FFFFFFFFFFFFh, который используется по умолчанию при поставке чипа с завода byte Byte[6]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //Ключ пароль на считывание карточки for (byte i = 0; i < 6; i++) { //Закладываем в массив значения ключа который записан в массив Byte keyA.keyByte[i] = Byte[i]; } } void loop() { if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // Проверить совместимость MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); Serial.println(mfrc522.PICC_GetTypeName(piccType)); if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { Serial.println(F("This sample only works with MIFARE Classic cards.")); return; } // Закладываем адреса сектора блока куда будем писать данные byte sector = 1; byte blockAddr = 7; byte dataBlock[] = { 0x00, 0x00, 0x00, 0x00, // Дамп заводского 0x00, 0x00, 0xFF, 0x07, // ключа 0x80, 0x69, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF // }; byte trailerBlock = 7; MFRC522::StatusCode status; byte buffer[18]; byte size = sizeof(buffer); // Аутентификация с использованием ключа A // Serial.println(F("Authenticating using key A...")); status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &keyA, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return; } // Аутентификация с использованием ключа B // Serial.println(F("Authenticating again using key B...")); status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &keyA, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return; } // Записать данные в блок // Serial.print(F("Writing data into block ")); Serial.print(blockAddr); // Serial.println(F(" ...")); // dump_byte_array(dataBlock, 16); Serial.println(); status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Write() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); } Serial.println(); // Чтение данных из блока (опять же, теперь должно быть то, что мы написали) Serial.print(F("Reading data from block ")); Serial.print(blockAddr); Serial.println(F(" ...")); status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); } Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":")); dump_byte_array(buffer, 16); Serial.println(); /* for (byte i = 0; i < 4; i++) { if (uidCard[i] != mfrc522.uid.uidByte[i]){} // return; } */ // Выдача серийного номера карточки "UID". for (byte i = 0; i < mfrc522.uid.size; i++) { uidDecTemp = mfrc522.uid.uidByte[i]; uidDec = uidDec*256+uidDecTemp; } Serial.print ("UID DEC = "); Serial.println (uidDec); // Остановить PICC mfrc522.PICC_HaltA(); // Остановить шифрование на PCD mfrc522.PCD_StopCrypto1(); } // Функция преобразования массива в шеснацетеричнвй вид void dump_byte_array(byte *buffer, byte bufferSize) { for (byte i = 0; i < bufferSize; i++) { Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } }
I have been playing around with my RPi2B (with Jessie), an adafruit breakout board and a RFID-RC522. I followed a guide to make it work, and it works like a charm
Guide for adding RFID-RC522 to RPi2B
I have managed to change the information on the key, from all 00, to 1,2,3 etc, but I can’t change the key used for authentication. The guide says that the key is a default key, only containing hexadecimal 0xFF, but I want to have my own key, especially if I use this to lock a door.
Is this possible?
I have included the code for the files I use.
Read.py for reading tags
#!/usr/bin/env python
# -*- coding: utf8 -*-
import RPi.GPIO as GPIO
import MFRC522
import signal
continue_reading = True
# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
global continue_reading
print "Ctrl+C captured, ending read."
continue_reading = False
GPIO.cleanup()
# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)
# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()
# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."
# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
# Scan for cards
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# If a card is found
if status == MIFAREReader.MI_OK:
print "Card detected"
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
if uid == [164,1,33,43,175]:
print "WHITE CARD"
# This is the default key for authentication
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
# Select the scanned tag
MIFAREReader.MFRC522_SelectTag(uid)
# Authenticate
status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
# Check if authenticated
if status == MIFAREReader.MI_OK:
MIFAREReader.MFRC522_Read(8)
MIFAREReader.MFRC522_StopCrypto1()
else:
print "Authentication error"
Write.py for writing tags
#!/usr/bin/env python
# -*- coding: utf8 -*-
import RPi.GPIO as GPIO
import MFRC522
import signal
continue_reading = True
# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
global continue_reading
print "Ctrl+C captured, ending read."
continue_reading = False
GPIO.cleanup()
# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)
# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()
# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
# Scan for cards
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# If a card is found
if status == MIFAREReader.MI_OK:
print "Card detected"
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
# This is the default key for authentication
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
# Select the scanned tag
MIFAREReader.MFRC522_SelectTag(uid)
# Authenticate
status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
print "n"
# Check if authenticated
if status == MIFAREReader.MI_OK:
# Variable for the data to write
data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
# Fill the data with 0xFF
# for x in range(0,16):
# data.append(0xFF)
print "Sector 8 looked like this:"
# Read block 8
MIFAREReader.MFRC522_Read(8)
print "n"
print "Sector 8 will now be filled with data in code:"
# Write the data
MIFAREReader.MFRC522_Write(8, data)
print "n"
print "It now looks like this:"
# Check to see if it was written
MIFAREReader.MFRC522_Read(8)
print "n"
# data = []
# Fill the data with 0x00
#for x in range(0,16):
# data.append(0x00)
#print "Now we fill it with 0x00:"
#MIFAREReader.MFRC522_Write(8, data)
#print "n"
#print "It is now empty:"
# Check to see if it was written
#MIFAREReader.MFRC522_Read(8)
#print "n"
# Stop
MIFAREReader.MFRC522_StopCrypto1()
# Make sure to stop reading for cards
continue_reading = False
else:
print "Authentication error"
MFRC522.py containing the functions used in the two above
import RPi.GPIO as GPIO
import spi
import signal
class MFRC522:
NRSTPD = 22
MAX_LEN = 16
PCD_IDLE = 0x00
PCD_AUTHENT = 0x0E
PCD_RECEIVE = 0x08
PCD_TRANSMIT = 0x04
PCD_TRANSCEIVE = 0x0C
PCD_RESETPHASE = 0x0F
PCD_CALCCRC = 0x03
PICC_REQIDL = 0x26
PICC_REQALL = 0x52
PICC_ANTICOLL = 0x93
PICC_SElECTTAG = 0x93
PICC_AUTHENT1A = 0x60
PICC_AUTHENT1B = 0x61
PICC_READ = 0x30
PICC_WRITE = 0xA0
PICC_DECREMENT = 0xC0
PICC_INCREMENT = 0xC1
PICC_RESTORE = 0xC2
PICC_TRANSFER = 0xB0
PICC_HALT = 0x50
MI_OK = 0
MI_NOTAGERR = 1
MI_ERR = 2
Reserved00 = 0x00
CommandReg = 0x01
CommIEnReg = 0x02
DivlEnReg = 0x03
CommIrqReg = 0x04
DivIrqReg = 0x05
ErrorReg = 0x06
Status1Reg = 0x07
Status2Reg = 0x08
FIFODataReg = 0x09
FIFOLevelReg = 0x0A
WaterLevelReg = 0x0B
ControlReg = 0x0C
BitFramingReg = 0x0D
CollReg = 0x0E
Reserved01 = 0x0F
Reserved10 = 0x10
ModeReg = 0x11
TxModeReg = 0x12
RxModeReg = 0x13
TxControlReg = 0x14
TxAutoReg = 0x15
TxSelReg = 0x16
RxSelReg = 0x17
RxThresholdReg = 0x18
DemodReg = 0x19
Reserved11 = 0x1A
Reserved12 = 0x1B
MifareReg = 0x1C
Reserved13 = 0x1D
Reserved14 = 0x1E
SerialSpeedReg = 0x1F
Reserved20 = 0x20
CRCResultRegM = 0x21
CRCResultRegL = 0x22
Reserved21 = 0x23
ModWidthReg = 0x24
Reserved22 = 0x25
RFCfgReg = 0x26
GsNReg = 0x27
CWGsPReg = 0x28
ModGsPReg = 0x29
TModeReg = 0x2A
TPrescalerReg = 0x2B
TReloadRegH = 0x2C
TReloadRegL = 0x2D
TCounterValueRegH = 0x2E
TCounterValueRegL = 0x2F
Reserved30 = 0x30
TestSel1Reg = 0x31
TestSel2Reg = 0x32
TestPinEnReg = 0x33
TestPinValueReg = 0x34
TestBusReg = 0x35
AutoTestReg = 0x36
VersionReg = 0x37
AnalogTestReg = 0x38
TestDAC1Reg = 0x39
TestDAC2Reg = 0x3A
TestADCReg = 0x3B
Reserved31 = 0x3C
Reserved32 = 0x3D
Reserved33 = 0x3E
Reserved34 = 0x3F
serNum = []
def __init__(self,spd=1000000):
spi.openSPI(speed=spd)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(22, GPIO.OUT)
GPIO.output(self.NRSTPD, 1)
self.MFRC522_Init()
def MFRC522_Reset(self):
self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE)
def Write_MFRC522(self,addr,val):
spi.transfer(((addr<<1)&0x7E,val))
def Read_MFRC522(self,addr):
val = spi.transfer((((addr<<1)&0x7E) | 0x80,0))
return val[1]
def SetBitMask(self, reg, mask):
tmp = self.Read_MFRC522(reg)
self.Write_MFRC522(reg, tmp | mask)
def ClearBitMask(self, reg, mask):
tmp = self.Read_MFRC522(reg);
self.Write_MFRC522(reg, tmp & (~mask))
def AntennaOn(self):
temp = self.Read_MFRC522(self.TxControlReg)
if(~(temp & 0x03)):
self.SetBitMask(self.TxControlReg, 0x03)
def AntennaOff(self):
self.ClearBitMask(self.TxControlReg, 0x03)
def MFRC522_ToCard(self,command,sendData):
backData = []
backLen = 0
status = self.MI_ERR
irqEn = 0x00
waitIRq = 0x00
lastBits = None
n = 0
i = 0
if command == self.PCD_AUTHENT:
irqEn = 0x12
waitIRq = 0x10
if command == self.PCD_TRANSCEIVE:
irqEn = 0x77
waitIRq = 0x30
self.Write_MFRC522(self.CommIEnReg, irqEn|0x80)
self.ClearBitMask(self.CommIrqReg, 0x80)
self.SetBitMask(self.FIFOLevelReg, 0x80)
self.Write_MFRC522(self.CommandReg, self.PCD_IDLE);
while(i<len(sendData)):
self.Write_MFRC522(self.FIFODataReg, sendData[i])
i = i+1
self.Write_MFRC522(self.CommandReg, command)
if command == self.PCD_TRANSCEIVE:
self.SetBitMask(self.BitFramingReg, 0x80)
i = 2000
while True:
n = self.Read_MFRC522(self.CommIrqReg)
i = i - 1
if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
break
self.ClearBitMask(self.BitFramingReg, 0x80)
if i != 0:
if (self.Read_MFRC522(self.ErrorReg) & 0x1B)==0x00:
status = self.MI_OK
if n & irqEn & 0x01:
status = self.MI_NOTAGERR
if command == self.PCD_TRANSCEIVE:
n = self.Read_MFRC522(self.FIFOLevelReg)
lastBits = self.Read_MFRC522(self.ControlReg) & 0x07
if lastBits != 0:
backLen = (n-1)*8 + lastBits
else:
backLen = n*8
if n == 0:
n = 1
if n > self.MAX_LEN:
n = self.MAX_LEN
i = 0
while i<n:
backData.append(self.Read_MFRC522(self.FIFODataReg))
i = i + 1;
else:
status = self.MI_ERR
return (status,backData,backLen)
def MFRC522_Request(self, reqMode):
status = None
backBits = None
TagType = []
self.Write_MFRC522(self.BitFramingReg, 0x07)
TagType.append(reqMode);
(status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType)
if ((status != self.MI_OK) | (backBits != 0x10)):
status = self.MI_ERR
return (status,backBits)
def MFRC522_Anticoll(self):
backData = []
serNumCheck = 0
serNum = []
self.Write_MFRC522(self.BitFramingReg, 0x00)
serNum.append(self.PICC_ANTICOLL)
serNum.append(0x20)
(status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum)
if(status == self.MI_OK):
i = 0
if len(backData)==5:
while i<4:
serNumCheck = serNumCheck ^ backData[i]
i = i + 1
if serNumCheck != backData[i]:
status = self.MI_ERR
else:
status = self.MI_ERR
return (status,backData)
def CalulateCRC(self, pIndata):
self.ClearBitMask(self.DivIrqReg, 0x04)
self.SetBitMask(self.FIFOLevelReg, 0x80);
i = 0
while i<len(pIndata):
self.Write_MFRC522(self.FIFODataReg, pIndata[i])
i = i + 1
self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC)
i = 0xFF
while True:
n = self.Read_MFRC522(self.DivIrqReg)
i = i - 1
if not ((i != 0) and not (n&0x04)):
break
pOutData = []
pOutData.append(self.Read_MFRC522(self.CRCResultRegL))
pOutData.append(self.Read_MFRC522(self.CRCResultRegM))
return pOutData
def MFRC522_SelectTag(self, serNum):
backData = []
buf = []
buf.append(self.PICC_SElECTTAG)
buf.append(0x70)
i = 0
while i<5:
buf.append(serNum[i])
i = i + 1
pOut = self.CalulateCRC(buf)
buf.append(pOut[0])
buf.append(pOut[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status == self.MI_OK) and (backLen == 0x18):
print("Size: " + str(backData[0]))
return backData[0]
else:
return 0
def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum):
buff = []
buff.append(authMode)
buff.append(BlockAddr)
i = 0
while(i < len(Sectorkey)):
buff.append(Sectorkey[i])
i = i + 1
i = 0
while(i < len(serNum)):
buff.append(serNum[i])
i = i +1
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff)
if not(status == self.MI_OK):
print("AUTH ERROR!!")
if not (self.Read_MFRC522(self.Status2Reg) & 0x08) != 0:
print("AUTH ERROR(status2reg & 0x08) != 0")
return status
def MFRC522_Read(self, blockAddr):
recvData = []
recvData.append(self.PICC_READ)
recvData.append(blockAddr)
pOut = self.CalulateCRC(recvData)
recvData.append(pOut[0])
recvData.append(pOut[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData)
if not(status == self.MI_OK):
print("Error while reading!")
print("Got data size: "+str(backLen))
i = 0
if len(backData) == 16:
print("Sector "+str(blockAddr)+" "+str(backData))
def MFRC522_Write(self, blockAddr, writeData):
buff = []
buff.append(self.PICC_WRITE)
buff.append(blockAddr)
crc = self.CalulateCRC(buff)
buff.append(crc[0])
buff.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff)
if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
status = self.MI_ERR
print(str(backLen)+" backdata &0x0F == 0x0A "+str(backData[0]&0x0F))
if status == self.MI_OK:
i = 0
buf = []
while i < 16:
buf.append(writeData[i])
i = i + 1
crc = self.CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf)
if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
print("Error while writing")
if status == self.MI_OK:
print("Data writen")
def MFRC522_Init(self):
GPIO.output(self.NRSTPD, 1)
self.MFRC522_Reset();
self.Write_MFRC522(self.TModeReg, 0x8D)
self.Write_MFRC522(self.TPrescalerReg, 0x3E)
self.Write_MFRC522(self.TReloadRegL, 30)
self.Write_MFRC522(self.TReloadRegH, 0)
self.Write_MFRC522(self.TxAutoReg, 0x40)
self.Write_MFRC522(self.ModeReg, 0x3D)
self.AntennaOn()
def GPIO_CLEEN(self):
GPIO.cleanup()
I have been playing around with my RPi2B (with Jessie), an adafruit breakout board and a RFID-RC522. I followed a guide to make it work, and it works like a charm
Guide for adding RFID-RC522 to RPi2B
I have managed to change the information on the key, from all 00, to 1,2,3 etc, but I can’t change the key used for authentication. The guide says that the key is a default key, only containing hexadecimal 0xFF, but I want to have my own key, especially if I use this to lock a door.
Is this possible?
I have included the code for the files I use.
Read.py for reading tags
#!/usr/bin/env python
# -*- coding: utf8 -*-
import RPi.GPIO as GPIO
import MFRC522
import signal
continue_reading = True
# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
global continue_reading
print "Ctrl+C captured, ending read."
continue_reading = False
GPIO.cleanup()
# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)
# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()
# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."
# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
# Scan for cards
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# If a card is found
if status == MIFAREReader.MI_OK:
print "Card detected"
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
if uid == [164,1,33,43,175]:
print "WHITE CARD"
# This is the default key for authentication
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
# Select the scanned tag
MIFAREReader.MFRC522_SelectTag(uid)
# Authenticate
status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
# Check if authenticated
if status == MIFAREReader.MI_OK:
MIFAREReader.MFRC522_Read(8)
MIFAREReader.MFRC522_StopCrypto1()
else:
print "Authentication error"
Write.py for writing tags
#!/usr/bin/env python
# -*- coding: utf8 -*-
import RPi.GPIO as GPIO
import MFRC522
import signal
continue_reading = True
# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
global continue_reading
print "Ctrl+C captured, ending read."
continue_reading = False
GPIO.cleanup()
# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)
# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()
# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:
# Scan for cards
(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
# If a card is found
if status == MIFAREReader.MI_OK:
print "Card detected"
# Get the UID of the card
(status,uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
# This is the default key for authentication
key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]
# Select the scanned tag
MIFAREReader.MFRC522_SelectTag(uid)
# Authenticate
status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
print "n"
# Check if authenticated
if status == MIFAREReader.MI_OK:
# Variable for the data to write
data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
# Fill the data with 0xFF
# for x in range(0,16):
# data.append(0xFF)
print "Sector 8 looked like this:"
# Read block 8
MIFAREReader.MFRC522_Read(8)
print "n"
print "Sector 8 will now be filled with data in code:"
# Write the data
MIFAREReader.MFRC522_Write(8, data)
print "n"
print "It now looks like this:"
# Check to see if it was written
MIFAREReader.MFRC522_Read(8)
print "n"
# data = []
# Fill the data with 0x00
#for x in range(0,16):
# data.append(0x00)
#print "Now we fill it with 0x00:"
#MIFAREReader.MFRC522_Write(8, data)
#print "n"
#print "It is now empty:"
# Check to see if it was written
#MIFAREReader.MFRC522_Read(8)
#print "n"
# Stop
MIFAREReader.MFRC522_StopCrypto1()
# Make sure to stop reading for cards
continue_reading = False
else:
print "Authentication error"
MFRC522.py containing the functions used in the two above
import RPi.GPIO as GPIO
import spi
import signal
class MFRC522:
NRSTPD = 22
MAX_LEN = 16
PCD_IDLE = 0x00
PCD_AUTHENT = 0x0E
PCD_RECEIVE = 0x08
PCD_TRANSMIT = 0x04
PCD_TRANSCEIVE = 0x0C
PCD_RESETPHASE = 0x0F
PCD_CALCCRC = 0x03
PICC_REQIDL = 0x26
PICC_REQALL = 0x52
PICC_ANTICOLL = 0x93
PICC_SElECTTAG = 0x93
PICC_AUTHENT1A = 0x60
PICC_AUTHENT1B = 0x61
PICC_READ = 0x30
PICC_WRITE = 0xA0
PICC_DECREMENT = 0xC0
PICC_INCREMENT = 0xC1
PICC_RESTORE = 0xC2
PICC_TRANSFER = 0xB0
PICC_HALT = 0x50
MI_OK = 0
MI_NOTAGERR = 1
MI_ERR = 2
Reserved00 = 0x00
CommandReg = 0x01
CommIEnReg = 0x02
DivlEnReg = 0x03
CommIrqReg = 0x04
DivIrqReg = 0x05
ErrorReg = 0x06
Status1Reg = 0x07
Status2Reg = 0x08
FIFODataReg = 0x09
FIFOLevelReg = 0x0A
WaterLevelReg = 0x0B
ControlReg = 0x0C
BitFramingReg = 0x0D
CollReg = 0x0E
Reserved01 = 0x0F
Reserved10 = 0x10
ModeReg = 0x11
TxModeReg = 0x12
RxModeReg = 0x13
TxControlReg = 0x14
TxAutoReg = 0x15
TxSelReg = 0x16
RxSelReg = 0x17
RxThresholdReg = 0x18
DemodReg = 0x19
Reserved11 = 0x1A
Reserved12 = 0x1B
MifareReg = 0x1C
Reserved13 = 0x1D
Reserved14 = 0x1E
SerialSpeedReg = 0x1F
Reserved20 = 0x20
CRCResultRegM = 0x21
CRCResultRegL = 0x22
Reserved21 = 0x23
ModWidthReg = 0x24
Reserved22 = 0x25
RFCfgReg = 0x26
GsNReg = 0x27
CWGsPReg = 0x28
ModGsPReg = 0x29
TModeReg = 0x2A
TPrescalerReg = 0x2B
TReloadRegH = 0x2C
TReloadRegL = 0x2D
TCounterValueRegH = 0x2E
TCounterValueRegL = 0x2F
Reserved30 = 0x30
TestSel1Reg = 0x31
TestSel2Reg = 0x32
TestPinEnReg = 0x33
TestPinValueReg = 0x34
TestBusReg = 0x35
AutoTestReg = 0x36
VersionReg = 0x37
AnalogTestReg = 0x38
TestDAC1Reg = 0x39
TestDAC2Reg = 0x3A
TestADCReg = 0x3B
Reserved31 = 0x3C
Reserved32 = 0x3D
Reserved33 = 0x3E
Reserved34 = 0x3F
serNum = []
def __init__(self,spd=1000000):
spi.openSPI(speed=spd)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(22, GPIO.OUT)
GPIO.output(self.NRSTPD, 1)
self.MFRC522_Init()
def MFRC522_Reset(self):
self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE)
def Write_MFRC522(self,addr,val):
spi.transfer(((addr<<1)&0x7E,val))
def Read_MFRC522(self,addr):
val = spi.transfer((((addr<<1)&0x7E) | 0x80,0))
return val[1]
def SetBitMask(self, reg, mask):
tmp = self.Read_MFRC522(reg)
self.Write_MFRC522(reg, tmp | mask)
def ClearBitMask(self, reg, mask):
tmp = self.Read_MFRC522(reg);
self.Write_MFRC522(reg, tmp & (~mask))
def AntennaOn(self):
temp = self.Read_MFRC522(self.TxControlReg)
if(~(temp & 0x03)):
self.SetBitMask(self.TxControlReg, 0x03)
def AntennaOff(self):
self.ClearBitMask(self.TxControlReg, 0x03)
def MFRC522_ToCard(self,command,sendData):
backData = []
backLen = 0
status = self.MI_ERR
irqEn = 0x00
waitIRq = 0x00
lastBits = None
n = 0
i = 0
if command == self.PCD_AUTHENT:
irqEn = 0x12
waitIRq = 0x10
if command == self.PCD_TRANSCEIVE:
irqEn = 0x77
waitIRq = 0x30
self.Write_MFRC522(self.CommIEnReg, irqEn|0x80)
self.ClearBitMask(self.CommIrqReg, 0x80)
self.SetBitMask(self.FIFOLevelReg, 0x80)
self.Write_MFRC522(self.CommandReg, self.PCD_IDLE);
while(i<len(sendData)):
self.Write_MFRC522(self.FIFODataReg, sendData[i])
i = i+1
self.Write_MFRC522(self.CommandReg, command)
if command == self.PCD_TRANSCEIVE:
self.SetBitMask(self.BitFramingReg, 0x80)
i = 2000
while True:
n = self.Read_MFRC522(self.CommIrqReg)
i = i - 1
if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
break
self.ClearBitMask(self.BitFramingReg, 0x80)
if i != 0:
if (self.Read_MFRC522(self.ErrorReg) & 0x1B)==0x00:
status = self.MI_OK
if n & irqEn & 0x01:
status = self.MI_NOTAGERR
if command == self.PCD_TRANSCEIVE:
n = self.Read_MFRC522(self.FIFOLevelReg)
lastBits = self.Read_MFRC522(self.ControlReg) & 0x07
if lastBits != 0:
backLen = (n-1)*8 + lastBits
else:
backLen = n*8
if n == 0:
n = 1
if n > self.MAX_LEN:
n = self.MAX_LEN
i = 0
while i<n:
backData.append(self.Read_MFRC522(self.FIFODataReg))
i = i + 1;
else:
status = self.MI_ERR
return (status,backData,backLen)
def MFRC522_Request(self, reqMode):
status = None
backBits = None
TagType = []
self.Write_MFRC522(self.BitFramingReg, 0x07)
TagType.append(reqMode);
(status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType)
if ((status != self.MI_OK) | (backBits != 0x10)):
status = self.MI_ERR
return (status,backBits)
def MFRC522_Anticoll(self):
backData = []
serNumCheck = 0
serNum = []
self.Write_MFRC522(self.BitFramingReg, 0x00)
serNum.append(self.PICC_ANTICOLL)
serNum.append(0x20)
(status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum)
if(status == self.MI_OK):
i = 0
if len(backData)==5:
while i<4:
serNumCheck = serNumCheck ^ backData[i]
i = i + 1
if serNumCheck != backData[i]:
status = self.MI_ERR
else:
status = self.MI_ERR
return (status,backData)
def CalulateCRC(self, pIndata):
self.ClearBitMask(self.DivIrqReg, 0x04)
self.SetBitMask(self.FIFOLevelReg, 0x80);
i = 0
while i<len(pIndata):
self.Write_MFRC522(self.FIFODataReg, pIndata[i])
i = i + 1
self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC)
i = 0xFF
while True:
n = self.Read_MFRC522(self.DivIrqReg)
i = i - 1
if not ((i != 0) and not (n&0x04)):
break
pOutData = []
pOutData.append(self.Read_MFRC522(self.CRCResultRegL))
pOutData.append(self.Read_MFRC522(self.CRCResultRegM))
return pOutData
def MFRC522_SelectTag(self, serNum):
backData = []
buf = []
buf.append(self.PICC_SElECTTAG)
buf.append(0x70)
i = 0
while i<5:
buf.append(serNum[i])
i = i + 1
pOut = self.CalulateCRC(buf)
buf.append(pOut[0])
buf.append(pOut[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
if (status == self.MI_OK) and (backLen == 0x18):
print("Size: " + str(backData[0]))
return backData[0]
else:
return 0
def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum):
buff = []
buff.append(authMode)
buff.append(BlockAddr)
i = 0
while(i < len(Sectorkey)):
buff.append(Sectorkey[i])
i = i + 1
i = 0
while(i < len(serNum)):
buff.append(serNum[i])
i = i +1
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff)
if not(status == self.MI_OK):
print("AUTH ERROR!!")
if not (self.Read_MFRC522(self.Status2Reg) & 0x08) != 0:
print("AUTH ERROR(status2reg & 0x08) != 0")
return status
def MFRC522_Read(self, blockAddr):
recvData = []
recvData.append(self.PICC_READ)
recvData.append(blockAddr)
pOut = self.CalulateCRC(recvData)
recvData.append(pOut[0])
recvData.append(pOut[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData)
if not(status == self.MI_OK):
print("Error while reading!")
print("Got data size: "+str(backLen))
i = 0
if len(backData) == 16:
print("Sector "+str(blockAddr)+" "+str(backData))
def MFRC522_Write(self, blockAddr, writeData):
buff = []
buff.append(self.PICC_WRITE)
buff.append(blockAddr)
crc = self.CalulateCRC(buff)
buff.append(crc[0])
buff.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff)
if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
status = self.MI_ERR
print(str(backLen)+" backdata &0x0F == 0x0A "+str(backData[0]&0x0F))
if status == self.MI_OK:
i = 0
buf = []
while i < 16:
buf.append(writeData[i])
i = i + 1
crc = self.CalulateCRC(buf)
buf.append(crc[0])
buf.append(crc[1])
(status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf)
if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
print("Error while writing")
if status == self.MI_OK:
print("Data writen")
def MFRC522_Init(self):
GPIO.output(self.NRSTPD, 1)
self.MFRC522_Reset();
self.Write_MFRC522(self.TModeReg, 0x8D)
self.Write_MFRC522(self.TPrescalerReg, 0x3E)
self.Write_MFRC522(self.TReloadRegL, 30)
self.Write_MFRC522(self.TReloadRegH, 0)
self.Write_MFRC522(self.TxAutoReg, 0x40)
self.Write_MFRC522(self.ModeReg, 0x3D)
self.AntennaOn()
def GPIO_CLEEN(self):
GPIO.cleanup()