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() {
126 Kevin 14
    TRISCbits.TRISC1 = 1; // IRQ Pin is RC5
15
    TRISCbits.TRISC2 = 0; // Reset Pin is RC2
16
 
121 Kevin 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;
126 Kevin 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
121 Kevin 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) {
126 Kevin 41
    NFC_FIRMWARE_VERSION response = {0, 0, 0, 0};
121 Kevin 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
126 Kevin 53
    if (strncmp((char *) nfc_data.packetbuffer, (char *) pn532response_firmwarevers, 8) != 0)
121 Kevin 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
 
126 Kevin 90
// Passive polling, waits for an ISO14443A target to enter the field
91
unsigned char NFC_readPassiveTargetID(NFC_TargetDataMiFare *cardData) {
92
 
121 Kevin 93
    nfc_data.packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
126 Kevin 94
    nfc_data.packetbuffer[1] = 2; // Max 2 cards at once
95
    nfc_data.packetbuffer[2] = PN532_MIFARE_ISO14443A;  // Mifare only
121 Kevin 96
 
97
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 3))
98
        return 0;
99
 
100
    // Wait for IRQ line
101
    while (NFC_I2C_Read_Status() != PN532_I2C_READY);
102
 
126 Kevin 103
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 35);
121 Kevin 104
 
126 Kevin 105
    /* InListPassiveTarget response should be in the following format:
106
     * Byte         Description
107
     * ----------   ------------------
108
     * b0           Data ACK
109
     * b1..7        Frame header and preamble
110
     * b8           Tags found
111
     * b9..N        NFC_TargetDataMiFare[2]
112
     * bN+1..N+2    Checksum + postamble
113
     */
121 Kevin 114
 
115
    // Check # of tags found
126 Kevin 116
    if (!nfc_data.packetbuffer[8])
121 Kevin 117
        return 0;
126 Kevin 118
 
119
    // Save data from first card
120
    if (nfc_data.packetbuffer[13] == 4) {
121
        memcpy((char *)&cardData[0], (const char *)&nfc_data.packetbuffer[9], 9);
122
    } else {
123
        memcpy((char *)&cardData[0], (const char *)&nfc_data.packetbuffer[9], 12);
124
    }
121 Kevin 125
 
126 Kevin 126
    // Save data from second card
127
    if (nfc_data.packetbuffer[8] == 2) {
128
        // Offset will vary depending on length of first card
129
        if (nfc_data.packetbuffer[13] == 4) {
130
            if (nfc_data.packetbuffer[22] == 4) {
131
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[18], 9);
132
            } else {
133
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[18], 12);
134
            }
135
        } else { // Length of first UID is 7
136
            if (nfc_data.packetbuffer[25] == 4) {
137
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[21], 9);
138
            } else {
139
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[21], 12);
140
            }
141
        }
142
    }
143
 
144
    // Return the number of cards detected
145
    return nfc_data.packetbuffer[8];
146
}
121 Kevin 147
 
126 Kevin 148
// Active polling, returns number of cards in the field
149
unsigned char NFC_pollTargets(unsigned char number, unsigned char period, NFC_TargetDataMiFare *cardData) {
150
 
151
    nfc_data.packetbuffer[0] = PN532_COMMAND_INAUTOPOLL;
152
    nfc_data.packetbuffer[1] = number; // Number of polling
153
    nfc_data.packetbuffer[2] = period; // Polling period in units of 150ms
154
    nfc_data.packetbuffer[3] = 0x10; // Check for Mifare cards only
155
 
156
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 4))
157
        return 0;
158
 
159
    // Wait for IRQ line
160
    while (NFC_I2C_Read_Status() != PN532_I2C_READY);
161
 
162
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 37);
163
 
164
    /* InAutoPoll response should be in the following format:
165
     * Byte         Description
166
     * ----------   ------------------
167
     * b0           Data ACK
168
     * b1..7        Frame header and preamble
169
     * b6           Tags found
170
     * b7           Polled target type (should be 0x10 Mifare)
171
     * b8           TargetData length (1/2)
172
     * b9..N        NFC_TargetDataMiFare[1/2]
173
     * bN+1..N+2    Checksum + postamble
174
     */
175
 
176
    // Check # of tags found
177
    if (!nfc_data.packetbuffer[8])
178
        return 0;
179
 
180
        // Save data from first card
