-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCardReaderEmulator.ino
150 lines (134 loc) · 3.82 KB
/
CardReaderEmulator.ino
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* Wiegand-26 cardreader emulator (scetch for Arduino TE-MINI328)
*
* @author: Alexander Korolev ([email protected])
*/
#include "pins_arduino.h"
/*
* an extension to the interrupt support for arduino.
* add pin change interrupts to the external interrupts, giving a way
* for users to have interrupts drive off of any pin.
* Refer to avr-gcc header files, arduino source and atmega datasheet.
*/
#define OUT_D0_PIN 17 // Выход D0 - A3
#define OUT_D1_PIN 16 // Выход D1 - A2
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
unsigned char facility = 0; // Код организации для формирования кода карты
boolean facilityInput = false; // Введён код организации
unsigned long cardCode = 0; // Код карты (26 бит)
void setup()
{
Serial.begin(9600);
Serial.println("TE-MINI CardEmulator v1.0");
Serial.print("Initialization... ");
// Настройка выходов D0 и D1
pinMode(OUT_D0_PIN, OUTPUT);
digitalWrite(OUT_D0_PIN, HIGH);
pinMode(OUT_D1_PIN, OUTPUT);
digitalWrite(OUT_D1_PIN, HIGH);
// Зарезервировать 40 байт для приёма данных
inputString.reserve(40);
Serial.println("OK");
Serial.println("Wiegand-26 output: A3 -> Data0, A2 -> Data1.");
Serial.println("Usage: \"<card_number>\\n\" or \"<facility>,<number>\\n\".");
}
void sendCardCode()
{
cardCode <<= 1;
cardCode |= 1;
// Вычислить бит чётности (0)
for ( int i = 1; i < 13; ++i )
{
if ( cardCode & (1 << i) )
cardCode ^= 1;
}
// Вычислить бит нечётности (25)
for ( int i = 13; i < 25; ++i )
{
if ( cardCode & (1L << i) )
cardCode ^= (1L << 25);
}
// Выдача кода карты (26 бит)
noInterrupts();
for ( int i = 25; i >= 0; i-- )
{
if ( cardCode & (1L << i) )
digitalWrite(OUT_D1_PIN, LOW);
else
digitalWrite(OUT_D0_PIN, LOW);
delayMicroseconds(200);
digitalWrite(OUT_D0_PIN, HIGH);
digitalWrite(OUT_D1_PIN, HIGH);
delayMicroseconds(1800);
}
interrupts();
}
void loop()
{
if ( stringComplete )
{
cardCode = inputString.toInt();
// clear the string:
inputString = "";
stringComplete = false;
if ( facilityInput )
{
facilityInput = false;
if ( cardCode & 0xFFFF0000 )
{
Serial.println("Wrong number format");
return;
}
cardCode |= ((unsigned long)facility) << 16;
}
else
{
if ( cardCode & 0xFF000000 )
{
Serial.println("Wrong number format");
return;
}
}
sendCardCode();
Serial.print((cardCode >> 1) & 0xFFFFFF);
Serial.print('(');
Serial.print((cardCode >> 17) & 0xFF);
Serial.print(',');
Serial.print((cardCode >> 1) & 0xFFFF);
Serial.println(")-OK");
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent()
{
while ( Serial.available() )
{
// get the new byte:
char inChar = (char)Serial.read();
if ( isDigit(inChar) )
{
inputString += inChar;
}
else if ( inChar == '\n' && inputString.length() > 0 )
{
stringComplete = true;
}
else if ( inChar == ',' && inputString.length() > 0 )
{
facility = inputString.toInt();
facilityInput = true;
inputString = "";
}
else
{
facilityInput = false;
inputString = "";
}
}
}