Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
121 Kevin 1
#include "maindefs.h"
2
#include "nfc.h"
3
#include "i2c.h"
4
#include <string.h>
5
#include <delays.h>
6
 
7
static NFC_DATA nfc_data;
8
 
9
// Const value arrays for comparison use
10
static char pn532response_firmwarevers[] = {0x01, 0x00, 0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
11
static char pn532ack[] = {0x01, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
12
 
13
void NFC_Init() {
14
    TRISCbits.TRISC1 = 1;   // IRQ Pin is RC5
15
    TRISCbits.TRISC2 = 0;   // Reset Pin is RC2
16
 
17
    // Reset the PN532
18
    LATCbits.LATC2 = 1;
19
    LATCbits.LATC2 = 0;
20
    Delay10TCYx(1);
21
    LATCbits.LATC2 = 1;
22
}
23
 
24
// Configures the SAM (Secure Access Module)
25
unsigned char NFC_SAMConfig() {
26
    nfc_data.packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
27
    nfc_data.packetbuffer[1] = 0x01;    // Normal mode
28
    nfc_data.packetbuffer[2] = 0x14;    // Timeout 50ms * 20 = 1s
29
    nfc_data.packetbuffer[3] = 0x01;    // Use IRQ pin
30
 
31
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 4))
32
        return 0;
33
 
34
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 8);
35
 
36
    return (nfc_data.packetbuffer[7] == 0x15);
37
}
38
 
39
// Checks the firmware version of the PN5xx chip
40
NFC_FIRMWARE_VERSION NFC_getFirmwareVersion(void) {
41
    NFC_FIRMWARE_VERSION response = {0,0,0,0};
42
 
43
    // Create and send command
44
    nfc_data.packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
45
 
46
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 1))
47
        return response;
48
 
49
    // Read back data from the PN532
50
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 12);
51
 
52
    // Compare and check returned values
53
    if (strncmp((char *)nfc_data.packetbuffer, (char *)pn532response_firmwarevers, 8) != 0)
54
        return response;
55
 
56
    // Save and return info
57
    response.IC = nfc_data.packetbuffer[8];
58
    response.Ver = nfc_data.packetbuffer[9];
59
    response.Rev = nfc_data.packetbuffer[10];
60
    response.Support = nfc_data.packetbuffer[11];
61
 
62
    return response;
63
}
64
 
65
// Sends a command and waits a specified period for the ACK
66
unsigned char NFC_sendCommandCheckAck(unsigned char *cmd, unsigned char cmdlen) {
67
    unsigned int timer = 0;
68
 
69
    // Write the command
70
    NFC_I2C_Write_Cmd(cmd, cmdlen);
71
 
72
    // Wait for chip to be ready
73
    while (NFC_I2C_Read_Status() != PN532_I2C_READY) {
74
        if (PN532_TIMEOUT != 0) {
75
            timer += 1;
76
            if (timer > PN532_TIMEOUT)
77
                return 0;
78
        }
79
        Delay10TCYx(1);
80
    }
81
 
82
    // Check ACK
83
    if (!NFC_I2C_Read_ACK()) {
84
        return 0;
85
    }
86
 
87
    return 1;
88
}
89
 
90
// Waits for an ISO14443A target to enter the field
91
unsigned char NFC_readPassiveTargetID(unsigned char cardbaudrate, unsigned char * uid, unsigned char * uidLength) {
92
    unsigned char i = 0;
93
 
94
    nfc_data.packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
95
    nfc_data.packetbuffer[1] = 1;  // max 1 cards at once (we can set this to 2 later)
96
    nfc_data.packetbuffer[2] = cardbaudrate;
97
 
98
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 3))
99
        return 0;
100
 
101
    // Wait for IRQ line
102
    while (NFC_I2C_Read_Status() != PN532_I2C_READY);
103
 
104
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 20);
105
 