181
    if (nfc_data.packetbuffer[15] == 4) {
182
        memcpy((char *)&cardData[0], (const char *)&nfc_data.packetbuffer[11], 9);
183
    } else {
184
        memcpy((char *)&cardData[0], (const char *)&nfc_data.packetbuffer[11], 12);
121 Kevin 185
    }
186
 
126 Kevin 187
    // Save data from second card
188
    if (nfc_data.packetbuffer[8] == 2) {
189
        // Offset will vary depending on length of first card
190
        if (nfc_data.packetbuffer[15] == 4) {
191
            if (nfc_data.packetbuffer[26] == 4) {
192
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[22], 9);
193
            } else {
194
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[22], 12);
195
            }
196
        } else {
197
            if (nfc_data.packetbuffer[29] == 4) {
198
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[25], 9);
199
            } else {
200
                memcpy((char *)&cardData[1], (const char *)&nfc_data.packetbuffer[25], 12);
201
            }
202
        }
203
    }
204
 
205
    // Return the number of cards detected
206
    return nfc_data.packetbuffer[8];
121 Kevin 207
}
208
 
209
// Indicates whether the specified block number is the first block
210
//      in the sector (block 0 relative to the current sector)
211
unsigned char NFC_mifareclassic_IsFirstBlock(unsigned long uiBlock) {
212
    // Test if we are in the small or big sectors
213
    if (uiBlock < 128)
214
        return ((uiBlock) % 4 == 0);
215
    else
216
        return ((uiBlock) % 16 == 0);
217
}
218
 
219
// Indicates whether the specified block number is the sector trailer
220
unsigned char NFC_mifareclassic_IsTrailerBlock(unsigned long uiBlock) {
221
    // Test if we are in the small or big sectors
222
    if (uiBlock < 128)
223
        return ((uiBlock + 1) % 4 == 0);
224
    else
225
        return ((uiBlock + 1) % 16 == 0);
226
}
227
 
228
// Tries to authenticate a block of memory on a MIFARE card using the INDATAEXCHANGE command
229
unsigned char NFC_mifareclassic_AuthenticateBlock(unsigned char *uid, unsigned char uidLen, unsigned long blockNumber, unsigned char keyNumber, unsigned char *keyData) {
230
    // See section 7.3.8 of the PN532 User Manual
231
    // blockNumber = The block number to authenticate.  (0..63 for 1KB cards, and 0..255 for 4KB cards)\
232
    // keyNumber = Which key type to use during authentication (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
233
    // keyData = Pointer to a byte array containing the 6 byte key value
126 Kevin 234
 
121 Kevin 235
    unsigned char i;
236
 
237
    // Assemble frame data
126 Kevin 238
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
239
    nfc_data.packetbuffer[1] = 1; /* Max card numbers */
121 Kevin 240
    nfc_data.packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_A : MIFARE_CMD_AUTH_B;
126 Kevin 241
    nfc_data.packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
121 Kevin 242
    for (i = 0; i < 6; i++) {
126 Kevin 243
        nfc_data.packetbuffer[4 + i] = keyData[i];
121 Kevin 244
    }
245
    for (i = 0; i < uidLen; i++) {
126 Kevin 246
        nfc_data.packetbuffer[10 + i] = uid[i];
121 Kevin 247
    }
248
 
249
    // Send frame and check for ACK
126 Kevin 250
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 10 + uidLen))
121 Kevin 251
        return 0;
252
 
253
    // Read response from PN532
254
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 12);
255
 
256
    return 1;
257
}
258
 
259
// Tries to read an entire 16-byte data block at the specified block address
260
unsigned char NFC_mifareclassic_ReadDataBlock(unsigned char blockNumber, unsigned char *data) {
261
    unsigned char i;
262
 
263
    // Assemble frame data
264
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
265
    nfc_data.packetbuffer[1] = 1; /* Card number */
266
    nfc_data.packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
267
    nfc_data.packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
268
 
269
    // Send frame and check for ACK
270
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 4))
271
        return 0;
272
 
273
    // Read reponse
274
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 26);
275
 
276
    // If byte 9 isnt 0x00 we probably have and error
277
    if (nfc_data.packetbuffer[8] != 0x00) {
278
        return 0;
279
    }
280
 
281
    // Copy the 16 data bytes into the data buffer
282
    // Block contents starts at byte 10 of a valid response
