-
Notifications
You must be signed in to change notification settings - Fork 1
/
rfid.ino
350 lines (243 loc) · 7.67 KB
/
rfid.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/*
BCC=LEN XOR Status XOR DATA
*/
#define STX 0x02
#define ETX 0x03
#define CMD_LENGTH 1 // CMD is Always 1
#define STATUS_LENGTH 1 // Status is awlays 1
#define PARA_RF_BIT 5
#define RF32 false
#define READER_TIMEOUT 1000
#define WORD_LENGTH 4 // One word is 4 bytes, i.e. 32 bits
void send_packet(char payload[], int payload_length){
// Sends a command packet to the reader
// Flush Serial in case there was a response halfway through
swSer.flush();
swSer.enableTx(true);
for(int i=0; i<payload_length; i++){
swSer.write(payload[i]);
}
swSer.enableTx(false);
}
byte format_para(byte address){
// Formats the PARA byte
byte output = 0x00;
// Address is the 4 last bits of PARA
byte address_truncated = address & 0x0f;
output |= address_truncated;
// In case of RF 32 communication, bit 5 must be set to 1
if(RF32) output |= (1 << 1);
return output;
}
void build_packet_and_send( byte cmd, char data[], byte data_len ){
/*
* Packet format (original);
* STX(0x02)+LEN(1byte)+CMD(1byte)+DATA(nbytes)+BCC(1byte)+ETX(0x03)
*
* BCC computation:
* BCC = LEN xor CMD xor DATA
*
* Notes:
* - In this implementation, DATA is combined with PARA
*/
//
// Packet length = STX (1) + LEN (1) + CMD (1) + BCC (1) + ETX (1) + PARA (variable)
byte packet_size = data_len + 5;
// Defien the packet
char packet[packet_size];
packet[0] = STX;
packet[1] = 1 + data_len;
packet[2] = cmd;
byte bcc_index = sizeof(packet)-2;
// DATA
for(int i=0; i<data_len; i++){
packet[i+3] = data[i];
}
// BCC
packet[bcc_index] = packet[1] ^ packet[2];
for(int i=0; i<data_len; i++){
packet[bcc_index] = packet[bcc_index] ^ packet[i+3];
}
// ETX
packet[sizeof(packet)-1] = ETX;
send_packet(packet, sizeof(packet));
}
void read_word(byte address){
// Read a word at a specific address
// 0x02+0x02+0x11+PARA(1byte) +BCC+0x03
// PARA contains the address to read in the last 4 bits
byte cmd = 0x11; // 0x11 is the command for reading
char para[1];
para[0] = format_para(address);
build_packet_and_send(cmd, para, sizeof(para) );
}
void write_word( byte address, char word_to_write[], byte word_length ){
/*
* writes a word at a specific address
* A word is 4 bytes, same length as an Arduino long
* Format: 0x02+0x06+0x10+PARA(1byte)+DATA(4bytes)+BCC+0x03
*
* Notes:
* - Para and Data are combiend into a 5-byte PARA
* - Para contaisn the address in 4 bits
*/
byte cmd = 0x10;
char para[5];
para[0] = format_para(address);
for(int i=0; i<word_length; i++){
para[i+1] = word_to_write[i];
}
build_packet_and_send(cmd, para, sizeof(para));
}
void login( char password[] ){
/*
* Login
*
* Para is password
*/
//0x02+0x05+0x12+PASSWORD(4bytes)+BCC+0x03
byte cmd = 0x12;
build_packet_and_send(cmd, password, sizeof(password) );
}
void protection( char para[] ){
// 0x02+0x05+0x13+PROTECTION(4bytes)+BCC+0x03
byte cmd = 0x13;
build_packet_and_send(cmd, para, sizeof(para) );
}
void disable(){
// PROBABLY DANGEROUS!
// 0x02+0x05+0x14+0xFF+0xFF +0xFF +0xFF +BCC+0x03
byte cmd = 0x14;
char para[WORD_LENGTH] = {0xFF,0xFF,0xFF,0xFF};
build_packet_and_send(cmd, para, sizeof(para) );
}
void read_em4100(){
/*
* STX + LEN + CMD + BCC + ETX
* 0x02 + 0x01 + 0x81 + BCC + 0x03
*/
byte cmd = 0x81;
char para[0];
build_packet_and_send(cmd, para, sizeof(para) );
}
long byte_array_to_long(char byte_array[], byte byte_array_length){
long output;
for(int i=0; i<byte_array_length; i++){
output |= byte_array[i] << (byte_array_length-1 - i)*8;
}
return output;
}
void long_to_char_array(char byte_array[], long input){
for(int i=0; i<sizeof(input); i++){
byte_array[i] = input >> (sizeof(input) -1 -i)*8;
}
}
Response get_reader_response_sync() {
/*
* This is a synchronous function, i.e. it waits for the response to the sent command
* Response format:
* STX(0x02)+LEN(1byte)+Status(1byte)+DATA(nbytes)+BCC(1byte)+ETX(0x03)
*/
boolean response_started = false;
int response_byte_index = 0;
Response response;
long start_time = millis();
while(true){
// Timeout
if(millis() - start_time > READER_TIMEOUT) break;
// if no byte available, do nothing
if (swSer.available()) {
// The current byte
byte received_byte = (byte) swSer.read();
// A full response starts with STX (0x02)
// Warning: DATA may also contain a 0x02
if(!response_started && received_byte == STX){
// Acknowledge start
response_started = true;
}
if(response_started){
// Second byte (index 1) sets the response length
if(response_byte_index == 1){
response.length = received_byte - STATUS_LENGTH;
}
// 3rd byte sets the status
if(response_byte_index == 2){
/*
0x0 --- success
0x1 --- failure (Happens when no tag is presented)
0x2 --- data error
0x3 --- command error
0x4 --- parameter errror
*/
response.status = received_byte;
}
// Dealing with the data if any
// Len = length of status (1) + length of data (N)
// Check if there is data to read
if(response.length){
byte data_start_index = 3;
byte data_end_index = data_start_index + response.length;
byte data_index = response_byte_index - 3; // because STX, LEN and STATUS before
// Store data in the array
if(response_byte_index >= data_start_index && response_byte_index < data_end_index){
response.data[data_index] = received_byte;
}
}
// finding final byte
// Adding STX LEN BCC and ETX
// Exit the loop once finished
boolean is_last_byte = response_byte_index == response.length +4;
if(is_last_byte && received_byte == ETX){
break;
}
response_byte_index ++;
}
}
}
// clear the serial buffer
// Maybe not ideal or necessary
swSer.flush();
return response;
}
Response read_word_sync( byte address ){
read_word(address);
delay(5);
return get_reader_response_sync();
}
Response read_em4100_sync(){
read_em4100();
delay(5);
return get_reader_response_sync();
}
Response login_sync( char password[] ){
login(password);
delay(5);
return get_reader_response_sync();
}
Response write_word_sync( byte address, char word_to_write[], byte word_length ){
write_word(address, word_to_write, word_length);
delay(5);
return get_reader_response_sync();
}
int compare_em4100(char target[]) {
/*
* -1: Read error
* 0: OK
* 1: Wrong
*/
Response response = read_em4100_sync();
if(response.status) return -1;
// for(int i=0; i<response.length; i++){
// Serial.print(response.data[i],HEX);
// Serial.println("");
// }
if(strncmp(target,response.data,response.length) == 0) return 0;
return 1;
}
boolean write_word_and_verify_sync( byte address, char word_to_write[], byte word_length ){
write_word_sync(address, word_to_write, word_length);
delay(10);
Response response = read_word_sync(address);
if(response.status) return false;
return strncmp(word_to_write, response.data, word_length) == 0;
}