f55621ab5d4977ea9d394d2f883acc86979f2d0c
[hackover2013-badge-firmware.git] / drivers / sensors / pn532 / pn532_drvr_spi.c
1 /**************************************************************************/
2 /*!
3 @file pn532_drvr_spi.c
4 */
5 /**************************************************************************/
6 #include "pn532_drvr.h"
7
8 #ifdef PN532_SPI
9
10 #include <string.h>
11 #include "core/systick/systick.h"
12 #include "core/gpio/gpio.h"
13 #include "core/ssp/ssp.h"
14
15 #define PN532_SELECT gpioSetValue(PN532_SPI_CSPORT, PN532_SPI_CSPIN, 0);
16 #define PN532_DESELECT gpioSetValue(PN532_SPI_CSPORT, PN532_SPI_CSPIN, 1);
17
18 #define PN532_SPI_STATREAD 0x02
19 #define PN532_SPI_DATAWRITE 0x01
20 #define PN532_SPI_DATAREAD 0x03
21 #define PN532_SPI_READY 0x01
22
23 // The number of attempts to make while waiting for the status ready bit
24 // Each attempt is 1ms
25 #define PN532_SPI_TIMEOUT 100
26
27 /**************************************************************************/
28 /*!
29 @brief Writes a single byte via SPI
30 */
31 /**************************************************************************/
32 uint8_t pn532SPIWrite(unsigned char data)
33 {
34 // Note: bits have to be reversed since SPI is LSB on the PN532
35 // Thankfully the M3 has a quick HW reverse command (RBIT)
36 while ((SSP_SSP0SR & SSP_SSP0SR_TNF_NOTFULL) == 0);
37 SSP_SSP0DR = ((unsigned char)(RBIT(data)>>24)); // Write
38 while ((SSP_SSP0SR & SSP_SSP0SR_RNE_NOTEMPTY) == 0);
39 data = ((unsigned char)(RBIT(SSP_SSP0DR)>>24)); // Read
40 return data;
41 }
42
43 /**************************************************************************/
44 /*!
45 @brief Writes a byte array via SPI
46 */
47 /**************************************************************************/
48 void pn532SPIWriteArray(byte_t * pbtData, size_t len)
49 {
50 while (len != 0)
51 {
52 pn532SPIWrite(*pbtData);
53 pbtData++;
54 len--;
55 }
56 }
57
58 /**************************************************************************/
59 /*!
60 @brief Reads a single byte via SPI
61 */
62 /**************************************************************************/
63 uint8_t pn532SPIRead(void)
64 {
65 return pn532SPIWrite(0x00);
66 }
67
68 /**************************************************************************/
69 /*!
70 @brief Reads a byte array via SPI
71 */
72 /**************************************************************************/
73 void pn532SPIReadArray(uint8_t* buff, size_t len)
74 {
75 size_t i;
76 for (i=0; i<len; i++)
77 {
78 buff[i] = pn532SPIRead();
79 }
80 }
81
82
83 /**************************************************************************/
84 /*!
85 @brief Sends a status request (SPI only)
86 */
87 /**************************************************************************/
88 uint8_t pn532GetStatus()
89 {
90 unsigned char res;
91
92 // Send SPI status request
93 PN532_SELECT;
94 pn532SPIWrite(PN532_SPI_STATREAD);
95 res = pn532SPIRead();
96 PN532_DESELECT;
97
98 return res;
99 }
100
101 /**************************************************************************/
102 /*!
103 @brief Initialises SPI and configures the PN532
104 */
105 /**************************************************************************/
106 void pn532HWInit(void)
107 {
108 PN532_DEBUG("Initialising SPI %s", CFG_PRINTF_NEWLINE);
109 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
110
111 // Configure CS pin
112 gpioSetDir(PN532_SPI_CSPORT, PN532_SPI_CSPIN, gpioDirection_Output);
113 PN532_DESELECT;
114
115 // Reset PN532 and wait for it to finish booting
116 gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
117 PN532_DEBUG("Resetting the PN532...\r\n");
118 gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
119 systickDelay(400);
120 gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
121 systickDelay(100);
122 }
123
124 /**************************************************************************/
125 /*!
126 @brief Builds a standard PN532 frame using the supplied data
127
128 @param pbtFrame Pointer to the field that will hold the frame data
129 @param pszFrame Pointer to the field that will hold the frame length
130 @param pbtData Pointer to the data to insert in a frame
131 @param swData Length of the data to insert in bytes
132
133 @note Possible error messages are:
134
135 - PN532_ERROR_EXTENDEDFRAME
136 */
137 /**************************************************************************/
138 pn532_error_t pn532BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
139 {
140 if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
141 {
142 // Extended frames currently unsupported
143 return PN532_ERROR_EXTENDEDFRAME;
144 }
145
146 // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
147 pbtFrame[3] = szData + 1;
148 // LCS - Packet length checksum
149 pbtFrame[4] = 256 - (szData + 1);
150 // TFI
151 pbtFrame[5] = 0xD4;
152 // DATA - Copy the PN53X command into the packet buffer
153 memcpy (pbtFrame + 6, pbtData, szData);
154
155 // DCS - Calculate data payload checksum
156 byte_t btDCS = (256 - 0xD4);
157 size_t szPos;
158 for (szPos = 0; szPos < szData; szPos++)
159 {
160 btDCS -= pbtData[szPos];
161 }
162 pbtFrame[6 + szData] = btDCS;
163
164 // 0x00 - End of stream marker
165 pbtFrame[szData + 7] = 0x00;
166
167 (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
168
169 return PN532_ERROR_NONE;
170 }
171
172 /**************************************************************************/
173 /*!
174 @brief Sends the specified command to the PN532, automatically
175 creating an appropriate frame for it
176
177 @param pdbData Pointer to the byte data to send
178 @param szData Length in bytes of the data to send
179
180 @note Possible error messages are:
181
182 - PN532_ERROR_BUSY
183 - PN532_ERROR_NOACK
184 - PN532_ERROR_INVALIDACK
185 - PN532_ERROR_SPIREADYSTATUSTIMEOUT
186 */
187 /**************************************************************************/
188 pn532_error_t pn532SendCommand(const byte_t * pbtData, const size_t szData)
189 {
190 pn532_pcb_t *pn532 = pn532GetPCB();
191
192 // Check busy flag
193 if (pn532->state == PN532_STATE_BUSY)
194 {
195 return PN532_ERROR_BUSY;
196 }
197 pn532->state = PN532_STATE_BUSY;
198
199 // Every packet must start with "00 00 ff"
200 byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
201 size_t szFrame = 0;
202
203 // Build the frame
204 pn532BuildFrame (abtFrame, &szFrame, pbtData, szData);
205
206 // Register the last command that was sent
207 pn532->lastCommand = pbtData[0];
208
209 // Output the frame data for debugging if requested
210 PN532_DEBUG("Sending (%02d): ", szFrame);
211 pn532PrintHex(abtFrame, szFrame);
212
213 PN532_SELECT;
214 systickDelay(5);
215
216 // Send data to the PN532
217 pn532SPIWrite(PN532_SPI_DATAWRITE);
218 pn532SPIWriteArray(abtFrame, szFrame);
219
220 // Wait for READY status
221 size_t t = 0;
222 while (pn532GetStatus() != PN532_SPI_READY)
223 {
224 if(t++>PN532_SPI_TIMEOUT)
225 {
226 PN532_DEBUG("Timeout waiting for READY status%s", CFG_PRINTF_NEWLINE);
227 pn532->state = PN532_STATE_READY;
228 return PN532_ERROR_SPIREADYSTATUSTIMEOUT;
229 }
230 systickDelay(1);
231 }
232
233 // Read ACK
234 PN532_SELECT;
235 pn532SPIWrite(PN532_SPI_DATAREAD);
236 const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
237 byte_t abtRxBuf[6];
238 pn532SPIReadArray(abtRxBuf, 6);
239 PN532_DESELECT;
240
241 // Make sure the received ACK matches the prototype
242 if (0 != (memcmp (abtRxBuf, abtAck, 6)))
243 {
244 PN532_DEBUG ("Invalid ACK: ");
245 pn532PrintHex(abtRxBuf, 6);
246 PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
247 pn532->state = PN532_STATE_READY;
248 return PN532_ERROR_INVALIDACK;
249 }
250
251 pn532->state = PN532_STATE_READY;
252 return PN532_ERROR_NONE;
253 }
254
255 /**************************************************************************/
256 /*!
257 @brief Reads a response from the PN532
258
259 @note Possible error message are:
260
261 - PN532_ERROR_BUSY
262 - PN532_ERROR_RESPONSEBUFFEREMPTY
263 - PN532_ERROR_PREAMBLEMISMATCH
264 - PN532_ERROR_APPLEVELERROR
265 - PN532_ERROR_EXTENDEDFRAME
266 - PN532_ERROR_LENCHECKSUMMISMATCH
267 - PN532_ERROR_SPIREADYSTATUSTIMEOUT
268 */
269 /**************************************************************************/
270 pn532_error_t pn532ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
271 {
272 size_t t, i;
273 pn532_pcb_t *pn532 = pn532GetPCB();
274
275 // Check if we're busy
276 if (pn532->state == PN532_STATE_BUSY)
277 {
278 return PN532_ERROR_BUSY;
279 }
280 pn532->state = PN532_STATE_BUSY;
281 pn532->appError = PN532_APPERROR_NONE;
282
283 // Wait for the response ready signal
284 t = 0;
285 while (pn532GetStatus() != PN532_SPI_READY)
286 {
287 if(t++>PN532_SPI_TIMEOUT)
288 {
289 PN532_DEBUG("Timeout waiting for READY status%s", CFG_PRINTF_NEWLINE);
290 pn532->state = PN532_STATE_READY;
291 return PN532_ERROR_SPIREADYSTATUSTIMEOUT;
292 }
293 systickDelay(1);
294 }
295
296 PN532_SELECT;
297 systickDelay(1);
298
299 pn532SPIWrite(PN532_SPI_DATAREAD);
300
301 // Check preamble
302 pbtResponse[0] = pn532SPIRead();
303 pbtResponse[1] = pn532SPIRead();
304 pbtResponse[2] = pn532SPIRead();
305 const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
306 if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
307 {
308 PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
309 pn532->state = PN532_STATE_READY;
310 return PN532_ERROR_PREAMBLEMISMATCH;
311 }
312
313 // Check the frame type
314 pbtResponse[3] = pn532SPIRead();
315 pbtResponse[4] = pn532SPIRead();
316 pbtResponse[5] = pn532SPIRead();
317 if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
318 {
319 // Error frame
320 PN532_DEBUG("Application level error (%02d)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
321 // Set application error message ID
322 pn532->appError = pbtResponse[5];
323 pn532->state = PN532_STATE_READY;
324 return PN532_ERROR_APPLEVELERROR;
325 }
326 else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
327 {
328 // Extended frame
329 PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
330 pn532->state = PN532_STATE_READY;
331 return PN532_ERROR_EXTENDEDFRAME;
332 }
333 else
334 {
335 // Check checksum, unless this is a response to the wakeup command
336 if (pn532->lastCommand = PN532_COMMAND_SAMCONFIGURATION)
337 {
338 *pszRxLen = 6;
339 }
340 else
341 {
342 // Normal frame
343 if (256 != (pbtResponse[3] + pbtResponse[4]))
344 {
345 // TODO: Retry
346 PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
347 pn532PrintHex(pbtResponse, 6);
348 pn532->state = PN532_STATE_READY;
349 return PN532_ERROR_LENCHECKSUMMISMATCH;
350 }
351 // Read payload
352 size_t szPayloadLen = pbtResponse[3] - 2;
353 for (i=0; i<szPayloadLen; i++)
354 {
355 pbtResponse[i+6] = pn532SPIRead();
356 }
357 // Get checksum and postamble
358 pbtResponse[i+7] = pn532SPIRead();
359 pbtResponse[i+8] = pn532SPIRead();
360 pbtResponse[i+9] = pn532SPIRead();
361 // Set frame length
362 *pszRxLen = i + 10;
363 }
364 }
365
366 // Display the raw response data for debugging if requested
367 PN532_DEBUG("Received (%02d): ", *pszRxLen);
368 pn532PrintHex(pbtResponse, *pszRxLen);
369
370 pn532->state = PN532_STATE_READY;
371 return PN532_ERROR_NONE;
372 }
373
374 /**************************************************************************/
375 /*!
376 @brief Sends the wakeup sequence to the PN532.
377 */
378 /**************************************************************************/
379 pn532_error_t pn532Wakeup(void)
380 {
381 size_t szLen;
382 byte_t abtWakeUp[] = { 0x01,0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
383 // byte_t abtWakeUp[] = { 0x01,0x00,0x00,0xff,0x03,0xfd,0xd4,PN532_COMMAND_SAMCONFIGURATION,0x01,0x17,0x00 };
384
385 pn532_pcb_t *pn532 = pn532GetPCB();
386
387 PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
388
389 PN532_SELECT;
390 systickDelay(2);
391
392 // Transmit wakeup sequence
393 pn532SPIWriteArray(abtWakeUp, sizeof(abtWakeUp));
394 systickDelay(100);
395
396 // Register the last command that was sent
397 pn532->lastCommand = PN532_COMMAND_SAMCONFIGURATION;
398
399 byte_t response[32];
400 pn532ReadResponse(response, &szLen);
401 PN532_DESELECT;
402
403 // Todo: Check for error ... currently throws a checksum error
404 // that isn't really an error
405
406 pn532->state = PN532_STATE_READY;
407 return PN532_ERROR_NONE;
408 }
409
410 #endif // #ifdef PN532_SPI
This page took 0.060909 seconds and 3 git commands to generate.