суббота, 10 мая 2014 г.

Система управления доступом и эмулятор ключей на базе iButton+NFC/RFID ридера из нано-буратины

Данный комплекс ПО предназначен для автономной работы с ключами iButton/RFID или картами NFC на базе модуля Arduino или ее клонов и передачи кодов идентификаторов ключей на верхний уровень по виртуальному COM-порту over интерфейса USB/BlueTooth в ОС NT/2000/2003/XP/Vista/7/8. Восстановление связи при использовании виртуального последовательного порта осуществляется автоматически.

Cистемные требования и зависимости:
  1. Windows XP/Vista/7/8/8.1/10.
  2. Наличие виртуального или физического COM-порта over USB/BlueTooth (модуль прозрачного UART over BlueTooth - HC-05).
  3. Модуль Arduino (любой).
  4. Ридер карт NFC/RFID - MFRC522.
  5. Ключи iButton.
  6. Карты NFC или RFID.



















Схема подключений для использования iButton:


Совмещенный скетч:
//-------------------------------------------------------
// iButton + NFC-RFID Reader realtime for Arduino Nano ATMega328
// Modification: Badlo Sergey Grigoryevich
// H-page:
http://raxp.radioliga.com
//-------------------------------------------------------

#include <OneWire.h>
#include <EEPROM.h>
#include <SPI.h>
#include <Wire.h>
#include <MFRC522.h>

/*
RC522 Card Read Module + Arduino Uno + Mega + Nano
 ----------------------------------------------------------------------------------------------
 * Pin layout should be as follows:
 * Signal         Pin                Pin          Pin           Pin
 *                   Arduino Uno   Mega       Nano328    MFRC522 board
 * --------------------------------------------------------------------------------------------
 * Reset           9                  5             D9            RST
 * SPI SS        10                 53           D10          SDA
 * SPI MOSI   11                 51            D11          MOSI
 * SPI MISO   12                 50            D12          MISO
 * SPI SCK     13                 52            D13          SCK
 */


#define PSDA 10
#define PRST 9
MFRC522 mfrc522(PSDA, PRST);
unsigned long uidDec, uidDecTemp;

// 100 ячеек EEPROM (100 клиентов)
unsigned long CardUIDReadEEPROM[] = {
  0,1,2,3,4,5,6,7,8,9,
  10,11,12,13,14,15,16,17,18,19,
  20,21,22,23,24,25,26,27,28,29,
  30,31,32,33,34,35,36,37,38,39,
  40,41,42,43,44,45,46,47,48,49,
  50,51,52,53,54,55,56,57,58,59,
  60,61,62,63,64,65,66,67,68,69,
  70,71,72,73,74,75,76,77,78,79,
  80,81,82,83,84,85,86,87,88,89,
  90,91,92,93,94,95,96,97,98,99};
 
int ARRAYindexUIDcard; // CardUIDReadEEPROM
int EEPROMstartAddr;   // EEPROM Card UID
int LockSwitch;

// идентификторы двух ключей iButton
byte key1[8] = {0x01, 0x5D, 0x90, 0x29, 0x10, 0x00, 0x00, 0x47}; // 01 5D 90 29 10 00 00 47
byte key2[8] = {0x01, 0x70, 0xC1, 0x0F, 0x10, 0x00, 0x00, 0x9A}; // 01 70 C1 0F 10 00 00 9A

int pinNumber = 2;      // подтянуть на Vcc через R=2.2 кОм
OneWire ds(pinNumber);


void setup(){  
  pinMode(3, OUTPUT);    // анод первого светодиода
  pinMode(4, OUTPUT);    // катод
  digitalWrite(3, LOW);  // включить - HIGH
  digitalWrite(4, LOW);

  // подтяжка к плюсу 10-пина
  pinMode(pinNumber, INPUT_PULLUP);

  Serial.begin(9600);
  SPI.begin();           // Init SPI bus.
  mfrc522.PCD_Init();    // Init MFRC522 card.

  // три раза помигаем
  mig(); mig(); mig();
  Serial.println("Portal http://raxp.radioliga.com...");
  SerialWAiT_CARD();
  EEPROMreadUIDcard();
}

