forked from ATrappmann/PN5180-Library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PN5180ISO14443.cpp
242 lines (223 loc) · 6.51 KB
/
PN5180ISO14443.cpp
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
// NAME: PN5180ISO14443.h
//
// DESC: ISO14443 protocol on NXP Semiconductors PN5180 module for Arduino.
//
// Copyright (c) 2019 by Dirk Carstensen. All rights reserved.
//
// This file is part of the PN5180 library for the Arduino environment.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// #define DEBUG 1
#include <Arduino.h>
#include "PN5180ISO14443.h"
#include <PN5180.h>
#include "Debug.h"
PN5180ISO14443::PN5180ISO14443(uint8_t SSpin, uint8_t BUSYpin, uint8_t RSTpin)
: PN5180(SSpin, BUSYpin, RSTpin) {
}
bool PN5180ISO14443::setupRF() {
PN5180DEBUG(F("Loading RF-Configuration...\n"));
if (loadRFConfig(0x00, 0x80)) { // ISO14443 parameters
PN5180DEBUG(F("done.\n"));
}
else return false;
PN5180DEBUG(F("Turning ON RF field...\n"));
if (setRF_on()) {
PN5180DEBUG(F("done.\n"));
}
else return false;
return true;
}
uint16_t PN5180ISO14443::rxBytesReceived() {
uint32_t rxStatus;
uint16_t len = 0;
readRegister(RX_STATUS, &rxStatus);
// Lower 9 bits has length
len = (uint16_t)(rxStatus & 0x000001ff);
return len;
}
/*
* buffer : must be 10 byte array
* buffer[0-1] is ATQA
* buffer[2] is sak
* buffer[3..6] is 4 byte UID
* buffer[7..9] is remaining 3 bytes of UID for 7 Byte UID tags
* kind : 0 we send REQA, 1 we send WUPA
*
* return value: the uid length:
* - zero if no tag was recognized
* - single Size UID (4 byte)
* - double Size UID (7 byte)
* - triple Size UID (10 byte) - not yet supported
*/
uint8_t PN5180ISO14443::activateTypeA(uint8_t *buffer, uint8_t kind) {
uint8_t cmd[7];
uint8_t uidLength = 0;
// Load standard TypeA protocol
if (!loadRFConfig(0x0, 0x80))
return 0;
// OFF Crypto
if (!writeRegisterWithAndMask(SYSTEM_CONFIG, 0xFFFFFFBF))
return 0;
// Clear RX CRC
if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE))
return 0;
// Clear TX CRC
if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE))
return 0;
//Send REQA/WUPA, 7 bits in last byte
cmd[0] = (kind == 0) ? 0x26 : 0x52;
if (!sendData(cmd, 1, 0x07))
return 0;
// READ 2 bytes ATQA into buffer
if (!readData(2, buffer))
return 0;
//Send Anti collision 1, 8 bits in last byte
cmd[0] = 0x93;
cmd[1] = 0x20;
if (!sendData(cmd, 2, 0x00))
return 0;
//Read 5 bytes, we will store at offset 2 for later usage
if (!readData(5, cmd+2))
return 0;
//Enable RX CRC calculation
if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01))
return 0;
//Enable TX CRC calculation
if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01))
return 0;
//Send Select anti collision 1, the remaining bytes are already in offset 2 onwards
cmd[0] = 0x93;
cmd[1] = 0x70;
if (!sendData(cmd, 7, 0x00))
return 0;
//Read 1 byte SAK into buffer[2]
if (!readData(1, buffer+2))
return 0;
// Check if the tag is 4 Byte UID or 7 byte UID and requires anti collision 2
// If Bit 3 is 0 it is 4 Byte UID
if ((buffer[2] & 0x04) == 0) {
// Take first 4 bytes of anti collision as UID store at offset 3 onwards. job done
for (int i = 0; i < 4; i++) buffer[3+i] = cmd[2 + i];
uidLength = 4;
}
else {
// Take First 3 bytes of UID, Ignore first byte 88(CT)
if (cmd[2] != 0x88)
return 0;
for (int i = 0; i < 3; i++) buffer[3+i] = cmd[3 + i];
// Clear RX CRC
if (!writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE))
return 0;
// Clear TX CRC
if (!writeRegisterWithAndMask(CRC_TX_CONFIG, 0xFFFFFFFE))
return 0;
// Do anti collision 2
cmd[0] = 0x95;
cmd[1] = 0x20;
if (!sendData(cmd, 2, 0x00))
return 0;
//Read 5 bytes. we will store at offset 2 for later use
if (!readData(5, cmd+2))
return 0;
// first 4 bytes belongs to last 4 UID bytes, we keep it.
for (int i = 0; i < 4; i++) {
buffer[6 + i] = cmd[2+i];
}
//Enable RX CRC calculation
if (!writeRegisterWithOrMask(CRC_RX_CONFIG, 0x01))
return 0;
//Enable TX CRC calculation
if (!writeRegisterWithOrMask(CRC_TX_CONFIG, 0x01))
return 0;
//Send Select anti collision 2
cmd[0] = 0x95;
cmd[1] = 0x70;
if (!sendData(cmd, 7, 0x00))
return 0;
//Read 1 byte SAK into buffer[2]
if (!readData(1, buffer + 2))
return 0;
uidLength = 7;
}
return uidLength;
}
bool PN5180ISO14443::mifareBlockRead(uint8_t blockno, uint8_t *buffer) {
bool success = false;
uint16_t len;
uint8_t cmd[2];
// Send mifare command 30,blockno
cmd[0] = 0x30;
cmd[1] = blockno;
if (!sendData(cmd, 2, 0x00))
return false;
//Check if we have received any data from the tag
delay(5);
len = rxBytesReceived();
if (len == 16) {
// READ 16 bytes into buffer
if (readData(16, buffer))
success = true;
}
return success;
}
uint8_t PN5180ISO14443::mifareBlockWrite16(uint8_t blockno, uint8_t *buffer) {
uint8_t cmd[1];
// Clear RX CRC
writeRegisterWithAndMask(CRC_RX_CONFIG, 0xFFFFFFFE);
// Mifare write part 1
cmd[0] = 0xA0;
cmd[1] = blockno;
sendData(cmd, 2, 0x00);
readData(1, cmd);
// Mifare write part 2
sendData(buffer,16, 0x00);
delay(10);
// Read ACK/NAK
readData(1, cmd);
//Enable RX CRC calculation
writeRegisterWithOrMask(CRC_RX_CONFIG, 0x1);
return cmd[0];
}
bool PN5180ISO14443::mifareHalt() {
uint8_t cmd[1];
//mifare Halt
cmd[0] = 0x50;
cmd[1] = 0x00;
sendData(cmd, 2, 0x00);
return true;
}
uint8_t PN5180ISO14443::readCardSerial(uint8_t *buffer) {
uint8_t response[10];
uint8_t uidLength;
// Always return 10 bytes
// Offset 0..1 is ATQA
// Offset 2 is SAK.
// UID 4 bytes : offset 3 to 6 is UID, offset 7 to 9 to Zero
// UID 7 bytes : offset 3 to 9 is UID
for (int i = 0; i < 10; i++) response[i] = 0;
uidLength = activateTypeA(response, 1);
if ((response[0] == 0xFF) && (response[1] == 0xFF))
return 0;
// check for valid uid
if ((response[3] == 0x00) && (response[4] == 0x00) && (response[5] == 0x00) && (response[6] == 0x00))
return 0;
if ((response[3] == 0xFF) && (response[4] == 0xFF) && (response[5] == 0xFF) && (response[6] == 0xFF))
return 0;
for (int i = 0; i < 7; i++) buffer[i] = response[i+3];
mifareHalt();
return uidLength;
}
bool PN5180ISO14443::isCardPresent() {
uint8_t buffer[10];
return (readCardSerial(buffer) >=4);
}