-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathntageepromadapter.cpp
224 lines (194 loc) · 6.1 KB
/
ntageepromadapter.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
//[BSD License](https://github.com/don/Ndef/blob/master/LICENSE.txt) (c) 2013-2014, Don Coleman
#include "ntageepromadapter.h"
NtagEepromAdapter::NtagEepromAdapter(Ntag* ntag)
{
_ntag=ntag;
}
bool NtagEepromAdapter::begin()
{
NtagAdapter::begin();
if((!_ntag->setSramMirrorRf(false, 0)) || (!_ntag->setFd_ReaderHandshake())){
Serial.println("Can't initialize tag");
return false;
}
return true;
}
bool NtagEepromAdapter::write(NdefMessage& m, unsigned int uiTimeout){
if(!waitUntilRfDone(uiTimeout))
{
return false;
}
if (isUnformatted())
{
Serial.println(F("WARNING: Tag is not formatted."));
return false;
}
if(!readCapabilityContainer())
{
return false;
}
messageLength = m.getEncodedSize();
ndefStartIndex = messageLength < 0xFF ? 2 : 4;
calculateBufferSize();
if(bufferSize>tagCapacity) {
#ifdef MIFARE_ULTRALIGHT_DEBUG
Serial.print(F("Encoded Message length exceeded tag Capacity "));Serial.println(tagCapacity);
#endif
return false;
}
uint8_t encoded[bufferSize];
// Set message size.
encoded[0] = 0x3;
if (messageLength < 0xFF)
{
encoded[1] = messageLength;
}
else
{
encoded[1] = 0xFF;
encoded[2] = ((messageLength >> 8) & 0xFF);
encoded[3] = (messageLength & 0xFF);
}
m.encode(encoded+ndefStartIndex);
// this is always at least 1 byte copy because of terminator.
memset(encoded+ndefStartIndex+messageLength,0,bufferSize-ndefStartIndex-messageLength);
encoded[ndefStartIndex+messageLength] = 0xFE; // terminator
#ifdef MIFARE_ULTRALIGHT_DEBUG
Serial.print(F("messageLength "));Serial.println(messageLength);
Serial.print(F("Tag Capacity "));Serial.println(tagCapacity);
nfc->PrintHex(encoded,bufferSize);
#endif
_ntag->writeEeprom(0,encoded,bufferSize);
_ntag->setLastNdefBlock();
_ntag->releaseI2c();
// for(int i=0;i<sizeof(buffer);i++){
// Serial.print(buffer[i], HEX);Serial.print(" ");
// if((i+1)%8==0)Serial.println();
// }
}
NfcTag NtagEepromAdapter::read(unsigned int uiTimeOut)
{
if (isUnformatted())
{
Serial.println(F("WARNING: Tag is not formatted."));
return NfcTag(uid, UID_LENGTH, NFC_FORUM_TAG_TYPE_2);
}
if(!readCapabilityContainer())
{
return NfcTag(uid, UID_LENGTH, NFC_FORUM_TAG_TYPE_2);;
}
findNdefMessage();
calculateBufferSize();
if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE
NdefMessage message = NdefMessage();
message.addEmptyRecord();
return NfcTag(uid, UID_LENGTH, NFC_FORUM_TAG_TYPE_2, message);
}
bool success;
uint8_t page;
uint8_t index = 0;
byte buffer[bufferSize];
_ntag->readEeprom(0,buffer, bufferSize);
NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength);
return NfcTag(uid, UID_LENGTH, NFC_FORUM_TAG_TYPE_2, ndefMessage);
}
// Mifare Ultralight can't be reset to factory state
// zero out tag data like the NXP Tag Write Android application
bool NtagEepromAdapter::clean()
{
if(!readCapabilityContainer())
{
return false;
}
byte blocks = (tagCapacity / NTAG_BLOCK_SIZE);
// factory tags have 0xFF, but OTP-CC blocks have already been set so we use 0x00
byte data[16];
memset(data,0x00,sizeof(data));
for (int i = 0; i < blocks; i++) {
#ifdef MIFARE_ULTRALIGHT_DEBUG
Serial.print(F("Wrote page "));Serial.print(i);Serial.print(F(" - "));
nfc->PrintHex(data, ULTRALIGHT_PAGE_SIZE);
#endif
if (!_ntag->writeEeprom(i,data,NTAG_BLOCK_SIZE)) {
return false;
}
}
return true;
}
bool NtagEepromAdapter::erase()
{
NdefMessage message = NdefMessage();
message.addEmptyRecord();
return write(message);
}
bool NtagEepromAdapter::isUnformatted()
{
const byte PAGE_4 = 0;//page 4 is base address of EEPROM from I²C perspective
byte data[NTAG_PAGE_SIZE];
bool success = _ntag->readEeprom(PAGE_4, data, NTAG_PAGE_SIZE);
if (success)
{
return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
}
else
{
Serial.print(F("Error. Failed read page 4"));
return false;
}
}
// page 3 has tag capabilities
bool NtagEepromAdapter::readCapabilityContainer()
{
byte data[4];
if (_ntag->getCapabilityContainer(data))
{
//http://apps4android.org/nfc-specifications/NFCForum-TS-Type-2-Tag_1.1.pdf
if(data[0]!=0xE1)
{
return false; //magic number
}
//NT3H1101 return 0x6D for data[2], which leads to 872 databytes, not 888.
tagCapacity = data[2] * 8;
#ifdef MIFARE_ULTRALIGHT_DEBUG
Serial.print(F("Tag capacity "));Serial.print(tagCapacity);Serial.println(F(" bytes"));
#endif
// TODO future versions should get lock information
}
return true;
}
// buffer is larger than the message, need to handle some data before and after
// message and need to ensure we read full pages
void NtagEepromAdapter::calculateBufferSize()
{
// TLV terminator 0xFE is 1 byte
bufferSize = messageLength + ndefStartIndex + 1;
if (bufferSize % NTAG_PAGE_SIZE != 0)
{
// buffer must be an increment of page size
bufferSize = ((bufferSize / NTAG_PAGE_SIZE) + 1) * NTAG_PAGE_SIZE;
}
}
// read enough of the message to find the ndef message length
void NtagEepromAdapter::findNdefMessage()
{
byte data[16]; // 4 pages
// the nxp read command reads 4 pages
if (_ntag->readEeprom(0,data,16))
{
if (data[0] == 0x03)
{
messageLength = data[1];
ndefStartIndex = 2;
}
else if (data[5] == 0x3) // page 5 byte 1
{
// TODO should really read the lock control TLV to ensure byte[5] is correct
messageLength = data[6];
ndefStartIndex = 7;
}
}
#ifdef MIFARE_ULTRALIGHT_DEBUG
Serial.print(F("messageLength "));Serial.println(messageLength);
Serial.print(F("ndefStartIndex "));Serial.println(ndefStartIndex);
#endif
}