void loop() {
  byte addr[8];
  byte val1 = 0;
  byte val2 = 0;
 
  delay(100);
  if (ds.search(addr)) {  // если обнаружен, шлем идентификатор на верхний уровень
   Serial.print("#");     // старт пакета
   for (int i=0; i<8; i++) {
       Serial.print(" "); // разделитель пробел
       Serial.print(addr[i], HEX);
      
       // 1-ключ (аппаратная идентификация, например мастер-ключа)
       if (addr[i] == key1[i]) val1++;
       // 2-ключ
       if (addr[i] == key2[i]) val2++;
   }
   Serial.print("@"); // стоп пакета
   Serial.println("");  
   ds.reset_search();
  }
 
  // мигаем два раза
  if (val1 == 8) {
     mig();
     delay(150);
     mig();
     Serial.println("Na proxodnoj Master Yoda");    
  }
  // мигаем три раза
  if (val2 == 8) {
     mig();
     delay(150);
     mig();
     delay(150);
     mig();
     Serial.println("Na proxodnoj Dj");   
  }  


  // ------------------------------------------------------------
  // Look for new cards

  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  // "UID".
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec*256+uidDecTemp; 
  } 

  // Вход в режим программирования по карте администратора
  if (uidDec == 445091925 || LockSwitch > 0)EEPROMwriteUIDcard();
  // ----------------------------------------


  if (LockSwitch == 0)
  {
    // CardUIDReadEEPROM.
    for(ARRAYindexUIDcard = 0; ARRAYindexUIDcard <= 99; ARRAYindexUIDcard++)
    {
      if (CardUIDReadEEPROM[ARRAYindexUIDcard] > 0)
      {
  
        if (CardUIDReadEEPROM[ARRAYindexUIDcard] == uidDec)
        {
          CommandsCARD();
          break;
        }
      }
    }  

    if (ARRAYindexUIDcard == 100){ Serial.println("NOT Found CARD-UID"); Serial.println(uidDec); }
    delay(2000);   
    ARRAYindexUIDcard = 0;
    SerialWAiT_CARD();
  }
}

void mig() {
 digitalWrite(3, HIGH);
 delay(50);
 digitalWrite(3, LOW);
}

void EEPROMwriteUIDcard() {

  if (LockSwitch == 0) //
  {
    Serial.println("Admin mode programming CardUID to EEPROM");
    for(int i = 0; i <= 2; i++) delay(500), mig(), delay(500), mig();
  }

  if (LockSwitch > 0) {
    if (uidDec == 445091925)
    {
      Serial.println("SKIP RECORD");
      Serial.println(EEPROMstartAddr/5);
      EEPROMstartAddr += 5;

      mig(), delay(200), mig();
    }

    else
    {
      EEPROM.write(EEPROMstartAddr, uidDec & 0xFF);
      EEPROM.write(EEPROMstartAddr + 1, (uidDec & 0xFF00) >> 8);
      EEPROM.write(EEPROMstartAddr + 2, (uidDec & 0xFF0000) >> 16);
      EEPROM.write(EEPROMstartAddr + 3, (uidDec & 0xFF000000) >> 24);
      delay(10);
      // --
      Serial.println("EEPROM OK");
      Serial.println(EEPROMstartAddr/5);
   

      EEPROMstartAddr += 5;
      for(int i = 0; i <= 40; i++)delay(5),mig(),delay(5),mig();
    }  
  }

  LockSwitch++;

  if (EEPROMstartAddr/5 == 100)
  {
    delay(2000);
    Serial.println("EEPROM SUCCEFUL");
    mig(),delay(2000),mig();

    EEPROMstartAddr = 0;  
    uidDec = 0;
    ARRAYindexUIDcard = 0;

    EEPROMreadUIDcard(); // CardUIDReadEEPROM
  }
}