106
    /* ISO14443A card response should be in the following format:
107
    // (byte 0 is actually 0x01 (data ready))
108
    byte            Description
109
    -------------   ------------------------------------------
110
    b0..6           Frame header and preamble
111
    b7              Tags Found
112
    b8              Tag Number (only one used in this example)
113
    b9..10          SENS_RES
114
    b11             SEL_RES
115
    b12             NFCID Length
116
    b13..NFCIDLen   NFCID                                      */
117
 
118
    // Check # of tags found
119
    if (nfc_data.packetbuffer[8] != 1)
120
        return 0;
121
 
122
    // Save UID length
123
    *uidLength = nfc_data.packetbuffer[13];
124
 
125
    // Save UID
126
    for (i = 0; i < *uidLength; i++) {
127
        uid[i] = nfc_data.packetbuffer[14+i];
128
    }
129
 
130
    return 1;
131
}
132
 
133
// Indicates whether the specified block number is the first block
134
//      in the sector (block 0 relative to the current sector)
135
unsigned char NFC_mifareclassic_IsFirstBlock(unsigned long uiBlock) {
136
    // Test if we are in the small or big sectors
137
    if (uiBlock < 128)
138
        return ((uiBlock) % 4 == 0);
139
    else
140
        return ((uiBlock) % 16 == 0);
141
}
142
 
143
// Indicates whether the specified block number is the sector trailer
144
unsigned char NFC_mifareclassic_IsTrailerBlock(unsigned long uiBlock) {
145
    // Test if we are in the small or big sectors
146
    if (uiBlock < 128)
147
        return ((uiBlock + 1) % 4 == 0);
148
    else
149
        return ((uiBlock + 1) % 16 == 0);
150
}
151
 
152
// Tries to authenticate a block of memory on a MIFARE card using the INDATAEXCHANGE command
153
unsigned char NFC_mifareclassic_AuthenticateBlock(unsigned char *uid, unsigned char uidLen, unsigned long blockNumber, unsigned char keyNumber, unsigned char *keyData) {
154
    // See section 7.3.8 of the PN532 User Manual
155
    // blockNumber = The block number to authenticate.  (0..63 for 1KB cards, and 0..255 for 4KB cards)\
156
    // keyNumber = Which key type to use during authentication (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
157
    // keyData = Pointer to a byte array containing the 6 byte key value
158
 
159
    unsigned char i;
160
 
161
    // Assemble frame data
162
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;    /* Data Exchange Header */
163
    nfc_data.packetbuffer[1] = 1;                               /* Max card numbers */
164
    nfc_data.packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_A : MIFARE_CMD_AUTH_B;
165
    nfc_data.packetbuffer[3] = blockNumber;             /* Block Number (1K = 0..63, 4K = 0..255 */
166
    for (i = 0; i < 6; i++) {
167
        nfc_data.packetbuffer[4+i] = keyData[i];
168
    }
169
    for (i = 0; i < uidLen; i++) {
170
        nfc_data.packetbuffer[10+i] = uid[i];
171
    }
172
 
173
    // Send frame and check for ACK
174
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 10+uidLen))
175
        return 0;
176
 
177
    // Read response from PN532
178
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 12);
179
 
180
    return 1;
181
}
182
 
183
// Tries to read an entire 16-byte data block at the specified block address
184
unsigned char NFC_mifareclassic_ReadDataBlock(unsigned char blockNumber, unsigned char *data) {
185
    unsigned char i;
186
 
187
    // Assemble frame data
188
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
189
    nfc_data.packetbuffer[1] = 1; /* Card number */
190
    nfc_data.packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
191
    nfc_data.packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
192
 
193
    // Send frame and check for ACK
194
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 4))
195
        return 0;
196
 
197
    // Read reponse
198
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 26);
199
 
200
    // If byte 9 isnt 0x00 we probably have and error
201
    if (nfc_data.packetbuffer[8] != 0x00) {
202
        return 0;
203
    }
204
 
205
    // Copy the 16 data bytes into the data buffer
206
    // Block contents starts at byte 10 of a valid response
207
    for (i = 0; i < 16; i++) {
208
        data[i] = nfc_data.packetbuffer[9+i];
209
    }
210
 
211
    return 1;
212
}
213
 