283
    for (i = 0; i < 16; i++) {
126 Kevin 284
        data[i] = nfc_data.packetbuffer[9 + i];
121 Kevin 285
    }
286
 
287
    return 1;
288
}
289
 
290
// Tries to write an entire 16-byte data block at the specified block address
291
unsigned char NFC_mifareclassic_WriteDataBlock(unsigned char blockNumber, unsigned char *data) {
292
    unsigned char i;
126 Kevin 293
 
121 Kevin 294
    // Assemble frame data
295
    nfc_data.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
126 Kevin 296
    nfc_data.packetbuffer[1] = 1; /* Card number */
297
    nfc_data.packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
298
    nfc_data.packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
299
    for (i = 0; i < 16; i++) { /* Data Payload */
300
        nfc_data.packetbuffer[4 + i] = data[i];
121 Kevin 301
    }
302
 
303
    // Send frame and check for ACK
304
    if (!NFC_sendCommandCheckAck(nfc_data.packetbuffer, 20))
305
        return 0;
306
 
307
    // Read response
308
    NFC_I2C_Read_Data(nfc_data.packetbuffer, 26);
309
 
310
    return 1;
311
}
312
 
126 Kevin 313
// Formats a Mifare Classic card to store NDEF Records
121 Kevin 314
unsigned char NFC_mifareclassic_FormatNDEF(void) {
315
    unsigned char sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
316
    unsigned char sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
317
    unsigned char sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
318
 
319
    // Write blocks 1 and 2
320
    if (!NFC_mifareclassic_WriteDataBlock(1, sectorbuffer1))
321
        return 0;
322
    if (!NFC_mifareclassic_WriteDataBlock(2, sectorbuffer2))
323
        return 0;
324
    // Write key A and access rights
325
    if (!NFC_mifareclassic_WriteDataBlock(3, sectorbuffer3))
326
        return 0;
327
 
328
    return 1;
329
}
330
 
331
// Writes an NDEF URI Record to the specified sector (1..15)
332
/* Note that this function assumes that the Mifare Classic card is
333
    already formatted to work as an "NFC Forum Tag" and uses a MAD1
334
    file system.  You can use the NXP TagWriter app on Android to
335
    properly format cards for this. */
336
unsigned char NFC_mifareclassic_WriteNDEFURI(unsigned char sectorNumber, unsigned char uriIdentifier, const char * url) {
337
    // uriIdentifier = The uri identifier code (0 = none, 0x01 = "http://www.", etc.)
338
    // url = The uri text to write (max 38 characters)
339
 
340
    // Figure out how long the string is
341
    unsigned char len = strlen(url);
126 Kevin 342
 
121 Kevin 343
    unsigned char sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
344
    unsigned char sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
345
    unsigned char sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
346
    unsigned char sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
347
 
348
    // Make sure we're within a 1K limit for the sector number
349
    if ((sectorNumber < 1) || (sectorNumber > 15))
350
        return 0;
351
 
352
    // Make sure the URI payload is between 1 and 38 chars
353
    if ((len < 1) || (len > 38))
354
        return 0;
355
 
356
    if (len <= 6) {
357
        // Unlikely we'll get a url this short, but why not ...
358
        memcpy(sectorbuffer1 + 9, url, len);
359
        sectorbuffer1[len + 9] = 0xFE;
360
    } else if (len == 7) {
361
        // 0xFE needs to be wrapped around to next block
362
        memcpy(sectorbuffer1 + 9, url, len);
363
        sectorbuffer2[0] = 0xFE;
364
    } else if ((len > 7) || (len <= 22)) {
365
        // Url fits in two blocks
366
        memcpy(sectorbuffer1 + 9, url, 7);
367
        memcpy(sectorbuffer2, url + 7, len - 7);
368
        sectorbuffer2[len - 7] = 0xFE;
369
    } else if (len == 23) {
370
        // 0xFE needs to be wrapped around to final block
371
        memcpy(sectorbuffer1 + 9, url, 7);
372
        memcpy(sectorbuffer2, url + 7, len - 7);
373
        sectorbuffer3[0] = 0xFE;
374
    } else {
375
        // Url fits in three blocks
376
        memcpy(sectorbuffer1 + 9, url, 7);
377
        memcpy(sectorbuffer2, url + 7, 16);
378
        memcpy(sectorbuffer3, url + 23, len - 24);
379
        sectorbuffer3[len - 22] = 0xFE;
380
    }
381
 
382
    // Now write all three blocks back to the card
383
    if (!(NFC_mifareclassic_WriteDataBlock(sectorNumber * 4, sectorbuffer1)))
384
        return 0;
385
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 1, sectorbuffer2)))
386
        return 0;