// Чтение CardUIDReadEEPROM из EEPROM
void EEPROMreadUIDcard()
{
  for(int i = 0; i <= 99; i++)
  {
    byte val = EEPROM.read(EEPROMstartAddr+3);  
    CardUIDReadEEPROM[ARRAYindexUIDcard] = (CardUIDReadEEPROM[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr+2);
    CardUIDReadEEPROM[ARRAYindexUIDcard] = (CardUIDReadEEPROM[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr+1); // EEPROMstartAddr + 1.
    CardUIDReadEEPROM[ARRAYindexUIDcard] = (CardUIDReadEEPROM[ARRAYindexUIDcard] << 8) | val;
    val = EEPROM.read(EEPROMstartAddr);
    CardUIDReadEEPROM[ARRAYindexUIDcard] = (CardUIDReadEEPROM[ARRAYindexUIDcard] << 8) | val;

    ARRAYindexUIDcard++;
    EEPROMstartAddr +=5;
  }

  ARRAYindexUIDcard = 0;
  EEPROMstartAddr = 0;
  uidDec = 0;
  LockSwitch = 0;
  SerialWAiT_CARD();       
}

// ждем карту
void SerialWAiT_CARD() {
 Serial.println("WAIT CARD");
}

// идентификация карт из EEPROM
void CommandsCARD()
{
  Serial.print("Na proxodnoj ");

  // ARRAYindexUIDcard
  if (ARRAYindexUIDcard == 0)
  {
    Serial.println("Sergey");
  }
  else if (ARRAYindexUIDcard == 1)
  {
    Serial.println("Marina");
  }
  else if (ARRAYindexUIDcard == 2)
  {
    Serial.println("Oksana");
  }
  else if (ARRAYindexUIDcard == 3)
  {
    Serial.println("Elena");
  }
  else if (ARRAYindexUIDcard == 99)
  {
    Serial.println("Larisa");
  }

  Serial.println(CardUIDReadEEPROM[ARRAYindexUIDcard]); // Card-UID
  Serial.println(ARRAYindexUIDcard); // Номер карты Card-UID
  // индицируем количество карт
  for(int i = 0; i <= ARRAYindexUIDcard; i++) delay(20), mig(), delay(20), mig();
  delay(1);
}
Эмулятор ключей iButton

Для чего необходимо? К примеру, связка из нескольких ключей вас не устраивает или не хочется платить местным домофонщикам за новый дубликат ключа. С помощью нашего ридера считайте сам ключ для которого потребуется сделать дубликат. Теперь берем нано-буратину, добавляем литиевую батарейку на 3.7В и пишем скетч эмулятора для отсылки ключа:
#include <OneWireSlave.h>

// идентификторы двух ключей iButton
byte key1[8] = {0x01, 0x5D, 0x90, 0x29, 0x10, 0x00, 0x00, 0x47}; // 01 5D 90 29 10 00 00 47
byte key2[8] = {0x01, 0x70, 0xC1, 0x0F, 0x10, 0x00, 0x00, 0x9A}; // 01 70 C1 0F 10 00 00 9A 

void setup() { 
 OneWireSlave KeySend(2);
}

void loop() {
          KeySend.setRom(key1);
          if(!KeySend.waitForRequest(0)){
              
          } else {

          } 
          KeySend.setRom(key2);
          if(!KeySend.waitForRequest(0)){
              
          } else {

          }
}
Запись ключей DS1990

Рассмотрим пример чтения и записи:

#include <OneWire.h>


byte key[8] = {0x03, 0xDA, 0x12, 0x10, 0x11, 0x16, 0x00, 0xD3};

#define pinkey=2
OneWire ds(pinkey); //1-Wire number pin Arduino


void setup(void) {

  Serial.begin(9600);
}


void send_impulse()

{
  pinMode(pin, OUTPUT);
  digitalWrite(pin, HIGH); 
  delay(60);
  digitalWrite(pin, LOW); 
  delay(5);
  digitalWrite(pin, HIGH); 
  delay(50); 
}


void loop(void) {

  byte i;
  byte data[8];


  delay(1000); // 1 sec  

  ds.reset();
  delay(50);
  ds.write(0x33); // команда чтения
  
  ds.read_bytes(data, 8);
  Serial.print("KEY ");
  for( i = 0; i < 8; i++) {
    Serial.print(data[i], HEX);
    if (i!= 7) Serial.print(":");
  }


  // проверка CRC

  if (data[0] & data[1] & data[2] & data[3] & data[4] & data[5] & data[6] & data[7] == 0xFF)
  {
    Serial.println("...ошибка!"); 
    return;
  }
  return;


  // Читаем ключ

  for (i = 0; i < 8; i++)
    if (data[i] != key[i])
      break;
    else
      if (i == 7)
      {
        Serial.println("ключ уже зашит");
        return;
      }

  Serial.println();
  Serial.print("запись нового ключа...");  
  for (uint8_t i = 0; i < 8; i++)
  {
    ds.reset();
    data[0] = 0x3C; // команда на запись
    data[1] = i;
    data[2] = 0;
    data[3] = key_to_write[i];
    ds.write_bytes(data, 4);
    Serial.print(".");
  
    uint8_t crc = ds.read();    
    if (OneWire::crc8(data, 4) != crc) {
        Serial.print("error!\r\n");
        return;
    }
    else Serial.print(".");    
    send_impulse();
  }  
  Serial.println("Выполнено!");
}

ПОРЯДОК ИСПОЛЬЗОВАНИЯ и ОГРАНИЧЕНИЯ
  1. Вы можете произвольно задавать COM порт в демонстрационном ПО 'iButton_Reader.exe'.
  2. Скетч 'iButton_RC522.ino' осуществляет автономное чтение любых 1-Wire устройств и распознавание двух установленных идентификаторов с последующими действиями, например включение нагрузки.
  3. Поддерживается запись и идентификация до 100 карт NFC и ключей RFID по админ-ключу.
  4. Для работы интерфейса 1-Wire требуется подтяжка порта (пин 2 в скетче) на плюс питания через сопротивление от 4.7 до 2 кОм (чем длиннее провода до контакта, тем меньшее сопротивление требуется выбрать для стабильной работы).
  5. Осуществляется автоотслеживание выдергивания конвертора UART/USB (через SetupAPI) и переподключение на заданный при инициализации порт.
  6. Распиновка для подключения модулей Arduino UNO/Mega/Nano и платы ридера MFRC522 приведена в скетче.
Ресурсы по тематике
  1. Мини-HASP ключ из любого USB-устройства
  2. Пример работы с HASP-ключом iButton USB reader
  3. Система управления доступом на базе iButton+NFC/RFID ридера из нано-буратины

    Комментариев нет:

    Отправить комментарий

    В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.