214
// Tries to write an entire 16-byte data block at the specified block address
215
unsigned char NFC_mifareclassic_WriteDataBlock(unsigned char blockNumber, unsigned char *data) {
216
    unsigned char i;
217
 
218
    // Assemble frame data
219
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
220
    nfc_data.packetbuffer[1] = 1;                   /* Card number */
221
    nfc_data.packetbuffer[2] = MIFARE_CMD_WRITE;    /* Mifare Write command = 0xA0 */
222
    nfc_data.packetbuffer[3] = blockNumber;         /* Block Number (0..63 for 1K, 0..255 for 4K) */
223
    for (i = 0; i < 16; i++) {                      /* Data Payload */
224
        nfc_data.packetbuffer[4+i] = data[i];
225
    }
226
 
227
    // Send frame and check for ACK
228
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 20))
229
        return 0;
230
 
231
    // Read response
232
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 26);
233
 
234
    return 1;
235
}
236
 
237
// Formats a Mifare Classic card to store NDEF Records 
238
unsigned char NFC_mifareclassic_FormatNDEF(void) {
239
    unsigned char sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
240
    unsigned char sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
241
    unsigned char sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
242
 
243
    // Write blocks 1 and 2
244
    if (!NFC_mifareclassic_WriteDataBlock(1, sectorbuffer1))
245
        return 0;
246
    if (!NFC_mifareclassic_WriteDataBlock(2, sectorbuffer2))
247
        return 0;
248
    // Write key A and access rights
249
    if (!NFC_mifareclassic_WriteDataBlock(3, sectorbuffer3))
250
        return 0;
251
 
252
    return 1;
253
}
254
 
255
// Writes an NDEF URI Record to the specified sector (1..15)
256
/* Note that this function assumes that the Mifare Classic card is
257
    already formatted to work as an "NFC Forum Tag" and uses a MAD1
258
    file system.  You can use the NXP TagWriter app on Android to
259
    properly format cards for this. */
260
unsigned char NFC_mifareclassic_WriteNDEFURI(unsigned char sectorNumber, unsigned char uriIdentifier, const char * url) {
261
    // uriIdentifier = The uri identifier code (0 = none, 0x01 = "http://www.", etc.)
262
    // url = The uri text to write (max 38 characters)
263
 
264
    // Figure out how long the string is
265
    unsigned char len = strlen(url);
266
 
267
    unsigned char sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
268
    unsigned char sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
269
    unsigned char sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
270
    unsigned char sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
271
 
272
    // Make sure we're within a 1K limit for the sector number
273
    if ((sectorNumber < 1) || (sectorNumber > 15))
274
        return 0;
275
 
276
    // Make sure the URI payload is between 1 and 38 chars
277
    if ((len < 1) || (len > 38))
278
        return 0;
279
 
280
    if (len <= 6) {
281
        // Unlikely we'll get a url this short, but why not ...
282
        memcpy(sectorbuffer1 + 9, url, len);
283
        sectorbuffer1[len + 9] = 0xFE;
284
    } else if (len == 7) {
285
        // 0xFE needs to be wrapped around to next block
286
        memcpy(sectorbuffer1 + 9, url, len);
287
        sectorbuffer2[0] = 0xFE;
288
    } else if ((len > 7) || (len <= 22)) {
289
        // Url fits in two blocks
290
        memcpy(sectorbuffer1 + 9, url, 7);
291
        memcpy(sectorbuffer2, url + 7, len - 7);
292
        sectorbuffer2[len - 7] = 0xFE;
293
    } else if (len == 23) {
294
        // 0xFE needs to be wrapped around to final block
295
        memcpy(sectorbuffer1 + 9, url, 7);
296
        memcpy(sectorbuffer2, url + 7, len - 7);
297
        sectorbuffer3[0] = 0xFE;
298
    } else {
299
        // Url fits in three blocks
300
        memcpy(sectorbuffer1 + 9, url, 7);
301
        memcpy(sectorbuffer2, url + 7, 16);
302
        memcpy(sectorbuffer3, url + 23, len - 24);
303
        sectorbuffer3[len - 22] = 0xFE;
304
    }
305
 
306
    // Now write all three blocks back to the card
307
    if (!(NFC_mifareclassic_WriteDataBlock(sectorNumber * 4, sectorbuffer1)))
308
        return 0;
309
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 1, sectorbuffer2)))
310
        return 0;
