Вот этот?
/*
Доработка проекта "Копировальщик ключей для домофона RFID с OLED дисплеем и хранением 8 ключей в памяти EEPROM"
Автор: МЕХАТРОН DIY, AlexMalov, 2019 https://github.com/AlexMalov/EasyKeyDublicatorRFID_OLED/
Аппаратная часть построена на Arduino Nano или Arduino Pro Mini
---------------------Мои доработки-----------------------------
1. Переназначил вывод генерации 125 кГц с вывода 11 на вывод 3 чтобы освободить шину SPI
2. Добавлена подержка работы с модулем RC522, модуль подключается по SPI шине к 11-12-13 пинам Arduino
3. Написаны функции чтения и записи UID в RFID метки типа Mifare 1k на заготовки типа Mifare Zero, этого как правило достаточно для нормальной работы брелка.
4. Добавил возможность принудительной очистки EEPROM, для этого перед вкл. прибора нужно зажать кнопку энкодера и неотпускать ее пока не засветится красный светодиод
5. Также в место режима blueMode я сделал режим очистки и восстановления Mifare метки, когда метка неопределяется и нечитается пробуем этот режим. Если кому то нужен режим blueMode, то просто раскоментируйте #define BLUE_MODE в начале кода.
*/
// Подключаем библиотеки
#include <OneWire.h>
#include <OneWireSlave.h>
#include "pitches.h"
#include <EEPROM.h>
#include <OLED_I2C.h>
OLED myOLED(SDA, SCL); //создаем экземпляр класса OLED с именем myOLED
extern uint8_t SmallFont[];
extern uint8_t BigNumbers[];
#include "GyverEncoder.h"
#include "TimerOne.h"
#include <SPI.h>
#include <MFRC522.h>
/*
* Typical pin layout used:
* -----------------------------------------------------------------------------------------
* MFRC522 Arduino Arduino Arduino Arduino Arduino
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro
* Signal Pin Pin Pin Pin Pin Pin
* -----------------------------------------------------------------------------------------
* SPI SS SDA(SS) 10 53 D10 10 10
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15
*/
// Настройки
// #define DEBUG_ENABLED // Раскоментируйте для вкл отладки
// #define BLUE_MODE // Раскоментируйте если вам нужен BlueMode
#define rfidUsePWD 0 // ключ использует пароль для изменения
#define rfidPWD 123456 // пароль для ключа
#define rfidBitRate 2 // Скорость обмена с rfid в kbps
// Контакты
#define iButtonPin A3 // Линия data ibutton
#define iBtnEmulPin A1 // Линия эмулятора ibutton
#define R_Led 2 // RGB Led
#define G_Led 4
#define B_Led 5
#define ACpin 6 // Вход Ain0 аналогового компаратора 0.1В для EM-Marie
#define speakerPin A2 // Спикер, он же buzzer, он же beeper
#define FreqGen 3 // генератор 125 кГц
#define CLK 8 // s1 энкодера
#define DT 9 // s2 энкодера
#define BtnPin 0 // Кнопка переключения режима чтение/запись
#define SS_PIN 10
#define RST_PIN A0
MFRC522 rfid(SS_PIN, RST_PIN); // Создаем объект MFRC522
MFRC522::MIFARE_Key key;
Encoder enc1(CLK, DT, BtnPin);
OneWire ibutton (iButtonPin);
OneWireSlave iBtnEmul(iBtnEmulPin); //Эмулятор iButton для BlueMode
byte maxKeyCount; // максимальное кол-во ключей, которое влазит в EEPROM, но не > 20
byte EEPROM_key_count; // количество ключей 0..maxKeyCount, хранящихся в EEPROM
byte EEPROM_key_index = 0; // 1..EEPROM_key_count номер последнего записанного в EEPROM ключа
byte addr[8]; // временный буфер
byte keyID[8]; // ID ключа для записи
byte rfidData[5]; // значащие данные frid em-marine
byte halfT; // полупериод для метаком
bool statOk = false; // статус успешной операции, чтобы запись или очистка не проиходила по кругу
enum emRWType {rwUnknown, TM01, RW1990_1, RW1990_2, TM2004, T5557, EM4305}; // тип болванки
enum emkeyType {keyUnknown, keyDallas, keyTM2004, keyCyfral, keyMetacom, keyEM_Marine, keyMifare}; // тип оригинального ключа
emkeyType keyType;
enum emMode {md_empty, md_read, md_write, md_threeMode}; // режим раоты копировальщика
emMode copierMode = md_empty;
void OLED_printKey(byte buf[8], byte msgType = 0){
String st;
switch (msgType){
case 0: st = "The key " + String(EEPROM_key_index) + " of " + String(EEPROM_key_count) + " in ROM"; break;
case 1: st = "Hold the Btn to save"; break;
case 3: st = "The key " + String(indxKeyInROM(buf)) + " exists in ROM"; break;
}
myOLED.clrScr();
myOLED.print(st, 0, 0);
st = "";
for (byte i = 0; i < 8; i++) st += String(buf[i], HEX) +":";
myOLED.print(st, 0, 12);
st = "Type ";
switch (keyType){
case keyDallas: st += "Dallas wire"; break;
case keyCyfral: st += "Cyfral wire"; break;
case keyMetacom: st += "Metakom wire"; break;
case keyEM_Marine: st += "EM_Marine rfid"; break;
case keyMifare: st += "Mifare rfid"; break;
case keyUnknown: st += "Unknown"; break;
}
myOLED.print(st, 0, 24);
myOLED.update();
}
void OLED_printError(String st, bool err = true){
myOLED.clrScr();
if (err) myOLED.print(F("Error!"), 0, 0);
else myOLED.print(F("OK"), 0, 0);
myOLED.print(st, 0, 12);
myOLED.update();
}
void setup() {
// Конфигурация пинов
pinMode(BtnPin, INPUT_PULLUP); // включаем чтение и подягиваем пин кнопки режима к +5В
pinMode(speakerPin, OUTPUT);
pinMode(ACpin, INPUT); // Вход аналогового компаратора 3В для Cyfral
pinMode(R_Led, OUTPUT); pinMode(G_Led, OUTPUT); pinMode(B_Led, OUTPUT); //RGB-led
clearLed();
pinMode(FreqGen, OUTPUT);
#ifdef DEBUG_ENABLED
Serial.begin(115200);
#endif
// Конфигурация OLED дисплея
myOLED.begin(SSD1306_128X32); //инициализируем дисплей
myOLED.clrScr(); //Очищаем буфер дисплея.
myOLED.setFont(SmallFont); //Перед выводом текста необходимо выбрать шрифт
myOLED.print(F("Hello, read a key..."), LEFT, 0);
char st[23] = { 98, 121, 32, 77, 69, 84, 80, 79, 72, 32, 38, 32, 83, 105, 98, 77, 97, 110, 32, 68, 73, 89, 0 };
myOLED.print(st, LEFT, 24);
myOLED.update();
// Конфигурация RC522
SPI.begin(); // Инициализируем SPI интерфейс
rfid.PCD_Init(); // Инициализируем MFRC522
if (!digitalRead(BtnPin)){ // Если зажать кнопку при включении то очистится EEPROM
digitalWrite(R_Led, HIGH);
for (int i = 0 ; i < EEPROM.length() ; i++) {
EEPROM.write(i, 0);
}
Serial.print(F("EEPROM cleared"));
delay(100);
clearLed();
}
Sd_StartOK(); // Издаем звук удачного запуска
EEPROM_key_count = EEPROM[0];
maxKeyCount = EEPROM.length() / 8 - 1; if (maxKeyCount > 20) maxKeyCount = 20;
if (EEPROM_key_count > maxKeyCount) EEPROM_key_count = 0;
if (EEPROM_key_count != 0 ) {
EEPROM_key_index = EEPROM[1];
Serial.print(F("Read key code from EEPROM: "));
EEPROM_get_key(EEPROM_key_index, keyID);
for (byte i = 0; i < 8; i++) {
Serial.print(keyID[i], HEX); Serial.print(F(":"));
}
Serial.println();
delay(3000);
OLED_printKey(keyID);
copierMode = md_read;
digitalWrite(G_Led, HIGH);
} else {
myOLED.print(F("ROM has no keys yet."), 0, 12);
myOLED.update();
}
enc1.setTickMode(AUTO);
enc1.setType(TYPE2);
// enc1.setDirection(REVERSE); // NORM / REVERSE
Timer1.initialize(1000); // установка таймера на каждые 1000 микросекунд (= 1 мс)
Timer1.attachInterrupt(timerIsr); // запуск таймера
}
void timerIsr() { // прерывание таймера для энкодера
enc1.tick();
}
void clearLed(){
digitalWrite(R_Led, LOW);
digitalWrite(G_Led, LOW);
digitalWrite(B_Led, LOW);
}
byte indxKeyInROM(byte buf[]){ //возвращает индекс или ноль если нет в ROM
byte buf1[8]; bool eq = true;
for (byte j = 1; j<=EEPROM_key_count; j++){ // ищем ключ в eeprom.
EEPROM.get(j*sizeof(buf1), buf1);
for (byte i = 0; i < 8; i++)
if (buf1[i] != buf[i]) { eq = false; break;}
if (eq) return j;
eq = true;
}
return 0;
}
bool EPPROM_AddKey(byte buf[]){
byte buf1[8]; byte indx;
indx = indxKeyInROM(buf); // ищем ключ в eeprom. Если находим, то не делаем запись, а индекс переводим в него
if ( indx != 0) {
EEPROM_key_index = indx;
EEPROM.update(1, EEPROM_key_index);
return false;
}
if (EEPROM_key_count <= maxKeyCount) EEPROM_key_count++;
if (EEPROM_key_count < maxKeyCount) EEPROM_key_index = EEPROM_key_count;
else EEPROM_key_index++;
if (EEPROM_key_index > EEPROM_key_count) EEPROM_key_index = 1;
Serial.println(F("Adding to EEPROM"));
for (byte i = 0; i < 8; i++) {
buf1[i] = buf[i];
Serial.print(buf[i], HEX); Serial.print(F(":"));
}
Serial.println();
EEPROM.put(EEPROM_key_index*sizeof(buf1), buf1);
EEPROM.update(0, EEPROM_key_count);
EEPROM.update(1, EEPROM_key_index);
return true;
}
void EEPROM_get_key(byte EEPROM_key_index1, byte buf[8]){
byte buf1[8];
int address = EEPROM_key_index1*sizeof(buf1);
if (address > EEPROM.length()) return;
EEPROM.get(address, buf1);
for (byte i = 0; i < 8; i++) buf[i] = buf1[i];
keyType = getKeyType(buf1);
}
emkeyType getKeyType(byte* buf){ // Определение типа ключа
if ((buf[0] == 0xFF) && vertEvenCheck(buf)) return keyEM_Marine;
if (buf[4] == 0 && buf[5] == 0 && buf[6] == 0 && buf[7] == 0) return keyMifare;
if (buf[0] == 0x01) return keyDallas;
if ((buf[0] >> 4) == 0b0001) return keyCyfral;
if ((buf[0] >> 4) == 0b0010) return keyMetacom;
return keyUnknown;
}
//*************** dallas **************
emRWType getRWtype(){
byte answer;
// TM01 это неизвестный тип болванки, делается попытка записи TM-01 без финализации для dallas или c финализацией под cyfral или metacom
// RW1990_1 - dallas-совместимые RW-1990, RW-1990.1, ТМ-08, ТМ-08v2
// RW1990_2 - dallas-совместимая RW-1990.2
// TM2004 - dallas-совместимая TM2004 в доп. памятью 1кб
// пробуем определить RW-1990.1
ibutton.reset(); ibutton.write(0xD1); // проуем снять флаг записи для RW-1990.1
ibutton.write_bit(1); // записываем значение флага записи = 1 - отключаем запись
delay(10); pinMode(iButtonPin, INPUT);
ibutton.reset(); ibutton.write(0xB5); // send 0xB5 - запрос на чтение флага записи
answer = ibutton.read();
//Serial.print(F("\n Answer RW-1990.1: ")); Serial.println(answer, HEX);
if (answer == 0xFE){
Serial.println(F(" Type: dallas RW-1990.1 "));
return RW1990_1; // это RW-1990.1
}
// пробуем определить RW-1990.2
ibutton.reset(); ibutton.write(0x1D); // пробуем установить флаг записи для RW-1990.2
ibutton.write_bit(1); // записываем значение флага записи = 1 - включаем запись
delay(10); pinMode(iButtonPin, INPUT);
ibutton.reset(); ibutton.write(0x1E); // send 0x1E - запрос на чтение флага записи
answer = ibutton.read();
if (answer == 0xFE){
ibutton.reset(); ibutton.write(0x1D); // возвращаем оратно запрет записи для RW-1990.2
ibutton.write_bit(0); // записываем значение флага записи = 0 - выключаем запись
delay(10); pinMode(iButtonPin, INPUT);
Serial.println(F(" Type: dallas RW-1990.2 "));
return RW1990_2; // это RW-1990.2
}
// пробуем определить TM-2004
ibutton.reset(); ibutton.write(0x33); // посылаем команду чтения ROM для перевода в расширенный 3-х байтовый режим
for ( byte i=0; i<8; i++) ibutton.read(); // читаем данные ключа
ibutton.write(0xAA); // пробуем прочитать регистр статуса для TM-2004
ibutton.write(0x00); ibutton.write(0x00); // передаем адрес для считывания
answer = ibutton.read(); // читаем CRC комманды и адреса
byte m1[3] = {0xAA, 0,0}; // вычисляем CRC комманды
if (OneWire::crc8(m1, 3) == answer) {
answer = ibutton.read(); // читаем регистр статуса
//Serial.print(" status: "); Serial.println(answer, HEX);
Serial.println(F(" Type: dallas TM2004"));
ibutton.reset();
return TM2004; // это Type: TM2004
}
ibutton.reset();
Serial.println(F(" Type: dallas unknown, trying TM-01! "));
return TM01; // это неизвестный тип DS1990, нужно перебирать алгоритмы записи (TM-01)
}
bool write2iBtnTM2004(){ // функция записи на TM2004
byte answer; bool result = true;
ibutton.reset();
ibutton.write(0x3C); // команда записи ROM для TM-2004
ibutton.write(0x00); ibutton.write(0x00); // передаем адрес с которого начинается запись
for (byte i = 0; i<8; i++){
digitalWrite(R_Led, !digitalRead(R_Led));
ibutton.write(keyID[i]);
answer = ibutton.read();
//if (OneWire::crc8(m1, 3) != answer){result = false; break;} // crc не верный
delayMicroseconds(600); ibutton.write_bit(1); delay(50); // испульс записи
pinMode(iButtonPin, INPUT);
Serial.print('*');
Sd_WriteStep();
if (keyID[i] != ibutton.read()) { result = false; break;} //читаем записанный байт и сравниваем, с тем что должно записаться
}
if (!result){
ibutton.reset();
Serial.println(F(" The key copy faild"));
OLED_printError(F("The key copy faild"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
return false;
}
ibutton.reset();
Serial.println(F(" The key has copied successfully"));
OLED_printError(F("The key has copied"), false);
Sd_ReadOK();
delay(2000);
digitalWrite(R_Led, HIGH);
return true;
}
bool write2iBtnRW1990_1_2_TM01(emRWType rwType){ // функция записи на RW1990.1, RW1990.2, TM-01C(F)
byte rwCmd, bitCnt = 64, rwFlag = 1;
switch (rwType){
case TM01: rwCmd = 0xC1; if ((keyType == keyMetacom)||(keyType == keyCyfral)) bitCnt = 36; break; //TM-01C(F)
case RW1990_1: rwCmd = 0xD1; rwFlag = 0; break; // RW1990.1 флаг записи инвертирован
case RW1990_2: rwCmd = 0x1D; break; // RW1990.2
}
ibutton.reset(); ibutton.write(rwCmd); // send 0xD1 - флаг записи
ibutton.write_bit(rwFlag); // записываем значение флага записи = 1 - разрешить запись
delay(5); pinMode(iButtonPin, INPUT);
ibutton.reset();
if (rwType == TM01) ibutton.write(0xC5);
else ibutton.write(0xD5); // команда на запись
if (bitCnt == 36) BurnByteMC(keyID);
else for (byte i = 0; i< (bitCnt >> 3); i++){
digitalWrite(R_Led, !digitalRead(R_Led));
if (rwType == RW1990_1) BurnByte(~keyID[i]); // запись происходит инверсно для RW1990.1
else BurnByte(keyID[i]);
Serial.print('*');
Sd_WriteStep();
}
if (bitCnt == 64) {
ibutton.write(rwCmd); // send 0xD1 - флаг записи
ibutton.write_bit(!rwFlag); // записываем значение флага записи = 1 - отключаем запись
delay(5); pinMode(iButtonPin, INPUT);
}
digitalWrite(R_Led, LOW);
if (!dataIsBurningOK(bitCnt)){ // проверяем корректность записи
Serial.println(F(" The key copy faild"));
OLED_printError(F("The key copy faild"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
return false;
}
Serial.println(F(" The key has copied successfully"));
if ((keyType == keyMetacom)||(keyType == keyCyfral)){ //переводим ключ из формата dallas
ibutton.reset();
if (keyType == keyCyfral) ibutton.write(0xCA); // send 0xCA - флаг финализации Cyfral
else ibutton.write(0xCB); // send 0xCB - флаг финализации metacom
ibutton.write_bit(1); // записываем значение флага финализации = 1 - перевезти формат
delay(10); pinMode(iButtonPin, INPUT);
}
OLED_printError(F("The key has copied"), false);
Sd_ReadOK();
delay(2000);
digitalWrite(R_Led, HIGH);
return true;
}
void BurnByte(byte data){
for(byte n_bit = 0; n_bit < 8; n_bit++){
ibutton.write_bit(data & 1);
delay(5); // даем время на прошивку каждого бита до 10 мс
data = data >> 1; // переходим к следующему bit
}
pinMode(iButtonPin, INPUT);
}
void BurnByteMC(byte buf[8]){
byte j = 0;
for(byte n_bit = 0; n_bit < 36; n_bit++){
ibutton.write_bit(((~buf[n_bit>>3]) >> (7-j) ) & 1);
delay(5); // даем время на прошивку каждого бита 5 мс
j++;
if (j > 7) j = 0;
}
pinMode(iButtonPin, INPUT);
}
void convetr2MC(byte buff[8]){
byte data;
for (byte i = 0; i < 5; i++){
data = ~buff[i];
buff[i] = 0;
for (byte j = 0; j < 8; j++)
if ( (data>>j)&1) bitSet(buff[i], 7-j);
}
buff[4] &= 0xf0; buff[5] = 0; buff[6] = 0; buff[7] = 0;
}
bool dataIsBurningOK(byte bitCnt){
byte buff[8];
if (!ibutton.reset()) return false;
ibutton.write(0x33);
ibutton.read_bytes(buff, 8);
if (bitCnt == 36) convetr2MC(buff);
byte Check = 0;
for (byte i = 0; i < 8; i++){
if (keyID[i] == buff[i]) Check++; // сравниваем код для записи с тем, что уже записано в ключе.
Serial.print(buff[i], HEX); Serial.print(":");
}
if (Check != 8) return false; // если коды совпадают, ключ успешно скопирован
return true;
}
bool write2iBtn(){
int Check = 0;
if (!ibutton.search(addr)) {
ibutton.reset_search();
return false;
}
Serial.print(F("The new key code is: "));
for (byte i = 0; i < 8; i++) {
Serial.print(addr[i], HEX); Serial.print(":");
if (keyID[i] == addr[i]) Check++; // сравниваем код для записи с тем, что уже записано в ключе.
}
if (Check == 8) { // если коды совпадают, ничего писать не нужно
digitalWrite(R_Led, LOW);
Serial.println(F(" it is the same key. Writing in not needed."));
OLED_printError(F("It is the same key"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
delay(1000);
return false;
}
emRWType rwType = getRWtype(); // определяем тип RW-1990.1 или 1990.2 или TM-01
Serial.print(F("\n Burning iButton ID: "));
if (rwType == TM2004) return write2iBtnTM2004(); //шьем TM2004
else return write2iBtnRW1990_1_2_TM01(rwType); //пробуем прошить другие форматы
}
bool searchIbutton(){
if (!ibutton.search(addr)) {
ibutton.reset_search();
return false;
}
for (byte i = 0; i < 8; i++) {
Serial.print(addr[i], HEX); Serial.print(":");
keyID[i] = addr[i]; // копируем прочтенный код в ReadID
}
if (addr[0] == 0x01) { // это ключ формата dallas
keyType = keyDallas;
if (getRWtype() == TM2004) keyType = keyTM2004;
if (OneWire::crc8(addr, 7) != addr[7]) {
Serial.println(F("CRC is not valid!"));
OLED_printError(F("CRC is not valid!"));
Sd_ErrorBeep();
digitalWrite(B_Led, HIGH);
return false;
}
return true;
}
switch (addr[0]>>4){
case 1: Serial.println(F(" Type: May be cyfral in dallas key")); break;
case 2: Serial.println(F(" Type: May be metacom in dallas key")); break;
case 3: Serial.println(F(" Type: unknown family dallas")); break;
}
keyType = keyUnknown;
return true;
}
//************ Cyfral ***********************
unsigned long pulseACompA(bool pulse, byte Average = 80, unsigned long timeOut = 1500){ // pulse HIGH or LOW
bool AcompState;
unsigned long tEnd = micros() + timeOut;
do {
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1 << ADSC)); // Wait until the ADSC bit has been cleared
if (ADCH > 200) return 0;
if (ADCH > Average) AcompState = HIGH; // читаем флаг компаратора
else AcompState = LOW;
if (AcompState == pulse) {
tEnd = micros() + timeOut;
do {
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1 << ADSC)); // Wait until the ADSC bit has been cleared
if (ADCH > Average) AcompState = HIGH; // читаем флаг компаратора
else AcompState = LOW;
if (AcompState != pulse) return (unsigned long)(micros() + timeOut - tEnd);
} while (micros() < tEnd);
return 0; //таймаут, импульс не вернуся оратно
} // end if
} while (micros() < tEnd);
return 0;
}
void ADCsetOn(){
ADMUX = (ADMUX&0b11110000) | 0b0011 | (1<<ADLAR);// (1 << REFS0); // подключаем к AC Линию A3 , левое выравние, измерение до Vcc
ADCSRB = (ADCSRB & 0b11111000) | (1<<ACME); // источник перезапуска ADC FreeRun, включаем мультиплексор AC
ADCSRA = (ADCSRA & 0b11111000) |0b011 | (1<<ADEN) | (1<<ADSC);// | (1<<ADATE); // 0b011 делитель скорости ADC, // включаем ADC и запускаем ADC и autotriger ADC
}
void ACsetOn(){
ACSR |= 1<<ACBG; // Подключаем ко входу Ain0 1.1V для Cyfral/Metacom
ADCSRA &= ~(1<<ADEN); // выключаем ADC
ADMUX = (ADMUX&0b11110000) | 0b0011; // подключаем к AC Линию A3
ADCSRB |= 1<<ACME; // включаем мультиплексор AC
}
bool read_cyfral(byte* buf, byte CyfralPin){
unsigned long ti; byte i=0, j = 0, k = 0;
analogRead(iButtonPin);
ADCsetOn();
byte aver = calcAverage();
unsigned long tEnd = millis() + 30;
do{
ti = pulseACompA(HIGH, aver);
if ((ti == 0) || (ti > 260) || (ti < 10)) {i = 0; j=0; k = 0; continue;}
if ((i < 3) && (ti > halfT)) {i = 0; j = 0; k = 0; continue;} //контроль стартовой последовательности 0b0001
if ((i == 3) && (ti < halfT)) continue;
if (ti > halfT) bitSet(buf[i >> 3], 7-j);
else if (i > 3) k++;
if ((i > 3) && ((i-3)%4 == 0) ){ //начиная с 4-го бита проверяем количество нулей каждой строки из 4-и бит
if (k != 1) {for (byte n = 0; n < (i >> 3)+2; n++) buf[n] = 0; i = 0; j = 0; k = 0; continue;} //если нулей больше одной - начинаем сначала
k = 0;
}
j++; if (j>7) j=0;
i++;
} while ((millis() < tEnd) && (i < 36));
if (i < 36) return false;
return true;
}
bool searchCyfral(){
byte buf[8];
for (byte i = 0; i < 8; i++) {addr[i] =0; buf[i] = 0;}
if (!read_cyfral(addr, iButtonPin)) return false;
if (!read_cyfral(buf, iButtonPin)) return false;
for (byte i = 0; i < 8; i++)
if (addr[i] != buf[i]) return false;
keyType = keyCyfral;
for (byte i = 0; i < 8; i++) {
Serial.print(addr[i], HEX); Serial.print(":");
keyID[i] = addr[i]; // копируем прочтенный код в ReadID
}
Serial.println(F(" Type: Cyfral "));
return true;
}
byte calcAverage(){
unsigned int sum = 127; byte preADCH = 0, j = 0;
for (byte i = 0; i<255; i++) {
ADCSRA |= (1<<ADSC);
delayMicroseconds(10);
while(ADCSRA & (1 << ADSC)); // Wait until the ADSC bit has been cleared
sum += ADCH;
}
sum = sum >> 8;
unsigned long tSt = micros();
for (byte i = 0; i<255; i++) {
delayMicroseconds(4);
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1 << ADSC)); // Wait until the ADSC bit has been cleared
if (((ADCH > sum)&&(preADCH < sum)) | ((ADCH < sum)&&(preADCH > sum))) {
j++;
preADCH = ADCH;
}
}
halfT = (byte)((micros() - tSt) / j);
return (byte)sum;
}
bool read_metacom(byte* buf, byte MetacomPin){
unsigned long ti; byte i = 0, j = 0, k = 0;
analogRead(iButtonPin);
ADCsetOn();
byte aver = calcAverage();
unsigned long tEnd = millis() + 30;
do{
ti = pulseACompA(LOW, aver);
if ((ti == 0) || (ti > 500)) {i = 0; j=0; k = 0; continue;}
if ((i == 0) && (ti+30 < (halfT<<1))) continue; //вычисляем период;
if ((i == 2) && (ti > halfT)) {i = 0; j = 0; continue;} //вычисляем период;
if (((i == 1) || (i == 3)) && (ti < halfT)) {i = 0; j = 0; continue;} //вычисляем период;
if (ti < halfT) {
bitSet(buf[i >> 3], 7-j);
if (i > 3) k++; // считаем кол-во единиц
}
if ((i > 3) && ((i-3)%8 == 0) ){ //начиная с 4-го бита проверяем контроль четности каждой строки из 8-и бит
if (k & 1) { for (byte n = 0; n < (i >> 3)+1; n++) buf[n] = 0; i = 0; j = 0; k = 0; continue;} //если нечетно - начинаем сначала
k = 0;
}
j++; if (j>7) j=0;
i++;
} while ((millis() < tEnd) && (i < 36));
if (i < 36) return false;
return true;
}
bool searchMetacom(){
byte buf[8];
for (byte i = 0; i < 8; i++) {addr[i] =0; buf[i] = 0;}
if (!read_metacom(addr, iButtonPin)) return false;
if (!read_metacom(buf, iButtonPin)) return false;
for (byte i = 0; i < 8; i++)
if (addr[i] != buf[i]) return false;
keyType = keyMetacom;
for (byte i = 0; i < 8; i++) {
Serial.print(addr[i], HEX); Serial.print(":");
keyID[i] = addr[i]; // копируем прочтенный код в ReadID
}
Serial.println(F(" Type: Metacom "));
return true;
}
//**********EM-Marine***************************
bool vertEvenCheck(byte* buf){ // проверка четности столбцов с данными
byte k;
k = 1&buf[1]>>6 + 1&buf[1]>>1 + 1&buf[2]>>4 + 1&buf[3]>>7 + 1&buf[3]>>2 + 1&buf[4]>>5 + 1&buf[4] + 1&buf[5]>>3 + 1&buf[6]>>6 + 1&buf[6]>>1 + 1&buf[7]>>4;
if (k&1) return false;
k = 1&buf[1]>>5 + 1&buf[1] + 1&buf[2]>>3 + 1&buf[3]>>6 + 1&buf[3]>>1 + 1&buf[4]>>4 + 1&buf[5]>>7 + 1&buf[5]>>2 + 1&buf[6]>>5 + 1&buf[6] + 1&buf[7]>>3;
if (k&1) return false;
k = 1&buf[1]>>4 + 1&buf[2]>>7 + 1&buf[2]>>2 + 1&buf[3]>>5 + 1&buf[3] + 1&buf[4]>>3 + 1&buf[5]>>6 + 1&buf[5]>>1 + 1&buf[6]>>4 + 1&buf[7]>>7 + 1&buf[7]>>2;
if (k&1) return false;
k = 1&buf[1]>>3 + 1&buf[2]>>6 + 1&buf[2]>>1 + 1&buf[3]>>4 + 1&buf[4]>>7 + 1&buf[4]>>2 + 1&buf[5]>>5 + 1&buf[5] + 1&buf[6]>>3 + 1&buf[7]>>6 + 1&buf[7]>>1;
if (k&1) return false;
if (1&buf[7]) return false;
//номер ключа, который написан на корпусе
rfidData[0] = (0b01111000&buf[1])<<1 | (0b11&buf[1])<<2 | buf[2]>>6;
rfidData[1] = (0b00011110&buf[2])<<3 | buf[3]>>4;
rfidData[2] = buf[3]<<5 | (0b10000000&buf[4])>>3 | (0b00111100&buf[4])>>2;
rfidData[3] = buf[4]<<7 | (0b11100000&buf[5])>>1 | 0b1111&buf[5];
rfidData[4] = (0b01111000&buf[6])<<1 | (0b11&buf[6])<<2 | buf[7]>>6;
return true;
}
byte ttAComp(unsigned long timeOut = 7000){ // pulse 0 or 1 or -1 if timeout
byte AcompState, AcompInitState;
unsigned long tEnd = micros() + timeOut;
AcompInitState = (ACSR >> ACO)&1; // читаем флаг компаратора
do {
AcompState = (ACSR >> ACO)&1; // читаем флаг компаратора
if (AcompState != AcompInitState) {
delayMicroseconds(1000/(rfidBitRate*4)); // 1/4 Period on 2 kBps = 125 mks
AcompState = (ACSR >> ACO)&1; // читаем флаг компаратора
delayMicroseconds(1000/(rfidBitRate*2)); // 1/2 Period on 2 kBps = 250 mks
return AcompState;
}
} while (micros() < tEnd);
return 2; //таймаут, компаратор не сменил состояние
}
bool readEM_Marie(byte* buf){
unsigned long tEnd = millis() + 50;
byte ti; byte j = 0, k=0;
for (int i = 0; i<64; i++){ // читаем 64 bit
ti = ttAComp();
if (ti == 2) break; //timeout
if ( ( ti == 0 ) && ( i < 9)) { // если не находим 9 стартовых единиц - начинаем сначала
if (millis() > tEnd) { ti=2; break;} //timeout
i = -1; j=0; continue;
}
if ((i > 8) && (i < 59)){ //начиная с 9-го бита проверяем контроль четности каждой строки
if (ti) k++; // считаем кол-во единиц
if ( (i-9)%5 == 4 ){ // конец строки с данными из 5-и бит,
if (k & 1) { //если нечетно - начинаем сначала
i = -1; j = 0; k = 0; continue;
}
k = 0;
}
}
if (ti) bitSet(buf[i >> 3], 7-j);
else bitClear(buf[i >> 3], 7-j);
j++; if (j>7) j=0;
}
if (ti == 2) return false; //timeout
return vertEvenCheck(buf);
}
void rfidACsetOn(){
//включаем генератор 125кГц
pinMode(FreqGen, OUTPUT);
// настраиваем таймер 2 для генерации сигнала на выводе 3
TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Включаем режим Phase correct PWM (8-битный) и счет таймера2 до OCR2A
TCCR2B = _BV(WGM22) | _BV(CS20); // Задаем делитель для таймера2 = 1 (частота 16 МГц)
OCR2A = 125; // Задаем период таймера (125 тактов на период, 125 кГц на выводе 3)
OCR2B = 62; // Задаем скважность на 50% (62/125)
// включаем компаратор
ADCSRB &= ~(1<<ACME); // отключаем мультиплексор AC
ACSR &= ~(1<<ACBG); // отключаем от входа Ain0 1.1V
}
bool searchEM_Marine( bool copyKey = true){
// byte gr = digitalRead(G_Led);
bool rez = false;
rfidACsetOn(); // включаем генератор 125кГц и компаратор
delay(6); //13 мс длятся переходные прцессы детектора
if (!readEM_Marie(addr)) {
if (!copyKey) TCCR2A &= ~_BV(COM2B1); //Оключить ШИМ COM2B (pin 3)
// digitalWrite(G_Led, gr);
return rez;
}
rez = true;
keyType = keyEM_Marine;
for (byte i = 0; i<8; i++){
if (copyKey) keyID[i] = addr [i];
Serial.print(addr[i], HEX); Serial.print(":");
}
Serial.print(F(" ( id "));
Serial.print(rfidData[0]); Serial.print(" key ");
unsigned long keyNum = (unsigned long)rfidData[1]<<24 | (unsigned long)rfidData[2]<<16 | (unsigned long)rfidData[3]<<8 | (unsigned long)rfidData[4];
Serial.print(keyNum);
Serial.println(F(") Type: EM-Marie "));
if (!copyKey) TCCR2A &= ~_BV(COM2B1); //Оключить ШИМ COM2B (pin 3)
// digitalWrite(G_Led, gr);
return rez;
}
void TxBitRfid(byte data){
if (data & 1) delayMicroseconds(54*8);
else delayMicroseconds(24*8);
rfidGap(19*8); //write gap
}
void TxByteRfid(byte data){
for(byte n_bit=0; n_bit<8; n_bit++){
TxBitRfid(data & 1);
data = data >> 1; // переходим к следующему bit
}
}
void rfidGap(unsigned int tm){
TCCR2A &= ~_BV(COM2B1); //Оключить ШИМ COM2B (pin 3)
delayMicroseconds(tm);
TCCR2A |= _BV(COM2B1); // Включить ШИМ COM2B (pin 3)
}
bool T5557_blockRead(byte* buf){
byte ti; byte j = 0, k=0;
for (int i = 0; i<33; i++){ // читаем стартовый 0 и 32 значащих bit
ti = ttAComp(2000);
if (ti == 2) break; //timeout
if ( ( ti == 1 ) && ( i == 0)) { ti=2; break; } // если не находим стартовый 0 - это ошибка
if (i > 0){ //начиная с 1-го бита пишем в буфер
if (ti) bitSet(buf[(i-1) >> 3], 7-j);
else bitClear(buf[(i-1) >> 3], 7-j);
j++; if (j>7) j=0;
}
}
if (ti == 2) return false; //timeout
return true;
}
bool sendOpT5557(byte opCode, unsigned long password = 0, byte lockBit = 0, unsigned long data = 0, byte blokAddr = 1){
TxBitRfid(opCode >> 1); TxBitRfid(opCode & 1); // передаем код операции 10
if (opCode == 0b00) return true;
// password
TxBitRfid(lockBit & 1); // lockbit 0
if (data != 0){
for (byte i = 0; i<32; i++) {
TxBitRfid((data>>(31-i)) & 1);
}
}
TxBitRfid(blokAddr>>2); TxBitRfid(blokAddr>>1); TxBitRfid(blokAddr & 1); // адрес блока для записи
delay(4); // ждем пока пишутся данные
return true;
}
bool write2rfidT5557(byte* buf){
bool result; unsigned long data32;
delay(6);
for (byte k = 0; k<2; k++){ // send key data
data32 = (unsigned long)buf[0 + (k<<2)]<<24 | (unsigned long)buf[1 + (k<<2)]<<16 | (unsigned long)buf[2 + (k<<2)]<<8 | (unsigned long)buf[3 + (k<<2)];
rfidGap(30 * 8); //start gap
sendOpT5557(0b10, 0, 0, data32, k+1); //передаем 32 бита ключа в blok k
Serial.print('*'); delay(6);
}
delay(6);
rfidGap(30 * 8); //start gap
sendOpT5557(0b00);
delay(4);
result = readEM_Marie(addr);
TCCR2A &= ~_BV(COM2B1); //Оключить ШИМ COM2B (pin 3)
for (byte i = 0; i < 8; i++)
if (addr[i] != keyID[i]) { result = false; break; }
if (!result){
Serial.println(F(" The key copy faild"));
OLED_printError(F("The key copy faild"));
Sd_ErrorBeep();
} else {
Serial.println(F(" The key has copied successfully"));
OLED_printError(F("The key has copied"), false);
Sd_ReadOK();
delay(2000);
}
digitalWrite(R_Led, HIGH);
return result;
}
emRWType getRfidRWtype(){
unsigned long data32, data33; byte buf[4] = {0, 0, 0, 0};
rfidACsetOn(); // включаем генератор 125кГц и компаратор
delay(13); //13 мс длятся переходные процессы детектора
rfidGap(30 * 8); //start gap
sendOpT5557(0b11, 0, 0, 0, 1); //переходим в режим чтения Vendor ID
if (!T5557_blockRead(buf)) return rwUnknown;
data32 = (unsigned long)buf[0]<<24 | (unsigned long)buf[1]<<16 | (unsigned long)buf[2]<<8 | (unsigned long)buf[3];
delay(4);
rfidGap(20 * 8); //gap
data33 = 0b00000000000101001000000001000000 | (rfidUsePWD << 4); //конфиг регистр 0b00000000000101001000000001000000
sendOpT5557(0b10, 0, 0, data33, 0); //передаем конфиг регистр
delay(4);
rfidGap(30 * 8); //start gap
sendOpT5557(0b11, 0, 0, 0, 1); //переходим в режим чтения Vendor ID
if (!T5557_blockRead(buf)) return rwUnknown;
data33 = (unsigned long)buf[0]<<24 | (unsigned long)buf[1]<<16 | (unsigned long)buf[2]<<8 | (unsigned long)buf[3];
sendOpT5557(0b00, 0, 0, 0, 0); // send Reset
delay(6);
if (data32 != data33) return rwUnknown;
Serial.print(F(" The rfid RW-key is T5557. Vendor ID is "));
Serial.println(data32, HEX);
return T5557;
}
bool write2rfid(){
bool Check = true;
if (searchEM_Marine(false)) {
for (byte i = 0; i < 8; i++)
if (addr[i] != keyID[i]) { Check = false; break; } // сравниваем код для записи с тем, что уже записано в ключе.
if (Check) { // если коды совпадают, ничего писать не нужно
digitalWrite(R_Led, LOW);
Serial.println(F(" it is the same key. Writing in not needed."));
OLED_printError(F("It is the same key"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
delay(1000);
return false;
}
}
emRWType rwType = getRfidRWtype(); // определяем тип T5557 (T5577) или EM4305
if (rwType != rwUnknown) Serial.print(F("\n Burning rfid ID: "));
switch (rwType){
case T5557: return write2rfidT5557(keyID); break; //пишем T5557
//case EM4305: return write2rfidEM4305(keyID); break; //пишем EM4305
case rwUnknown: break;
}
return false;
}
//**********Mifare***************************
bool searchMifare() {
bool result = false;
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
// Ожидаем считывания метки
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
// Копируем UID метки в массив
for (byte i = 0; i < rfid.uid.size; i++) {
addr[i] = rfid.uid.uidByte[i];
}
rfid.PICC_HaltA(); // Останавливаем считывание метки
keyType = keyMifare;
for (byte i = 0; i<8; i++){
keyID[i] = addr [i];
Serial.print(addr[i], HEX); Serial.print(":");
}
Serial.println(F(") Type: Mifare "));
result = true;
}
return result;
}
bool write2Mifare() {
bool result = false;
bool Check = false;
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
// Считываем UID метки
for (byte i = 0; i < rfid.uid.size; i++) {
addr[i] = rfid.uid.uidByte[i];
if (addr[i] != keyID[i]) { Check = true; break; } // сравниваем код для записи с тем, что уже записано в ключе.
}
if (Check) { // сравниваем код для записи с тем, что уже записано в ключе.
// Если коды не совпадают пишем новый UID на метку
if ( rfid.MIFARE_SetUid(keyID, (byte)4, true) ) {
Serial.println(F(" The key has copied successfully "));
OLED_printError(F("The key has copied"), false);
Sd_ReadOK();
result = true;
statOk = result;
}
else {
digitalWrite(R_Led, LOW);
Serial.println(F(" The key copy faild "));
OLED_printError(F("The key copy faild"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
delay(1000);
}
}
else {
digitalWrite(R_Led, LOW);
Serial.println(F(" it is the same key. Writing in not needed."));
OLED_printError(F("It is the same key"));
Sd_ErrorBeep();
digitalWrite(R_Led, HIGH);
delay(1000);
}
}
rfid.PICC_HaltA(); // Останавливаем считывание метки
rfid.PCD_StopCrypto1();
return result;
}
#ifndef BLUE_MODE
bool clear2Mifare() {
bool result = false;
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
Serial.println("Card detected");
// Очищаем карту
for (byte i = 0; i < 16; i++) {
byte buffer[18];
memset(buffer, 0, sizeof(buffer));
if (rfid.MIFARE_Write(i, buffer, 16)) {
Serial.println("Block " + String(i) + " cleared");
OLED_printError(F("Clear ..."), false);
Sd_WriteStep();
}
else {
Serial.println("Failed to clear block " + String(i));
OLED_printError(F("Failed cleared"));
Sd_ErrorBeep();
result = false;
}
}
// Останавливаем считывание метки
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
Sd_ReadOK();
OLED_printError(F("Cleared successfully"), false);
result = true;
}
else if ( rfid.MIFARE_UnbrickUidSector(false) ) {
Serial.println(F("Cleared sector 0, set UID to 1234. Card should be responsive again now."));
OLED_printError(F("Unbrick Sector 0"), false);
Sd_ReadOK();
result = true;
}
statOk = result;
return result;
}
#endif
//**********BlueMode***************************
#ifdef BLUE_MODE
void SendEM_Marine(byte* buf){
TCCR2A &= ~_BV(COM2B1); // отключаем шим
digitalWrite(FreqGen, LOW);
//FF:A9:8A:A4:87:78:98:6A
delay(20);
for (byte k = 0; k<10; k++){
for (byte i = 0; i<8; i++){
for (byte j = 0; j<8; j++){
if (1 & (buf[i]>>(7-j))) {
pinMode(FreqGen, INPUT);
delayMicroseconds(250);
pinMode(FreqGen, OUTPUT);
delayMicroseconds(250);
} else {
pinMode(FreqGen, OUTPUT);
delayMicroseconds(250);
pinMode(FreqGen, INPUT);
delayMicroseconds(250);
}
}
}
// delay(1);
}
}
void SendDallas(byte* buf){
iBtnEmul.init(buf);
//iBtnEmul.waitForRequest(false);
unsigned long tStart = millis();
do {
if (!iBtnEmul.waitReset(10) ) continue;
if (!iBtnEmul.presence() ) continue;
if (iBtnEmul.recvAndProcessCmd() ) break;
} while (millis() < 200 + tStart);
}
void BM_SendKey(byte* buf){
switch (keyType){
case keyEM_Marine: SendEM_Marine(buf); break;
default: SendDallas(buf); break;
}
}
#endif
unsigned long stTimer = millis();
void loop() {
char echo = Serial.read();
if (echo == 'e'){
myOLED.print(F("EEPROM cleared success!"), 0, 0);
Serial.println(F("EEPROM cleared"));
EEPROM.update(0, 0); EEPROM.update(1, 0);
EEPROM_key_count = 0; EEPROM_key_index = 0;
Sd_ReadOK();
myOLED.update();
}
if ((echo == 't') || enc1.isClick()) { // переключаель режима чтение/запись
switch (copierMode){
case md_empty: Sd_ErrorBeep(); break;
case md_read: copierMode = md_write; clearLed(); digitalWrite(R_Led, HIGH); break;
delayMicroseconds(5); break;
case md_write: copierMode = md_threeMode; clearLed(); digitalWrite(B_Led, HIGH);
delayMicroseconds(5); break;
case md_threeMode: copierMode = md_read; clearLed(); digitalWrite(G_Led, HIGH);
delayMicroseconds(5); break;
}
OLED_printKey(keyID);
Serial.print(F("Mode: ")); Serial.println(copierMode);
Sd_WriteStep();
statOk = false;
}
if (enc1.isLeft() && (EEPROM_key_count > 0)){ //при повороте энкодера листаем ключи из eeprom
EEPROM_key_index--;
if (EEPROM_key_index < 1) EEPROM_key_index = EEPROM_key_count;
EEPROM_get_key(EEPROM_key_index, keyID);
OLED_printKey(keyID);
Sd_WriteStep();
// statOk = false;
}
if (enc1.isRight() && (EEPROM_key_count > 0)){
EEPROM_key_index++;
if (EEPROM_key_index > EEPROM_key_count) EEPROM_key_index = 1;
EEPROM_get_key(EEPROM_key_index, keyID);
OLED_printKey(keyID);
Sd_WriteStep();
// statOk = false;
}
if ((copierMode != md_empty) && enc1.isHolded()){ // Если зажать кнопкку - ключ сохранися в EEPROM
if (EPPROM_AddKey(keyID)) {
OLED_printError(F("The key saved"), false);
Sd_ReadOK();
delay(1000);
}
else Sd_ErrorBeep();
OLED_printKey(keyID);
}
if (millis() - stTimer < 100) return; //задержка в 100 мс
stTimer = millis();
switch (copierMode){
case md_empty: case md_read:
if (searchCyfral() || searchMetacom() || searchEM_Marine() || searchIbutton() || searchMifare()){ // запускаем поиск cyfral, затем поиск EM_Marine, затем поиск dallas
//keyID[0] = 0xFF; keyID[1] = 0xA9; keyID[2] = 0x8A; keyID[3] = 0xA4; keyID[4] = 0x87; keyID[5] = 0x78; keyID[6] = 0x98; keyID[7] = 0x6A;
Sd_ReadOK();
copierMode = md_read;
digitalWrite(G_Led, HIGH);
if (indxKeyInROM(keyID) == 0) OLED_printKey(keyID, 1);
else OLED_printKey(keyID, 3);
}
break;
case md_write:
if (keyType == keyEM_Marine) write2rfid();
else if (keyType == keyMifare) write2Mifare();
else write2iBtn();
break;
case md_threeMode:
#ifdef BLUE_MODE
BM_SendKey(keyID);
break;
#endif
#ifndef BLUE_MODE
if(!statOk){
clear2Mifare();
break;
}
#endif
} //end switch
}
//***************** звуки****************
void Sd_ReadOK() { // звук ОК
for (int i=400; i<6000; i=i*1.5) { tone(speakerPin, i); delay(20); }
noTone(speakerPin);
}
void Sd_WriteStep(){ // звук "очередной шаг"
for (int i=2500; i<6000; i=i*1.5) { tone(speakerPin, i); delay(10); }
noTone(speakerPin);
}
void Sd_ErrorBeep() { // звук "ERROR"
for (int j=0; j <3; j++){
for (int i=1000; i<2000; i=i*1.1) { tone(speakerPin, i); delay(10); }
delay(50);
for (int i=1000; i>500; i=i*1.9) { tone(speakerPin, i); delay(10); }
delay(50);
}
noTone(speakerPin);
}
void Sd_StartOK(){ // звук "Успешное включение"
tone(speakerPin, NOTE_A7); delay(100);
tone(speakerPin, NOTE_G7); delay(100);
tone(speakerPin, NOTE_E7); delay(100);
tone(speakerPin, NOTE_C7); delay(100);
tone(speakerPin, NOTE_D7); delay(100);
tone(speakerPin, NOTE_B7); delay(100);
tone(speakerPin, NOTE_F7); delay(100);
tone(speakerPin, NOTE_C7); delay(100);
noTone(speakerPin);
}