387
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 2, sectorbuffer3)))
388
        return 0;
389
    if (!(NFC_mifareclassic_WriteDataBlock((sectorNumber * 4) + 3, sectorbuffer4)))
390
        return 0;
391
 
392
    return 1;
393
}
394
 
395
// Reads and checks for the ACK signal
396
unsigned char NFC_I2C_Read_ACK() {
397
    unsigned char buffer[7];
398
 
399
    // Check ACK
400
    NFC_I2C_Read_Data(buffer, 6);
401
 
126 Kevin 402
    // Return if the 7 bytes matches the ACK pattern
403
    return (strncmp((char *) buffer, (char *) pn532ack, 7) == 0);
121 Kevin 404
}
405
 
406
// Checks the IRQ pin to know if the PN532 is ready
407
unsigned char NFC_I2C_Read_Status() {
408
    if (PORTCbits.RC1 == 1) {
409
        return PN532_I2C_BUSY;
410
    } else {
411
        return PN532_I2C_READY;
412
    }
413
}
414
 
415
// Reads n bytes of data from the PN532 via I2C
416
void NFC_I2C_Read_Data(unsigned char *buffer, unsigned char length) {
417
    unsigned char result;
418
 
419
    // Wait for IRQ to go low
420
    while (NFC_I2C_Read_Status() != PN532_I2C_READY);
421
 
422
    // Read bytes from PN532 into buffer
126 Kevin 423
    I2C_Master_Recv(PN532_I2C_ADDRESS, length + 2);
121 Kevin 424
    result = I2C_Get_Status();
425
    while (!result) {
426
        result = I2C_Get_Status();
427
    }
126 Kevin 428
    I2C_Read_Buffer((char *) buffer);
121 Kevin 429
 
430
    /* Remaining packet byte layout is as follows:
431
     Byte       Description
432
     -----      ----------------------
126 Kevin 433
     * 0        Data ready ACK
434
     * 1        Preamble (0x00)
435
     * 2-3      Start code (0x00,0xFF)
436
     * 4        Length (TFI to N)
437
     * 5        Length Checksum (Length + LCS = 0x00)
438
     * 6        TFI (Frame identifier)
121 Kevin 439
     *              0xD4 - Host to PN532
440
     *              0xD5 - PN532 to Host
126 Kevin 441
     * 7-N      Data (Length - 1 bytes)
121 Kevin 442
     * N+1      Data checksum (TFI + Data~N + DCS = 0x00)
443
     * N+2      Postamble (0x00)              */
444
}
445
 
446
// Writes a command to the PN532, automatically inserting the preamble and required frame details (checksum, len, etc.)
447
void NFC_I2C_Write_Cmd(unsigned char* cmd, unsigned char cmdlen) {
448
    int i;
449
    unsigned char checksum;
126 Kevin 450
    unsigned char buffer[PN532_PACKBUFFSIZ + 8];
121 Kevin 451
    unsigned char buffer_ind = 6;
452
    cmdlen++;
453
 
454
    checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2 + PN532_HOSTTOPN532;
455
 
456
    // Fill out required frame fields
457
    buffer[0] = PN532_PREAMBLE;
458
    buffer[1] = PN532_PREAMBLE;
459
    buffer[2] = PN532_STARTCODE2;
460
    buffer[3] = cmdlen;
461
    buffer[4] = ~cmdlen + 1;
462
    buffer[5] = PN532_HOSTTOPN532;
463
 
464
 
465
    // Copy cmd to be sent
126 Kevin 466
    for (i = 0; i < cmdlen - 1; i++) {
121 Kevin 467
        checksum += cmd[i];
468
        buffer[buffer_ind] = cmd[i];
469
        buffer_ind++;
470
    }
126 Kevin 471
 
121 Kevin 472
    buffer[buffer_ind] = ~checksum;
473
    buffer_ind++;
474
    buffer[buffer_ind] = PN532_POSTAMBLE;
475
    buffer_ind++;
476
 
477
    I2C_Master_Send(PN532_I2C_ADDRESS, buffer_ind, buffer);
478
}