311
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 2, sectorbuffer3)))
312
        return 0;
313
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 3, sectorbuffer4)))
314
        return 0;
315
 
316
    return 1;
317
}
318
 
319
// Reads and checks for the ACK signal
320
unsigned char NFC_I2C_Read_ACK() {
321
    unsigned char buffer[7];
322
 
323
    // Check ACK
324
    NFC_I2C_Read_Data(buffer, 6);
325
 
326
    // Return if the 7 bytes matches the ACK
327
    return (strncmp((char *)buffer, (char *)pn532ack, 7) == 0);
328
}
329
 
330
// Checks the IRQ pin to know if the PN532 is ready
331
unsigned char NFC_I2C_Read_Status() {
332
    if (PORTCbits.RC1 == 1) {
333
        return PN532_I2C_BUSY;
334
    } else {
335
        return PN532_I2C_READY;
336
    }
337
}
338
 
339
// Reads n bytes of data from the PN532 via I2C
340
void NFC_I2C_Read_Data(unsigned char *buffer, unsigned char length) {
341
    unsigned char result;
342
 
343
    // Wait for IRQ to go low
344
    while (NFC_I2C_Read_Status() != PN532_I2C_READY);
345
 
346
    // Read bytes from PN532 into buffer
347
    I2C_Master_Recv(PN532_I2C_ADDRESS, length+2);
348
    result = I2C_Get_Status();
349
    while (!result) {
350
        result = I2C_Get_Status();
351
    }
352
    I2C_Read_Buffer((char *)buffer);
353
 
354
    // Note: First byte is always 0x01 (ready status from PN532)
355
    /* Remaining packet byte layout is as follows:
356
     Byte       Description
357
     -----      ----------------------
358
     * 0        Preamble (0x00)
359
     * 1-2      Start code (0x00,0xFF)
360
     * 3        Length (TFI to N)
361
     * 4        Length Checksum (Length + LCS = 0x00)
362
     * 5        TFI (Frame identifier)
363
     *              0xD4 - Host to PN532
364
     *              0xD5 - PN532 to Host
365
     * 6-N      Data (Length - 1 bytes)
366
     * N+1      Data checksum (TFI + Data~N + DCS = 0x00)
367
     * N+2      Postamble (0x00)              */
368
}
369
 
370
// Writes a command to the PN532, automatically inserting the preamble and required frame details (checksum, len, etc.)
371
void NFC_I2C_Write_Cmd(unsigned char* cmd, unsigned char cmdlen) {
372
    int i;
373
    unsigned char checksum;
374
    unsigned char buffer[PN532_PACKBUFFSIZ+8];
375
    unsigned char buffer_ind = 6;
376
    cmdlen++;
377
 
378
    checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2 + PN532_HOSTTOPN532;
379
 
380
    // Fill out required frame fields
381
    buffer[0] = PN532_PREAMBLE;
382
    buffer[1] = PN532_PREAMBLE;
383
    buffer[2] = PN532_STARTCODE2;
384
    buffer[3] = cmdlen;
385
    buffer[4] = ~cmdlen + 1;
386
    buffer[5] = PN532_HOSTTOPN532;
387
 
388
 
389
    // Copy cmd to be sent
390
    for (i = 0; i < cmdlen-1; i++) {
391
        checksum += cmd[i];
392
        buffer[buffer_ind] = cmd[i];
393
        buffer_ind++;
394
    }
395
 
396
    buffer[buffer_ind] = ~checksum;
397
    buffer_ind++;
398
    buffer[buffer_ind] = PN532_POSTAMBLE;
399
    buffer_ind++;
400
 
401
    I2C_Master_Send(PN532_I2C_ADDRESS, buffer_ind, buffer);
402
}