Commit 1a2e5ee4bfcaf0e8b8d185137a62b35c5c0127c1
1 parent
aff6dccd
Big revision
Everything rewritten in C/C++ Customized version of Seed Studio's PN532 NFC Library
Showing
38 changed files
with
5069 additions
and
44 deletions
Show diff stats
@@ -0,0 +1,218 @@ | @@ -0,0 +1,218 @@ | ||
1 | +/* | ||
2 | + pins_arduino.h - Pin definition functions for Arduino | ||
3 | + Part of Arduino - http://www.arduino.cc/ | ||
4 | + | ||
5 | + Copyright (c) 2007 David A. Mellis | ||
6 | + | ||
7 | + This library is free software; you can redistribute it and/or | ||
8 | + modify it under the terms of the GNU Lesser General Public | ||
9 | + License as published by the Free Software Foundation; either | ||
10 | + version 2.1 of the License, or (at your option) any later version. | ||
11 | + | ||
12 | + This library is distributed in the hope that it will be useful, | ||
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | + Lesser General Public License for more details. | ||
16 | + | ||
17 | + You should have received a copy of the GNU Lesser General | ||
18 | + Public License along with this library; if not, write to the | ||
19 | + Free Software Foundation, Inc., 59 Temple Place, Suite 330, | ||
20 | + Boston, MA 02111-1307 USA | ||
21 | + | ||
22 | + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ | ||
23 | +*/ | ||
24 | + | ||
25 | +#ifndef Pins_Arduino_h | ||
26 | +#define Pins_Arduino_h | ||
27 | + | ||
28 | +#include <avr/pgmspace.h> | ||
29 | + | ||
30 | +#define NUM_DIGITAL_PINS 20 | ||
31 | +#define NUM_ANALOG_INPUTS 6 | ||
32 | +#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1) | ||
33 | + | ||
34 | +#if defined(__AVR_ATmega8__) | ||
35 | +#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11) | ||
36 | +#else | ||
37 | +#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11) | ||
38 | +#endif | ||
39 | + | ||
40 | +static const uint8_t SS = 10; | ||
41 | +static const uint8_t MOSI = 11; | ||
42 | +static const uint8_t MISO = 12; | ||
43 | +static const uint8_t SCK = 13; | ||
44 | + | ||
45 | +static const uint8_t SDA = 18; | ||
46 | +static const uint8_t SCL = 19; | ||
47 | +static const uint8_t LED_BUILTIN = 13; | ||
48 | + | ||
49 | +static const uint8_t A0 = 14; | ||
50 | +static const uint8_t A1 = 15; | ||
51 | +static const uint8_t A2 = 16; | ||
52 | +static const uint8_t A3 = 17; | ||
53 | +static const uint8_t A4 = 18; | ||
54 | +static const uint8_t A5 = 19; | ||
55 | +static const uint8_t A6 = 20; | ||
56 | +static const uint8_t A7 = 21; | ||
57 | + | ||
58 | +#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) | ||
59 | +#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) | ||
60 | +#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) | ||
61 | +#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) | ||
62 | + | ||
63 | +#ifdef ARDUINO_MAIN | ||
64 | + | ||
65 | +// On the Arduino board, digital pins are also used | ||
66 | +// for the analog output (software PWM). Analog input | ||
67 | +// pins are a separate set. | ||
68 | + | ||
69 | +// ATMEL ATMEGA8 & 168 / ARDUINO | ||
70 | +// | ||
71 | +// +-\/-+ | ||
72 | +// PC6 1| |28 PC5 (AI 5) | ||
73 | +// (D 0) PD0 2| |27 PC4 (AI 4) | ||
74 | +// (D 1) PD1 3| |26 PC3 (AI 3) | ||
75 | +// (D 2) PD2 4| |25 PC2 (AI 2) | ||
76 | +// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) | ||
77 | +// (D 4) PD4 6| |23 PC0 (AI 0) | ||
78 | +// VCC 7| |22 GND | ||
79 | +// GND 8| |21 AREF | ||
80 | +// PB6 9| |20 AVCC | ||
81 | +// PB7 10| |19 PB5 (D 13) | ||
82 | +// PWM+ (D 5) PD5 11| |18 PB4 (D 12) | ||
83 | +// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM | ||
84 | +// (D 7) PD7 13| |16 PB2 (D 10) PWM | ||
85 | +// (D 8) PB0 14| |15 PB1 (D 9) PWM | ||
86 | +// +----+ | ||
87 | +// | ||
88 | +// (PWM+ indicates the additional PWM pins on the ATmega168.) | ||
89 | + | ||
90 | +// ATMEL ATMEGA1280 / ARDUINO | ||
91 | +// | ||
92 | +// 0-7 PE0-PE7 works | ||
93 | +// 8-13 PB0-PB5 works | ||
94 | +// 14-21 PA0-PA7 works | ||
95 | +// 22-29 PH0-PH7 works | ||
96 | +// 30-35 PG5-PG0 works | ||
97 | +// 36-43 PC7-PC0 works | ||
98 | +// 44-51 PJ7-PJ0 works | ||
99 | +// 52-59 PL7-PL0 works | ||
100 | +// 60-67 PD7-PD0 works | ||
101 | +// A0-A7 PF0-PF7 | ||
102 | +// A8-A15 PK0-PK7 | ||
103 | + | ||
104 | + | ||
105 | +// these arrays map port names (e.g. port B) to the | ||
106 | +// appropriate addresses for various functions (e.g. reading | ||
107 | +// and writing) | ||
108 | +const uint16_t PROGMEM port_to_mode_PGM[] = { | ||
109 | + NOT_A_PORT, | ||
110 | + NOT_A_PORT, | ||
111 | + (uint16_t) &DDRB, | ||
112 | + (uint16_t) &DDRC, | ||
113 | + (uint16_t) &DDRD, | ||
114 | +}; | ||
115 | + | ||
116 | +const uint16_t PROGMEM port_to_output_PGM[] = { | ||
117 | + NOT_A_PORT, | ||
118 | + NOT_A_PORT, | ||
119 | + (uint16_t) &PORTB, | ||
120 | + (uint16_t) &PORTC, | ||
121 | + (uint16_t) &PORTD, | ||
122 | +}; | ||
123 | + | ||
124 | +const uint16_t PROGMEM port_to_input_PGM[] = { | ||
125 | + NOT_A_PORT, | ||
126 | + NOT_A_PORT, | ||
127 | + (uint16_t) &PINB, | ||
128 | + (uint16_t) &PINC, | ||
129 | + (uint16_t) &PIND, | ||
130 | +}; | ||
131 | + | ||
132 | +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { | ||
133 | + PD, /* 0 */ | ||
134 | + PD, | ||
135 | + PD, | ||
136 | + PD, | ||
137 | + PD, | ||
138 | + PD, | ||
139 | + PD, | ||
140 | + PD, | ||
141 | + PB, /* 8 */ | ||
142 | + PB, | ||
143 | + PB, | ||
144 | + PB, | ||
145 | + PB, | ||
146 | + PB, | ||
147 | + PC, /* 14 */ | ||
148 | + PC, | ||
149 | + PC, | ||
150 | + PC, | ||
151 | + PC, | ||
152 | + PC, | ||
153 | +}; | ||
154 | + | ||
155 | +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { | ||
156 | + _BV(0), /* 0, port D */ | ||
157 | + _BV(1), | ||
158 | + _BV(2), | ||
159 | + _BV(3), | ||
160 | + _BV(4), | ||
161 | + _BV(5), | ||
162 | + _BV(6), | ||
163 | + _BV(7), | ||
164 | + _BV(0), /* 8, port B */ | ||
165 | + _BV(1), | ||
166 | + _BV(2), | ||
167 | + _BV(3), | ||
168 | + _BV(4), | ||
169 | + _BV(5), | ||
170 | + _BV(0), /* 14, port C */ | ||
171 | + _BV(1), | ||
172 | + _BV(2), | ||
173 | + _BV(3), | ||
174 | + _BV(4), | ||
175 | + _BV(5), | ||
176 | +}; | ||
177 | + | ||
178 | +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { | ||
179 | + NOT_ON_TIMER, /* 0 - port D */ | ||
180 | + NOT_ON_TIMER, | ||
181 | + NOT_ON_TIMER, | ||
182 | + // on the ATmega168, digital pin 3 has hardware pwm | ||
183 | +#if defined(__AVR_ATmega8__) | ||
184 | + NOT_ON_TIMER, | ||
185 | +#else | ||
186 | + TIMER2B, | ||
187 | +#endif | ||
188 | + NOT_ON_TIMER, | ||
189 | + // on the ATmega168, digital pins 5 and 6 have hardware pwm | ||
190 | +#if defined(__AVR_ATmega8__) | ||
191 | + NOT_ON_TIMER, | ||
192 | + NOT_ON_TIMER, | ||
193 | +#else | ||
194 | + TIMER0B, | ||
195 | + TIMER0A, | ||
196 | +#endif | ||
197 | + NOT_ON_TIMER, | ||
198 | + NOT_ON_TIMER, /* 8 - port B */ | ||
199 | + TIMER1A, | ||
200 | + TIMER1B, | ||
201 | +#if defined(__AVR_ATmega8__) | ||
202 | + TIMER2, | ||
203 | +#else | ||
204 | + TIMER2A, | ||
205 | +#endif | ||
206 | + NOT_ON_TIMER, | ||
207 | + NOT_ON_TIMER, | ||
208 | + NOT_ON_TIMER, | ||
209 | + NOT_ON_TIMER, /* 14 - port C */ | ||
210 | + NOT_ON_TIMER, | ||
211 | + NOT_ON_TIMER, | ||
212 | + NOT_ON_TIMER, | ||
213 | + NOT_ON_TIMER, | ||
214 | +}; | ||
215 | + | ||
216 | +#endif | ||
217 | + | ||
218 | +#endif |
@@ -0,0 +1,324 @@ | @@ -0,0 +1,324 @@ | ||
1 | +/* | ||
2 | + wiring.c - Partial implementation of the Wiring API for the ATmega8. | ||
3 | + Part of Arduino - http://www.arduino.cc/ | ||
4 | + | ||
5 | + Copyright (c) 2005-2006 David A. Mellis | ||
6 | + | ||
7 | + This library is free software; you can redistribute it and/or | ||
8 | + modify it under the terms of the GNU Lesser General Public | ||
9 | + License as published by the Free Software Foundation; either | ||
10 | + version 2.1 of the License, or (at your option) any later version. | ||
11 | + | ||
12 | + This library is distributed in the hope that it will be useful, | ||
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | + Lesser General Public License for more details. | ||
16 | + | ||
17 | + You should have received a copy of the GNU Lesser General | ||
18 | + Public License along with this library; if not, write to the | ||
19 | + Free Software Foundation, Inc., 59 Temple Place, Suite 330, | ||
20 | + Boston, MA 02111-1307 USA | ||
21 | + | ||
22 | + $Id$ | ||
23 | +*/ | ||
24 | + | ||
25 | +#include "wiring_private.h" | ||
26 | + | ||
27 | +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the | ||
28 | +// the overflow handler is called every 256 ticks. | ||
29 | +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) | ||
30 | + | ||
31 | +// the whole number of milliseconds per timer0 overflow | ||
32 | +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) | ||
33 | + | ||
34 | +// the fractional number of milliseconds per timer0 overflow. we shift right | ||
35 | +// by three to fit these numbers into a byte. (for the clock speeds we care | ||
36 | +// about - 8 and 16 MHz - this doesn't lose precision.) | ||
37 | +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) | ||
38 | +#define FRACT_MAX (1000 >> 3) | ||
39 | + | ||
40 | +volatile unsigned long timer0_overflow_count = 0; | ||
41 | +volatile unsigned long timer0_millis = 0; | ||
42 | +static unsigned char timer0_fract = 0; | ||
43 | + | ||
44 | +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) | ||
45 | +ISR(TIM0_OVF_vect) | ||
46 | +#else | ||
47 | +ISR(TIMER0_OVF_vect) | ||
48 | +#endif | ||
49 | +{ | ||
50 | + // copy these to local variables so they can be stored in registers | ||
51 | + // (volatile variables must be read from memory on every access) | ||
52 | + unsigned long m = timer0_millis; | ||
53 | + unsigned char f = timer0_fract; | ||
54 | + | ||
55 | + m += MILLIS_INC; | ||
56 | + f += FRACT_INC; | ||
57 | + if (f >= FRACT_MAX) { | ||
58 | + f -= FRACT_MAX; | ||
59 | + m += 1; | ||
60 | + } | ||
61 | + | ||
62 | + timer0_fract = f; | ||
63 | + timer0_millis = m; | ||
64 | + timer0_overflow_count++; | ||
65 | +} | ||
66 | + | ||
67 | +unsigned long millis() | ||
68 | +{ | ||
69 | + unsigned long m; | ||
70 | + uint8_t oldSREG = SREG; | ||
71 | + | ||
72 | + // disable interrupts while we read timer0_millis or we might get an | ||
73 | + // inconsistent value (e.g. in the middle of a write to timer0_millis) | ||
74 | + cli(); | ||
75 | + m = timer0_millis; | ||
76 | + SREG = oldSREG; | ||
77 | + | ||
78 | + return m; | ||
79 | +} | ||
80 | + | ||
81 | +unsigned long micros() { | ||
82 | + unsigned long m; | ||
83 | + uint8_t oldSREG = SREG, t; | ||
84 | + | ||
85 | + cli(); | ||
86 | + m = timer0_overflow_count; | ||
87 | +#if defined(TCNT0) | ||
88 | + t = TCNT0; | ||
89 | +#elif defined(TCNT0L) | ||
90 | + t = TCNT0L; | ||
91 | +#else | ||
92 | + #error TIMER 0 not defined | ||
93 | +#endif | ||
94 | + | ||
95 | + | ||
96 | +#ifdef TIFR0 | ||
97 | + if ((TIFR0 & _BV(TOV0)) && (t < 255)) | ||
98 | + m++; | ||
99 | +#else | ||
100 | + if ((TIFR & _BV(TOV0)) && (t < 255)) | ||
101 | + m++; | ||
102 | +#endif | ||
103 | + | ||
104 | + SREG = oldSREG; | ||
105 | + | ||
106 | + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); | ||
107 | +} | ||
108 | + | ||
109 | +void delay(unsigned long ms) | ||
110 | +{ | ||
111 | + uint16_t start = (uint16_t)micros(); | ||
112 | + | ||
113 | + while (ms > 0) { | ||
114 | + if (((uint16_t)micros() - start) >= 1000) { | ||
115 | + ms--; | ||
116 | + start += 1000; | ||
117 | + } | ||
118 | + } | ||
119 | +} | ||
120 | + | ||
121 | +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ | ||
122 | +void delayMicroseconds(unsigned int us) | ||
123 | +{ | ||
124 | + // calling avrlib's delay_us() function with low values (e.g. 1 or | ||
125 | + // 2 microseconds) gives delays longer than desired. | ||
126 | + //delay_us(us); | ||
127 | +#if F_CPU >= 20000000L | ||
128 | + // for the 20 MHz clock on rare Arduino boards | ||
129 | + | ||
130 | + // for a one-microsecond delay, simply wait 2 cycle and return. The overhead | ||
131 | + // of the function call yields a delay of exactly a one microsecond. | ||
132 | + __asm__ __volatile__ ( | ||
133 | + "nop" "\n\t" | ||
134 | + "nop"); //just waiting 2 cycle | ||
135 | + if (--us == 0) | ||
136 | + return; | ||
137 | + | ||
138 | + // the following loop takes a 1/5 of a microsecond (4 cycles) | ||
139 | + // per iteration, so execute it five times for each microsecond of | ||
140 | + // delay requested. | ||
141 | + us = (us<<2) + us; // x5 us | ||
142 | + | ||
143 | + // account for the time taken in the preceeding commands. | ||
144 | + us -= 2; | ||
145 | + | ||
146 | +#elif F_CPU >= 16000000L | ||
147 | + // for the 16 MHz clock on most Arduino boards | ||
148 | + | ||
149 | + // for a one-microsecond delay, simply return. the overhead | ||
150 | + // of the function call yields a delay of approximately 1 1/8 us. | ||
151 | + if (--us == 0) | ||
152 | + return; | ||
153 | + | ||
154 | + // the following loop takes a quarter of a microsecond (4 cycles) | ||
155 | + // per iteration, so execute it four times for each microsecond of | ||
156 | + // delay requested. | ||
157 | + us <<= 2; | ||
158 | + | ||
159 | + // account for the time taken in the preceeding commands. | ||
160 | + us -= 2; | ||
161 | +#else | ||
162 | + // for the 8 MHz internal clock on the ATmega168 | ||
163 | + | ||
164 | + // for a one- or two-microsecond delay, simply return. the overhead of | ||
165 | + // the function calls takes more than two microseconds. can't just | ||
166 | + // subtract two, since us is unsigned; we'd overflow. | ||
167 | + if (--us == 0) | ||
168 | + return; | ||
169 | + if (--us == 0) | ||
170 | + return; | ||
171 | + | ||
172 | + // the following loop takes half of a microsecond (4 cycles) | ||
173 | + // per iteration, so execute it twice for each microsecond of | ||
174 | + // delay requested. | ||
175 | + us <<= 1; | ||
176 | + | ||
177 | + // partially compensate for the time taken by the preceeding commands. | ||
178 | + // we can't subtract any more than this or we'd overflow w/ small delays. | ||
179 | + us--; | ||
180 | +#endif | ||
181 | + | ||
182 | + // busy wait | ||
183 | + __asm__ __volatile__ ( | ||
184 | + "1: sbiw %0,1" "\n\t" // 2 cycles | ||
185 | + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles | ||
186 | + ); | ||
187 | +} | ||
188 | + | ||
189 | +void init() | ||
190 | +{ | ||
191 | + // this needs to be called before setup() or some functions won't | ||
192 | + // work there | ||
193 | + sei(); | ||
194 | + | ||
195 | + // on the ATmega168, timer 0 is also used for fast hardware pwm | ||
196 | + // (using phase-correct PWM would mean that timer 0 overflowed half as often | ||
197 | + // resulting in different millis() behavior on the ATmega8 and ATmega168) | ||
198 | +#if defined(TCCR0A) && defined(WGM01) | ||
199 | + sbi(TCCR0A, WGM01); | ||
200 | + sbi(TCCR0A, WGM00); | ||
201 | +#endif | ||
202 | + | ||
203 | + // set timer 0 prescale factor to 64 | ||
204 | +#if defined(__AVR_ATmega128__) | ||
205 | + // CPU specific: different values for the ATmega128 | ||
206 | + sbi(TCCR0, CS02); | ||
207 | +#elif defined(TCCR0) && defined(CS01) && defined(CS00) | ||
208 | + // this combination is for the standard atmega8 | ||
209 | + sbi(TCCR0, CS01); | ||
210 | + sbi(TCCR0, CS00); | ||
211 | +#elif defined(TCCR0B) && defined(CS01) && defined(CS00) | ||
212 | + // this combination is for the standard 168/328/1280/2560 | ||
213 | + sbi(TCCR0B, CS01); | ||
214 | + sbi(TCCR0B, CS00); | ||
215 | +#elif defined(TCCR0A) && defined(CS01) && defined(CS00) | ||
216 | + // this combination is for the __AVR_ATmega645__ series | ||
217 | + sbi(TCCR0A, CS01); | ||
218 | + sbi(TCCR0A, CS00); | ||
219 | +#else | ||
220 | + #error Timer 0 prescale factor 64 not set correctly | ||
221 | +#endif | ||
222 | + | ||
223 | + // enable timer 0 overflow interrupt | ||
224 | +#if defined(TIMSK) && defined(TOIE0) | ||
225 | + sbi(TIMSK, TOIE0); | ||
226 | +#elif defined(TIMSK0) && defined(TOIE0) | ||
227 | + sbi(TIMSK0, TOIE0); | ||
228 | +#else | ||
229 | + #error Timer 0 overflow interrupt not set correctly | ||
230 | +#endif | ||
231 | + | ||
232 | + // timers 1 and 2 are used for phase-correct hardware pwm | ||
233 | + // this is better for motors as it ensures an even waveform | ||
234 | + // note, however, that fast pwm mode can achieve a frequency of up | ||
235 | + // 8 MHz (with a 16 MHz clock) at 50% duty cycle | ||
236 | + | ||
237 | +#if defined(TCCR1B) && defined(CS11) && defined(CS10) | ||
238 | + TCCR1B = 0; | ||
239 | + | ||
240 | + // set timer 1 prescale factor to 64 | ||
241 | + sbi(TCCR1B, CS11); | ||
242 | +#if F_CPU >= 8000000L | ||
243 | + sbi(TCCR1B, CS10); | ||
244 | +#endif | ||
245 | +#elif defined(TCCR1) && defined(CS11) && defined(CS10) | ||
246 | + sbi(TCCR1, CS11); | ||
247 | +#if F_CPU >= 8000000L | ||
248 | + sbi(TCCR1, CS10); | ||
249 | +#endif | ||
250 | +#endif | ||
251 | + // put timer 1 in 8-bit phase correct pwm mode | ||
252 | +#if defined(TCCR1A) && defined(WGM10) | ||
253 | + sbi(TCCR1A, WGM10); | ||
254 | +#elif defined(TCCR1) | ||
255 | + #warning this needs to be finished | ||
256 | +#endif | ||
257 | + | ||
258 | + // set timer 2 prescale factor to 64 | ||
259 | +#if defined(TCCR2) && defined(CS22) | ||
260 | + sbi(TCCR2, CS22); | ||
261 | +#elif defined(TCCR2B) && defined(CS22) | ||
262 | + sbi(TCCR2B, CS22); | ||
263 | +#else | ||
264 | + #warning Timer 2 not finished (may not be present on this CPU) | ||
265 | +#endif | ||
266 | + | ||
267 | + // configure timer 2 for phase correct pwm (8-bit) | ||
268 | +#if defined(TCCR2) && defined(WGM20) | ||
269 | + sbi(TCCR2, WGM20); | ||
270 | +#elif defined(TCCR2A) && defined(WGM20) | ||
271 | + sbi(TCCR2A, WGM20); | ||
272 | +#else | ||
273 | + #warning Timer 2 not finished (may not be present on this CPU) | ||
274 | +#endif | ||
275 | + | ||
276 | +#if defined(TCCR3B) && defined(CS31) && defined(WGM30) | ||
277 | + sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 | ||
278 | + sbi(TCCR3B, CS30); | ||
279 | + sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode | ||
280 | +#endif | ||
281 | + | ||
282 | +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ | ||
283 | + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 | ||
284 | + sbi(TCCR4B, CS41); | ||
285 | + sbi(TCCR4B, CS40); | ||
286 | + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode | ||
287 | + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A | ||
288 | + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D | ||
289 | +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ | ||
290 | +#if defined(TCCR4B) && defined(CS41) && defined(WGM40) | ||
291 | + sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 | ||
292 | + sbi(TCCR4B, CS40); | ||
293 | + sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode | ||
294 | +#endif | ||
295 | +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ | ||
296 | + | ||
297 | +#if defined(TCCR5B) && defined(CS51) && defined(WGM50) | ||
298 | + sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 | ||
299 | + sbi(TCCR5B, CS50); | ||
300 | + sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode | ||
301 | +#endif | ||
302 | + | ||
303 | +#if defined(ADCSRA) | ||
304 | + // set a2d prescale factor to 128 | ||
305 | + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. | ||
306 | + // XXX: this will not work properly for other clock speeds, and | ||
307 | + // this code should use F_CPU to determine the prescale factor. | ||
308 | + sbi(ADCSRA, ADPS2); | ||
309 | + sbi(ADCSRA, ADPS1); | ||
310 | + sbi(ADCSRA, ADPS0); | ||
311 | + | ||
312 | + // enable a2d conversions | ||
313 | + sbi(ADCSRA, ADEN); | ||
314 | +#endif | ||
315 | + | ||
316 | + // the bootloader connects pins 0 and 1 to the USART; disconnect them | ||
317 | + // here so they can be used as normal digital i/o; they will be | ||
318 | + // reconnected in Serial.begin() | ||
319 | +#if defined(UCSRB) | ||
320 | + UCSRB = 0; | ||
321 | +#elif defined(UCSR0B) | ||
322 | + UCSR0B = 0; | ||
323 | +#endif | ||
324 | +} |
@@ -0,0 +1,178 @@ | @@ -0,0 +1,178 @@ | ||
1 | +/* | ||
2 | + wiring_digital.c - digital input and output functions | ||
3 | + Part of Arduino - http://www.arduino.cc/ | ||
4 | + | ||
5 | + Copyright (c) 2005-2006 David A. Mellis | ||
6 | + | ||
7 | + This library is free software; you can redistribute it and/or | ||
8 | + modify it under the terms of the GNU Lesser General Public | ||
9 | + License as published by the Free Software Foundation; either | ||
10 | + version 2.1 of the License, or (at your option) any later version. | ||
11 | + | ||
12 | + This library is distributed in the hope that it will be useful, | ||
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | + Lesser General Public License for more details. | ||
16 | + | ||
17 | + You should have received a copy of the GNU Lesser General | ||
18 | + Public License along with this library; if not, write to the | ||
19 | + Free Software Foundation, Inc., 59 Temple Place, Suite 330, | ||
20 | + Boston, MA 02111-1307 USA | ||
21 | + | ||
22 | + Modified 28 September 2010 by Mark Sproul | ||
23 | + | ||
24 | + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ | ||
25 | +*/ | ||
26 | + | ||
27 | +#define ARDUINO_MAIN | ||
28 | +#include "wiring_private.h" | ||
29 | +#include "pins_arduino.h" | ||
30 | + | ||
31 | +void pinMode(uint8_t pin, uint8_t mode) | ||
32 | +{ | ||
33 | + uint8_t bit = digitalPinToBitMask(pin); | ||
34 | + uint8_t port = digitalPinToPort(pin); | ||
35 | + volatile uint8_t *reg, *out; | ||
36 | + | ||
37 | + if (port == NOT_A_PIN) return; | ||
38 | + | ||
39 | + // JWS: can I let the optimizer do this? | ||
40 | + reg = portModeRegister(port); | ||
41 | + out = portOutputRegister(port); | ||
42 | + | ||
43 | + if (mode == INPUT) { | ||
44 | + uint8_t oldSREG = SREG; | ||
45 | + cli(); | ||
46 | + *reg &= ~bit; | ||
47 | + *out &= ~bit; | ||
48 | + SREG = oldSREG; | ||
49 | + } else if (mode == INPUT_PULLUP) { | ||
50 | + uint8_t oldSREG = SREG; | ||
51 | + cli(); | ||
52 | + *reg &= ~bit; | ||
53 | + *out |= bit; | ||
54 | + SREG = oldSREG; | ||
55 | + } else { | ||
56 | + uint8_t oldSREG = SREG; | ||
57 | + cli(); | ||
58 | + *reg |= bit; | ||
59 | + SREG = oldSREG; | ||
60 | + } | ||
61 | +} | ||
62 | + | ||
63 | +// Forcing this inline keeps the callers from having to push their own stuff | ||
64 | +// on the stack. It is a good performance win and only takes 1 more byte per | ||
65 | +// user than calling. (It will take more bytes on the 168.) | ||
66 | +// | ||
67 | +// But shouldn't this be moved into pinMode? Seems silly to check and do on | ||
68 | +// each digitalread or write. | ||
69 | +// | ||
70 | +// Mark Sproul: | ||
71 | +// - Removed inline. Save 170 bytes on atmega1280 | ||
72 | +// - changed to a switch statment; added 32 bytes but much easier to read and maintain. | ||
73 | +// - Added more #ifdefs, now compiles for atmega645 | ||
74 | +// | ||
75 | +//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); | ||
76 | +//static inline void turnOffPWM(uint8_t timer) | ||
77 | +static void turnOffPWM(uint8_t timer) | ||
78 | +{ | ||
79 | + switch (timer) | ||
80 | + { | ||
81 | + #if defined(TCCR1A) && defined(COM1A1) | ||
82 | + case TIMER1A: cbi(TCCR1A, COM1A1); break; | ||
83 | + #endif | ||
84 | + #if defined(TCCR1A) && defined(COM1B1) | ||
85 | + case TIMER1B: cbi(TCCR1A, COM1B1); break; | ||
86 | + #endif | ||
87 | + | ||
88 | + #if defined(TCCR2) && defined(COM21) | ||
89 | + case TIMER2: cbi(TCCR2, COM21); break; | ||
90 | + #endif | ||
91 | + | ||
92 | + #if defined(TCCR0A) && defined(COM0A1) | ||
93 | + case TIMER0A: cbi(TCCR0A, COM0A1); break; | ||
94 | + #endif | ||
95 | + | ||
96 | + #if defined(TIMER0B) && defined(COM0B1) | ||
97 | + case TIMER0B: cbi(TCCR0A, COM0B1); break; | ||
98 | + #endif | ||
99 | + #if defined(TCCR2A) && defined(COM2A1) | ||
100 | + case TIMER2A: cbi(TCCR2A, COM2A1); break; | ||
101 | + #endif | ||
102 | + #if defined(TCCR2A) && defined(COM2B1) | ||
103 | + case TIMER2B: cbi(TCCR2A, COM2B1); break; | ||
104 | + #endif | ||
105 | + | ||
106 | + #if defined(TCCR3A) && defined(COM3A1) | ||
107 | + case TIMER3A: cbi(TCCR3A, COM3A1); break; | ||
108 | + #endif | ||
109 | + #if defined(TCCR3A) && defined(COM3B1) | ||
110 | + case TIMER3B: cbi(TCCR3A, COM3B1); break; | ||
111 | + #endif | ||
112 | + #if defined(TCCR3A) && defined(COM3C1) | ||
113 | + case TIMER3C: cbi(TCCR3A, COM3C1); break; | ||
114 | + #endif | ||
115 | + | ||
116 | + #if defined(TCCR4A) && defined(COM4A1) | ||
117 | + case TIMER4A: cbi(TCCR4A, COM4A1); break; | ||
118 | + #endif | ||
119 | + #if defined(TCCR4A) && defined(COM4B1) | ||
120 | + case TIMER4B: cbi(TCCR4A, COM4B1); break; | ||
121 | + #endif | ||
122 | + #if defined(TCCR4A) && defined(COM4C1) | ||
123 | + case TIMER4C: cbi(TCCR4A, COM4C1); break; | ||
124 | + #endif | ||
125 | + #if defined(TCCR4C) && defined(COM4D1) | ||
126 | + case TIMER4D: cbi(TCCR4C, COM4D1); break; | ||
127 | + #endif | ||
128 | + | ||
129 | + #if defined(TCCR5A) | ||
130 | + case TIMER5A: cbi(TCCR5A, COM5A1); break; | ||
131 | + case TIMER5B: cbi(TCCR5A, COM5B1); break; | ||
132 | + case TIMER5C: cbi(TCCR5A, COM5C1); break; | ||
133 | + #endif | ||
134 | + } | ||
135 | +} | ||
136 | + | ||
137 | +void digitalWrite(uint8_t pin, uint8_t val) | ||
138 | +{ | ||
139 | + uint8_t timer = digitalPinToTimer(pin); | ||
140 | + uint8_t bit = digitalPinToBitMask(pin); | ||
141 | + uint8_t port = digitalPinToPort(pin); | ||
142 | + volatile uint8_t *out; | ||
143 | + | ||
144 | + if (port == NOT_A_PIN) return; | ||
145 | + | ||
146 | + // If the pin that support PWM output, we need to turn it off | ||
147 | + // before doing a digital write. | ||
148 | + if (timer != NOT_ON_TIMER) turnOffPWM(timer); | ||
149 | + | ||
150 | + out = portOutputRegister(port); | ||
151 | + | ||
152 | + uint8_t oldSREG = SREG; | ||
153 | + cli(); | ||
154 | + | ||
155 | + if (val == LOW) { | ||
156 | + *out &= ~bit; | ||
157 | + } else { | ||
158 | + *out |= bit; | ||
159 | + } | ||
160 | + | ||
161 | + SREG = oldSREG; | ||
162 | +} | ||
163 | + | ||
164 | +int digitalRead(uint8_t pin) | ||
165 | +{ | ||
166 | + uint8_t timer = digitalPinToTimer(pin); | ||
167 | + uint8_t bit = digitalPinToBitMask(pin); | ||
168 | + uint8_t port = digitalPinToPort(pin); | ||
169 | + | ||
170 | + if (port == NOT_A_PIN) return LOW; | ||
171 | + | ||
172 | + // If the pin that support PWM output, we need to turn it off | ||
173 | + // before getting a digital reading. | ||
174 | + if (timer != NOT_ON_TIMER) turnOffPWM(timer); | ||
175 | + | ||
176 | + if (*portInputRegister(port) & bit) return HIGH; | ||
177 | + return LOW; | ||
178 | +} |
@@ -0,0 +1,71 @@ | @@ -0,0 +1,71 @@ | ||
1 | +/* | ||
2 | + wiring_private.h - Internal header file. | ||
3 | + Part of Arduino - http://www.arduino.cc/ | ||
4 | + | ||
5 | + Copyright (c) 2005-2006 David A. Mellis | ||
6 | + | ||
7 | + This library is free software; you can redistribute it and/or | ||
8 | + modify it under the terms of the GNU Lesser General Public | ||
9 | + License as published by the Free Software Foundation; either | ||
10 | + version 2.1 of the License, or (at your option) any later version. | ||
11 | + | ||
12 | + This library is distributed in the hope that it will be useful, | ||
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | + Lesser General Public License for more details. | ||
16 | + | ||
17 | + You should have received a copy of the GNU Lesser General | ||
18 | + Public License along with this library; if not, write to the | ||
19 | + Free Software Foundation, Inc., 59 Temple Place, Suite 330, | ||
20 | + Boston, MA 02111-1307 USA | ||
21 | + | ||
22 | + $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ | ||
23 | +*/ | ||
24 | + | ||
25 | +#ifndef WiringPrivate_h | ||
26 | +#define WiringPrivate_h | ||
27 | + | ||
28 | +#include <avr/io.h> | ||
29 | +#include <avr/interrupt.h> | ||
30 | +#include <stdio.h> | ||
31 | +#include <stdarg.h> | ||
32 | + | ||
33 | +#include "Arduino.h" | ||
34 | + | ||
35 | +#ifdef __cplusplus | ||
36 | +extern "C"{ | ||
37 | +#endif | ||
38 | + | ||
39 | +#ifndef cbi | ||
40 | +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) | ||
41 | +#endif | ||
42 | +#ifndef sbi | ||
43 | +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) | ||
44 | +#endif | ||
45 | + | ||
46 | +#define EXTERNAL_INT_0 0 | ||
47 | +#define EXTERNAL_INT_1 1 | ||
48 | +#define EXTERNAL_INT_2 2 | ||
49 | +#define EXTERNAL_INT_3 3 | ||
50 | +#define EXTERNAL_INT_4 4 | ||
51 | +#define EXTERNAL_INT_5 5 | ||
52 | +#define EXTERNAL_INT_6 6 | ||
53 | +#define EXTERNAL_INT_7 7 | ||
54 | + | ||
55 | +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||
56 | +#define EXTERNAL_NUM_INTERRUPTS 8 | ||
57 | +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) | ||
58 | +#define EXTERNAL_NUM_INTERRUPTS 3 | ||
59 | +#elif defined(__AVR_ATmega32U4__) | ||
60 | +#define EXTERNAL_NUM_INTERRUPTS 5 | ||
61 | +#else | ||
62 | +#define EXTERNAL_NUM_INTERRUPTS 2 | ||
63 | +#endif | ||
64 | + | ||
65 | +typedef void (*voidFuncPtr)(void); | ||
66 | + | ||
67 | +#ifdef __cplusplus | ||
68 | +} // extern "C" | ||
69 | +#endif | ||
70 | + | ||
71 | +#endif |
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +export CC = avr-g++ | ||
2 | + | ||
3 | +export MCU = atmega328p | ||
4 | +export TARGET_ARCH = -mmcu=$(MCU) | ||
5 | + | ||
6 | +export CFLAGS = -Wall -I./ -I/usr/share/arduino/hardware/arduino/variants/standard -I./PN532_SPI -I./PN532 -I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/libraries/SPI -I/usr/share/arduino/libraries -DF_CPU=16000000 -Os #-g | ||
7 | +export LDFLAGS = -g $(TARGET_ARCH) -lm -Wl,--gc-sections # -Os | ||
8 | + | ||
9 | +TARGET = usb | ||
10 | +TERM = /dev/ttyACM0 | ||
11 | +CPPFLAGS = -mmcu=$(MCU) | ||
12 | +PGMER = -c stk500v1 -b 57600 -P $(TERM) | ||
13 | +PGMERISP = -c stk500v1 -b 115200 -P $(TERM) | ||
14 | +ARVDUDECONF= -C /usr/local/arduino/arduino-0022/hardware/tools/avrdude.conf | ||
15 | +export DUDE = /usr/bin/avrdude -F -v -p $(MCU) $(AVRDUDECONF) | ||
16 | + | ||
17 | +C_SRC = main.c Arduino/wiring_digital.c | ||
18 | +CPP_SRC = PN532_SPI/PN532_SPI.cpp PN532/PN532.cpp PN532/SPI.cpp | ||
19 | +OBJS = $(C_SRC:.c=.o) | ||
20 | +OBJS += $(CPP_SRC:.cpp=.o) | ||
21 | + | ||
22 | +all: $(TARGET).hex | ||
23 | + | ||
24 | +clean: | ||
25 | + rm -f *.o *.hex *.elf | ||
26 | + | ||
27 | +%.o:%.c | ||
28 | + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ | ||
29 | +%.o:%.cpp | ||
30 | + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ | ||
31 | + | ||
32 | +$(TARGET).elf: $(OBJS) | ||
33 | + $(CC) $(LDFLAGS) -o $@ $(OBJS) | ||
34 | + | ||
35 | +$(TARGET).hex: $(TARGET).elf | ||
36 | + avr-objcopy -j .text -j .data -O ihex $(TARGET).elf $(TARGET).hex | ||
37 | + avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex $(TARGET).elf eeprom.hex | ||
38 | + | ||
39 | +upload: $(TARGET).hex | ||
40 | + stty -F $(TERM) hupcl # reset | ||
41 | + $(DUDE) $(PGMERISP) -U flash:w:$(TARGET).hex | ||
42 | + |
@@ -0,0 +1,886 @@ | @@ -0,0 +1,886 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + @file PN532.cpp | ||
4 | + @author Adafruit Industries & Seeed Studio | ||
5 | + @license BSD | ||
6 | +*/ | ||
7 | +/**************************************************************************/ | ||
8 | + | ||
9 | +#include "Arduino.h" | ||
10 | +#include "PN532.h" | ||
11 | +#include "PN532_debug.h" | ||
12 | +#include <string.h> | ||
13 | + | ||
14 | +#define HAL(func) (_interface->func) | ||
15 | + | ||
16 | +void send_serial(unsigned char); | ||
17 | + | ||
18 | +PN532::PN532(PN532Interface &interface) | ||
19 | +{ | ||
20 | + _interface = &interface; | ||
21 | +} | ||
22 | + | ||
23 | +/**************************************************************************/ | ||
24 | +/*! | ||
25 | + @brief Setups the HW | ||
26 | +*/ | ||
27 | +/**************************************************************************/ | ||
28 | +void PN532::begin() | ||
29 | +{ | ||
30 | + send_serial('A'); | ||
31 | + HAL(begin)(); | ||
32 | + send_serial('B'); | ||
33 | + HAL(wakeup)(); | ||
34 | + send_serial('C'); | ||
35 | +} | ||
36 | + | ||
37 | +/**************************************************************************/ | ||
38 | +/*! | ||
39 | + @brief Prints a hexadecimal value in plain characters | ||
40 | + | ||
41 | + @param data Pointer to the uint8_t data | ||
42 | + @param numBytes Data length in bytes | ||
43 | +*/ | ||
44 | +/**************************************************************************/ | ||
45 | +void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes) | ||
46 | +{ | ||
47 | +#ifdef ARDUINO | ||
48 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
49 | + if (data[i] < 0x10) { | ||
50 | + Serial.print(" 0"); | ||
51 | + } else { | ||
52 | + Serial.print(' '); | ||
53 | + } | ||
54 | + Serial.print(data[i], HEX); | ||
55 | + } | ||
56 | + Serial.println(""); | ||
57 | +#else | ||
58 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
59 | + printf(" %2X", data[i]); | ||
60 | + } | ||
61 | + printf("\n"); | ||
62 | +#endif | ||
63 | +} | ||
64 | + | ||
65 | +/**************************************************************************/ | ||
66 | +/*! | ||
67 | + @brief Prints a hexadecimal value in plain characters, along with | ||
68 | + the char equivalents in the following format | ||
69 | + | ||
70 | + 00 00 00 00 00 00 ...... | ||
71 | + | ||
72 | + @param data Pointer to the data | ||
73 | + @param numBytes Data length in bytes | ||
74 | +*/ | ||
75 | +/**************************************************************************/ | ||
76 | +void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes) | ||
77 | +{ | ||
78 | +#ifdef ARDUINO | ||
79 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
80 | + if (data[i] < 0x10) { | ||
81 | + Serial.print(" 0"); | ||
82 | + } else { | ||
83 | + Serial.print(' '); | ||
84 | + } | ||
85 | + Serial.print(data[i], HEX); | ||
86 | + } | ||
87 | + Serial.print(" "); | ||
88 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
89 | + char c = data[i]; | ||
90 | + if (c <= 0x1f || c > 0x7f) { | ||
91 | + Serial.print('.'); | ||
92 | + } else { | ||
93 | + Serial.print(c); | ||
94 | + } | ||
95 | + } | ||
96 | + Serial.println(""); | ||
97 | +#else | ||
98 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
99 | + printf(" %2X", data[i]); | ||
100 | + } | ||
101 | + printf(" "); | ||
102 | + for (uint8_t i = 0; i < numBytes; i++) { | ||
103 | + char c = data[i]; | ||
104 | + if (c <= 0x1f || c > 0x7f) { | ||
105 | + printf("."); | ||
106 | + } else { | ||
107 | + printf("%c", c); | ||
108 | + } | ||
109 | + printf("\n"); | ||
110 | + } | ||
111 | +#endif | ||
112 | +} | ||
113 | + | ||
114 | +/**************************************************************************/ | ||
115 | +/*! | ||
116 | + @brief Checks the firmware version of the PN5xx chip | ||
117 | + | ||
118 | + @returns The chip's firmware version and ID | ||
119 | +*/ | ||
120 | +/**************************************************************************/ | ||
121 | +uint32_t PN532::getFirmwareVersion(void) | ||
122 | +{ | ||
123 | + uint32_t response; | ||
124 | + | ||
125 | + pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; | ||
126 | + | ||
127 | + if (HAL(writeCommand)(pn532_packetbuffer, 1)) { | ||
128 | + return 0; | ||
129 | + } | ||
130 | + | ||
131 | + // read data packet | ||
132 | + int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
133 | + if (0 > status) { | ||
134 | + return 0; | ||
135 | + } | ||
136 | + | ||
137 | + response = pn532_packetbuffer[0]; | ||
138 | + response <<= 8; | ||
139 | + response |= pn532_packetbuffer[1]; | ||
140 | + response <<= 8; | ||
141 | + response |= pn532_packetbuffer[2]; | ||
142 | + response <<= 8; | ||
143 | + response |= pn532_packetbuffer[3]; | ||
144 | + | ||
145 | + return response; | ||
146 | +} | ||
147 | + | ||
148 | + | ||
149 | +/**************************************************************************/ | ||
150 | +/*! | ||
151 | + Writes an 8-bit value that sets the state of the PN532's GPIO pins | ||
152 | + | ||
153 | + @warning This function is provided exclusively for board testing and | ||
154 | + is dangerous since it will throw an error if any pin other | ||
155 | + than the ones marked "Can be used as GPIO" are modified! All | ||
156 | + pins that can not be used as GPIO should ALWAYS be left high | ||
157 | + (value = 1) or the system will become unstable and a HW reset | ||
158 | + will be required to recover the PN532. | ||
159 | + | ||
160 | + pinState[0] = P30 Can be used as GPIO | ||
161 | + pinState[1] = P31 Can be used as GPIO | ||
162 | + pinState[2] = P32 *** RESERVED (Must be 1!) *** | ||
163 | + pinState[3] = P33 Can be used as GPIO | ||
164 | + pinState[4] = P34 *** RESERVED (Must be 1!) *** | ||
165 | + pinState[5] = P35 Can be used as GPIO | ||
166 | + | ||
167 | + @returns 1 if everything executed properly, 0 for an error | ||
168 | +*/ | ||
169 | +/**************************************************************************/ | ||
170 | +bool PN532::writeGPIO(uint8_t pinstate) | ||
171 | +{ | ||
172 | + // Make sure pinstate does not try to toggle P32 or P34 | ||
173 | + pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34); | ||
174 | + | ||
175 | + // Fill command buffer | ||
176 | + pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO; | ||
177 | + pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins | ||
178 | + pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by I2C) | ||
179 | + | ||
180 | + DMSG("Writing P3 GPIO: "); | ||
181 | + DMSG_HEX(pn532_packetbuffer[1]); | ||
182 | + DMSG("\n"); | ||
183 | + | ||
184 | + // Send the WRITEGPIO command (0x0E) | ||
185 | + if (HAL(writeCommand)(pn532_packetbuffer, 3)) | ||
186 | + return 0; | ||
187 | + | ||
188 | + return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); | ||
189 | +} | ||
190 | + | ||
191 | +/**************************************************************************/ | ||
192 | +/*! | ||
193 | + Reads the state of the PN532's GPIO pins | ||
194 | + | ||
195 | + @returns An 8-bit value containing the pin state where: | ||
196 | + | ||
197 | + pinState[0] = P30 | ||
198 | + pinState[1] = P31 | ||
199 | + pinState[2] = P32 | ||
200 | + pinState[3] = P33 | ||
201 | + pinState[4] = P34 | ||
202 | + pinState[5] = P35 | ||
203 | +*/ | ||
204 | +/**************************************************************************/ | ||
205 | +uint8_t PN532::readGPIO(void) | ||
206 | +{ | ||
207 | + pn532_packetbuffer[0] = PN532_COMMAND_READGPIO; | ||
208 | + | ||
209 | + // Send the READGPIO command (0x0C) | ||
210 | + if (HAL(writeCommand)(pn532_packetbuffer, 1)) | ||
211 | + return 0x0; | ||
212 | + | ||
213 | + HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
214 | + | ||
215 | + /* READGPIO response without prefix and suffix should be in the following format: | ||
216 | + | ||
217 | + byte Description | ||
218 | + ------------- ------------------------------------------ | ||
219 | + b0 P3 GPIO Pins | ||
220 | + b1 P7 GPIO Pins (not used ... taken by I2C) | ||
221 | + b2 Interface Mode Pins (not used ... bus select pins) | ||
222 | + */ | ||
223 | + | ||
224 | + | ||
225 | + DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]); | ||
226 | + DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]); | ||
227 | + DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]); | ||
228 | + DMSG("\n"); | ||
229 | + | ||
230 | + return pn532_packetbuffer[0]; | ||
231 | +} | ||
232 | + | ||
233 | +/**************************************************************************/ | ||
234 | +/*! | ||
235 | + @brief Configures the SAM (Secure Access Module) | ||
236 | +*/ | ||
237 | +/**************************************************************************/ | ||
238 | +bool PN532::SAMConfig(void) | ||
239 | +{ | ||
240 | + pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; | ||
241 | + pn532_packetbuffer[1] = 0x01; // normal mode; | ||
242 | + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second | ||
243 | + pn532_packetbuffer[3] = 0x01; // use IRQ pin! | ||
244 | + | ||
245 | + DMSG("SAMConfig\n"); | ||
246 | + | ||
247 | + if (HAL(writeCommand)(pn532_packetbuffer, 4)) | ||
248 | + return false; | ||
249 | + | ||
250 | + return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); | ||
251 | +} | ||
252 | + | ||
253 | +/**************************************************************************/ | ||
254 | +/*! | ||
255 | + Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register | ||
256 | + | ||
257 | + @param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout | ||
258 | + after mxRetries | ||
259 | + | ||
260 | + @returns 1 if everything executed properly, 0 for an error | ||
261 | +*/ | ||
262 | +/**************************************************************************/ | ||
263 | +bool PN532::setPassiveActivationRetries(uint8_t maxRetries) | ||
264 | +{ | ||
265 | + pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; | ||
266 | + pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries) | ||
267 | + pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF) | ||
268 | + pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01) | ||
269 | + pn532_packetbuffer[4] = maxRetries; | ||
270 | + | ||
271 | + if (HAL(writeCommand)(pn532_packetbuffer, 5)) | ||
272 | + return 0x0; // no ACK | ||
273 | + | ||
274 | + return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); | ||
275 | +} | ||
276 | + | ||
277 | +/***** ISO14443A Commands ******/ | ||
278 | + | ||
279 | +/**************************************************************************/ | ||
280 | +/*! | ||
281 | + Waits for an ISO14443A target to enter the field | ||
282 | + | ||
283 | + @param cardBaudRate Baud rate of the card | ||
284 | + @param uid Pointer to the array that will be populated | ||
285 | + with the card's UID (up to 7 bytes) | ||
286 | + @param uidLength Pointer to the variable that will hold the | ||
287 | + length of the card's UID. | ||
288 | + @param timeout The number of tries before timing out | ||
289 | + @param inlist If set to true, the card will be inlisted | ||
290 | + | ||
291 | + @returns 1 if everything executed properly, 0 for an error | ||
292 | +*/ | ||
293 | +/**************************************************************************/ | ||
294 | +bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout, bool inlist) | ||
295 | +{ | ||
296 | + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; | ||
297 | + pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) | ||
298 | + pn532_packetbuffer[2] = cardbaudrate; | ||
299 | + | ||
300 | + if (HAL(writeCommand)(pn532_packetbuffer, 3)) { | ||
301 | + return 0x0; // command failed | ||
302 | + } | ||
303 | + | ||
304 | + // read data packet | ||
305 | + if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { | ||
306 | + return 0x0; | ||
307 | + } | ||
308 | + | ||
309 | + // check some basic stuff | ||
310 | + /* ISO14443A card response should be in the following format: | ||
311 | + | ||
312 | + byte Description | ||
313 | + ------------- ------------------------------------------ | ||
314 | + b0 Tags Found | ||
315 | + b1 Tag Number (only one used in this example) | ||
316 | + b2..3 SENS_RES | ||
317 | + b4 SEL_RES | ||
318 | + b5 NFCID Length | ||
319 | + b6..NFCIDLen NFCID | ||
320 | + */ | ||
321 | + | ||
322 | + if (pn532_packetbuffer[0] != 1) | ||
323 | + return 0; | ||
324 | + | ||
325 | + uint16_t sens_res = pn532_packetbuffer[2]; | ||
326 | + sens_res <<= 8; | ||
327 | + sens_res |= pn532_packetbuffer[3]; | ||
328 | + | ||
329 | + DMSG("ATQA: 0x"); DMSG_HEX(sens_res); | ||
330 | + DMSG("SAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]); | ||
331 | + DMSG("\n"); | ||
332 | + | ||
333 | + /* Card appears to be Mifare Classic */ | ||
334 | + *uidLength = pn532_packetbuffer[5]; | ||
335 | + | ||
336 | + for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) { | ||
337 | + uid[i] = pn532_packetbuffer[6 + i]; | ||
338 | + } | ||
339 | + | ||
340 | + if (inlist) { | ||
341 | + inListedTag = pn532_packetbuffer[1]; | ||
342 | + } | ||
343 | + | ||
344 | + return 1; | ||
345 | +} | ||
346 | + | ||
347 | + | ||
348 | +/***** Mifare Classic Functions ******/ | ||
349 | + | ||
350 | +/**************************************************************************/ | ||
351 | +/*! | ||
352 | + Indicates whether the specified block number is the first block | ||
353 | + in the sector (block 0 relative to the current sector) | ||
354 | +*/ | ||
355 | +/**************************************************************************/ | ||
356 | +bool PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock) | ||
357 | +{ | ||
358 | + // Test if we are in the small or big sectors | ||
359 | + if (uiBlock < 128) | ||
360 | + return ((uiBlock) % 4 == 0); | ||
361 | + else | ||
362 | + return ((uiBlock) % 16 == 0); | ||
363 | +} | ||
364 | + | ||
365 | +/**************************************************************************/ | ||
366 | +/*! | ||
367 | + Indicates whether the specified block number is the sector trailer | ||
368 | +*/ | ||
369 | +/**************************************************************************/ | ||
370 | +bool PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock) | ||
371 | +{ | ||
372 | + // Test if we are in the small or big sectors | ||
373 | + if (uiBlock < 128) | ||
374 | + return ((uiBlock + 1) % 4 == 0); | ||
375 | + else | ||
376 | + return ((uiBlock + 1) % 16 == 0); | ||
377 | +} | ||
378 | + | ||
379 | +/**************************************************************************/ | ||
380 | +/*! | ||
381 | + Tries to authenticate a block of memory on a MIFARE card using the | ||
382 | + INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual | ||
383 | + for more information on sending MIFARE and other commands. | ||
384 | + | ||
385 | + @param uid Pointer to a byte array containing the card UID | ||
386 | + @param uidLen The length (in bytes) of the card's UID (Should | ||
387 | + be 4 for MIFARE Classic) | ||
388 | + @param blockNumber The block number to authenticate. (0..63 for | ||
389 | + 1KB cards, and 0..255 for 4KB cards). | ||
390 | + @param keyNumber Which key type to use during authentication | ||
391 | + (0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B) | ||
392 | + @param keyData Pointer to a byte array containing the 6 bytes | ||
393 | + key value | ||
394 | + | ||
395 | + @returns 1 if everything executed properly, 0 for an error | ||
396 | +*/ | ||
397 | +/**************************************************************************/ | ||
398 | +uint8_t PN532::mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) | ||
399 | +{ | ||
400 | + uint8_t i; | ||
401 | + | ||
402 | + // Hang on to the key and uid data | ||
403 | + memcpy (_key, keyData, 6); | ||
404 | + memcpy (_uid, uid, uidLen); | ||
405 | + _uidLen = uidLen; | ||
406 | + | ||
407 | + // Prepare the authentication command // | ||
408 | + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ | ||
409 | + pn532_packetbuffer[1] = 1; /* Max card numbers */ | ||
410 | + pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; | ||
411 | + pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ | ||
412 | + memcpy (pn532_packetbuffer + 4, _key, 6); | ||
413 | + for (i = 0; i < _uidLen; i++) { | ||
414 | + pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ | ||
415 | + } | ||
416 | + | ||
417 | + if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen)) | ||
418 | + return 0; | ||
419 | + | ||
420 | + // Read the response packet | ||
421 | + HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
422 | + | ||
423 | + // Check if the response is valid and we are authenticated??? | ||
424 | + // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 | ||
425 | + // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good | ||
426 | + if (pn532_packetbuffer[0] != 0x00) { | ||
427 | + DMSG("Authentification failed\n"); | ||
428 | + return 0; | ||
429 | + } | ||
430 | + | ||
431 | + return 1; | ||
432 | +} | ||
433 | + | ||
434 | +/**************************************************************************/ | ||
435 | +/*! | ||
436 | + Tries to read an entire 16-bytes data block at the specified block | ||
437 | + address. | ||
438 | + | ||
439 | + @param blockNumber The block number to authenticate. (0..63 for | ||
440 | + 1KB cards, and 0..255 for 4KB cards). | ||
441 | + @param data Pointer to the byte array that will hold the | ||
442 | + retrieved data (if any) | ||
443 | + | ||
444 | + @returns 1 if everything executed properly, 0 for an error | ||
445 | +*/ | ||
446 | +/**************************************************************************/ | ||
447 | +uint8_t PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) | ||
448 | +{ | ||
449 | + DMSG("Trying to read 16 bytes from block "); | ||
450 | + DMSG_INT(blockNumber); | ||
451 | + | ||
452 | + /* Prepare the command */ | ||
453 | + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; | ||
454 | + pn532_packetbuffer[1] = 1; /* Card number */ | ||
455 | + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ | ||
456 | + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ | ||
457 | + | ||
458 | + /* Send the command */ | ||
459 | + if (HAL(writeCommand)(pn532_packetbuffer, 4)) { | ||
460 | + return 0; | ||
461 | + } | ||
462 | + | ||
463 | + /* Read the response packet */ | ||
464 | + HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
465 | + | ||
466 | + /* If byte 8 isn't 0x00 we probably have an error */ | ||
467 | + if (pn532_packetbuffer[0] != 0x00) { | ||
468 | + return 0; | ||
469 | + } | ||
470 | + | ||
471 | + /* Copy the 16 data bytes to the output buffer */ | ||
472 | + /* Block content starts at byte 9 of a valid response */ | ||
473 | + memcpy (data, pn532_packetbuffer + 1, 16); | ||
474 | + | ||
475 | + return 1; | ||
476 | +} | ||
477 | + | ||
478 | +/**************************************************************************/ | ||
479 | +/*! | ||
480 | + Tries to write an entire 16-bytes data block at the specified block | ||
481 | + address. | ||
482 | + | ||
483 | + @param blockNumber The block number to authenticate. (0..63 for | ||
484 | + 1KB cards, and 0..255 for 4KB cards). | ||
485 | + @param data The byte array that contains the data to write. | ||
486 | + | ||
487 | + @returns 1 if everything executed properly, 0 for an error | ||
488 | +*/ | ||
489 | +/**************************************************************************/ | ||
490 | +uint8_t PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) | ||
491 | +{ | ||
492 | + /* Prepare the first command */ | ||
493 | + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; | ||
494 | + pn532_packetbuffer[1] = 1; /* Card number */ | ||
495 | + pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ | ||
496 | + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ | ||
497 | + memcpy (pn532_packetbuffer + 4, data, 16); /* Data Payload */ | ||
498 | + | ||
499 | + /* Send the command */ | ||
500 | + if (HAL(writeCommand)(pn532_packetbuffer, 20)) { | ||
501 | + return 0; | ||
502 | + } | ||
503 | + | ||
504 | + /* Read the response packet */ | ||
505 | + return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); | ||
506 | +} | ||
507 | + | ||
508 | +/**************************************************************************/ | ||
509 | +/*! | ||
510 | + Formats a Mifare Classic card to store NDEF Records | ||
511 | + | ||
512 | + @returns 1 if everything executed properly, 0 for an error | ||
513 | +*/ | ||
514 | +/**************************************************************************/ | ||
515 | +uint8_t PN532::mifareclassic_FormatNDEF (void) | ||
516 | +{ | ||
517 | + uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; | ||
518 | + uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1}; | ||
519 | + uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
520 | + | ||
521 | + // Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A | ||
522 | + // for the MAD sector in NDEF records (sector 0) | ||
523 | + | ||
524 | + // Write block 1 and 2 to the card | ||
525 | + if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1))) | ||
526 | + return 0; | ||
527 | + if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2))) | ||
528 | + return 0; | ||
529 | + // Write key A and access rights card | ||
530 | + if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3))) | ||
531 | + return 0; | ||
532 | + | ||
533 | + // Seems that everything was OK (?!) | ||
534 | + return 1; | ||
535 | +} | ||
536 | + | ||
537 | +/**************************************************************************/ | ||
538 | +/*! | ||
539 | + Writes an NDEF URI Record to the specified sector (1..15) | ||
540 | + | ||
541 | + Note that this function assumes that the Mifare Classic card is | ||
542 | + already formatted to work as an "NFC Forum Tag" and uses a MAD1 | ||
543 | + file system. You can use the NXP TagWriter app on Android to | ||
544 | + properly format cards for this. | ||
545 | + | ||
546 | + @param sectorNumber The sector that the URI record should be written | ||
547 | + to (can be 1..15 for a 1K card) | ||
548 | + @param uriIdentifier The uri identifier code (0 = none, 0x01 = | ||
549 | + "http://www.", etc.) | ||
550 | + @param url The uri text to write (max 38 characters). | ||
551 | + | ||
552 | + @returns 1 if everything executed properly, 0 for an error | ||
553 | +*/ | ||
554 | +/**************************************************************************/ | ||
555 | +uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url) | ||
556 | +{ | ||
557 | + // Figure out how long the string is | ||
558 | + uint8_t len = strlen(url); | ||
559 | + | ||
560 | + // Make sure we're within a 1K limit for the sector number | ||
561 | + if ((sectorNumber < 1) || (sectorNumber > 15)) | ||
562 | + return 0; | ||
563 | + | ||
564 | + // Make sure the URI payload is between 1 and 38 chars | ||
565 | + if ((len < 1) || (len > 38)) | ||
566 | + return 0; | ||
567 | + | ||
568 | + // Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A | ||
569 | + // in NDEF records | ||
570 | + | ||
571 | + // Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message) | ||
572 | + uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, len + 5, 0xD1, 0x01, len + 1, 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
573 | + uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
574 | + uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
575 | + uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
576 | + if (len <= 6) { | ||
577 | + // Unlikely we'll get a url this short, but why not ... | ||
578 | + memcpy (sectorbuffer1 + 9, url, len); | ||
579 | + sectorbuffer1[len + 9] = 0xFE; | ||
580 | + } else if (len == 7) { | ||
581 | + // 0xFE needs to be wrapped around to next block | ||
582 | + memcpy (sectorbuffer1 + 9, url, len); | ||
583 | + sectorbuffer2[0] = 0xFE; | ||
584 | + } else if ((len > 7) || (len <= 22)) { | ||
585 | + // Url fits in two blocks | ||
586 | + memcpy (sectorbuffer1 + 9, url, 7); | ||
587 | + memcpy (sectorbuffer2, url + 7, len - 7); | ||
588 | + sectorbuffer2[len - 7] = 0xFE; | ||
589 | + } else if (len == 23) { | ||
590 | + // 0xFE needs to be wrapped around to final block | ||
591 | + memcpy (sectorbuffer1 + 9, url, 7); | ||
592 | + memcpy (sectorbuffer2, url + 7, len - 7); | ||
593 | + sectorbuffer3[0] = 0xFE; | ||
594 | + } else { | ||
595 | + // Url fits in three blocks | ||
596 | + memcpy (sectorbuffer1 + 9, url, 7); | ||
597 | + memcpy (sectorbuffer2, url + 7, 16); | ||
598 | + memcpy (sectorbuffer3, url + 23, len - 24); | ||
599 | + sectorbuffer3[len - 22] = 0xFE; | ||
600 | + } | ||
601 | + | ||
602 | + // Now write all three blocks back to the card | ||
603 | + if (!(mifareclassic_WriteDataBlock (sectorNumber * 4, sectorbuffer1))) | ||
604 | + return 0; | ||
605 | + if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 1, sectorbuffer2))) | ||
606 | + return 0; | ||
607 | + if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 2, sectorbuffer3))) | ||
608 | + return 0; | ||
609 | + if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 3, sectorbuffer4))) | ||
610 | + return 0; | ||
611 | + | ||
612 | + // Seems that everything was OK (?!) | ||
613 | + return 1; | ||
614 | +} | ||
615 | + | ||
616 | +/***** Mifare Ultralight Functions ******/ | ||
617 | + | ||
618 | +/**************************************************************************/ | ||
619 | +/*! | ||
620 | + Tries to read an entire 4-bytes page at the specified address. | ||
621 | + | ||
622 | + @param page The page number (0..63 in most cases) | ||
623 | + @param buffer Pointer to the byte array that will hold the | ||
624 | + retrieved data (if any) | ||
625 | +*/ | ||
626 | +/**************************************************************************/ | ||
627 | +uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer) | ||
628 | +{ | ||
629 | + if (page >= 64) { | ||
630 | + DMSG("Page value out of range\n"); | ||
631 | + return 0; | ||
632 | + } | ||
633 | + | ||
634 | + /* Prepare the command */ | ||
635 | + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; | ||
636 | + pn532_packetbuffer[1] = 1; /* Card number */ | ||
637 | + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ | ||
638 | + pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */ | ||
639 | + | ||
640 | + /* Send the command */ | ||
641 | + if (HAL(writeCommand)(pn532_packetbuffer, 4)) { | ||
642 | + return 0; | ||
643 | + } | ||
644 | + | ||
645 | + /* Read the response packet */ | ||
646 | + HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
647 | + | ||
648 | + /* If byte 8 isn't 0x00 we probably have an error */ | ||
649 | + if (pn532_packetbuffer[0] == 0x00) { | ||
650 | + /* Copy the 4 data bytes to the output buffer */ | ||
651 | + /* Block content starts at byte 9 of a valid response */ | ||
652 | + /* Note that the command actually reads 16 bytes or 4 */ | ||
653 | + /* pages at a time ... we simply discard the last 12 */ | ||
654 | + /* bytes */ | ||
655 | + memcpy (buffer, pn532_packetbuffer + 1, 4); | ||
656 | + } else { | ||
657 | + return 0; | ||
658 | + } | ||
659 | + | ||
660 | + // Return OK signal | ||
661 | + return 1; | ||
662 | +} | ||
663 | + | ||
664 | +/**************************************************************************/ | ||
665 | +/*! | ||
666 | + Tries to write an entire 4-bytes data buffer at the specified page | ||
667 | + address. | ||
668 | + | ||
669 | + @param page The page number to write into. (0..63). | ||
670 | + @param buffer The byte array that contains the data to write. | ||
671 | + | ||
672 | + @returns 1 if everything executed properly, 0 for an error | ||
673 | +*/ | ||
674 | +/**************************************************************************/ | ||
675 | +uint8_t PN532::mifareultralight_WritePage (uint8_t page, uint8_t *buffer) | ||
676 | +{ | ||
677 | + /* Prepare the first command */ | ||
678 | + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; | ||
679 | + pn532_packetbuffer[1] = 1; /* Card number */ | ||
680 | + pn532_packetbuffer[2] = MIFARE_CMD_WRITE_ULTRALIGHT; /* Mifare UL Write cmd = 0xA2 */ | ||
681 | + pn532_packetbuffer[3] = page; /* page Number (0..63) */ | ||
682 | + memcpy (pn532_packetbuffer + 4, buffer, 4); /* Data Payload */ | ||
683 | + | ||
684 | + /* Send the command */ | ||
685 | + if (HAL(writeCommand)(pn532_packetbuffer, 8)) { | ||
686 | + return 0; | ||
687 | + } | ||
688 | + | ||
689 | + /* Read the response packet */ | ||
690 | + return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer))); | ||
691 | +} | ||
692 | + | ||
693 | +/**************************************************************************/ | ||
694 | +/*! | ||
695 | + @brief Exchanges an APDU with the currently inlisted peer | ||
696 | + | ||
697 | + @param send Pointer to data to send | ||
698 | + @param sendLength Length of the data to send | ||
699 | + @param response Pointer to response data | ||
700 | + @param responseLength Pointer to the response data length | ||
701 | +*/ | ||
702 | +/**************************************************************************/ | ||
703 | +bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength) | ||
704 | +{ | ||
705 | + uint8_t i; | ||
706 | + | ||
707 | + pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE; | ||
708 | + pn532_packetbuffer[1] = inListedTag; | ||
709 | + | ||
710 | + if (HAL(writeCommand)(pn532_packetbuffer, 2, send, sendLength)) { | ||
711 | + return false; | ||
712 | + } | ||
713 | + | ||
714 | + int16_t status = HAL(readResponse)(response, *responseLength, 1000); | ||
715 | + if (status < 0) { | ||
716 | + return false; | ||
717 | + } | ||
718 | + | ||
719 | + if ((response[0] & 0x3f) != 0) { | ||
720 | + DMSG("Status code indicates an error\n"); | ||
721 | + return false; | ||
722 | + } | ||
723 | + | ||
724 | + uint8_t length = status; | ||
725 | + length -= 1; | ||
726 | + | ||
727 | + if (length > *responseLength) { | ||
728 | + length = *responseLength; // silent truncation... | ||
729 | + } | ||
730 | + | ||
731 | + for (uint8_t i = 0; i < length; i++) { | ||
732 | + response[i] = response[i + 1]; | ||
733 | + } | ||
734 | + *responseLength = length; | ||
735 | + | ||
736 | + return true; | ||
737 | +} | ||
738 | + | ||
739 | +/**************************************************************************/ | ||
740 | +/*! | ||
741 | + @brief 'InLists' a passive target. PN532 acting as reader/initiator, | ||
742 | + peer acting as card/responder. | ||
743 | +*/ | ||
744 | +/**************************************************************************/ | ||
745 | +bool PN532::inListPassiveTarget() | ||
746 | +{ | ||
747 | + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; | ||
748 | + pn532_packetbuffer[1] = 1; | ||
749 | + pn532_packetbuffer[2] = 0; | ||
750 | + | ||
751 | + DMSG("inList passive target\n"); | ||
752 | + | ||
753 | + if (HAL(writeCommand)(pn532_packetbuffer, 3)) { | ||
754 | + return false; | ||
755 | + } | ||
756 | + | ||
757 | + int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000); | ||
758 | + if (status < 0) { | ||
759 | + return false; | ||
760 | + } | ||
761 | + | ||
762 | + if (pn532_packetbuffer[0] != 1) { | ||
763 | + return false; | ||
764 | + } | ||
765 | + | ||
766 | + inListedTag = pn532_packetbuffer[1]; | ||
767 | + | ||
768 | + return true; | ||
769 | +} | ||
770 | + | ||
771 | +int8_t PN532::tgInitAsTarget(const uint8_t* command, const uint8_t len, const uint16_t timeout){ | ||
772 | + | ||
773 | + int8_t status = HAL(writeCommand)(command, len); | ||
774 | + if (status < 0) { | ||
775 | + return -1; | ||
776 | + } | ||
777 | + | ||
778 | + status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout); | ||
779 | + if (status > 0) { | ||
780 | + return 1; | ||
781 | + } else if (PN532_TIMEOUT == status) { | ||
782 | + return 0; | ||
783 | + } else { | ||
784 | + return -2; | ||
785 | + } | ||
786 | +} | ||
787 | + | ||
788 | +/** | ||
789 | + * Peer to Peer | ||
790 | + */ | ||
791 | +int8_t PN532::tgInitAsTarget(uint16_t timeout) | ||
792 | +{ | ||
793 | + const uint8_t command[] = { | ||
794 | + PN532_COMMAND_TGINITASTARGET, | ||
795 | + 0, | ||
796 | + 0x00, 0x00, //SENS_RES | ||
797 | + 0x00, 0x00, 0x00, //NFCID1 | ||
798 | + 0x40, //SEL_RES | ||
799 | + | ||
800 | + 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES | ||
801 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
802 | + 0xFF, 0xFF, | ||
803 | + | ||
804 | + 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value | ||
805 | + | ||
806 | + 0x06, 0x46, 0x66, 0x6D, 0x01, 0x01, 0x10, 0x00// LLCP magic number and version parameter | ||
807 | + }; | ||
808 | + return tgInitAsTarget(command, sizeof(command), timeout); | ||
809 | +} | ||
810 | + | ||
811 | +int16_t PN532::tgGetData(uint8_t *buf, uint8_t len) | ||
812 | +{ | ||
813 | + buf[0] = PN532_COMMAND_TGGETDATA; | ||
814 | + | ||
815 | + if (HAL(writeCommand)(buf, 1)) { | ||
816 | + return -1; | ||
817 | + } | ||
818 | + | ||
819 | + int16_t status = HAL(readResponse)(buf, len, 3000); | ||
820 | + if (0 >= status) { | ||
821 | + return status; | ||
822 | + } | ||
823 | + | ||
824 | + uint16_t length = status - 1; | ||
825 | + | ||
826 | + | ||
827 | + if (buf[0] != 0) { | ||
828 | + DMSG("status is not ok\n"); | ||
829 | + return -5; | ||
830 | + } | ||
831 | + | ||
832 | + for (uint8_t i = 0; i < length; i++) { | ||
833 | + buf[i] = buf[i + 1]; | ||
834 | + } | ||
835 | + | ||
836 | + return length; | ||
837 | +} | ||
838 | + | ||
839 | +bool PN532::tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
840 | +{ | ||
841 | + if (hlen > (sizeof(pn532_packetbuffer) - 1)) { | ||
842 | + if ((body != 0) || (header == pn532_packetbuffer)) { | ||
843 | + DMSG("tgSetData:buffer too small\n"); | ||
844 | + return false; | ||
845 | + } | ||
846 | + | ||
847 | + pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA; | ||
848 | + if (HAL(writeCommand)(pn532_packetbuffer, 1, header, hlen)) { | ||
849 | + return false; | ||
850 | + } | ||
851 | + } else { | ||
852 | + for (int8_t i = hlen - 1; i >= 0; i--){ | ||
853 | + pn532_packetbuffer[i + 1] = header[i]; | ||
854 | + } | ||
855 | + pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA; | ||
856 | + | ||
857 | + if (HAL(writeCommand)(pn532_packetbuffer, hlen + 1, body, blen)) { | ||
858 | + return false; | ||
859 | + } | ||
860 | + } | ||
861 | + | ||
862 | + if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) { | ||
863 | + return false; | ||
864 | + } | ||
865 | + | ||
866 | + if (0 != pn532_packetbuffer[0]) { | ||
867 | + return false; | ||
868 | + } | ||
869 | + | ||
870 | + return true; | ||
871 | +} | ||
872 | + | ||
873 | +int16_t PN532::inRelease(const uint8_t relevantTarget){ | ||
874 | + | ||
875 | + pn532_packetbuffer[0] = PN532_COMMAND_INRELEASE; | ||
876 | + pn532_packetbuffer[1] = relevantTarget; | ||
877 | + | ||
878 | + if (HAL(writeCommand)(pn532_packetbuffer, 2)) { | ||
879 | + return 0; | ||
880 | + } | ||
881 | + | ||
882 | + // read data packet | ||
883 | + return HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)); | ||
884 | +} | ||
885 | + | ||
886 | + |
@@ -0,0 +1,179 @@ | @@ -0,0 +1,179 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + @file PN532.h | ||
4 | + @author Adafruit Industries & Seeed Studio | ||
5 | + @license BSD | ||
6 | +*/ | ||
7 | +/**************************************************************************/ | ||
8 | + | ||
9 | +#ifndef __PN532_H__ | ||
10 | +#define __PN532_H__ | ||
11 | + | ||
12 | +#include <stdint.h> | ||
13 | +#include "PN532Interface.h" | ||
14 | + | ||
15 | +// PN532 Commands | ||
16 | +#define PN532_COMMAND_DIAGNOSE (0x00) | ||
17 | +#define PN532_COMMAND_GETFIRMWAREVERSION (0x02) | ||
18 | +#define PN532_COMMAND_GETGENERALSTATUS (0x04) | ||
19 | +#define PN532_COMMAND_READREGISTER (0x06) | ||
20 | +#define PN532_COMMAND_WRITEREGISTER (0x08) | ||
21 | +#define PN532_COMMAND_READGPIO (0x0C) | ||
22 | +#define PN532_COMMAND_WRITEGPIO (0x0E) | ||
23 | +#define PN532_COMMAND_SETSERIALBAUDRATE (0x10) | ||
24 | +#define PN532_COMMAND_SETPARAMETERS (0x12) | ||
25 | +#define PN532_COMMAND_SAMCONFIGURATION (0x14) | ||
26 | +#define PN532_COMMAND_POWERDOWN (0x16) | ||
27 | +#define PN532_COMMAND_RFCONFIGURATION (0x32) | ||
28 | +#define PN532_COMMAND_RFREGULATIONTEST (0x58) | ||
29 | +#define PN532_COMMAND_INJUMPFORDEP (0x56) | ||
30 | +#define PN532_COMMAND_INJUMPFORPSL (0x46) | ||
31 | +#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A) | ||
32 | +#define PN532_COMMAND_INATR (0x50) | ||
33 | +#define PN532_COMMAND_INPSL (0x4E) | ||
34 | +#define PN532_COMMAND_INDATAEXCHANGE (0x40) | ||
35 | +#define PN532_COMMAND_INCOMMUNICATETHRU (0x42) | ||
36 | +#define PN532_COMMAND_INDESELECT (0x44) | ||
37 | +#define PN532_COMMAND_INRELEASE (0x52) | ||
38 | +#define PN532_COMMAND_INSELECT (0x54) | ||
39 | +#define PN532_COMMAND_INAUTOPOLL (0x60) | ||
40 | +#define PN532_COMMAND_TGINITASTARGET (0x8C) | ||
41 | +#define PN532_COMMAND_TGSETGENERALBYTES (0x92) | ||
42 | +#define PN532_COMMAND_TGGETDATA (0x86) | ||
43 | +#define PN532_COMMAND_TGSETDATA (0x8E) | ||
44 | +#define PN532_COMMAND_TGSETMETADATA (0x94) | ||
45 | +#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88) | ||
46 | +#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90) | ||
47 | +#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A) | ||
48 | + | ||
49 | +#define PN532_RESPONSE_INDATAEXCHANGE (0x41) | ||
50 | +#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B) | ||
51 | + | ||
52 | + | ||
53 | +#define PN532_MIFARE_ISO14443A (0x00) | ||
54 | + | ||
55 | +// Mifare Commands | ||
56 | +#define MIFARE_CMD_AUTH_A (0x60) | ||
57 | +#define MIFARE_CMD_AUTH_B (0x61) | ||
58 | +#define MIFARE_CMD_READ (0x30) | ||
59 | +#define MIFARE_CMD_WRITE (0xA0) | ||
60 | +#define MIFARE_CMD_WRITE_ULTRALIGHT (0xA2) | ||
61 | +#define MIFARE_CMD_TRANSFER (0xB0) | ||
62 | +#define MIFARE_CMD_DECREMENT (0xC0) | ||
63 | +#define MIFARE_CMD_INCREMENT (0xC1) | ||
64 | +#define MIFARE_CMD_STORE (0xC2) | ||
65 | + | ||
66 | +// Prefixes for NDEF Records (to identify record type) | ||
67 | +#define NDEF_URIPREFIX_NONE (0x00) | ||
68 | +#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01) | ||
69 | +#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02) | ||
70 | +#define NDEF_URIPREFIX_HTTP (0x03) | ||
71 | +#define NDEF_URIPREFIX_HTTPS (0x04) | ||
72 | +#define NDEF_URIPREFIX_TEL (0x05) | ||
73 | +#define NDEF_URIPREFIX_MAILTO (0x06) | ||
74 | +#define NDEF_URIPREFIX_FTP_ANONAT (0x07) | ||
75 | +#define NDEF_URIPREFIX_FTP_FTPDOT (0x08) | ||
76 | +#define NDEF_URIPREFIX_FTPS (0x09) | ||
77 | +#define NDEF_URIPREFIX_SFTP (0x0A) | ||
78 | +#define NDEF_URIPREFIX_SMB (0x0B) | ||
79 | +#define NDEF_URIPREFIX_NFS (0x0C) | ||
80 | +#define NDEF_URIPREFIX_FTP (0x0D) | ||
81 | +#define NDEF_URIPREFIX_DAV (0x0E) | ||
82 | +#define NDEF_URIPREFIX_NEWS (0x0F) | ||
83 | +#define NDEF_URIPREFIX_TELNET (0x10) | ||
84 | +#define NDEF_URIPREFIX_IMAP (0x11) | ||
85 | +#define NDEF_URIPREFIX_RTSP (0x12) | ||
86 | +#define NDEF_URIPREFIX_URN (0x13) | ||
87 | +#define NDEF_URIPREFIX_POP (0x14) | ||
88 | +#define NDEF_URIPREFIX_SIP (0x15) | ||
89 | +#define NDEF_URIPREFIX_SIPS (0x16) | ||
90 | +#define NDEF_URIPREFIX_TFTP (0x17) | ||
91 | +#define NDEF_URIPREFIX_BTSPP (0x18) | ||
92 | +#define NDEF_URIPREFIX_BTL2CAP (0x19) | ||
93 | +#define NDEF_URIPREFIX_BTGOEP (0x1A) | ||
94 | +#define NDEF_URIPREFIX_TCPOBEX (0x1B) | ||
95 | +#define NDEF_URIPREFIX_IRDAOBEX (0x1C) | ||
96 | +#define NDEF_URIPREFIX_FILE (0x1D) | ||
97 | +#define NDEF_URIPREFIX_URN_EPC_ID (0x1E) | ||
98 | +#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F) | ||
99 | +#define NDEF_URIPREFIX_URN_EPC_PAT (0x20) | ||
100 | +#define NDEF_URIPREFIX_URN_EPC_RAW (0x21) | ||
101 | +#define NDEF_URIPREFIX_URN_EPC (0x22) | ||
102 | +#define NDEF_URIPREFIX_URN_NFC (0x23) | ||
103 | + | ||
104 | +#define PN532_GPIO_VALIDATIONBIT (0x80) | ||
105 | +#define PN532_GPIO_P30 (0) | ||
106 | +#define PN532_GPIO_P31 (1) | ||
107 | +#define PN532_GPIO_P32 (2) | ||
108 | +#define PN532_GPIO_P33 (3) | ||
109 | +#define PN532_GPIO_P34 (4) | ||
110 | +#define PN532_GPIO_P35 (5) | ||
111 | + | ||
112 | +class PN532 | ||
113 | +{ | ||
114 | +public: | ||
115 | + PN532(PN532Interface &interface); | ||
116 | + | ||
117 | + void begin(void); | ||
118 | + | ||
119 | + // Generic PN532 functions | ||
120 | + bool SAMConfig(void); | ||
121 | + uint32_t getFirmwareVersion(void); | ||
122 | + bool writeGPIO(uint8_t pinstate); | ||
123 | + uint8_t readGPIO(void); | ||
124 | + bool setPassiveActivationRetries(uint8_t maxRetries); | ||
125 | + | ||
126 | + /** | ||
127 | + * @brief Init PN532 as a target | ||
128 | + * @param timeout max time to wait, 0 means no timeout | ||
129 | + * @return > 0 success | ||
130 | + * = 0 timeout | ||
131 | + * < 0 failed | ||
132 | + */ | ||
133 | + int8_t tgInitAsTarget(uint16_t timeout = 0); | ||
134 | + int8_t tgInitAsTarget(const uint8_t* command, const uint8_t len, const uint16_t timeout = 0); | ||
135 | + | ||
136 | + int16_t tgGetData(uint8_t *buf, uint8_t len); | ||
137 | + bool tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
138 | + | ||
139 | + int16_t inRelease(const uint8_t relevantTarget = 0); | ||
140 | + | ||
141 | + // ISO14443A functions | ||
142 | + bool inListPassiveTarget(); | ||
143 | + bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 1000, bool inlist = false); | ||
144 | + bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength); | ||
145 | + | ||
146 | + // Mifare Classic functions | ||
147 | + bool mifareclassic_IsFirstBlock (uint32_t uiBlock); | ||
148 | + bool mifareclassic_IsTrailerBlock (uint32_t uiBlock); | ||
149 | + uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData); | ||
150 | + uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data); | ||
151 | + uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data); | ||
152 | + uint8_t mifareclassic_FormatNDEF (void); | ||
153 | + uint8_t mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url); | ||
154 | + | ||
155 | + // Mifare Ultralight functions | ||
156 | + uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t *buffer); | ||
157 | + uint8_t mifareultralight_WritePage (uint8_t page, uint8_t *buffer); | ||
158 | + | ||
159 | + // Help functions to display formatted text | ||
160 | + static void PrintHex(const uint8_t *data, const uint32_t numBytes); | ||
161 | + static void PrintHexChar(const uint8_t *pbtData, const uint32_t numBytes); | ||
162 | + | ||
163 | + uint8_t *getBuffer(uint8_t *len) { | ||
164 | + *len = sizeof(pn532_packetbuffer) - 4; | ||
165 | + return pn532_packetbuffer; | ||
166 | + }; | ||
167 | + | ||
168 | +private: | ||
169 | + uint8_t _uid[7]; // ISO14443A uid | ||
170 | + uint8_t _uidLen; // uid len | ||
171 | + uint8_t _key[6]; // Mifare Classic key | ||
172 | + uint8_t inListedTag; // Tg number of inlisted tag. | ||
173 | + | ||
174 | + uint8_t pn532_packetbuffer[64]; | ||
175 | + | ||
176 | + PN532Interface *_interface; | ||
177 | +}; | ||
178 | + | ||
179 | +#endif |
@@ -0,0 +1,56 @@ | @@ -0,0 +1,56 @@ | ||
1 | + | ||
2 | + | ||
3 | +#ifndef __PN532_INTERFACE_H__ | ||
4 | +#define __PN532_INTERFACE_H__ | ||
5 | + | ||
6 | +#include <stdint.h> | ||
7 | + | ||
8 | +#define PN532_PREAMBLE (0x00) | ||
9 | +#define PN532_STARTCODE1 (0x00) | ||
10 | +#define PN532_STARTCODE2 (0xFF) | ||
11 | +#define PN532_POSTAMBLE (0x00) | ||
12 | + | ||
13 | +#define PN532_HOSTTOPN532 (0xD4) | ||
14 | +#define PN532_PN532TOHOST (0xD5) | ||
15 | + | ||
16 | +#define PN532_ACK_WAIT_TIME (10) // ms, timeout of waiting for ACK | ||
17 | + | ||
18 | +#define PN532_INVALID_ACK (-1) | ||
19 | +#define PN532_TIMEOUT (-2) | ||
20 | +#define PN532_INVALID_FRAME (-3) | ||
21 | +#define PN532_NO_SPACE (-4) | ||
22 | + | ||
23 | +#define REVERSE_BITS_ORDER(b) b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; \ | ||
24 | + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; \ | ||
25 | + b = (b & 0xAA) >> 1 | (b & 0x55) << 1 | ||
26 | + | ||
27 | +class PN532Interface | ||
28 | +{ | ||
29 | +public: | ||
30 | + virtual void begin() = 0; | ||
31 | + virtual void wakeup() = 0; | ||
32 | + | ||
33 | + /** | ||
34 | + * @brief write a command and check ack | ||
35 | + * @param header packet header | ||
36 | + * @param hlen length of header | ||
37 | + * @param body packet body | ||
38 | + * @param blen length of body | ||
39 | + * @return 0 success | ||
40 | + * not 0 failed | ||
41 | + */ | ||
42 | + virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) = 0; | ||
43 | + | ||
44 | + /** | ||
45 | + * @brief read the response of a command, strip prefix and suffix | ||
46 | + * @param buf to contain the response data | ||
47 | + * @param len lenght to read | ||
48 | + * @param timeout max time to wait, 0 means no timeout | ||
49 | + * @return >=0 length of response without prefix and suffix | ||
50 | + * <0 failed to read response | ||
51 | + */ | ||
52 | + virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 1000) = 0; | ||
53 | +}; | ||
54 | + | ||
55 | +#endif | ||
56 | + |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +#ifndef __DEBUG_H__ | ||
2 | +#define __DEBUG_H__ | ||
3 | + | ||
4 | +//#define DEBUG | ||
5 | + | ||
6 | +#include "Arduino.h" | ||
7 | + | ||
8 | +#ifdef DEBUG | ||
9 | +#define DMSG(args...) Serial.print(args) | ||
10 | +#define DMSG_STR(str) Serial.println(str) | ||
11 | +#define DMSG_HEX(num) Serial.print(' '); Serial.print(num, HEX) | ||
12 | +#define DMSG_INT(num) Serial.print(' '); Serial.print(num) | ||
13 | +#else | ||
14 | +#define DMSG(args...) | ||
15 | +#define DMSG_STR(str) | ||
16 | +#define DMSG_HEX(num) | ||
17 | +#define DMSG_INT(num) | ||
18 | +#endif | ||
19 | + | ||
20 | +#endif |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +## NFC library for Arduino | ||
2 | + | ||
3 | +This is an Arduino library for PN532 to use NFC technology. | ||
4 | +It works with | ||
5 | + | ||
6 | ++ [NFC Shield](http://goo.gl/Cac2OH) | ||
7 | ++ [Xadow NFC](http://goo.gl/qBZMt0) | ||
8 | ++ [PN532 NFC/RFID controller breakout board](http://goo.gl/tby9Sw) | ||
9 | + | ||
10 | +### Features | ||
11 | ++ Support I2C, SPI and HSU of PN532 | ||
12 | ++ Read/write Mifare Classic Card | ||
13 | ++ Works with [Don's NDEF Library](http://goo.gl/jDjsXl) | ||
14 | ++ Support Peer to Peer communication(exchange data with android 4.0+) | ||
15 | ++ Support [mbed platform](http://goo.gl/kGPovZ) | ||
16 | + | ||
17 | +### Getting Started | ||
18 | +1. Download [zip file](http://goo.gl/F6beRM) and | ||
19 | +extract the 4 folders(PN532, PN532_SPI, PN532_I2C and PN532_HSU) into Arduino's libraries. | ||
20 | +2. Downlaod [Don's NDEF library](http://goo.gl/ewxeAe) and extract it intro Arduino's libraries. | ||
21 | +3. Follow the examples of the two libraries. | ||
22 | + | ||
23 | +### To do | ||
24 | ++ Card emulation | ||
25 | + | ||
26 | +### Contribution | ||
27 | +It's based on [Adafruit_NFCShield_I2C](http://goo.gl/pk3FdB). | ||
28 | +[Seeed Studio](http://goo.gl/zh1iQh) adds SPI interface and peer to peer communication support. | ||
29 | +@Don writes the [NDEF library](http://goo.gl/jDjsXl) to make it more easy to use. | ||
30 | +@JiapengLi adds HSU interface. |
@@ -0,0 +1,66 @@ | @@ -0,0 +1,66 @@ | ||
1 | +/* | ||
2 | + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> | ||
3 | + * SPI Master library for arduino. | ||
4 | + * | ||
5 | + * This file is free software; you can redistribute it and/or modify | ||
6 | + * it under the terms of either the GNU General Public License version 2 | ||
7 | + * or the GNU Lesser General Public License version 2.1, both as | ||
8 | + * published by the Free Software Foundation. | ||
9 | + */ | ||
10 | + | ||
11 | +#include "pins_arduino.h" | ||
12 | +#include "SPI.h" | ||
13 | + | ||
14 | +SPIClass SPI; | ||
15 | + | ||
16 | +void SPIClass::begin() { | ||
17 | + | ||
18 | + // Set SS to high so a connected chip will be "deselected" by default | ||
19 | + digitalWrite(SS, HIGH); | ||
20 | + | ||
21 | + // When the SS pin is set as OUTPUT, it can be used as | ||
22 | + // a general purpose output port (it doesn't influence | ||
23 | + // SPI operations). | ||
24 | + pinMode(SS, OUTPUT); | ||
25 | + | ||
26 | + // Warning: if the SS pin ever becomes a LOW INPUT then SPI | ||
27 | + // automatically switches to Slave, so the data direction of | ||
28 | + // the SS pin MUST be kept as OUTPUT. | ||
29 | + SPCR |= _BV(MSTR); | ||
30 | + SPCR |= _BV(SPE); | ||
31 | + | ||
32 | + // Set direction register for SCK and MOSI pin. | ||
33 | + // MISO pin automatically overrides to INPUT. | ||
34 | + // By doing this AFTER enabling SPI, we avoid accidentally | ||
35 | + // clocking in a single bit since the lines go directly | ||
36 | + // from "input" to SPI control. | ||
37 | + // http://code.google.com/p/arduino/issues/detail?id=888 | ||
38 | + pinMode(SCK, OUTPUT); | ||
39 | + pinMode(MOSI, OUTPUT); | ||
40 | +} | ||
41 | + | ||
42 | + | ||
43 | +void SPIClass::end() { | ||
44 | + SPCR &= ~_BV(SPE); | ||
45 | +} | ||
46 | + | ||
47 | +void SPIClass::setBitOrder(uint8_t bitOrder) | ||
48 | +{ | ||
49 | + if(bitOrder == LSBFIRST) { | ||
50 | + SPCR |= _BV(DORD); | ||
51 | + } else { | ||
52 | + SPCR &= ~(_BV(DORD)); | ||
53 | + } | ||
54 | +} | ||
55 | + | ||
56 | +void SPIClass::setDataMode(uint8_t mode) | ||
57 | +{ | ||
58 | + SPCR = (SPCR & ~SPI_MODE_MASK) | mode; | ||
59 | +} | ||
60 | + | ||
61 | +void SPIClass::setClockDivider(uint8_t rate) | ||
62 | +{ | ||
63 | + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); | ||
64 | + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); | ||
65 | +} | ||
66 | + |
@@ -0,0 +1,70 @@ | @@ -0,0 +1,70 @@ | ||
1 | +/* | ||
2 | + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> | ||
3 | + * SPI Master library for arduino. | ||
4 | + * | ||
5 | + * This file is free software; you can redistribute it and/or modify | ||
6 | + * it under the terms of either the GNU General Public License version 2 | ||
7 | + * or the GNU Lesser General Public License version 2.1, both as | ||
8 | + * published by the Free Software Foundation. | ||
9 | + */ | ||
10 | + | ||
11 | +#ifndef _SPI_H_INCLUDED | ||
12 | +#define _SPI_H_INCLUDED | ||
13 | + | ||
14 | +#include <stdio.h> | ||
15 | +#include <Arduino.h> | ||
16 | +#include <avr/pgmspace.h> | ||
17 | + | ||
18 | +#define SPI_CLOCK_DIV4 0x00 | ||
19 | +#define SPI_CLOCK_DIV16 0x01 | ||
20 | +#define SPI_CLOCK_DIV64 0x02 | ||
21 | +#define SPI_CLOCK_DIV128 0x03 | ||
22 | +#define SPI_CLOCK_DIV2 0x04 | ||
23 | +#define SPI_CLOCK_DIV8 0x05 | ||
24 | +#define SPI_CLOCK_DIV32 0x06 | ||
25 | +//#define SPI_CLOCK_DIV64 0x07 | ||
26 | + | ||
27 | +#define SPI_MODE0 0x00 | ||
28 | +#define SPI_MODE1 0x04 | ||
29 | +#define SPI_MODE2 0x08 | ||
30 | +#define SPI_MODE3 0x0C | ||
31 | + | ||
32 | +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR | ||
33 | +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR | ||
34 | +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR | ||
35 | + | ||
36 | +class SPIClass { | ||
37 | +public: | ||
38 | + inline static byte transfer(byte _data); | ||
39 | + | ||
40 | + // SPI Configuration methods | ||
41 | + | ||
42 | + inline static void attachInterrupt(); | ||
43 | + inline static void detachInterrupt(); // Default | ||
44 | + | ||
45 | + static void begin(); // Default | ||
46 | + static void end(); | ||
47 | + | ||
48 | + static void setBitOrder(uint8_t); | ||
49 | + static void setDataMode(uint8_t); | ||
50 | + static void setClockDivider(uint8_t); | ||
51 | +}; | ||
52 | + | ||
53 | +extern SPIClass SPI; | ||
54 | + | ||
55 | +byte SPIClass::transfer(byte _data) { | ||
56 | + SPDR = _data; | ||
57 | + while (!(SPSR & _BV(SPIF))) | ||
58 | + ; | ||
59 | + return SPDR; | ||
60 | +} | ||
61 | + | ||
62 | +void SPIClass::attachInterrupt() { | ||
63 | + SPCR |= _BV(SPIE); | ||
64 | +} | ||
65 | + | ||
66 | +void SPIClass::detachInterrupt() { | ||
67 | + SPCR &= ~_BV(SPIE); | ||
68 | +} | ||
69 | + | ||
70 | +#endif |
@@ -0,0 +1,255 @@ | @@ -0,0 +1,255 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + @file emulatetag.cpp | ||
4 | + @author Armin Wieser | ||
5 | + @license BSD | ||
6 | +*/ | ||
7 | +/**************************************************************************/ | ||
8 | + | ||
9 | +#include "emulatetag.h" | ||
10 | +#include "PN532_debug.h" | ||
11 | + | ||
12 | +#include <string.h> | ||
13 | + | ||
14 | +#define MAX_TGREAD | ||
15 | + | ||
16 | + | ||
17 | +// Command APDU | ||
18 | +#define C_APDU_CLA 0 | ||
19 | +#define C_APDU_INS 1 // instruction | ||
20 | +#define C_APDU_P1 2 // parameter 1 | ||
21 | +#define C_APDU_P2 3 // parameter 2 | ||
22 | +#define C_APDU_LC 4 // length command | ||
23 | +#define C_APDU_DATA 5 // data | ||
24 | + | ||
25 | +#define C_APDU_P1_SELECT_BY_ID 0x00 | ||
26 | +#define C_APDU_P1_SELECT_BY_NAME 0x04 | ||
27 | + | ||
28 | +// Response APDU | ||
29 | +#define R_APDU_SW1_COMMAND_COMPLETE 0x90 | ||
30 | +#define R_APDU_SW2_COMMAND_COMPLETE 0x00 | ||
31 | + | ||
32 | +#define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a | ||
33 | +#define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82 | ||
34 | + | ||
35 | +#define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A | ||
36 | +#define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81 | ||
37 | + | ||
38 | +#define R_APDU_SW1_MEMORY_FAILURE 0x65 | ||
39 | +#define R_APDU_SW2_MEMORY_FAILURE 0x81 | ||
40 | + | ||
41 | +#define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62 | ||
42 | +#define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82 | ||
43 | + | ||
44 | +// ISO7816-4 commands | ||
45 | +#define ISO7816_SELECT_FILE 0xA4 | ||
46 | +#define ISO7816_READ_BINARY 0xB0 | ||
47 | +#define ISO7816_UPDATE_BINARY 0xD6 | ||
48 | + | ||
49 | +typedef enum { NONE, CC, NDEF } tag_file; // CC ... Compatibility Container | ||
50 | + | ||
51 | +bool EmulateTag::init(){ | ||
52 | + pn532.begin(); | ||
53 | + return pn532.SAMConfig(); | ||
54 | +} | ||
55 | + | ||
56 | +void EmulateTag::setNdefFile(const uint8_t* ndef, const int16_t ndefLength){ | ||
57 | + if(ndefLength > (NDEF_MAX_LENGTH -2)){ | ||
58 | + DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting"); | ||
59 | + return; | ||
60 | + } | ||
61 | + | ||
62 | + ndef_file[0] = ndefLength >> 8; | ||
63 | + ndef_file[1] = ndefLength & 0xFF; | ||
64 | + memcpy(ndef_file+2, ndef, ndefLength); | ||
65 | +} | ||
66 | + | ||
67 | +void EmulateTag::setUid(uint8_t* uid){ | ||
68 | + uidPtr = uid; | ||
69 | +} | ||
70 | + | ||
71 | +bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){ | ||
72 | + | ||
73 | + uint8_t command[] = { | ||
74 | + PN532_COMMAND_TGINITASTARGET, | ||
75 | + 5, // MODE: PICC only, Passive only | ||
76 | + | ||
77 | + 0x04, 0x00, // SENS_RES | ||
78 | + 0x00, 0x00, 0x00, // NFCID1 | ||
79 | + 0x20, // SEL_RES | ||
80 | + | ||
81 | + 0,0,0,0,0,0,0,0, | ||
82 | + 0,0,0,0,0,0,0,0, // FeliCaParams | ||
83 | + 0,0, | ||
84 | + | ||
85 | + 0,0,0,0,0,0,0,0,0,0, // NFCID3t | ||
86 | + | ||
87 | + 0, // length of general bytes | ||
88 | + 0 // length of historical bytes | ||
89 | + }; | ||
90 | + | ||
91 | + if(uidPtr != 0){ // if uid is set copy 3 bytes to nfcid1 | ||
92 | + memcpy(command + 4, uidPtr, 3); | ||
93 | + } | ||
94 | + | ||
95 | + if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){ | ||
96 | + DMSG("tgInitAsTarget failed or timed out!"); | ||
97 | + return false; | ||
98 | + } | ||
99 | + | ||
100 | + uint8_t compatibility_container[] = { | ||
101 | + 0, 0x0F, | ||
102 | + 0x20, | ||
103 | + 0, 0x54, | ||
104 | + 0, 0xFF, | ||
105 | + 0x04, // T | ||
106 | + 0x06, // L | ||
107 | + 0xE1, 0x04, // File identifier | ||
108 | + ((NDEF_MAX_LENGTH & 0xFF00) >> 8), (NDEF_MAX_LENGTH & 0xFF), // maximum NDEF file size | ||
109 | + 0x00, // read access 0x0 = granted | ||
110 | + 0x00 // write access 0x0 = granted | 0xFF = deny | ||
111 | + }; | ||
112 | + | ||
113 | + if(tagWriteable == false){ | ||
114 | + compatibility_container[14] = 0xFF; | ||
115 | + } | ||
116 | + | ||
117 | + tagWrittenByInitiator = false; | ||
118 | + | ||
119 | + uint8_t rwbuf[128]; | ||
120 | + uint8_t sendlen; | ||
121 | + int16_t status; | ||
122 | + tag_file currentFile = NONE; | ||
123 | + uint16_t cc_size = sizeof(compatibility_container); | ||
124 | + bool runLoop = true; | ||
125 | + | ||
126 | + while(runLoop){ | ||
127 | + status = pn532.tgGetData(rwbuf, sizeof(rwbuf)); | ||
128 | + if(status < 0){ | ||
129 | + DMSG("tgGetData failed!\n"); | ||
130 | + pn532.inRelease(); | ||
131 | + return true; | ||
132 | + } | ||
133 | + | ||
134 | + uint8_t p1 = rwbuf[C_APDU_P1]; | ||
135 | + uint8_t p2 = rwbuf[C_APDU_P2]; | ||
136 | + uint8_t lc = rwbuf[C_APDU_LC]; | ||
137 | + uint16_t p1p2_length = ((int16_t) p1 << 8) + p2; | ||
138 | + | ||
139 | + switch(rwbuf[C_APDU_INS]){ | ||
140 | + case ISO7816_SELECT_FILE: | ||
141 | + switch(p1){ | ||
142 | + case C_APDU_P1_SELECT_BY_ID: | ||
143 | + if(p2 != 0x0c){ | ||
144 | + DMSG("C_APDU_P2 != 0x0c\n"); | ||
145 | + setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); | ||
146 | + } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){ | ||
147 | + setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); | ||
148 | + if(rwbuf[C_APDU_DATA+1] == 0x03){ | ||
149 | + currentFile = CC; | ||
150 | + } else if(rwbuf[C_APDU_DATA+1] == 0x04){ | ||
151 | + currentFile = NDEF; | ||
152 | + } | ||
153 | + } else { | ||
154 | + setResponse(TAG_NOT_FOUND, rwbuf, &sendlen); | ||
155 | + } | ||
156 | + break; | ||
157 | + case C_APDU_P1_SELECT_BY_NAME: | ||
158 | + const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 }; | ||
159 | + if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){ | ||
160 | + setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); | ||
161 | + } else{ | ||
162 | + DMSG("function not supported\n"); | ||
163 | + setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); | ||
164 | + } | ||
165 | + break; | ||
166 | + } | ||
167 | + break; | ||
168 | + case ISO7816_READ_BINARY: | ||
169 | + switch(currentFile){ | ||
170 | + case NONE: | ||
171 | + setResponse(TAG_NOT_FOUND, rwbuf, &sendlen); | ||
172 | + break; | ||
173 | + case CC: | ||
174 | + if( p1p2_length > NDEF_MAX_LENGTH){ | ||
175 | + setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen); | ||
176 | + }else { | ||
177 | + memcpy(rwbuf,compatibility_container + p1p2_length, lc); | ||
178 | + setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc); | ||
179 | + } | ||
180 | + break; | ||
181 | + case NDEF: | ||
182 | + if( p1p2_length > NDEF_MAX_LENGTH){ | ||
183 | + setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen); | ||
184 | + }else { | ||
185 | + memcpy(rwbuf, ndef_file + p1p2_length, lc); | ||
186 | + setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc); | ||
187 | + } | ||
188 | + break; | ||
189 | + } | ||
190 | + break; | ||
191 | + case ISO7816_UPDATE_BINARY: | ||
192 | + if(!tagWriteable){ | ||
193 | + setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); | ||
194 | + } else{ | ||
195 | + if( p1p2_length > NDEF_MAX_LENGTH){ | ||
196 | + setResponse(MEMORY_FAILURE, rwbuf, &sendlen); | ||
197 | + } | ||
198 | + else{ | ||
199 | + memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc); | ||
200 | + setResponse(COMMAND_COMPLETE, rwbuf, &sendlen); | ||
201 | + tagWrittenByInitiator = true; | ||
202 | + | ||
203 | + uint16_t ndef_length = (ndef_file[0] << 8) + ndef_file[1]; | ||
204 | + if ((ndef_length > 0) && (updateNdefCallback != 0)) { | ||
205 | + updateNdefCallback(ndef_file + 2, ndef_length); | ||
206 | + } | ||
207 | + } | ||
208 | + } | ||
209 | + break; | ||
210 | + default: | ||
211 | + DMSG("Command not supported!"); | ||
212 | + DMSG_HEX(rwbuf[C_APDU_INS]); | ||
213 | + DMSG("\n"); | ||
214 | + setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen); | ||
215 | + } | ||
216 | + status = pn532.tgSetData(rwbuf, sendlen); | ||
217 | + if(status < 0){ | ||
218 | + DMSG("tgSetData failed\n!"); | ||
219 | + pn532.inRelease(); | ||
220 | + return true; | ||
221 | + } | ||
222 | + } | ||
223 | + pn532.inRelease(); | ||
224 | + return true; | ||
225 | +} | ||
226 | + | ||
227 | +void EmulateTag::setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset){ | ||
228 | + switch(cmd){ | ||
229 | + case COMMAND_COMPLETE: | ||
230 | + buf[0] = R_APDU_SW1_COMMAND_COMPLETE; | ||
231 | + buf[1] = R_APDU_SW2_COMMAND_COMPLETE; | ||
232 | + *sendlen = 2 + sendlenOffset; | ||
233 | + break; | ||
234 | + case TAG_NOT_FOUND: | ||
235 | + buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND; | ||
236 | + buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND; | ||
237 | + *sendlen = 2; | ||
238 | + break; | ||
239 | + case FUNCTION_NOT_SUPPORTED: | ||
240 | + buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED; | ||
241 | + buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED; | ||
242 | + *sendlen = 2; | ||
243 | + break; | ||
244 | + case MEMORY_FAILURE: | ||
245 | + buf[0] = R_APDU_SW1_MEMORY_FAILURE; | ||
246 | + buf[1] = R_APDU_SW2_MEMORY_FAILURE; | ||
247 | + *sendlen = 2; | ||
248 | + break; | ||
249 | + case END_OF_FILE_BEFORE_REACHED_LE_BYTES: | ||
250 | + buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES; | ||
251 | + buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES; | ||
252 | + *sendlen= 2; | ||
253 | + break; | ||
254 | + } | ||
255 | +} |
@@ -0,0 +1,71 @@ | @@ -0,0 +1,71 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + @file emulatetag.h | ||
4 | + @author Armin Wieser | ||
5 | + @license BSD | ||
6 | + | ||
7 | + Implemented using NFC forum documents & library of libnfc | ||
8 | +*/ | ||
9 | +/**************************************************************************/ | ||
10 | + | ||
11 | +#ifndef __EMULATETAG_H__ | ||
12 | +#define __EMULATETAG_H__ | ||
13 | + | ||
14 | +#include "PN532.h" | ||
15 | + | ||
16 | +#define NDEF_MAX_LENGTH 128 // altough ndef can handle up to 0xfffe in size, arduino cannot. | ||
17 | +typedef enum {COMMAND_COMPLETE, TAG_NOT_FOUND, FUNCTION_NOT_SUPPORTED, MEMORY_FAILURE, END_OF_FILE_BEFORE_REACHED_LE_BYTES} responseCommand; | ||
18 | + | ||
19 | +class EmulateTag{ | ||
20 | + | ||
21 | +public: | ||
22 | +EmulateTag(PN532Interface &interface) : pn532(interface), uidPtr(0), tagWrittenByInitiator(false), tagWriteable(true), updateNdefCallback(0) { } | ||
23 | + | ||
24 | + bool init(); | ||
25 | + | ||
26 | + bool emulate(const uint16_t tgInitAsTargetTimeout = 0); | ||
27 | + | ||
28 | + /* | ||
29 | + * @param uid pointer to byte array of length 3 (uid is 4 bytes - first byte is fixed) or zero for uid | ||
30 | + */ | ||
31 | + void setUid(uint8_t* uid = 0); | ||
32 | + | ||
33 | + void setNdefFile(const uint8_t* ndef, const int16_t ndefLength); | ||
34 | + | ||
35 | + void getContent(uint8_t** buf, uint16_t* length){ | ||
36 | + *buf = ndef_file + 2; // first 2 bytes = length | ||
37 | + *length = (ndef_file[0] << 8) + ndef_file[1]; | ||
38 | + } | ||
39 | + | ||
40 | + bool writeOccured(){ | ||
41 | + return tagWrittenByInitiator; | ||
42 | + } | ||
43 | + | ||
44 | + void setTagWriteable(bool setWriteable){ | ||
45 | + tagWriteable = setWriteable; | ||
46 | + } | ||
47 | + | ||
48 | + uint8_t* getNdefFilePtr(){ | ||
49 | + return ndef_file; | ||
50 | + } | ||
51 | + | ||
52 | + uint8_t getNdefMaxLength(){ | ||
53 | + return NDEF_MAX_LENGTH; | ||
54 | + } | ||
55 | + | ||
56 | + void attach(void (*func)(uint8_t *buf, uint16_t length)) { | ||
57 | + updateNdefCallback = func; | ||
58 | + }; | ||
59 | + | ||
60 | +private: | ||
61 | + PN532 pn532; | ||
62 | + uint8_t ndef_file[NDEF_MAX_LENGTH]; | ||
63 | + uint8_t* uidPtr; | ||
64 | + bool tagWrittenByInitiator; | ||
65 | + bool tagWriteable; | ||
66 | + void (*updateNdefCallback)(uint8_t *ndef, uint16_t length); | ||
67 | + | ||
68 | + void setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset = 0); | ||
69 | +}; | ||
70 | + | ||
71 | +#endif |
@@ -0,0 +1,135 @@ | @@ -0,0 +1,135 @@ | ||
1 | +#include <SPI.h> | ||
2 | +#include <PN532_SPI.h> | ||
3 | +#include <PN532Interface.h> | ||
4 | +#include <PN532.h> | ||
5 | + | ||
6 | +PN532_SPI pn532spi(SPI, 10); | ||
7 | +PN532 nfc(pn532spi); | ||
8 | + | ||
9 | + | ||
10 | +void setup() | ||
11 | +{ | ||
12 | + Serial.begin(115200); | ||
13 | + Serial.println("-------Peer to Peer HCE--------"); | ||
14 | + | ||
15 | + nfc.begin(); | ||
16 | + | ||
17 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
18 | + if (! versiondata) { | ||
19 | + Serial.print("Didn't find PN53x board"); | ||
20 | + while (1); // halt | ||
21 | + } | ||
22 | + | ||
23 | + // Got ok data, print it out! | ||
24 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
25 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
26 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
27 | + | ||
28 | + // Set the max number of retry attempts to read from a card | ||
29 | + // This prevents us from waiting forever for a card, which is | ||
30 | + // the default behaviour of the PN532. | ||
31 | + //nfc.setPassiveActivationRetries(0xFF); | ||
32 | + | ||
33 | + // configure board to read RFID tags | ||
34 | + nfc.SAMConfig(); | ||
35 | +} | ||
36 | + | ||
37 | +void loop() | ||
38 | +{ | ||
39 | + bool success; | ||
40 | + | ||
41 | + uint8_t responseLength = 32; | ||
42 | + | ||
43 | + Serial.println("Waiting for an ISO14443A card"); | ||
44 | + | ||
45 | + // set shield to inListPassiveTarget | ||
46 | + success = nfc.inListPassiveTarget(); | ||
47 | + | ||
48 | + if(success) { | ||
49 | + | ||
50 | + Serial.println("Found something!"); | ||
51 | + | ||
52 | + uint8_t selectApdu[] = { 0x00, /* CLA */ | ||
53 | + 0xA4, /* INS */ | ||
54 | + 0x04, /* P1 */ | ||
55 | + 0x00, /* P2 */ | ||
56 | + 0x07, /* Length of AID */ | ||
57 | + 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* AID defined on Android App */ | ||
58 | + 0x00 /* Le */ }; | ||
59 | + | ||
60 | + uint8_t response[32]; | ||
61 | + | ||
62 | + success = nfc.inDataExchange(selectApdu, sizeof(selectApdu), response, &responseLength); | ||
63 | + | ||
64 | + if(success) { | ||
65 | + | ||
66 | + Serial.print("responseLength: "); Serial.println(responseLength); | ||
67 | + | ||
68 | + nfc.PrintHexChar(response, responseLength); | ||
69 | + | ||
70 | + do { | ||
71 | + uint8_t apdu[] = "Hello from Arduino"; | ||
72 | + uint8_t back[32]; | ||
73 | + uint8_t length = 32; | ||
74 | + | ||
75 | + success = nfc.inDataExchange(apdu, sizeof(apdu), back, &length); | ||
76 | + | ||
77 | + if(success) { | ||
78 | + | ||
79 | + Serial.print("responseLength: "); Serial.println(length); | ||
80 | + | ||
81 | + nfc.PrintHexChar(back, length); | ||
82 | + } | ||
83 | + else { | ||
84 | + | ||
85 | + Serial.println("Broken connection?"); | ||
86 | + } | ||
87 | + } | ||
88 | + while(success); | ||
89 | + } | ||
90 | + else { | ||
91 | + | ||
92 | + Serial.println("Failed sending SELECT AID"); | ||
93 | + } | ||
94 | + } | ||
95 | + else { | ||
96 | + | ||
97 | + Serial.println("Didn't find anything!"); | ||
98 | + } | ||
99 | + | ||
100 | + delay(1000); | ||
101 | +} | ||
102 | + | ||
103 | +void printResponse(uint8_t *response, uint8_t responseLength) { | ||
104 | + | ||
105 | + String respBuffer; | ||
106 | + | ||
107 | + for (int i = 0; i < responseLength; i++) { | ||
108 | + | ||
109 | + if (response[i] < 0x10) | ||
110 | + respBuffer = respBuffer + "0"; //Adds leading zeros if hex value is smaller than 0x10 | ||
111 | + | ||
112 | + respBuffer = respBuffer + String(response[i], HEX) + " "; | ||
113 | + } | ||
114 | + | ||
115 | + Serial.print("response: "); Serial.println(respBuffer); | ||
116 | +} | ||
117 | + | ||
118 | +void setupNFC() { | ||
119 | + | ||
120 | + nfc.begin(); | ||
121 | + | ||
122 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
123 | + if (! versiondata) { | ||
124 | + Serial.print("Didn't find PN53x board"); | ||
125 | + while (1); // halt | ||
126 | + } | ||
127 | + | ||
128 | + // Got ok data, print it out! | ||
129 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
130 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
131 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
132 | + | ||
133 | + // configure board to read RFID tags | ||
134 | + nfc.SAMConfig(); | ||
135 | +} |
PN532/examples/emulate_tag_ndef/emulate_tag_ndef.ino
0 → 100644
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | + | ||
2 | +#include "SPI.h" | ||
3 | +#include "PN532_SPI.h" | ||
4 | +#include "emulatetag.h" | ||
5 | +#include "NdefMessage.h" | ||
6 | + | ||
7 | +PN532_SPI pn532spi(SPI, 10); | ||
8 | +EmulateTag nfc(pn532spi); | ||
9 | + | ||
10 | +uint8_t ndefBuf[120]; | ||
11 | +NdefMessage message; | ||
12 | +int messageSize; | ||
13 | + | ||
14 | +uint8_t uid[3] = { 0x12, 0x34, 0x56 }; | ||
15 | + | ||
16 | +void setup() | ||
17 | +{ | ||
18 | + Serial.begin(115200); | ||
19 | + Serial.println("------- Emulate Tag --------"); | ||
20 | + | ||
21 | + message = NdefMessage(); | ||
22 | + message.addUriRecord("http://www.seeedstudio.com"); | ||
23 | + messageSize = message.getEncodedSize(); | ||
24 | + if (messageSize > sizeof(ndefBuf)) { | ||
25 | + Serial.println("ndefBuf is too small"); | ||
26 | + while (1) { } | ||
27 | + } | ||
28 | + | ||
29 | + Serial.print("Ndef encoded message size: "); | ||
30 | + Serial.println(messageSize); | ||
31 | + | ||
32 | + message.encode(ndefBuf); | ||
33 | + | ||
34 | + // comment out this command for no ndef message | ||
35 | + nfc.setNdefFile(ndefBuf, messageSize); | ||
36 | + | ||
37 | + // uid must be 3 bytes! | ||
38 | + nfc.setUid(uid); | ||
39 | + | ||
40 | + nfc.init(); | ||
41 | +} | ||
42 | + | ||
43 | +void loop(){ | ||
44 | + // uncomment for overriding ndef in case a write to this tag occured | ||
45 | + //nfc.setNdefFile(ndefBuf, messageSize); | ||
46 | + | ||
47 | + // start emulation (blocks) | ||
48 | + nfc.emulate(); | ||
49 | + | ||
50 | + // or start emulation with timeout | ||
51 | + /*if(!nfc.emulate(1000)){ // timeout 1 second | ||
52 | + Serial.println("timed out"); | ||
53 | + }*/ | ||
54 | + | ||
55 | + // deny writing to the tag | ||
56 | + // nfc.setTagWriteable(false); | ||
57 | + | ||
58 | + if(nfc.writeOccured()){ | ||
59 | + Serial.println("\nWrite occured !"); | ||
60 | + uint8_t* tag_buf; | ||
61 | + uint16_t length; | ||
62 | + | ||
63 | + nfc.getContent(&tag_buf, &length); | ||
64 | + NdefMessage msg = NdefMessage(tag_buf, length); | ||
65 | + msg.print(); | ||
66 | + } | ||
67 | + | ||
68 | + delay(1000); | ||
69 | +} |
@@ -0,0 +1,77 @@ | @@ -0,0 +1,77 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + This example will attempt to connect to an ISO14443A | ||
4 | + card or tag and retrieve some basic information about it | ||
5 | + that can be used to determine what type of card it is. | ||
6 | + | ||
7 | + Note that you need the baud rate to be 115200 because we need to print | ||
8 | + out the data and read from the card at the same time! | ||
9 | + | ||
10 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
11 | + | ||
12 | +*/ | ||
13 | +/**************************************************************************/ | ||
14 | + | ||
15 | +#include <SPI.h> | ||
16 | +#include <PN532_SPI.h> | ||
17 | +#include "PN532.h" | ||
18 | + | ||
19 | +PN532_SPI pn532spi(SPI, 10); | ||
20 | +PN532 nfc(pn532spi); | ||
21 | + | ||
22 | +void setup(void) { | ||
23 | + Serial.begin(115200); | ||
24 | + Serial.println("Hello!"); | ||
25 | + | ||
26 | + nfc.begin(); | ||
27 | + | ||
28 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
29 | + if (! versiondata) { | ||
30 | + Serial.print("Didn't find PN53x board"); | ||
31 | + while (1); // halt | ||
32 | + } | ||
33 | + | ||
34 | + // Got ok data, print it out! | ||
35 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
36 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
37 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
38 | + | ||
39 | + // Set the max number of retry attempts to read from a card | ||
40 | + // This prevents us from waiting forever for a card, which is | ||
41 | + // the default behaviour of the PN532. | ||
42 | + nfc.setPassiveActivationRetries(0xFF); | ||
43 | + | ||
44 | + // configure board to read RFID tags | ||
45 | + nfc.SAMConfig(); | ||
46 | + | ||
47 | + Serial.println("Waiting for an ISO14443A card"); | ||
48 | +} | ||
49 | + | ||
50 | +void loop(void) { | ||
51 | + boolean success; | ||
52 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
53 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
54 | + | ||
55 | + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found | ||
56 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
57 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
58 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength); | ||
59 | + | ||
60 | + if (success) { | ||
61 | + Serial.println("Found a card!"); | ||
62 | + Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
63 | + Serial.print("UID Value: "); | ||
64 | + for (uint8_t i=0; i < uidLength; i++) | ||
65 | + { | ||
66 | + Serial.print(" 0x");Serial.print(uid[i], HEX); | ||
67 | + } | ||
68 | + Serial.println(""); | ||
69 | + // Wait 1 second before continuing | ||
70 | + delay(1000); | ||
71 | + } | ||
72 | + else | ||
73 | + { | ||
74 | + // PN532 probably timed out waiting for a card | ||
75 | + Serial.println("Timed out waiting for a card"); | ||
76 | + } | ||
77 | +} | ||
0 | \ No newline at end of file | 78 | \ No newline at end of file |
PN532/examples/mifareclassic_formatndef/mifareclassic_formatndef.pde
0 → 100644
@@ -0,0 +1,170 @@ | @@ -0,0 +1,170 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + This example attempts to format a clean Mifare Classic 1K card as | ||
4 | + an NFC Forum tag (to store NDEF messages that can be read by any | ||
5 | + NFC enabled Android phone, etc.) | ||
6 | + | ||
7 | + Note that you need the baud rate to be 115200 because we need to print | ||
8 | + out the data and read from the card at the same time! | ||
9 | + | ||
10 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
11 | +*/ | ||
12 | +/**************************************************************************/ | ||
13 | + | ||
14 | +#include <SPI.h> | ||
15 | +#include <PN532_SPI.h> | ||
16 | +#include "PN532.h" | ||
17 | + | ||
18 | +PN532_SPI pn532spi(SPI, 10); | ||
19 | +PN532 nfc(pn532spi); | ||
20 | + | ||
21 | +/* | ||
22 | + We can encode many different kinds of pointers to the card, | ||
23 | + from a URL, to an Email address, to a phone number, and many more | ||
24 | + check the library header .h file to see the large # of supported | ||
25 | + prefixes! | ||
26 | +*/ | ||
27 | +// For a http://www. url: | ||
28 | +const char * url = "seeedstudio.com"; | ||
29 | +uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT; | ||
30 | + | ||
31 | +// for an email address | ||
32 | +//const char * url = "mail@example.com"; | ||
33 | +//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO; | ||
34 | + | ||
35 | +// for a phone number | ||
36 | +//const char * url = "+1 212 555 1212"; | ||
37 | +//uint8_t ndefprefix = NDEF_URIPREFIX_TEL; | ||
38 | + | ||
39 | + | ||
40 | +void setup(void) { | ||
41 | + Serial.begin(115200); | ||
42 | + Serial.println("Looking for PN532..."); | ||
43 | + | ||
44 | + nfc.begin(); | ||
45 | + | ||
46 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
47 | + if (! versiondata) { | ||
48 | + Serial.print("Didn't find PN53x board"); | ||
49 | + while (1); // halt | ||
50 | + } | ||
51 | + | ||
52 | + // Got ok data, print it out! | ||
53 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
54 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
55 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
56 | + | ||
57 | + // configure board to read RFID tags | ||
58 | + nfc.SAMConfig(); | ||
59 | +} | ||
60 | + | ||
61 | +void loop(void) { | ||
62 | + uint8_t success; // Flag to check if there was an error with the PN532 | ||
63 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
64 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
65 | + bool authenticated = false; // Flag to indicate if the sector is authenticated | ||
66 | + | ||
67 | + // Use the default key | ||
68 | + uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
69 | + | ||
70 | + Serial.println(""); | ||
71 | + Serial.println("PLEASE NOTE: Formatting your card for NDEF records will change the"); | ||
72 | + Serial.println("authentication keys. To reformat your NDEF tag as a clean Mifare"); | ||
73 | + Serial.println("Classic tag, use the mifareclassic_ndeftoclassic example!"); | ||
74 | + Serial.println(""); | ||
75 | + Serial.println("Place your Mifare Classic card on the reader to format with NDEF"); | ||
76 | + Serial.println("and press any key to continue ..."); | ||
77 | + // Wait for user input before proceeding | ||
78 | + while (!Serial.available()); | ||
79 | + // a key was pressed1 | ||
80 | + while (Serial.available()) Serial.read(); | ||
81 | + | ||
82 | + // Wait for an ISO14443A type card (Mifare, etc.). When one is found | ||
83 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
84 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
85 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | ||
86 | + | ||
87 | + if (success) | ||
88 | + { | ||
89 | + // Display some basic information about the card | ||
90 | + Serial.println("Found an ISO14443A card"); | ||
91 | + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
92 | + Serial.print(" UID Value: "); | ||
93 | + nfc.PrintHex(uid, uidLength); | ||
94 | + for (uint8_t i = 0; i < uidLength; i++) { | ||
95 | + Serial.print(uid[i], HEX); | ||
96 | + Serial.print(' '); | ||
97 | + } | ||
98 | + Serial.println(""); | ||
99 | + | ||
100 | + // Make sure this is a Mifare Classic card | ||
101 | + if (uidLength != 4) | ||
102 | + { | ||
103 | + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); | ||
104 | + return; | ||
105 | + } | ||
106 | + | ||
107 | + // We probably have a Mifare Classic card ... | ||
108 | + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); | ||
109 | + | ||
110 | + // Try to format the card for NDEF data | ||
111 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 0, 0, keya); | ||
112 | + if (!success) | ||
113 | + { | ||
114 | + Serial.println("Unable to authenticate block 0 to enable card formatting!"); | ||
115 | + return; | ||
116 | + } | ||
117 | + success = nfc.mifareclassic_FormatNDEF(); | ||
118 | + if (!success) | ||
119 | + { | ||
120 | + Serial.println("Unable to format the card for NDEF"); | ||
121 | + return; | ||
122 | + } | ||
123 | + | ||
124 | + Serial.println("Card has been formatted for NDEF data using MAD1"); | ||
125 | + | ||
126 | + // Try to authenticate block 4 (first block of sector 1) using our key | ||
127 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keya); | ||
128 | + | ||
129 | + // Make sure the authentification process didn't fail | ||
130 | + if (!success) | ||
131 | + { | ||
132 | + Serial.println("Authentication failed."); | ||
133 | + return; | ||
134 | + } | ||
135 | + | ||
136 | + // Try to write a URL | ||
137 | + Serial.println("Writing URI to sector 1 as an NDEF Message"); | ||
138 | + | ||
139 | + // Authenticated seems to have worked | ||
140 | + // Try to write an NDEF record to sector 1 | ||
141 | + // Use 0x01 for the URI Identifier Code to prepend "http://www." | ||
142 | + // to the url (and save some space). For information on URI ID Codes | ||
143 | + // see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef | ||
144 | + if (strlen(url) > 38) | ||
145 | + { | ||
146 | + // The length is also checked in the WriteNDEFURI function, but lets | ||
147 | + // warn users here just in case they change the value and it's bigger | ||
148 | + // than it should be | ||
149 | + Serial.println("URI is too long ... must be less than 38 characters long"); | ||
150 | + return; | ||
151 | + } | ||
152 | + | ||
153 | + // URI is within size limits ... write it to the card and report success/failure | ||
154 | + success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url); | ||
155 | + if (success) | ||
156 | + { | ||
157 | + Serial.println("NDEF URI Record written to sector 1"); | ||
158 | + } | ||
159 | + else | ||
160 | + { | ||
161 | + Serial.println("NDEF Record creation failed! :("); | ||
162 | + } | ||
163 | + } | ||
164 | + | ||
165 | + // Wait a bit before trying again | ||
166 | + Serial.println("\n\nDone!"); | ||
167 | + delay(1000); | ||
168 | + Serial.flush(); | ||
169 | + while(Serial.available()) Serial.read(); | ||
170 | +} | ||
0 | \ No newline at end of file | 171 | \ No newline at end of file |
PN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde
0 → 100644
@@ -0,0 +1,157 @@ | @@ -0,0 +1,157 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + This example attempts to dump the contents of a Mifare Classic 1K card | ||
4 | + | ||
5 | + Note that you need the baud rate to be 115200 because we need to print | ||
6 | + out the data and read from the card at the same time! | ||
7 | + | ||
8 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
9 | +*/ | ||
10 | +/**************************************************************************/ | ||
11 | + | ||
12 | +#include <SPI.h> | ||
13 | +#include <PN532_SPI.h> | ||
14 | +#include "PN532.h" | ||
15 | + | ||
16 | +PN532_SPI pn532spi(SPI, 10); | ||
17 | +PN532 nfc(pn532spi); | ||
18 | + | ||
19 | +void setup(void) { | ||
20 | + // has to be fast to dump the entire memory contents! | ||
21 | + Serial.begin(115200); | ||
22 | + Serial.println("Looking for PN532..."); | ||
23 | + | ||
24 | + nfc.begin(); | ||
25 | + | ||
26 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
27 | + if (! versiondata) { | ||
28 | + Serial.print("Didn't find PN53x board"); | ||
29 | + while (1); // halt | ||
30 | + } | ||
31 | + // Got ok data, print it out! | ||
32 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
33 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
34 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
35 | + | ||
36 | + // configure board to read RFID tags | ||
37 | + nfc.SAMConfig(); | ||
38 | + | ||
39 | + Serial.println("Waiting for an ISO14443A Card ..."); | ||
40 | +} | ||
41 | + | ||
42 | + | ||
43 | +void loop(void) { | ||
44 | + uint8_t success; // Flag to check if there was an error with the PN532 | ||
45 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
46 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
47 | + uint8_t currentblock; // Counter to keep track of which block we're on | ||
48 | + bool authenticated = false; // Flag to indicate if the sector is authenticated | ||
49 | + uint8_t data[16]; // Array to store block data during reads | ||
50 | + | ||
51 | + // Keyb on NDEF and Mifare Classic should be the same | ||
52 | + uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
53 | + | ||
54 | + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found | ||
55 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
56 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
57 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | ||
58 | + | ||
59 | + if (success) { | ||
60 | + // Display some basic information about the card | ||
61 | + Serial.println("Found an ISO14443A card"); | ||
62 | + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
63 | + Serial.print(" UID Value: "); | ||
64 | + for (uint8_t i = 0; i < uidLength; i++) { | ||
65 | + Serial.print(uid[i], HEX); | ||
66 | + Serial.print(' '); | ||
67 | + } | ||
68 | + Serial.println(""); | ||
69 | + | ||
70 | + if (uidLength == 4) | ||
71 | + { | ||
72 | + // We probably have a Mifare Classic card ... | ||
73 | + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); | ||
74 | + | ||
75 | + // Now we try to go through all 16 sectors (each having 4 blocks) | ||
76 | + // authenticating each sector, and then dumping the blocks | ||
77 | + for (currentblock = 0; currentblock < 64; currentblock++) | ||
78 | + { | ||
79 | + // Check if this is a new block so that we can reauthenticate | ||
80 | + if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false; | ||
81 | + | ||
82 | + // If the sector hasn't been authenticated, do so first | ||
83 | + if (!authenticated) | ||
84 | + { | ||
85 | + // Starting of a new sector ... try to to authenticate | ||
86 | + Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------"); | ||
87 | + if (currentblock == 0) | ||
88 | + { | ||
89 | + // This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!) | ||
90 | + // or 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 for NDEF formatted cards using key a, | ||
91 | + // but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF) | ||
92 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal); | ||
93 | + } | ||
94 | + else | ||
95 | + { | ||
96 | + // This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!) | ||
97 | + // or 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 for NDEF formatted cards using key a, | ||
98 | + // but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF) | ||
99 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal); | ||
100 | + } | ||
101 | + if (success) | ||
102 | + { | ||
103 | + authenticated = true; | ||
104 | + } | ||
105 | + else | ||
106 | + { | ||
107 | + Serial.println("Authentication error"); | ||
108 | + } | ||
109 | + } | ||
110 | + // If we're still not authenticated just skip the block | ||
111 | + if (!authenticated) | ||
112 | + { | ||
113 | + Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate"); | ||
114 | + } | ||
115 | + else | ||
116 | + { | ||
117 | + // Authenticated ... we should be able to read the block now | ||
118 | + // Dump the data into the 'data' array | ||
119 | + success = nfc.mifareclassic_ReadDataBlock(currentblock, data); | ||
120 | + if (success) | ||
121 | + { | ||
122 | + // Read successful | ||
123 | + Serial.print("Block ");Serial.print(currentblock, DEC); | ||
124 | + if (currentblock < 10) | ||
125 | + { | ||
126 | + Serial.print(" "); | ||
127 | + } | ||
128 | + else | ||
129 | + { | ||
130 | + Serial.print(" "); | ||
131 | + } | ||
132 | + // Dump the raw data | ||
133 | + nfc.PrintHexChar(data, 16); | ||
134 | + } | ||
135 | + else | ||
136 | + { | ||
137 | + // Oops ... something happened | ||
138 | + Serial.print("Block ");Serial.print(currentblock, DEC); | ||
139 | + Serial.println(" unable to read this block"); | ||
140 | + } | ||
141 | + } | ||
142 | + } | ||
143 | + } | ||
144 | + else | ||
145 | + { | ||
146 | + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); | ||
147 | + } | ||
148 | + } | ||
149 | + // Wait a bit before trying again | ||
150 | + Serial.println("\n\nSend a character to run the mem dumper again!"); | ||
151 | + Serial.flush(); | ||
152 | + while (!Serial.available()); | ||
153 | + while (Serial.available()) { | ||
154 | + Serial.read(); | ||
155 | + } | ||
156 | + Serial.flush(); | ||
157 | +} | ||
0 | \ No newline at end of file | 158 | \ No newline at end of file |
PN532/examples/mifareclassic_ndeftoclassic/mifareclassic_ndeftoclassic.pde
0 → 100644
@@ -0,0 +1,172 @@ | @@ -0,0 +1,172 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + This examples attempts to take a Mifare Classic 1K card that has been | ||
4 | + formatted for NDEF messages using mifareclassic_formatndef, and resets | ||
5 | + the authentication keys back to the Mifare Classic defaults | ||
6 | + | ||
7 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
8 | +*/ | ||
9 | +/**************************************************************************/ | ||
10 | + | ||
11 | +#include <SPI.h> | ||
12 | +#include <PN532_SPI.h> | ||
13 | +#include "PN532.h" | ||
14 | + | ||
15 | +PN532_SPI pn532spi(SPI, 10); | ||
16 | +PN532 nfc(pn532spi); | ||
17 | + | ||
18 | + | ||
19 | +#define NR_SHORTSECTOR (32) // Number of short sectors on Mifare 1K/4K | ||
20 | +#define NR_LONGSECTOR (8) // Number of long sectors on Mifare 4K | ||
21 | +#define NR_BLOCK_OF_SHORTSECTOR (4) // Number of blocks in a short sector | ||
22 | +#define NR_BLOCK_OF_LONGSECTOR (16) // Number of blocks in a long sector | ||
23 | + | ||
24 | +// Determine the sector trailer block based on sector number | ||
25 | +#define BLOCK_NUMBER_OF_SECTOR_TRAILER(sector) (((sector)<NR_SHORTSECTOR)? \ | ||
26 | + ((sector)*NR_BLOCK_OF_SHORTSECTOR + NR_BLOCK_OF_SHORTSECTOR-1):\ | ||
27 | + (NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR + NR_BLOCK_OF_LONGSECTOR-1)) | ||
28 | + | ||
29 | +// Determine the sector's first block based on the sector number | ||
30 | +#define BLOCK_NUMBER_OF_SECTOR_1ST_BLOCK(sector) (((sector)<NR_SHORTSECTOR)? \ | ||
31 | + ((sector)*NR_BLOCK_OF_SHORTSECTOR):\ | ||
32 | + (NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR)) | ||
33 | + | ||
34 | +// The default Mifare Classic key | ||
35 | +static const uint8_t KEY_DEFAULT_KEYAB[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
36 | + | ||
37 | +void setup(void) { | ||
38 | + Serial.begin(115200); | ||
39 | + Serial.println("Looking for PN532..."); | ||
40 | + | ||
41 | + nfc.begin(); | ||
42 | + | ||
43 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
44 | + if (! versiondata) { | ||
45 | + Serial.print("Didn't find PN53x board"); | ||
46 | + while (1); // halt | ||
47 | + } | ||
48 | + | ||
49 | + // Got ok data, print it out! | ||
50 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
51 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
52 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
53 | + | ||
54 | + // configure board to read RFID tags | ||
55 | + nfc.SAMConfig(); | ||
56 | +} | ||
57 | + | ||
58 | +void loop(void) { | ||
59 | + uint8_t success; // Flag to check if there was an error with the PN532 | ||
60 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
61 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
62 | + bool authenticated = false; // Flag to indicate if the sector is authenticated | ||
63 | + uint8_t blockBuffer[16]; // Buffer to store block contents | ||
64 | + uint8_t blankAccessBits[3] = { 0xff, 0x07, 0x80 }; | ||
65 | + uint8_t idx = 0; | ||
66 | + uint8_t numOfSector = 16; // Assume Mifare Classic 1K for now (16 4-block sectors) | ||
67 | + | ||
68 | + Serial.println("Place your NDEF formatted Mifare Classic 1K card on the reader"); | ||
69 | + Serial.println("and press any key to continue ..."); | ||
70 | + | ||
71 | + // Wait for user input before proceeding | ||
72 | + while (!Serial.available()); | ||
73 | + while (Serial.available()) Serial.read(); | ||
74 | + | ||
75 | + // Wait for an ISO14443A type card (Mifare, etc.). When one is found | ||
76 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
77 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
78 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | ||
79 | + | ||
80 | + if (success) | ||
81 | + { | ||
82 | + // We seem to have a tag ... | ||
83 | + // Display some basic information about it | ||
84 | + Serial.println("Found an ISO14443A card/tag"); | ||
85 | + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
86 | + Serial.print(" UID Value: "); | ||
87 | + nfc.PrintHex(uid, uidLength); | ||
88 | + Serial.println(""); | ||
89 | + | ||
90 | + // Make sure this is a Mifare Classic card | ||
91 | + if (uidLength != 4) | ||
92 | + { | ||
93 | + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); | ||
94 | + return; | ||
95 | + } | ||
96 | + | ||
97 | + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); | ||
98 | + Serial.println(""); | ||
99 | + Serial.println("Reformatting card for Mifare Classic (please don't touch it!) ... "); | ||
100 | + | ||
101 | + // Now run through the card sector by sector | ||
102 | + for (idx = 0; idx < numOfSector; idx++) | ||
103 | + { | ||
104 | + // Step 1: Authenticate the current sector using key B 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF | ||
105 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, BLOCK_NUMBER_OF_SECTOR_TRAILER(idx), 1, (uint8_t *)KEY_DEFAULT_KEYAB); | ||
106 | + if (!success) | ||
107 | + { | ||
108 | + Serial.print("Authentication failed for sector "); Serial.println(numOfSector); | ||
109 | + return; | ||
110 | + } | ||
111 | + | ||
112 | + // Step 2: Write to the other blocks | ||
113 | + if (idx == 16) | ||
114 | + { | ||
115 | + memset(blockBuffer, 0, sizeof(blockBuffer)); | ||
116 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer))) | ||
117 | + { | ||
118 | + Serial.print("Unable to write to sector "); Serial.println(numOfSector); | ||
119 | + return; | ||
120 | + } | ||
121 | + } | ||
122 | + if ((idx == 0) || (idx == 16)) | ||
123 | + { | ||
124 | + memset(blockBuffer, 0, sizeof(blockBuffer)); | ||
125 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer))) | ||
126 | + { | ||
127 | + Serial.print("Unable to write to sector "); Serial.println(numOfSector); | ||
128 | + return; | ||
129 | + } | ||
130 | + } | ||
131 | + else | ||
132 | + { | ||
133 | + memset(blockBuffer, 0, sizeof(blockBuffer)); | ||
134 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer))) | ||
135 | + { | ||
136 | + Serial.print("Unable to write to sector "); Serial.println(numOfSector); | ||
137 | + return; | ||
138 | + } | ||
139 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer))) | ||
140 | + { | ||
141 | + Serial.print("Unable to write to sector "); Serial.println(numOfSector); | ||
142 | + return; | ||
143 | + } | ||
144 | + } | ||
145 | + memset(blockBuffer, 0, sizeof(blockBuffer)); | ||
146 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 1, blockBuffer))) | ||
147 | + { | ||
148 | + Serial.print("Unable to write to sector "); Serial.println(numOfSector); | ||
149 | + return; | ||
150 | + } | ||
151 | + | ||
152 | + // Step 3: Reset both keys to 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF | ||
153 | + memcpy(blockBuffer, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB)); | ||
154 | + memcpy(blockBuffer + 6, blankAccessBits, sizeof(blankAccessBits)); | ||
155 | + blockBuffer[9] = 0x69; | ||
156 | + memcpy(blockBuffer + 10, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB)); | ||
157 | + | ||
158 | + // Step 4: Write the trailer block | ||
159 | + if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)), blockBuffer))) | ||
160 | + { | ||
161 | + Serial.print("Unable to write trailer block of sector "); Serial.println(numOfSector); | ||
162 | + return; | ||
163 | + } | ||
164 | + } | ||
165 | + } | ||
166 | + | ||
167 | + // Wait a bit before trying again | ||
168 | + Serial.println("\n\nDone!"); | ||
169 | + delay(1000); | ||
170 | + Serial.flush(); | ||
171 | + while(Serial.available()) Serial.read(); | ||
172 | +} | ||
0 | \ No newline at end of file | 173 | \ No newline at end of file |
PN532/examples/mifareclassic_updatendef/mifareclassic_updatendef.pde
0 → 100644
@@ -0,0 +1,145 @@ | @@ -0,0 +1,145 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + Updates a sector that is already formatted for NDEF (using | ||
4 | + mifareclassic_formatndef.pde for example), inserting a new url | ||
5 | + | ||
6 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
7 | +*/ | ||
8 | +/**************************************************************************/ | ||
9 | + | ||
10 | +#include <SPI.h> | ||
11 | +#include <PN532_SPI.h> | ||
12 | +#include "PN532.h" | ||
13 | + | ||
14 | +PN532_SPI pn532spi(SPI, 10); | ||
15 | +PN532 nfc(pn532spi); | ||
16 | + | ||
17 | + | ||
18 | + | ||
19 | +/* | ||
20 | + We can encode many different kinds of pointers to the card, | ||
21 | + from a URL, to an Email address, to a phone number, and many more | ||
22 | + check the library header .h file to see the large # of supported | ||
23 | + prefixes! | ||
24 | +*/ | ||
25 | +// For a http://www. url: | ||
26 | +const char * url = "seeedstudio.com"; | ||
27 | +uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT; | ||
28 | + | ||
29 | +// for an email address | ||
30 | +//const char * url = "mail@example.com"; | ||
31 | +//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO; | ||
32 | + | ||
33 | +// for a phone number | ||
34 | +//const char * url = "+1 212 555 1212"; | ||
35 | +//uint8_t ndefprefix = NDEF_URIPREFIX_TEL; | ||
36 | + | ||
37 | + | ||
38 | +void setup(void) { | ||
39 | + Serial.begin(115200); | ||
40 | + Serial.println("Looking for PN532..."); | ||
41 | + | ||
42 | + nfc.begin(); | ||
43 | + | ||
44 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
45 | + if (! versiondata) { | ||
46 | + Serial.print("Didn't find PN53x board"); | ||
47 | + while (1); // halt | ||
48 | + } | ||
49 | + | ||
50 | + // Got ok data, print it out! | ||
51 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
52 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
53 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
54 | + | ||
55 | + // configure board to read RFID tags | ||
56 | + nfc.SAMConfig(); | ||
57 | +} | ||
58 | + | ||
59 | +void loop(void) { | ||
60 | + uint8_t success; // Flag to check if there was an error with the PN532 | ||
61 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
62 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
63 | + bool authenticated = false; // Flag to indicate if the sector is authenticated | ||
64 | + | ||
65 | + // Use the default NDEF keys (these would have have set by mifareclassic_formatndef.pde!) | ||
66 | + uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 }; | ||
67 | + uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 }; | ||
68 | + | ||
69 | + Serial.println("Place your NDEF formatted Mifare Classic card on the reader to update the"); | ||
70 | + Serial.println("NDEF record and press any key to continue ..."); | ||
71 | + // Wait for user input before proceeding | ||
72 | + while (!Serial.available()); | ||
73 | + // a key was pressed1 | ||
74 | + while (Serial.available()) Serial.read(); | ||
75 | + | ||
76 | + // Wait for an ISO14443A type card (Mifare, etc.). When one is found | ||
77 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
78 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
79 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | ||
80 | + | ||
81 | + if (success) | ||
82 | + { | ||
83 | + // Display some basic information about the card | ||
84 | + Serial.println("Found an ISO14443A card"); | ||
85 | + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
86 | + Serial.print(" UID Value: "); | ||
87 | + nfc.PrintHex(uid, uidLength); | ||
88 | + Serial.println(""); | ||
89 | + | ||
90 | + // Make sure this is a Mifare Classic card | ||
91 | + if (uidLength != 4) | ||
92 | + { | ||
93 | + Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!"); | ||
94 | + return; | ||
95 | + } | ||
96 | + | ||
97 | + // We probably have a Mifare Classic card ... | ||
98 | + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); | ||
99 | + | ||
100 | + // Check if this is an NDEF card (using first block of sector 1 from mifareclassic_formatndef.pde) | ||
101 | + // Must authenticate on the first key using 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 | ||
102 | + success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keyb); | ||
103 | + if (!success) | ||
104 | + { | ||
105 | + Serial.println("Unable to authenticate block 4 ... is this card NDEF formatted?"); | ||
106 | + return; | ||
107 | + } | ||
108 | + | ||
109 | + Serial.println("Authentication succeeded (seems to be an NDEF/NFC Forum tag) ..."); | ||
110 | + | ||
111 | + // Authenticated seems to have worked | ||
112 | + // Try to write an NDEF record to sector 1 | ||
113 | + // Use 0x01 for the URI Identifier Code to prepend "http://www." | ||
114 | + // to the url (and save some space). For information on URI ID Codes | ||
115 | + // see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef | ||
116 | + if (strlen(url) > 38) | ||
117 | + { | ||
118 | + // The length is also checked in the WriteNDEFURI function, but lets | ||
119 | + // warn users here just in case they change the value and it's bigger | ||
120 | + // than it should be | ||
121 | + Serial.println("URI is too long ... must be less than 38 characters!"); | ||
122 | + return; | ||
123 | + } | ||
124 | + | ||
125 | + Serial.println("Updating sector 1 with URI as NDEF Message"); | ||
126 | + | ||
127 | + // URI is within size limits ... write it to the card and report success/failure | ||
128 | + success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url); | ||
129 | + if (success) | ||
130 | + { | ||
131 | + Serial.println("NDEF URI Record written to sector 1"); | ||
132 | + Serial.println(""); | ||
133 | + } | ||
134 | + else | ||
135 | + { | ||
136 | + Serial.println("NDEF Record creation failed! :("); | ||
137 | + } | ||
138 | + } | ||
139 | + | ||
140 | + // Wait a bit before trying again | ||
141 | + Serial.println("\n\nDone!"); | ||
142 | + delay(1000); | ||
143 | + Serial.flush(); | ||
144 | + while(Serial.available()) Serial.read(); | ||
145 | +} |
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +// snep_test.ino | ||
2 | +// send a SNEP message to adnroid and get a message from android | ||
3 | + | ||
4 | +#include "SPI.h" | ||
5 | +#include "PN532_SPI.h" | ||
6 | +#include "llcp.h" | ||
7 | +#include "snep.h" | ||
8 | + | ||
9 | +PN532_SPI pn532spi(SPI, 10); | ||
10 | +SNEP nfc(pn532spi); | ||
11 | + | ||
12 | +void setup() | ||
13 | +{ | ||
14 | + Serial.begin(115200); | ||
15 | + Serial.println("-------Peer to Peer--------"); | ||
16 | +} | ||
17 | + | ||
18 | +uint8_t message[] = { | ||
19 | +0xD2, 0xA, 0xB, 0x74,0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, | ||
20 | +0x61, 0x69, 0x6E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, | ||
21 | +0x6F, 0x72, 0x6C, 0x64}; | ||
22 | + | ||
23 | +uint8_t buf[128]; | ||
24 | + | ||
25 | +void loop() | ||
26 | +{ | ||
27 | + | ||
28 | + nfc.write(message, sizeof(message)); | ||
29 | + delay(3000); | ||
30 | + | ||
31 | + int16_t len = nfc.read(buf, sizeof(buf)); | ||
32 | + if (len > 0) { | ||
33 | + Serial.println("get a SNEP message:"); | ||
34 | + for (uint8_t i = 0; i < len; i++) { | ||
35 | + Serial.print(buf[i], HEX); | ||
36 | + Serial.print(' '); | ||
37 | + } | ||
38 | + Serial.print('\n'); | ||
39 | + for (uint8_t i = 0; i < len; i++) { | ||
40 | + char c = buf[i]; | ||
41 | + if (c <= 0x1f || c > 0x7f) { | ||
42 | + Serial.print('.'); | ||
43 | + } else { | ||
44 | + Serial.print(c); | ||
45 | + } | ||
46 | + } | ||
47 | + Serial.print('\n'); | ||
48 | + } | ||
49 | + delay(3000); | ||
50 | +} | ||
51 | + |
PN532/examples/p2p_with_ndef_library/p2p_with_ndef_library.ino
0 → 100644
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +// send a NDEF message to adnroid or get a NDEF message | ||
2 | +// | ||
3 | +// note: [NDEF library](https://github.com/Don/NDEF) is needed. | ||
4 | + | ||
5 | +#include "SPI.h" | ||
6 | +#include "PN532_SPI.h" | ||
7 | +#include "snep.h" | ||
8 | +#include "NdefMessage.h" | ||
9 | + | ||
10 | +PN532_SPI pn532spi(SPI, 10); | ||
11 | +SNEP nfc(pn532spi); | ||
12 | +uint8_t ndefBuf[128]; | ||
13 | + | ||
14 | +void setup() | ||
15 | +{ | ||
16 | + Serial.begin(115200); | ||
17 | + Serial.println("-------Peer to Peer--------"); | ||
18 | +} | ||
19 | + | ||
20 | +void loop() | ||
21 | +{ | ||
22 | +#if 1 | ||
23 | + Serial.println("Send a message to Android"); | ||
24 | + NdefMessage message = NdefMessage(); | ||
25 | + message.addUriRecord("http://www.seeedstudio.com"); | ||
26 | + int messageSize = message.getEncodedSize(); | ||
27 | + if (messageSize > sizeof(ndefBuf)) { | ||
28 | + Serial.println("ndefBuf is too small"); | ||
29 | + while (1) { | ||
30 | + } | ||
31 | + | ||
32 | + } | ||
33 | + | ||
34 | + message.encode(ndefBuf); | ||
35 | + if (0 >= nfc.write(ndefBuf, messageSize)) { | ||
36 | + Serial.println("Failed"); | ||
37 | + } else { | ||
38 | + Serial.println("Success"); | ||
39 | + } | ||
40 | + | ||
41 | + delay(3000); | ||
42 | +#else | ||
43 | + Serial.println("Get a message from Android"); | ||
44 | + int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf)); | ||
45 | + if (msgSize > 0) { | ||
46 | + NdefMessage msg = NdefMessage(ndefBuf, msgSize); | ||
47 | + msg.print(); | ||
48 | + Serial.println("\nSuccess"); | ||
49 | + } else { | ||
50 | + Serial.println("failed"); | ||
51 | + } | ||
52 | + delay(3000); | ||
53 | +#endif | ||
54 | +} | ||
55 | + |
@@ -0,0 +1,145 @@ | @@ -0,0 +1,145 @@ | ||
1 | +/**************************************************************************/ | ||
2 | +/*! | ||
3 | + This example will wait for any ISO14443A card or tag, and | ||
4 | + depending on the size of the UID will attempt to read from it. | ||
5 | + | ||
6 | + If the card has a 4-byte UID it is probably a Mifare | ||
7 | + Classic card, and the following steps are taken: | ||
8 | + | ||
9 | + - Authenticate block 4 (the first block of Sector 1) using | ||
10 | + the default KEYA of 0XFF 0XFF 0XFF 0XFF 0XFF 0XFF | ||
11 | + - If authentication succeeds, we can then read any of the | ||
12 | + 4 blocks in that sector (though only block 4 is read here) | ||
13 | + | ||
14 | + If the card has a 7-byte UID it is probably a Mifare | ||
15 | + Ultralight card, and the 4 byte pages can be read directly. | ||
16 | + Page 4 is read by default since this is the first 'general- | ||
17 | + purpose' page on the tags. | ||
18 | + | ||
19 | + To enable debug message, define DEBUG in PN532/PN532_debug.h | ||
20 | +*/ | ||
21 | +/**************************************************************************/ | ||
22 | + | ||
23 | +#include <SPI.h> | ||
24 | +#include <PN532_SPI.h> | ||
25 | +#include "PN532.h" | ||
26 | + | ||
27 | +PN532_SPI pn532spi(SPI, 10); | ||
28 | +PN532 nfc(pn532spi); | ||
29 | + | ||
30 | +void setup(void) { | ||
31 | + Serial.begin(115200); | ||
32 | + Serial.println("Hello!"); | ||
33 | + | ||
34 | + nfc.begin(); | ||
35 | + | ||
36 | + uint32_t versiondata = nfc.getFirmwareVersion(); | ||
37 | + if (! versiondata) { | ||
38 | + Serial.print("Didn't find PN53x board"); | ||
39 | + while (1); // halt | ||
40 | + } | ||
41 | + // Got ok data, print it out! | ||
42 | + Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); | ||
43 | + Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); | ||
44 | + Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); | ||
45 | + | ||
46 | + // configure board to read RFID tags | ||
47 | + nfc.SAMConfig(); | ||
48 | + | ||
49 | + Serial.println("Waiting for an ISO14443A Card ..."); | ||
50 | +} | ||
51 | + | ||
52 | + | ||
53 | +void loop(void) { | ||
54 | + uint8_t success; | ||
55 | + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID | ||
56 | + uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) | ||
57 | + | ||
58 | + // Wait for an ISO14443A type cards (Mifare, etc.). When one is found | ||
59 | + // 'uid' will be populated with the UID, and uidLength will indicate | ||
60 | + // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) | ||
61 | + success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | ||
62 | + | ||
63 | + if (success) { | ||
64 | + // Display some basic information about the card | ||
65 | + Serial.println("Found an ISO14443A card"); | ||
66 | + Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes"); | ||
67 | + Serial.print(" UID Value: "); | ||
68 | + nfc.PrintHex(uid, uidLength); | ||
69 | + Serial.println(""); | ||
70 | + | ||
71 | + if (uidLength == 4) | ||
72 | + { | ||
73 | + // We probably have a Mifare Classic card ... | ||
74 | + Serial.println("Seems to be a Mifare Classic card (4 byte UID)"); | ||
75 | + | ||
76 | + // Now we need to try to authenticate it for read/write access | ||
77 | + // Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF | ||
78 | + Serial.println("Trying to authenticate block 4 with default KEYA value"); | ||
79 | + uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
80 | + | ||
81 | + // Start with block 4 (the first block of sector 1) since sector 0 | ||
82 | + // contains the manufacturer data and it's probably better just | ||
83 | + // to leave it alone unless you know what you're doing | ||
84 | + success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya); | ||
85 | + | ||
86 | + if (success) | ||
87 | + { | ||
88 | + Serial.println("Sector 1 (Blocks 4..7) has been authenticated"); | ||
89 | + uint8_t data[16]; | ||
90 | + | ||
91 | + // If you want to write something to block 4 to test with, uncomment | ||
92 | + // the following line and this text should be read back in a minute | ||
93 | + // data = { 'a', 'd', 'a', 'f', 'r', 'u', 'i', 't', '.', 'c', 'o', 'm', 0, 0, 0, 0}; | ||
94 | + // success = nfc.mifareclassic_WriteDataBlock (4, data); | ||
95 | + | ||
96 | + // Try to read the contents of block 4 | ||
97 | + success = nfc.mifareclassic_ReadDataBlock(4, data); | ||
98 | + | ||
99 | + if (success) | ||
100 | + { | ||
101 | + // Data seems to have been read ... spit it out | ||
102 | + Serial.println("Reading Block 4:"); | ||
103 | + nfc.PrintHexChar(data, 16); | ||
104 | + Serial.println(""); | ||
105 | + | ||
106 | + // Wait a bit before reading the card again | ||
107 | + delay(1000); | ||
108 | + } | ||
109 | + else | ||
110 | + { | ||
111 | + Serial.println("Ooops ... unable to read the requested block. Try another key?"); | ||
112 | + } | ||
113 | + } | ||
114 | + else | ||
115 | + { | ||
116 | + Serial.println("Ooops ... authentication failed: Try another key?"); | ||
117 | + } | ||
118 | + } | ||
119 | + | ||
120 | + if (uidLength == 7) | ||
121 | + { | ||
122 | + // We probably have a Mifare Ultralight card ... | ||
123 | + Serial.println("Seems to be a Mifare Ultralight tag (7 byte UID)"); | ||
124 | + | ||
125 | + // Try to read the first general-purpose user page (#4) | ||
126 | + Serial.println("Reading page 4"); | ||
127 | + uint8_t data[32]; | ||
128 | + success = nfc.mifareultralight_ReadPage (4, data); | ||
129 | + if (success) | ||
130 | + { | ||
131 | + // Data seems to have been read ... spit it out | ||
132 | + nfc.PrintHexChar(data, 4); | ||
133 | + Serial.println(""); | ||
134 | + | ||
135 | + // Wait a bit before reading the card again | ||
136 | + delay(1000); | ||
137 | + } | ||
138 | + else | ||
139 | + { | ||
140 | + Serial.println("Ooops ... unable to read the requested page!?"); | ||
141 | + } | ||
142 | + } | ||
143 | + } | ||
144 | +} | ||
145 | + |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +Software License Agreement (BSD License) | ||
2 | + | ||
3 | +Copyright (c) 2012, Adafruit Industries | ||
4 | +Copyright (c) 2013, Seeed Technology Inc. | ||
5 | +All rights reserved. | ||
6 | + | ||
7 | +Redistribution and use in source and binary forms, with or without | ||
8 | +modification, are permitted provided that the following conditions are met: | ||
9 | +1. Redistributions of source code must retain the above copyright | ||
10 | +notice, this list of conditions and the following disclaimer. | ||
11 | +2. Redistributions in binary form must reproduce the above copyright | ||
12 | +notice, this list of conditions and the following disclaimer in the | ||
13 | +documentation and/or other materials provided with the distribution. | ||
14 | +3. Neither the name of the copyright holders nor the | ||
15 | +names of its contributors may be used to endorse or promote products | ||
16 | +derived from this software without specific prior written permission. | ||
17 | + | ||
18 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY | ||
19 | +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
20 | +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
21 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY | ||
22 | +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
23 | +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
24 | +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
25 | +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
26 | +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
27 | +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@@ -0,0 +1,309 @@ | @@ -0,0 +1,309 @@ | ||
1 | + | ||
2 | +#include "llcp.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | + | ||
5 | +// LLCP PDU Type Values | ||
6 | +#define PDU_SYMM 0x00 | ||
7 | +#define PDU_PAX 0x01 | ||
8 | +#define PDU_CONNECT 0x04 | ||
9 | +#define PDU_DISC 0x05 | ||
10 | +#define PDU_CC 0x06 | ||
11 | +#define PDU_DM 0x07 | ||
12 | +#define PDU_I 0x0c | ||
13 | +#define PDU_RR 0x0d | ||
14 | + | ||
15 | +uint8_t LLCP::SYMM_PDU[2] = {0, 0}; | ||
16 | + | ||
17 | +inline uint8_t getPType(const uint8_t *buf) | ||
18 | +{ | ||
19 | + return ((buf[0] & 0x3) << 2) + (buf[1] >> 6); | ||
20 | +} | ||
21 | + | ||
22 | +inline uint8_t getSSAP(const uint8_t *buf) | ||
23 | +{ | ||
24 | + return buf[1] & 0x3f; | ||
25 | +} | ||
26 | + | ||
27 | +inline uint8_t getDSAP(const uint8_t *buf) | ||
28 | +{ | ||
29 | + return buf[0] >> 2; | ||
30 | +} | ||
31 | + | ||
32 | +int8_t LLCP::activate(uint16_t timeout) | ||
33 | +{ | ||
34 | + return link.activateAsTarget(timeout); | ||
35 | +} | ||
36 | + | ||
37 | +int8_t LLCP::waitForConnection(uint16_t timeout) | ||
38 | +{ | ||
39 | + uint8_t type; | ||
40 | + | ||
41 | + mode = 1; | ||
42 | + ns = 0; | ||
43 | + nr = 0; | ||
44 | + | ||
45 | + // Get CONNECT PDU | ||
46 | + DMSG("wait for a CONNECT PDU\n"); | ||
47 | + do { | ||
48 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
49 | + return -1; | ||
50 | + } | ||
51 | + | ||
52 | + type = getPType(headerBuf); | ||
53 | + if (PDU_CONNECT == type) { | ||
54 | + break; | ||
55 | + } else if (PDU_SYMM == type) { | ||
56 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
57 | + return -2; | ||
58 | + } | ||
59 | + } else { | ||
60 | + return -3; | ||
61 | + } | ||
62 | + | ||
63 | + } while (1); | ||
64 | + | ||
65 | + // Put CC PDU | ||
66 | + DMSG("put a CC(Connection Complete) PDU to response the CONNECT PDU\n"); | ||
67 | + ssap = getDSAP(headerBuf); | ||
68 | + dsap = getSSAP(headerBuf); | ||
69 | + headerBuf[0] = (dsap << 2) + ((PDU_CC >> 2) & 0x3); | ||
70 | + headerBuf[1] = ((PDU_CC & 0x3) << 6) + ssap; | ||
71 | + if (!link.write(headerBuf, 2)) { | ||
72 | + return -2; | ||
73 | + } | ||
74 | + | ||
75 | + return 1; | ||
76 | +} | ||
77 | + | ||
78 | +int8_t LLCP::waitForDisconnection(uint16_t timeout) | ||
79 | +{ | ||
80 | + uint8_t type; | ||
81 | + | ||
82 | + // Get DISC PDU | ||
83 | + DMSG("wait for a DISC PDU\n"); | ||
84 | + do { | ||
85 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
86 | + return -1; | ||
87 | + } | ||
88 | + | ||
89 | + type = getPType(headerBuf); | ||
90 | + if (PDU_DISC == type) { | ||
91 | + break; | ||
92 | + } else if (PDU_SYMM == type) { | ||
93 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
94 | + return -2; | ||
95 | + } | ||
96 | + } else { | ||
97 | + return -3; | ||
98 | + } | ||
99 | + | ||
100 | + } while (1); | ||
101 | + | ||
102 | + // Put DM PDU | ||
103 | + DMSG("put a DM(Disconnect Mode) PDU to response the DISC PDU\n"); | ||
104 | + // ssap = getDSAP(headerBuf); | ||
105 | + // dsap = getSSAP(headerBuf); | ||
106 | + headerBuf[0] = (dsap << 2) + (PDU_DM >> 2); | ||
107 | + headerBuf[1] = ((PDU_DM & 0x3) << 6) + ssap; | ||
108 | + if (!link.write(headerBuf, 2)) { | ||
109 | + return -2; | ||
110 | + } | ||
111 | + | ||
112 | + return 1; | ||
113 | +} | ||
114 | + | ||
115 | +int8_t LLCP::connect(uint16_t timeout) | ||
116 | +{ | ||
117 | + uint8_t type; | ||
118 | + | ||
119 | + mode = 0; | ||
120 | + dsap = LLCP_DEFAULT_DSAP; | ||
121 | + ssap = LLCP_DEFAULT_SSAP; | ||
122 | + ns = 0; | ||
123 | + nr = 0; | ||
124 | + | ||
125 | + // try to get a SYMM PDU | ||
126 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
127 | + return -1; | ||
128 | + } | ||
129 | + type = getPType(headerBuf); | ||
130 | + if (PDU_SYMM != type) { | ||
131 | + return -1; | ||
132 | + } | ||
133 | + | ||
134 | + // put a CONNECT PDU | ||
135 | + headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_CONNECT >> 2); | ||
136 | + headerBuf[1] = ((PDU_CONNECT & 0x03) << 6) + LLCP_DEFAULT_SSAP; | ||
137 | + uint8_t body[] = " urn:nfc:sn:snep"; | ||
138 | + body[0] = 0x06; | ||
139 | + body[1] = sizeof(body) - 2 - 1; | ||
140 | + if (!link.write(headerBuf, 2, body, sizeof(body) - 1)) { | ||
141 | + return -2; | ||
142 | + } | ||
143 | + | ||
144 | + // wait for a CC PDU | ||
145 | + DMSG("wait for a CC PDU\n"); | ||
146 | + do { | ||
147 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
148 | + return -1; | ||
149 | + } | ||
150 | + | ||
151 | + type = getPType(headerBuf); | ||
152 | + if (PDU_CC == type) { | ||
153 | + break; | ||
154 | + } else if (PDU_SYMM == type) { | ||
155 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
156 | + return -2; | ||
157 | + } | ||
158 | + } else { | ||
159 | + return -3; | ||
160 | + } | ||
161 | + | ||
162 | + } while (1); | ||
163 | + | ||
164 | + return 1; | ||
165 | +} | ||
166 | + | ||
167 | +int8_t LLCP::disconnect(uint16_t timeout) | ||
168 | +{ | ||
169 | + uint8_t type; | ||
170 | + | ||
171 | + // try to get a SYMM PDU | ||
172 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
173 | + return -1; | ||
174 | + } | ||
175 | + type = getPType(headerBuf); | ||
176 | + if (PDU_SYMM != type) { | ||
177 | + return -1; | ||
178 | + } | ||
179 | + | ||
180 | + // put a DISC PDU | ||
181 | + headerBuf[0] = (LLCP_DEFAULT_DSAP << 2) + (PDU_DISC >> 2); | ||
182 | + headerBuf[1] = ((PDU_DISC & 0x03) << 6) + LLCP_DEFAULT_SSAP; | ||
183 | + if (!link.write(headerBuf, 2)) { | ||
184 | + return -2; | ||
185 | + } | ||
186 | + | ||
187 | + // wait for a DM PDU | ||
188 | + DMSG("wait for a DM PDU\n"); | ||
189 | + do { | ||
190 | + if (2 > link.read(headerBuf, headerBufLen)) { | ||
191 | + return -1; | ||
192 | + } | ||
193 | + | ||
194 | + type = getPType(headerBuf); | ||
195 | + if (PDU_CC == type) { | ||
196 | + break; | ||
197 | + } else if (PDU_DM == type) { | ||
198 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
199 | + return -2; | ||
200 | + } | ||
201 | + } else { | ||
202 | + return -3; | ||
203 | + } | ||
204 | + | ||
205 | + } while (1); | ||
206 | + | ||
207 | + return 1; | ||
208 | +} | ||
209 | + | ||
210 | +bool LLCP::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
211 | +{ | ||
212 | + uint8_t type; | ||
213 | + uint8_t buf[3]; | ||
214 | + | ||
215 | + if (mode) { | ||
216 | + // Get a SYMM PDU | ||
217 | + if (2 != link.read(buf, sizeof(buf))) { | ||
218 | + return false; | ||
219 | + } | ||
220 | + } | ||
221 | + | ||
222 | + if (headerBufLen < (hlen + 3)) { | ||
223 | + return false; | ||
224 | + } | ||
225 | + | ||
226 | + for (int8_t i = hlen - 1; i >= 0; i--) { | ||
227 | + headerBuf[i + 3] = header[i]; | ||
228 | + } | ||
229 | + | ||
230 | + headerBuf[0] = (dsap << 2) + (PDU_I >> 2); | ||
231 | + headerBuf[1] = ((PDU_I & 0x3) << 6) + ssap; | ||
232 | + headerBuf[2] = (ns << 4) + nr; | ||
233 | + if (!link.write(headerBuf, 3 + hlen, body, blen)) { | ||
234 | + return false; | ||
235 | + } | ||
236 | + | ||
237 | + ns++; | ||
238 | + | ||
239 | + // Get a RR PDU | ||
240 | + int16_t status; | ||
241 | + do { | ||
242 | + status = link.read(headerBuf, headerBufLen); | ||
243 | + if (2 > status) { | ||
244 | + return false; | ||
245 | + } | ||
246 | + | ||
247 | + type = getPType(headerBuf); | ||
248 | + if (PDU_RR == type) { | ||
249 | + break; | ||
250 | + } else if (PDU_SYMM == type) { | ||
251 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
252 | + return false; | ||
253 | + } | ||
254 | + } else { | ||
255 | + return false; | ||
256 | + } | ||
257 | + } while (1); | ||
258 | + | ||
259 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
260 | + return false; | ||
261 | + } | ||
262 | + | ||
263 | + return true; | ||
264 | +} | ||
265 | + | ||
266 | +int16_t LLCP::read(uint8_t *buf, uint8_t length) | ||
267 | +{ | ||
268 | + uint8_t type; | ||
269 | + uint16_t status; | ||
270 | + | ||
271 | + // Get INFO PDU | ||
272 | + do { | ||
273 | + status = link.read(buf, length); | ||
274 | + if (2 > status) { | ||
275 | + return -1; | ||
276 | + } | ||
277 | + | ||
278 | + type = getPType(buf); | ||
279 | + if (PDU_I == type) { | ||
280 | + break; | ||
281 | + } else if (PDU_SYMM == type) { | ||
282 | + if (!link.write(SYMM_PDU, sizeof(SYMM_PDU))) { | ||
283 | + return -2; | ||
284 | + } | ||
285 | + } else { | ||
286 | + return -3; | ||
287 | + } | ||
288 | + | ||
289 | + } while (1); | ||
290 | + | ||
291 | + uint8_t len = status - 3; | ||
292 | + ssap = getDSAP(buf); | ||
293 | + dsap = getSSAP(buf); | ||
294 | + | ||
295 | + headerBuf[0] = (dsap << 2) + (PDU_RR >> 2); | ||
296 | + headerBuf[1] = ((PDU_RR & 0x3) << 6) + ssap; | ||
297 | + headerBuf[2] = (buf[2] >> 4) + 1; | ||
298 | + if (!link.write(headerBuf, 3)) { | ||
299 | + return -2; | ||
300 | + } | ||
301 | + | ||
302 | + for (uint8_t i = 0; i < len; i++) { | ||
303 | + buf[i] = buf[i + 3]; | ||
304 | + } | ||
305 | + | ||
306 | + nr++; | ||
307 | + | ||
308 | + return len; | ||
309 | +} |
@@ -0,0 +1,75 @@ | @@ -0,0 +1,75 @@ | ||
1 | + | ||
2 | +#ifndef __LLCP_H__ | ||
3 | +#define __LLCP_H__ | ||
4 | + | ||
5 | +#include "mac_link.h" | ||
6 | + | ||
7 | +#define LLCP_DEFAULT_TIMEOUT 20000 | ||
8 | +#define LLCP_DEFAULT_DSAP 0x04 | ||
9 | +#define LLCP_DEFAULT_SSAP 0x20 | ||
10 | + | ||
11 | +class LLCP { | ||
12 | +public: | ||
13 | + LLCP(PN532Interface &interface) : link(interface) { | ||
14 | + headerBuf = link.getHeaderBuffer(&headerBufLen); | ||
15 | + ns = 0; | ||
16 | + nr = 0; | ||
17 | + }; | ||
18 | + | ||
19 | + /** | ||
20 | + * @brief Actiave PN532 as a target | ||
21 | + * @param timeout max time to wait, 0 means no timeout | ||
22 | + * @return > 0 success | ||
23 | + * = 0 timeout | ||
24 | + * < 0 failed | ||
25 | + */ | ||
26 | + int8_t activate(uint16_t timeout = 0); | ||
27 | + | ||
28 | + int8_t waitForConnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT); | ||
29 | + | ||
30 | + int8_t waitForDisconnection(uint16_t timeout = LLCP_DEFAULT_TIMEOUT); | ||
31 | + | ||
32 | + int8_t connect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT); | ||
33 | + | ||
34 | + int8_t disconnect(uint16_t timeout = LLCP_DEFAULT_TIMEOUT); | ||
35 | + | ||
36 | + /** | ||
37 | + * @brief write a packet, the packet should be less than (255 - 2) bytes | ||
38 | + * @param header packet header | ||
39 | + * @param hlen length of header | ||
40 | + * @param body packet body | ||
41 | + * @param blen length of body | ||
42 | + * @return true success | ||
43 | + * false failed | ||
44 | + */ | ||
45 | + bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
46 | + | ||
47 | + /** | ||
48 | + * @brief read a packet, the packet will be less than (255 - 2) bytes | ||
49 | + * @param buf the buffer to contain the packet | ||
50 | + * @param len lenght of the buffer | ||
51 | + * @return >=0 length of the packet | ||
52 | + * <0 failed | ||
53 | + */ | ||
54 | + int16_t read(uint8_t *buf, uint8_t len); | ||
55 | + | ||
56 | + uint8_t *getHeaderBuffer(uint8_t *len) { | ||
57 | + uint8_t *buf = link.getHeaderBuffer(len); | ||
58 | + len -= 3; // I PDU header has 3 bytes | ||
59 | + return buf; | ||
60 | + }; | ||
61 | + | ||
62 | +private: | ||
63 | + MACLink link; | ||
64 | + uint8_t mode; | ||
65 | + uint8_t ssap; | ||
66 | + uint8_t dsap; | ||
67 | + uint8_t *headerBuf; | ||
68 | + uint8_t headerBufLen; | ||
69 | + uint8_t ns; // Number of I PDU Sent | ||
70 | + uint8_t nr; // Number of I PDU Received | ||
71 | + | ||
72 | + static uint8_t SYMM_PDU[2]; | ||
73 | +}; | ||
74 | + | ||
75 | +#endif // __LLCP_H__ |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | + | ||
2 | +#include "mac_link.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | + | ||
5 | +int8_t MACLink::activateAsTarget(uint16_t timeout) | ||
6 | +{ | ||
7 | + pn532.begin(); | ||
8 | + pn532.SAMConfig(); | ||
9 | + return pn532.tgInitAsTarget(timeout); | ||
10 | +} | ||
11 | + | ||
12 | +bool MACLink::write(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
13 | +{ | ||
14 | + return pn532.tgSetData(header, hlen, body, blen); | ||
15 | +} | ||
16 | + | ||
17 | +int16_t MACLink::read(uint8_t *buf, uint8_t len) | ||
18 | +{ | ||
19 | + return pn532.tgGetData(buf, len); | ||
20 | +} |
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | + | ||
2 | + | ||
3 | +#ifndef __MAC_LINK_H__ | ||
4 | +#define __MAC_LINK_H__ | ||
5 | + | ||
6 | +#include "PN532.h" | ||
7 | + | ||
8 | +class MACLink { | ||
9 | +public: | ||
10 | + MACLink(PN532Interface &interface) : pn532(interface) { | ||
11 | + | ||
12 | + }; | ||
13 | + | ||
14 | + /** | ||
15 | + * @brief Activate PN532 as a target | ||
16 | + * @param timeout max time to wait, 0 means no timeout | ||
17 | + * @return > 0 success | ||
18 | + * = 0 timeout | ||
19 | + * < 0 failed | ||
20 | + */ | ||
21 | + int8_t activateAsTarget(uint16_t timeout = 0); | ||
22 | + | ||
23 | + /** | ||
24 | + * @brief write a PDU packet, the packet should be less than (255 - 2) bytes | ||
25 | + * @param header packet header | ||
26 | + * @param hlen length of header | ||
27 | + * @param body packet body | ||
28 | + * @param blen length of body | ||
29 | + * @return true success | ||
30 | + * false failed | ||
31 | + */ | ||
32 | + bool write(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
33 | + | ||
34 | + /** | ||
35 | + * @brief read a PDU packet, the packet will be less than (255 - 2) bytes | ||
36 | + * @param buf the buffer to contain the PDU packet | ||
37 | + * @param len lenght of the buffer | ||
38 | + * @return >=0 length of the PDU packet | ||
39 | + * <0 failed | ||
40 | + */ | ||
41 | + int16_t read(uint8_t *buf, uint8_t len); | ||
42 | + | ||
43 | + uint8_t *getHeaderBuffer(uint8_t *len) { | ||
44 | + return pn532.getBuffer(len); | ||
45 | + }; | ||
46 | + | ||
47 | +private: | ||
48 | + PN532 pn532; | ||
49 | +}; | ||
50 | + | ||
51 | +#endif // __MAC_LINK_H__ |
@@ -0,0 +1,106 @@ | @@ -0,0 +1,106 @@ | ||
1 | + | ||
2 | +#include "snep.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | + | ||
5 | +int8_t SNEP::write(const uint8_t *buf, uint8_t len, uint16_t timeout) | ||
6 | +{ | ||
7 | + if (0 >= llcp.activate(timeout)) { | ||
8 | + DMSG("failed to activate PN532 as a target\n"); | ||
9 | + return -1; | ||
10 | + } | ||
11 | + | ||
12 | + if (0 >= llcp.connect(timeout)) { | ||
13 | + DMSG("failed to set up a connection\n"); | ||
14 | + return -2; | ||
15 | + } | ||
16 | + | ||
17 | + // response a success SNEP message | ||
18 | + headerBuf[0] = SNEP_DEFAULT_VERSION; | ||
19 | + headerBuf[1] = SNEP_REQUEST_PUT; | ||
20 | + headerBuf[2] = 0; | ||
21 | + headerBuf[3] = 0; | ||
22 | + headerBuf[4] = 0; | ||
23 | + headerBuf[5] = len; | ||
24 | + if (0 >= llcp.write(headerBuf, 6, buf, len)) { | ||
25 | + return -3; | ||
26 | + } | ||
27 | + | ||
28 | + uint8_t rbuf[16]; | ||
29 | + if (6 > llcp.read(rbuf, sizeof(rbuf))) { | ||
30 | + return -4; | ||
31 | + } | ||
32 | + | ||
33 | + // check SNEP version | ||
34 | + if (SNEP_DEFAULT_VERSION != rbuf[0]) { | ||
35 | + DMSG("The received SNEP message's major version is different\n"); | ||
36 | + // To-do: send Unsupported Version response | ||
37 | + return -4; | ||
38 | + } | ||
39 | + | ||
40 | + // expect a put request | ||
41 | + if (SNEP_RESPONSE_SUCCESS != rbuf[1]) { | ||
42 | + DMSG("Expect a success response\n"); | ||
43 | + return -4; | ||
44 | + } | ||
45 | + | ||
46 | + llcp.disconnect(timeout); | ||
47 | + | ||
48 | + return 1; | ||
49 | +} | ||
50 | + | ||
51 | +int16_t SNEP::read(uint8_t *buf, uint8_t len, uint16_t timeout) | ||
52 | +{ | ||
53 | + if (0 >= llcp.activate(timeout)) { | ||
54 | + DMSG("failed to activate PN532 as a target\n"); | ||
55 | + return -1; | ||
56 | + } | ||
57 | + | ||
58 | + if (0 >= llcp.waitForConnection(timeout)) { | ||
59 | + DMSG("failed to set up a connection\n"); | ||
60 | + return -2; | ||
61 | + } | ||
62 | + | ||
63 | + uint16_t status = llcp.read(buf, len); | ||
64 | + if (6 > status) { | ||
65 | + return -3; | ||
66 | + } | ||
67 | + | ||
68 | + | ||
69 | + // check SNEP version | ||
70 | + if (SNEP_DEFAULT_VERSION != buf[0]) { | ||
71 | + DMSG("The received SNEP message's major version is different\n"); | ||
72 | + // To-do: send Unsupported Version response | ||
73 | + return -4; | ||
74 | + } | ||
75 | + | ||
76 | + // expect a put request | ||
77 | + if (SNEP_REQUEST_PUT != buf[1]) { | ||
78 | + DMSG("Expect a put request\n"); | ||
79 | + return -4; | ||
80 | + } | ||
81 | + | ||
82 | + // check message's length | ||
83 | + uint32_t length = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8) + buf[5]; | ||
84 | + // length should not be more than 244 (header + body < 255, header = 6 + 3 + 2) | ||
85 | + if (length > (status - 6)) { | ||
86 | + DMSG("The SNEP message is too large: "); | ||
87 | + DMSG_INT(length); | ||
88 | + DMSG_INT(status - 6); | ||
89 | + DMSG("\n"); | ||
90 | + return -4; | ||
91 | + } | ||
92 | + for (uint8_t i = 0; i < length; i++) { | ||
93 | + buf[i] = buf[i + 6]; | ||
94 | + } | ||
95 | + | ||
96 | + // response a success SNEP message | ||
97 | + headerBuf[0] = SNEP_DEFAULT_VERSION; | ||
98 | + headerBuf[1] = SNEP_RESPONSE_SUCCESS; | ||
99 | + headerBuf[2] = 0; | ||
100 | + headerBuf[3] = 0; | ||
101 | + headerBuf[4] = 0; | ||
102 | + headerBuf[5] = 0; | ||
103 | + llcp.write(headerBuf, 6); | ||
104 | + | ||
105 | + return length; | ||
106 | +} |
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | + | ||
2 | + | ||
3 | +#ifndef __SNEP_H__ | ||
4 | +#define __SNEP_H__ | ||
5 | + | ||
6 | +#include "llcp.h" | ||
7 | + | ||
8 | +#define SNEP_DEFAULT_VERSION 0x10 // Major: 1, Minor: 0 | ||
9 | + | ||
10 | +#define SNEP_REQUEST_PUT 0x02 | ||
11 | +#define SNEP_REQUEST_GET 0x01 | ||
12 | + | ||
13 | +#define SNEP_RESPONSE_SUCCESS 0x81 | ||
14 | +#define SNEP_RESPONSE_REJECT 0xFF | ||
15 | + | ||
16 | +class SNEP { | ||
17 | +public: | ||
18 | + SNEP(PN532Interface &interface) : llcp(interface) { | ||
19 | + headerBuf = llcp.getHeaderBuffer(&headerBufLen); | ||
20 | + }; | ||
21 | + | ||
22 | + /** | ||
23 | + * @brief write a SNEP packet, the packet should be less than (255 - 2 - 3) bytes | ||
24 | + * @param buf the buffer to contain the packet | ||
25 | + * @param len lenght of the buffer | ||
26 | + * @param timeout max time to wait, 0 means no timeout | ||
27 | + * @return >0 success | ||
28 | + * =0 timeout | ||
29 | + * <0 failed | ||
30 | + */ | ||
31 | + int8_t write(const uint8_t *buf, uint8_t len, uint16_t timeout = 0); | ||
32 | + | ||
33 | + /** | ||
34 | + * @brief read a SNEP packet, the packet will be less than (255 - 2 - 3) bytes | ||
35 | + * @param buf the buffer to contain the packet | ||
36 | + * @param len lenght of the buffer | ||
37 | + * @param timeout max time to wait, 0 means no timeout | ||
38 | + * @return >=0 length of the packet | ||
39 | + * <0 failed | ||
40 | + */ | ||
41 | + int16_t read(uint8_t *buf, uint8_t len, uint16_t timeout = 0); | ||
42 | + | ||
43 | +private: | ||
44 | + LLCP llcp; | ||
45 | + uint8_t *headerBuf; | ||
46 | + uint8_t headerBufLen; | ||
47 | +}; | ||
48 | + | ||
49 | +#endif // __SNEP_H__ |
@@ -0,0 +1,196 @@ | @@ -0,0 +1,196 @@ | ||
1 | + | ||
2 | +#include "PN532_HSU.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | + | ||
5 | + | ||
6 | +PN532_HSU::PN532_HSU(HardwareSerial &serial) | ||
7 | +{ | ||
8 | + _serial = &serial; | ||
9 | + command = 0; | ||
10 | +} | ||
11 | + | ||
12 | +void PN532_HSU::begin() | ||
13 | +{ | ||
14 | + _serial->begin(115200); | ||
15 | +} | ||
16 | + | ||
17 | +void PN532_HSU::wakeup() | ||
18 | +{ | ||
19 | + _serial->write(0x55); | ||
20 | + _serial->write(0x55); | ||
21 | + _serial->write(0); | ||
22 | + _serial->write(0); | ||
23 | + _serial->write(0); | ||
24 | + | ||
25 | + /** dump serial buffer */ | ||
26 | + if(_serial->available()){ | ||
27 | + DMSG("Dump serial buffer: "); | ||
28 | + } | ||
29 | + while(_serial->available()){ | ||
30 | + uint8_t ret = _serial->read(); | ||
31 | + DMSG_HEX(ret); | ||
32 | + } | ||
33 | + | ||
34 | +} | ||
35 | + | ||
36 | +int8_t PN532_HSU::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
37 | +{ | ||
38 | + | ||
39 | + /** dump serial buffer */ | ||
40 | + if(_serial->available()){ | ||
41 | + DMSG("Dump serial buffer: "); | ||
42 | + } | ||
43 | + while(_serial->available()){ | ||
44 | + uint8_t ret = _serial->read(); | ||
45 | + DMSG_HEX(ret); | ||
46 | + } | ||
47 | + | ||
48 | + command = header[0]; | ||
49 | + | ||
50 | + _serial->write(PN532_PREAMBLE); | ||
51 | + _serial->write(PN532_STARTCODE1); | ||
52 | + _serial->write(PN532_STARTCODE2); | ||
53 | + | ||
54 | + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA | ||
55 | + _serial->write(length); | ||
56 | + _serial->write(~length + 1); // checksum of length | ||
57 | + | ||
58 | + _serial->write(PN532_HOSTTOPN532); | ||
59 | + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA | ||
60 | + | ||
61 | + DMSG("\nWrite: "); | ||
62 | + | ||
63 | + _serial->write(header, hlen); | ||
64 | + for (uint8_t i = 0; i < hlen; i++) { | ||
65 | + sum += header[i]; | ||
66 | + | ||
67 | + DMSG_HEX(header[i]); | ||
68 | + } | ||
69 | + | ||
70 | + _serial->write(body, blen); | ||
71 | + for (uint8_t i = 0; i < blen; i++) { | ||
72 | + sum += body[i]; | ||
73 | + | ||
74 | + DMSG_HEX(body[i]); | ||
75 | + } | ||
76 | + | ||
77 | + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA | ||
78 | + _serial->write(checksum); | ||
79 | + _serial->write(PN532_POSTAMBLE); | ||
80 | + | ||
81 | + return readAckFrame(); | ||
82 | +} | ||
83 | + | ||
84 | +int16_t PN532_HSU::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) | ||
85 | +{ | ||
86 | + uint8_t tmp[3]; | ||
87 | + | ||
88 | + DMSG("\nRead: "); | ||
89 | + | ||
90 | + /** Frame Preamble and Start Code */ | ||
91 | + if(receive(tmp, 3, timeout)<=0){ | ||
92 | + return PN532_TIMEOUT; | ||
93 | + } | ||
94 | + if(0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]){ | ||
95 | + DMSG("Preamble error"); | ||
96 | + return PN532_INVALID_FRAME; | ||
97 | + } | ||
98 | + | ||
99 | + /** receive length and check */ | ||
100 | + uint8_t length[2]; | ||
101 | + if(receive(length, 2, timeout) <= 0){ | ||
102 | + return PN532_TIMEOUT; | ||
103 | + } | ||
104 | + if( 0 != (uint8_t)(length[0] + length[1]) ){ | ||
105 | + DMSG("Length error"); | ||
106 | + return PN532_INVALID_FRAME; | ||
107 | + } | ||
108 | + length[0] -= 2; | ||
109 | + if( length[0] > len){ | ||
110 | + return PN532_NO_SPACE; | ||
111 | + } | ||
112 | + | ||
113 | + /** receive command byte */ | ||
114 | + uint8_t cmd = command + 1; // response command | ||
115 | + if(receive(tmp, 2, timeout) <= 0){ | ||
116 | + return PN532_TIMEOUT; | ||
117 | + } | ||
118 | + if( PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]){ | ||
119 | + DMSG("Command error"); | ||
120 | + return PN532_INVALID_FRAME; | ||
121 | + } | ||
122 | + | ||
123 | + if(receive(buf, length[0], timeout) != length[0]){ | ||
124 | + return PN532_TIMEOUT; | ||
125 | + } | ||
126 | + uint8_t sum = PN532_PN532TOHOST + cmd; | ||
127 | + for(uint8_t i=0; i<length[0]; i++){ | ||
128 | + sum += buf[i]; | ||
129 | + } | ||
130 | + | ||
131 | + /** checksum and postamble */ | ||
132 | + if(receive(tmp, 2, timeout) <= 0){ | ||
133 | + return PN532_TIMEOUT; | ||
134 | + } | ||
135 | + if( 0 != (uint8_t)(sum + tmp[0]) || 0 != tmp[1] ){ | ||
136 | + DMSG("Checksum error"); | ||
137 | + return PN532_INVALID_FRAME; | ||
138 | + } | ||
139 | + | ||
140 | + return length[0]; | ||
141 | +} | ||
142 | + | ||
143 | +int8_t PN532_HSU::readAckFrame() | ||
144 | +{ | ||
145 | + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; | ||
146 | + uint8_t ackBuf[sizeof(PN532_ACK)]; | ||
147 | + | ||
148 | + DMSG("\nAck: "); | ||
149 | + | ||
150 | + if( receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0 ){ | ||
151 | + DMSG("Timeout\n"); | ||
152 | + return PN532_TIMEOUT; | ||
153 | + } | ||
154 | + | ||
155 | + if( memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)) ){ | ||
156 | + DMSG("Invalid\n"); | ||
157 | + return PN532_INVALID_ACK; | ||
158 | + } | ||
159 | + return 0; | ||
160 | +} | ||
161 | + | ||
162 | +/** | ||
163 | + @brief receive data . | ||
164 | + @param buf --> return value buffer. | ||
165 | + len --> length expect to receive. | ||
166 | + timeout --> time of reveiving | ||
167 | + @retval number of received bytes, 0 means no data received. | ||
168 | +*/ | ||
169 | +int8_t PN532_HSU::receive(uint8_t *buf, int len, uint16_t timeout) | ||
170 | +{ | ||
171 | + int read_bytes = 0; | ||
172 | + int ret; | ||
173 | + unsigned long start_millis; | ||
174 | + | ||
175 | + while (read_bytes < len) { | ||
176 | + start_millis = millis(); | ||
177 | + do { | ||
178 | + ret = _serial->read(); | ||
179 | + if (ret >= 0) { | ||
180 | + break; | ||
181 | + } | ||
182 | + } while((timeout == 0) || ((millis()- start_millis ) < timeout)); | ||
183 | + | ||
184 | + if (ret < 0) { | ||
185 | + if(read_bytes){ | ||
186 | + return read_bytes; | ||
187 | + }else{ | ||
188 | + return PN532_TIMEOUT; | ||
189 | + } | ||
190 | + } | ||
191 | + buf[read_bytes] = (uint8_t)ret; | ||
192 | + DMSG_HEX(ret); | ||
193 | + read_bytes++; | ||
194 | + } | ||
195 | + return read_bytes; | ||
196 | +} |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | + | ||
2 | +#ifndef __PN532_HSU_H__ | ||
3 | +#define __PN532_HSU_H__ | ||
4 | + | ||
5 | +#include "PN532Interface.h" | ||
6 | +#include "Arduino.h" | ||
7 | + | ||
8 | +#define PN532_HSU_DEBUG | ||
9 | + | ||
10 | +#define PN532_HSU_READ_TIMEOUT (1000) | ||
11 | + | ||
12 | +class PN532_HSU : public PN532Interface { | ||
13 | +public: | ||
14 | + PN532_HSU(HardwareSerial &serial); | ||
15 | + | ||
16 | + void begin(); | ||
17 | + void wakeup(); | ||
18 | + virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
19 | + int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout); | ||
20 | + | ||
21 | +private: | ||
22 | + HardwareSerial* _serial; | ||
23 | + uint8_t command; | ||
24 | + | ||
25 | + int8_t readAckFrame(); | ||
26 | + | ||
27 | + int8_t receive(uint8_t *buf, int len, uint16_t timeout=PN532_HSU_READ_TIMEOUT); | ||
28 | +}; | ||
29 | + | ||
30 | +#endif |
@@ -0,0 +1,181 @@ | @@ -0,0 +1,181 @@ | ||
1 | + | ||
2 | +#include "PN532_I2C.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | +#include "Arduino.h" | ||
5 | + | ||
6 | +#define PN532_I2C_ADDRESS (0x48 >> 1) | ||
7 | + | ||
8 | + | ||
9 | +PN532_I2C::PN532_I2C(TwoWire &wire) | ||
10 | +{ | ||
11 | + _wire = &wire; | ||
12 | + command = 0; | ||
13 | +} | ||
14 | + | ||
15 | +void PN532_I2C::begin() | ||
16 | +{ | ||
17 | + _wire->begin(); | ||
18 | +} | ||
19 | + | ||
20 | +void PN532_I2C::wakeup() | ||
21 | +{ | ||
22 | + _wire->beginTransmission(PN532_I2C_ADDRESS); // I2C start | ||
23 | + delay(20); | ||
24 | + _wire->endTransmission(); // I2C end | ||
25 | +} | ||
26 | + | ||
27 | +int8_t PN532_I2C::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
28 | +{ | ||
29 | + command = header[0]; | ||
30 | + _wire->beginTransmission(PN532_I2C_ADDRESS); | ||
31 | + | ||
32 | + write(PN532_PREAMBLE); | ||
33 | + write(PN532_STARTCODE1); | ||
34 | + write(PN532_STARTCODE2); | ||
35 | + | ||
36 | + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA | ||
37 | + write(length); | ||
38 | + write(~length + 1); // checksum of length | ||
39 | + | ||
40 | + write(PN532_HOSTTOPN532); | ||
41 | + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA | ||
42 | + | ||
43 | + DMSG("write: "); | ||
44 | + | ||
45 | + for (uint8_t i = 0; i < hlen; i++) { | ||
46 | + if (write(header[i])) { | ||
47 | + sum += header[i]; | ||
48 | + | ||
49 | + DMSG_HEX(header[i]); | ||
50 | + } else { | ||
51 | + DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes | ||
52 | + return PN532_INVALID_FRAME; | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + for (uint8_t i = 0; i < blen; i++) { | ||
57 | + if (write(body[i])) { | ||
58 | + sum += body[i]; | ||
59 | + | ||
60 | + DMSG_HEX(body[i]); | ||
61 | + } else { | ||
62 | + DMSG("\nToo many data to send, I2C doesn't support such a big packet\n"); // I2C max packet: 32 bytes | ||
63 | + return PN532_INVALID_FRAME; | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA | ||
68 | + write(checksum); | ||
69 | + write(PN532_POSTAMBLE); | ||
70 | + | ||
71 | + _wire->endTransmission(); | ||
72 | + | ||
73 | + DMSG('\n'); | ||
74 | + | ||
75 | + return readAckFrame(); | ||
76 | +} | ||
77 | + | ||
78 | +int16_t PN532_I2C::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) | ||
79 | +{ | ||
80 | + uint16_t time = 0; | ||
81 | + | ||
82 | + do { | ||
83 | + if (_wire->requestFrom(PN532_I2C_ADDRESS, len + 2)) { | ||
84 | + if (read() & 1) { // check first byte --- status | ||
85 | + break; // PN532 is ready | ||
86 | + } | ||
87 | + } | ||
88 | + | ||
89 | + delay(1); | ||
90 | + time++; | ||
91 | + if ((0 != timeout) && (time > timeout)) { | ||
92 | + return -1; | ||
93 | + } | ||
94 | + } while (1); | ||
95 | + | ||
96 | + if (0x00 != read() || // PREAMBLE | ||
97 | + 0x00 != read() || // STARTCODE1 | ||
98 | + 0xFF != read() // STARTCODE2 | ||
99 | + ) { | ||
100 | + | ||
101 | + return PN532_INVALID_FRAME; | ||
102 | + } | ||
103 | + | ||
104 | + uint8_t length = read(); | ||
105 | + if (0 != (uint8_t)(length + read())) { // checksum of length | ||
106 | + return PN532_INVALID_FRAME; | ||
107 | + } | ||
108 | + | ||
109 | + uint8_t cmd = command + 1; // response command | ||
110 | + if (PN532_PN532TOHOST != read() || (cmd) != read()) { | ||
111 | + return PN532_INVALID_FRAME; | ||
112 | + } | ||
113 | + | ||
114 | + length -= 2; | ||
115 | + if (length > len) { | ||
116 | + return PN532_NO_SPACE; // not enough space | ||
117 | + } | ||
118 | + | ||
119 | + DMSG("read: "); | ||
120 | + DMSG_HEX(cmd); | ||
121 | + | ||
122 | + uint8_t sum = PN532_PN532TOHOST + cmd; | ||
123 | + for (uint8_t i = 0; i < length; i++) { | ||
124 | + buf[i] = read(); | ||
125 | + sum += buf[i]; | ||
126 | + | ||
127 | + DMSG_HEX(buf[i]); | ||
128 | + } | ||
129 | + DMSG('\n'); | ||
130 | + | ||
131 | + uint8_t checksum = read(); | ||
132 | + if (0 != (uint8_t)(sum + checksum)) { | ||
133 | + DMSG("checksum is not ok\n"); | ||
134 | + return PN532_INVALID_FRAME; | ||
135 | + } | ||
136 | + read(); // POSTAMBLE | ||
137 | + | ||
138 | + return length; | ||
139 | +} | ||
140 | + | ||
141 | +int8_t PN532_I2C::readAckFrame() | ||
142 | +{ | ||
143 | + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; | ||
144 | + uint8_t ackBuf[sizeof(PN532_ACK)]; | ||
145 | + | ||
146 | + DMSG("wait for ack at : "); | ||
147 | + DMSG(millis()); | ||
148 | + DMSG('\n'); | ||
149 | + | ||
150 | + uint16_t time = 0; | ||
151 | + do { | ||
152 | + if (_wire->requestFrom(PN532_I2C_ADDRESS, sizeof(PN532_ACK) + 1)) { | ||
153 | + if (read() & 1) { // check first byte --- status | ||
154 | + break; // PN532 is ready | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + delay(1); | ||
159 | + time++; | ||
160 | + if (time > PN532_ACK_WAIT_TIME) { | ||
161 | + DMSG("Time out when waiting for ACK\n"); | ||
162 | + return PN532_TIMEOUT; | ||
163 | + } | ||
164 | + } while (1); | ||
165 | + | ||
166 | + DMSG("ready at : "); | ||
167 | + DMSG(millis()); | ||
168 | + DMSG('\n'); | ||
169 | + | ||
170 | + | ||
171 | + for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { | ||
172 | + ackBuf[i] = read(); | ||
173 | + } | ||
174 | + | ||
175 | + if (memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK))) { | ||
176 | + DMSG("Invalid ACK\n"); | ||
177 | + return PN532_INVALID_ACK; | ||
178 | + } | ||
179 | + | ||
180 | + return 0; | ||
181 | +} |
@@ -0,0 +1,40 @@ | @@ -0,0 +1,40 @@ | ||
1 | + | ||
2 | +#ifndef __PN532_I2C_H__ | ||
3 | +#define __PN532_I2C_H__ | ||
4 | + | ||
5 | +#include <Wire.h> | ||
6 | +#include "PN532Interface.h" | ||
7 | + | ||
8 | +class PN532_I2C : public PN532Interface { | ||
9 | +public: | ||
10 | + PN532_I2C(TwoWire &wire); | ||
11 | + | ||
12 | + void begin(); | ||
13 | + void wakeup(); | ||
14 | + virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
15 | + int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout); | ||
16 | + | ||
17 | +private: | ||
18 | + TwoWire* _wire; | ||
19 | + uint8_t command; | ||
20 | + | ||
21 | + int8_t readAckFrame(); | ||
22 | + | ||
23 | + inline uint8_t write(uint8_t data) { | ||
24 | + #if ARDUINO >= 100 | ||
25 | + return _wire->write(data); | ||
26 | + #else | ||
27 | + return _wire->send(data); | ||
28 | + #endif | ||
29 | + } | ||
30 | + | ||
31 | + inline uint8_t read() { | ||
32 | + #if ARDUINO >= 100 | ||
33 | + return _wire->read(); | ||
34 | + #else | ||
35 | + return _wire->receive(); | ||
36 | + #endif | ||
37 | + } | ||
38 | +}; | ||
39 | + | ||
40 | +#endif |
@@ -0,0 +1,217 @@ | @@ -0,0 +1,217 @@ | ||
1 | +#include <util/delay.h> | ||
2 | +#include "PN532_SPI.h" | ||
3 | +#include "PN532_debug.h" | ||
4 | +#include "Arduino.h" | ||
5 | + | ||
6 | +#define STATUS_READ 2 | ||
7 | +#define DATA_WRITE 1 | ||
8 | +#define DATA_READ 3 | ||
9 | +#define delay(a) _delay_ms(a) | ||
10 | + | ||
11 | +void send_serial(unsigned char); | ||
12 | + | ||
13 | +PN532_SPI::PN532_SPI(SPIClass &spi, uint8_t ss) | ||
14 | +{ | ||
15 | + command = 0; | ||
16 | + _spi = &spi; | ||
17 | + _ss = ss; | ||
18 | +} | ||
19 | + | ||
20 | +void PN532_SPI::begin() | ||
21 | +{ | ||
22 | + pinMode(_ss, OUTPUT); | ||
23 | + | ||
24 | + _spi->begin(); | ||
25 | + _spi->setDataMode(SPI_MODE0); // PN532 only supports mode0 | ||
26 | + _spi->setBitOrder(LSBFIRST); | ||
27 | +#ifndef __SAM3X8E__ | ||
28 | + _spi->setClockDivider(SPI_CLOCK_DIV8); // set clock 2MHz(max: 5MHz) | ||
29 | +#else | ||
30 | + /** DUE spi library does not support SPI_CLOCK_DIV8 macro */ | ||
31 | + _spi->setClockDivider(42); // set clock 2MHz(max: 5MHz) | ||
32 | +#endif | ||
33 | + | ||
34 | +} | ||
35 | + | ||
36 | +void PN532_SPI::wakeup() | ||
37 | +{ | ||
38 | + send_serial('Z'); | ||
39 | + digitalWrite(_ss, LOW); | ||
40 | + send_serial('E'); | ||
41 | + delay(2); | ||
42 | + send_serial('R'); | ||
43 | + digitalWrite(_ss, HIGH); | ||
44 | + send_serial('T'); | ||
45 | +} | ||
46 | + | ||
47 | + | ||
48 | + | ||
49 | +int8_t PN532_SPI::writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
50 | +{ | ||
51 | + command = header[0]; | ||
52 | + writeFrame(header, hlen, body, blen); | ||
53 | + | ||
54 | + uint8_t timeout = PN532_ACK_WAIT_TIME; | ||
55 | + while (!isReady()) { | ||
56 | + delay(1); | ||
57 | + timeout--; | ||
58 | + if (0 == timeout) { | ||
59 | + DMSG("Time out when waiting for ACK\n"); | ||
60 | + return -2; | ||
61 | + } | ||
62 | + } | ||
63 | + if (readAckFrame()) { | ||
64 | + DMSG("Invalid ACK\n"); | ||
65 | + return PN532_INVALID_ACK; | ||
66 | + } | ||
67 | + return 0; | ||
68 | +} | ||
69 | + | ||
70 | +int16_t PN532_SPI::readResponse(uint8_t buf[], uint8_t len, uint16_t timeout) | ||
71 | +{ | ||
72 | + uint16_t time = 0; | ||
73 | + while (!isReady()) { | ||
74 | + delay(1); | ||
75 | + time++; | ||
76 | + if (timeout > 0 && time > timeout) { | ||
77 | + return PN532_TIMEOUT; | ||
78 | + } | ||
79 | + } | ||
80 | + | ||
81 | + digitalWrite(_ss, LOW); | ||
82 | + delay(1); | ||
83 | + | ||
84 | + int16_t result; | ||
85 | + do { | ||
86 | + write(DATA_READ); | ||
87 | + | ||
88 | + if (0x00 != read() || // PREAMBLE | ||
89 | + 0x00 != read() || // STARTCODE1 | ||
90 | + 0xFF != read() // STARTCODE2 | ||
91 | + ) { | ||
92 | + | ||
93 | + result = PN532_INVALID_FRAME; | ||
94 | + break; | ||
95 | + } | ||
96 | + | ||
97 | + uint8_t length = read(); | ||
98 | + if (0 != (uint8_t)(length + read())) { // checksum of length | ||
99 | + result = PN532_INVALID_FRAME; | ||
100 | + break; | ||
101 | + } | ||
102 | + | ||
103 | + uint8_t cmd = command + 1; // response command | ||
104 | + if (PN532_PN532TOHOST != read() || (cmd) != read()) { | ||
105 | + result = PN532_INVALID_FRAME; | ||
106 | + break; | ||
107 | + } | ||
108 | + | ||
109 | + DMSG("read: "); | ||
110 | + DMSG_HEX(cmd); | ||
111 | + | ||
112 | + length -= 2; | ||
113 | + if (length > len) { | ||
114 | + for (uint8_t i = 0; i < length; i++) { | ||
115 | + DMSG_HEX(read()); // dump message | ||
116 | + } | ||
117 | + DMSG("\nNot enough space\n"); | ||
118 | + read(); | ||
119 | + read(); | ||
120 | + result = PN532_NO_SPACE; // not enough space | ||
121 | + break; | ||
122 | + } | ||
123 | + | ||
124 | + uint8_t sum = PN532_PN532TOHOST + cmd; | ||
125 | + for (uint8_t i = 0; i < length; i++) { | ||
126 | + buf[i] = read(); | ||
127 | + sum += buf[i]; | ||
128 | + | ||
129 | + DMSG_HEX(buf[i]); | ||
130 | + } | ||
131 | + DMSG('\n'); | ||
132 | + | ||
133 | + uint8_t checksum = read(); | ||
134 | + if (0 != (uint8_t)(sum + checksum)) { | ||
135 | + DMSG("checksum is not ok\n"); | ||
136 | + result = PN532_INVALID_FRAME; | ||
137 | + break; | ||
138 | + } | ||
139 | + read(); // POSTAMBLE | ||
140 | + | ||
141 | + result = length; | ||
142 | + } while (0); | ||
143 | + | ||
144 | + digitalWrite(_ss, HIGH); | ||
145 | + | ||
146 | + return result; | ||
147 | +} | ||
148 | + | ||
149 | +boolean PN532_SPI::isReady() | ||
150 | +{ | ||
151 | + digitalWrite(_ss, LOW); | ||
152 | + | ||
153 | + write(STATUS_READ); | ||
154 | + uint8_t status = read() & 1; | ||
155 | + digitalWrite(_ss, HIGH); | ||
156 | + return status; | ||
157 | +} | ||
158 | + | ||
159 | +void PN532_SPI::writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen) | ||
160 | +{ | ||
161 | + digitalWrite(_ss, LOW); | ||
162 | + delay(2); // wake up PN532 | ||
163 | + | ||
164 | + write(DATA_WRITE); | ||
165 | + write(PN532_PREAMBLE); | ||
166 | + write(PN532_STARTCODE1); | ||
167 | + write(PN532_STARTCODE2); | ||
168 | + | ||
169 | + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA | ||
170 | + write(length); | ||
171 | + write(~length + 1); // checksum of length | ||
172 | + | ||
173 | + write(PN532_HOSTTOPN532); | ||
174 | + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA | ||
175 | + | ||
176 | + DMSG("write: "); | ||
177 | + | ||
178 | + for (uint8_t i = 0; i < hlen; i++) { | ||
179 | + write(header[i]); | ||
180 | + sum += header[i]; | ||
181 | + | ||
182 | + DMSG_HEX(header[i]); | ||
183 | + } | ||
184 | + for (uint8_t i = 0; i < blen; i++) { | ||
185 | + write(body[i]); | ||
186 | + sum += body[i]; | ||
187 | + | ||
188 | + DMSG_HEX(body[i]); | ||
189 | + } | ||
190 | + | ||
191 | + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA | ||
192 | + write(checksum); | ||
193 | + write(PN532_POSTAMBLE); | ||
194 | + | ||
195 | + digitalWrite(_ss, HIGH); | ||
196 | + | ||
197 | + DMSG('\n'); | ||
198 | +} | ||
199 | + | ||
200 | +int8_t PN532_SPI::readAckFrame() | ||
201 | +{ | ||
202 | + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; | ||
203 | + | ||
204 | + uint8_t ackBuf[sizeof(PN532_ACK)]; | ||
205 | + | ||
206 | + digitalWrite(_ss, LOW); | ||
207 | + delay(1); | ||
208 | + write(DATA_READ); | ||
209 | + | ||
210 | + for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { | ||
211 | + ackBuf[i] = read(); | ||
212 | + } | ||
213 | + | ||
214 | + digitalWrite(_ss, HIGH); | ||
215 | + | ||
216 | + return memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)); | ||
217 | +} |
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | + | ||
2 | +#ifndef __PN532_SPI_H__ | ||
3 | +#define __PN532_SPI_H__ | ||
4 | + | ||
5 | +#include <SPI.h> | ||
6 | +#include "PN532Interface.h" | ||
7 | + | ||
8 | +class PN532_SPI : public PN532Interface { | ||
9 | +public: | ||
10 | + PN532_SPI(SPIClass &spi, uint8_t ss); | ||
11 | + | ||
12 | + void begin(); | ||
13 | + void wakeup(); | ||
14 | + int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
15 | + | ||
16 | + int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout); | ||
17 | + | ||
18 | +private: | ||
19 | + SPIClass* _spi; | ||
20 | + uint8_t _ss; | ||
21 | + uint8_t command; | ||
22 | + | ||
23 | + boolean isReady(); | ||
24 | + void writeFrame(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0); | ||
25 | + int8_t readAckFrame(); | ||
26 | + | ||
27 | + inline void write(uint8_t data) { | ||
28 | + _spi->transfer(data); | ||
29 | + }; | ||
30 | + | ||
31 | + inline uint8_t read() { | ||
32 | + return _spi->transfer(0); | ||
33 | + }; | ||
34 | +}; | ||
35 | + | ||
36 | +#endif |
tweekd_nfc.ino renamed to main.c
1 | -#include <SPI.h> | ||
2 | -#include <PN532_SPI.h> | 1 | +#include <util/delay.h> |
2 | +#include <avr/io.h> | ||
3 | #include "PN532.h" | 3 | #include "PN532.h" |
4 | +#include <PN532_SPI/PN532_SPI.h> | ||
4 | 5 | ||
5 | #define MODEL_QUERY 0x80 | 6 | #define MODEL_QUERY 0x80 |
6 | #define SERIAL_ERROR 0x55 | 7 | #define SERIAL_ERROR 0x55 |
@@ -8,9 +9,9 @@ | @@ -8,9 +9,9 @@ | ||
8 | #define NFC_TAGQUERY_UID 0x84 | 9 | #define NFC_TAGQUERY_UID 0x84 |
9 | #define NFC_ARDUINO 0x02 | 10 | #define NFC_ARDUINO 0x02 |
10 | #define NFC_NOTAG 0x81 | 11 | #define NFC_NOTAG 0x81 |
11 | - | ||
12 | -#define NFC_TYPE_PROFESSOR 0x00 | 12 | +#define NFC_TYPE_PROFESSOR 0x04 |
13 | #define NFC_TYPE_STUDENT 0x01 | 13 | #define NFC_TYPE_STUDENT 0x01 |
14 | +#define CPU_FREQ 16000000L | ||
14 | 15 | ||
15 | boolean tagDetected; | 16 | boolean tagDetected; |
16 | boolean tagType; | 17 | boolean tagType; |
@@ -18,33 +19,56 @@ boolean tagType; | @@ -18,33 +19,56 @@ boolean tagType; | ||
18 | PN532_SPI pn532spi(SPI, 10); | 19 | PN532_SPI pn532spi(SPI, 10); |
19 | PN532 nfc(pn532spi); | 20 | PN532 nfc(pn532spi); |
20 | 21 | ||
22 | +void init_serial(int speed) | ||
23 | +{ | ||
24 | + UBRR0 = CPU_FREQ/(((unsigned long int)speed)<<4)-1; | ||
25 | + UCSR0B = (1<<TXEN0 | 1<<RXEN0); | ||
26 | + UCSR0C = (1<<UCSZ01 | 1<<UCSZ00); | ||
27 | + UCSR0A &= ~(1 << U2X0); | ||
28 | +} | ||
29 | + | ||
30 | +void send_serial(unsigned char c) | ||
31 | +{ | ||
32 | + loop_until_bit_is_set(UCSR0A, UDRE0); | ||
33 | + UDR0 = c; | ||
34 | +} | ||
35 | + | ||
36 | +unsigned char get_serial(void) | ||
37 | +{ | ||
38 | + loop_until_bit_is_set(UCSR0A, RXC0); | ||
39 | + return UDR0; | ||
40 | +} | ||
41 | + | ||
42 | + | ||
21 | void setup(void) | 43 | void setup(void) |
22 | { | 44 | { |
23 | int ser; | 45 | int ser; |
24 | 46 | ||
25 | - Serial.begin(115200); | 47 | + init_serial(9600); |
26 | 48 | ||
49 | + send_serial('1'); | ||
27 | nfc.begin(); | 50 | nfc.begin(); |
28 | 51 | ||
52 | + send_serial('2'); | ||
29 | uint32_t versiondata = nfc.getFirmwareVersion(); | 53 | uint32_t versiondata = nfc.getFirmwareVersion(); |
30 | if(!versiondata) | 54 | if(!versiondata) |
31 | { | 55 | { |
32 | - Serial.print(SERIAL_ERROR); | 56 | + send_serial(SERIAL_ERROR); |
33 | while (1); | 57 | while (1); |
34 | } | 58 | } |
35 | 59 | ||
60 | + send_serial('3'); | ||
36 | nfc.SAMConfig(); | 61 | nfc.SAMConfig(); |
37 | 62 | ||
38 | tagDetected = false; | 63 | tagDetected = false; |
39 | 64 | ||
40 | do | 65 | do |
41 | { | 66 | { |
42 | - while(!(Serial.available() > 0)); | ||
43 | - ser = Serial.read(); | 67 | + ser = get_serial(); |
44 | if(ser == MODEL_QUERY) | 68 | if(ser == MODEL_QUERY) |
45 | - Serial.print(NFC_ARDUINO); | 69 | + send_serial(NFC_ARDUINO); |
46 | else | 70 | else |
47 | - Serial.print(SERIAL_ERROR); | 71 | + send_serial(SERIAL_ERROR); |
48 | }while(ser != MODEL_QUERY); | 72 | }while(ser != MODEL_QUERY); |
49 | } | 73 | } |
50 | 74 | ||
@@ -56,7 +80,8 @@ void loop(void) | @@ -56,7 +80,8 @@ void loop(void) | ||
56 | uint8_t uidLength; | 80 | uint8_t uidLength; |
57 | uint8_t data1[16]; | 81 | uint8_t data1[16]; |
58 | uint8_t data2[16]; | 82 | uint8_t data2[16]; |
59 | - uint8_t dataf[8]; | 83 | + char professorTag[7]; |
84 | + char studentTag[9]; | ||
60 | int ser; | 85 | int ser; |
61 | 86 | ||
62 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); | 87 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); |
@@ -87,24 +112,24 @@ void loop(void) | @@ -87,24 +112,24 @@ void loop(void) | ||
87 | data1[9] == data2[4]) | 112 | data1[9] == data2[4]) |
88 | { | 113 | { |
89 | tagType = NFC_TYPE_PROFESSOR; | 114 | tagType = NFC_TYPE_PROFESSOR; |
90 | - dataf[0] = data1[4]; | ||
91 | - dataf[1] = data1[5]; | ||
92 | - dataf[2] = data1[6]; | ||
93 | - dataf[3] = data1[7]; | ||
94 | - dataf[4] = data1[8]; | ||
95 | - dataf[5] = data1[9]; | 115 | + professorTag[0] = (char) 48 + data1[4]; |
116 | + professorTag[1] = (char) 48 + data1[5]; | ||
117 | + professorTag[2] = (char) 48 + data1[6]; | ||
118 | + professorTag[3] = (char) 48 + data1[7]; | ||
119 | + professorTag[4] = (char) 48 + data1[8]; | ||
120 | + professorTag[5] = (char) 48 + data1[9]; | ||
96 | } | 121 | } |
97 | else | 122 | else |
98 | { | 123 | { |
99 | tagType = NFC_TYPE_STUDENT; | 124 | tagType = NFC_TYPE_STUDENT; |
100 | - dataf[0] = data1[15]; | ||
101 | - dataf[1] = data2[0]; | ||
102 | - dataf[2] = data2[1]; | ||
103 | - dataf[3] = data2[2]; | ||
104 | - dataf[4] = data2[3]; | ||
105 | - dataf[5] = data2[4]; | ||
106 | - dataf[6] = data2[5]; | ||
107 | - dataf[7] = data2[6]; | 125 | + studentTag[0] = (char) 48 + data1[15]; |
126 | + studentTag[1] = (char) 48 + data2[0]; | ||
127 | + studentTag[2] = (char) 48 + data2[1]; | ||
128 | + studentTag[3] = (char) 48 + data2[2]; | ||
129 | + studentTag[4] = (char) 48 + data2[3]; | ||
130 | + studentTag[5] = (char) 48 + data2[4]; | ||
131 | + studentTag[6] = (char) 48 + data2[5]; | ||
132 | + studentTag[7] = (char) 48 + data2[6]; | ||
108 | } | 133 | } |
109 | } | 134 | } |
110 | } | 135 | } |
@@ -113,32 +138,53 @@ void loop(void) | @@ -113,32 +138,53 @@ void loop(void) | ||
113 | } | 138 | } |
114 | else if(tagDetected) | 139 | else if(tagDetected) |
115 | { | 140 | { |
116 | - while(!(Serial.available() > 0)); | ||
117 | - ser = Serial.read(); | 141 | + ser = get_serial(); |
118 | if(ser == NFC_TAGQUERY) | 142 | if(ser == NFC_TAGQUERY) |
119 | - Serial.print(tagType); | 143 | + send_serial(tagType); |
120 | else if(ser == NFC_TAGQUERY_UID) | 144 | else if(ser == NFC_TAGQUERY_UID) |
121 | { | 145 | { |
122 | - Serial.print((char) dataf[0]); | ||
123 | - Serial.print((char) dataf[1]); | ||
124 | - Serial.print((char) dataf[2]); | ||
125 | - Serial.print((char) dataf[3]); | ||
126 | - Serial.print((char) dataf[4]); | ||
127 | - Serial.print((char) dataf[5]); | ||
128 | - if(tagType == NFC_TYPE_STUDENT) | ||
129 | - { | ||
130 | - Serial.print((char) dataf[6]); | ||
131 | - Serial.print((char) dataf[7]); | ||
132 | - } | ||
133 | - tagDetected = false; | 146 | + if(tagType == NFC_TYPE_STUDENT) |
147 | + {/* | ||
148 | + Serial.print((char) studentTag[0]); | ||
149 | + Serial.print((char) studentTag[1]); | ||
150 | + Serial.print((char) studentTag[2]); | ||
151 | + Serial.print((char) studentTag[3]); | ||
152 | + Serial.print((char) studentTag[4]); | ||
153 | + Serial.print((char) studentTag[5]); | ||
154 | + Serial.print((char) studentTag[6]); | ||
155 | + Serial.print((char) studentTag[7]);*/ | ||
156 | + send_serial(0x10); | ||
157 | + send_serial(0x20); | ||
158 | + send_serial(0x30); | ||
159 | + send_serial(0x40); | ||
160 | + send_serial(0x50); | ||
161 | + send_serial(0x60); | ||
162 | + send_serial(0x70); | ||
163 | + send_serial(0x80); | ||
164 | + } | ||
165 | + else | ||
166 | + { | ||
167 | + send_serial(professorTag[0]); | ||
168 | + } | ||
169 | + tagDetected = false; | ||
134 | } | 170 | } |
135 | else | 171 | else |
136 | - Serial.print(SERIAL_ERROR); | 172 | + send_serial((char) SERIAL_ERROR); |
137 | } | 173 | } |
138 | else | 174 | else |
139 | { | 175 | { |
140 | - if(Serial.available() > 0) | ||
141 | - if(Serial.read() == NFC_TAGQUERY) | ||
142 | - Serial.print(NFC_NOTAG); | 176 | + if(get_serial() == NFC_TAGQUERY) |
177 | + send_serial(NFC_NOTAG); | ||
143 | } | 178 | } |
144 | } | 179 | } |
180 | + | ||
181 | +int main(void) | ||
182 | +{ | ||
183 | + setup(); | ||
184 | + | ||
185 | + while(1) | ||
186 | + send_serial('Y'); | ||
187 | + //loop(); | ||
188 | + | ||
189 | + return 0; | ||
190 | +} |