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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 78 | \ No newline at end of file | ... | ... |
PN532/examples/mifareclassic_formatndef/mifareclassic_formatndef.pde
0 → 100644
... | ... | @@ -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 | 171 | \ No newline at end of file | ... | ... |
PN532/examples/mifareclassic_memdump/mifareclassic_memdump.pde
0 → 100644
... | ... | @@ -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 | 158 | \ No newline at end of file | ... | ... |
PN532/examples/mifareclassic_ndeftoclassic/mifareclassic_ndeftoclassic.pde
0 → 100644
... | ... | @@ -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 | 173 | \ No newline at end of file | ... | ... |
PN532/examples/mifareclassic_updatendef/mifareclassic_updatendef.pde
0 → 100644
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 3 | #include "PN532.h" |
4 | +#include <PN532_SPI/PN532_SPI.h> | |
4 | 5 | |
5 | 6 | #define MODEL_QUERY 0x80 |
6 | 7 | #define SERIAL_ERROR 0x55 |
... | ... | @@ -8,9 +9,9 @@ |
8 | 9 | #define NFC_TAGQUERY_UID 0x84 |
9 | 10 | #define NFC_ARDUINO 0x02 |
10 | 11 | #define NFC_NOTAG 0x81 |
11 | - | |
12 | -#define NFC_TYPE_PROFESSOR 0x00 | |
12 | +#define NFC_TYPE_PROFESSOR 0x04 | |
13 | 13 | #define NFC_TYPE_STUDENT 0x01 |
14 | +#define CPU_FREQ 16000000L | |
14 | 15 | |
15 | 16 | boolean tagDetected; |
16 | 17 | boolean tagType; |
... | ... | @@ -18,33 +19,56 @@ boolean tagType; |
18 | 19 | PN532_SPI pn532spi(SPI, 10); |
19 | 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 | 43 | void setup(void) |
22 | 44 | { |
23 | 45 | int ser; |
24 | 46 | |
25 | - Serial.begin(115200); | |
47 | + init_serial(9600); | |
26 | 48 | |
49 | + send_serial('1'); | |
27 | 50 | nfc.begin(); |
28 | 51 | |
52 | + send_serial('2'); | |
29 | 53 | uint32_t versiondata = nfc.getFirmwareVersion(); |
30 | 54 | if(!versiondata) |
31 | 55 | { |
32 | - Serial.print(SERIAL_ERROR); | |
56 | + send_serial(SERIAL_ERROR); | |
33 | 57 | while (1); |
34 | 58 | } |
35 | 59 | |
60 | + send_serial('3'); | |
36 | 61 | nfc.SAMConfig(); |
37 | 62 | |
38 | 63 | tagDetected = false; |
39 | 64 | |
40 | 65 | do |
41 | 66 | { |
42 | - while(!(Serial.available() > 0)); | |
43 | - ser = Serial.read(); | |
67 | + ser = get_serial(); | |
44 | 68 | if(ser == MODEL_QUERY) |
45 | - Serial.print(NFC_ARDUINO); | |
69 | + send_serial(NFC_ARDUINO); | |
46 | 70 | else |
47 | - Serial.print(SERIAL_ERROR); | |
71 | + send_serial(SERIAL_ERROR); | |
48 | 72 | }while(ser != MODEL_QUERY); |
49 | 73 | } |
50 | 74 | |
... | ... | @@ -56,7 +80,8 @@ void loop(void) |
56 | 80 | uint8_t uidLength; |
57 | 81 | uint8_t data1[16]; |
58 | 82 | uint8_t data2[16]; |
59 | - uint8_t dataf[8]; | |
83 | + char professorTag[7]; | |
84 | + char studentTag[9]; | |
60 | 85 | int ser; |
61 | 86 | |
62 | 87 | success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); |
... | ... | @@ -87,24 +112,24 @@ void loop(void) |
87 | 112 | data1[9] == data2[4]) |
88 | 113 | { |
89 | 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 | 122 | else |
98 | 123 | { |
99 | 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 | 138 | } |
114 | 139 | else if(tagDetected) |
115 | 140 | { |
116 | - while(!(Serial.available() > 0)); | |
117 | - ser = Serial.read(); | |
141 | + ser = get_serial(); | |
118 | 142 | if(ser == NFC_TAGQUERY) |
119 | - Serial.print(tagType); | |
143 | + send_serial(tagType); | |
120 | 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 | 171 | else |
136 | - Serial.print(SERIAL_ERROR); | |
172 | + send_serial((char) SERIAL_ERROR); | |
137 | 173 | } |
138 | 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 | +} | ... | ... |