Initial commit
[hackover2013-badge-firmware.git] / drivers / sensors / pn532 / pn532_drvr_uart.c
1 /**************************************************************************/
2 /*!
3 @file pn532_drvr_uart.c
4 */
5 /**************************************************************************/
6 #include <string.h>
7
8 #include "pn532.h"
9 #include "pn532_drvr.h"
10
11 #ifdef PN532_UART
12
13 #include "core/systick/systick.h"
14 #include "core/gpio/gpio.h"
15 #include "core/uart/uart.h"
16
17 /**************************************************************************/
18 /*!
19 @brief Initialises UART and configures the PN532
20 */
21 /**************************************************************************/
22 void pn532HWInit(void)
23 {
24 PN532_DEBUG("Initialising UART (%d)%s", PN532_UART_BAUDRATE, CFG_PRINTF_NEWLINE);
25 uartInit(PN532_UART_BAUDRATE);
26
27 // Set reset pin as output and reset device
28 gpioSetDir(PN532_RSTPD_PORT, PN532_RSTPD_PIN, gpioDirection_Output);
29 PN532_DEBUG("Resetting the PN532...\r\n");
30 gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 0);
31 systickDelay(400);
32 gpioSetValue(PN532_RSTPD_PORT, PN532_RSTPD_PIN, 1);
33
34 // Wait for the PN532 to finish booting
35 systickDelay(100);
36 }
37
38 /**************************************************************************/
39 /*!
40 @brief Builds a standard PN532 frame using the supplied data
41
42 @param pbtFrame Pointer to the field that will hold the frame data
43 @param pszFrame Pointer to the field that will hold the frame length
44 @param pbtData Pointer to the data to insert in a frame
45 @param swData Length of the data to insert in bytes
46
47 @note Possible error messages are:
48
49 - PN532_ERROR_EXTENDEDFRAME
50 */
51 /**************************************************************************/
52 pn532_error_t pn532BuildFrame(byte_t * pbtFrame, size_t * pszFrame, const byte_t * pbtData, const size_t szData)
53 {
54 if (szData > PN532_NORMAL_FRAME__DATA_MAX_LEN)
55 {
56 // Extended frames currently unsupported
57 return PN532_ERROR_EXTENDEDFRAME;
58 }
59
60 // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
61 pbtFrame[3] = szData + 1;
62 // LCS - Packet length checksum
63 pbtFrame[4] = 256 - (szData + 1);
64 // TFI
65 pbtFrame[5] = 0xD4;
66 // DATA - Copy the PN53X command into the packet buffer
67 memcpy (pbtFrame + 6, pbtData, szData);
68
69 // DCS - Calculate data payload checksum
70 byte_t btDCS = (256 - 0xD4);
71 size_t szPos;
72 for (szPos = 0; szPos < szData; szPos++)
73 {
74 btDCS -= pbtData[szPos];
75 }
76 pbtFrame[6 + szData] = btDCS;
77
78 // 0x00 - End of stream marker
79 pbtFrame[szData + 7] = 0x00;
80
81 (*pszFrame) = szData + PN532_NORMAL_FRAME__OVERHEAD;
82
83 return PN532_ERROR_NONE;
84 }
85
86 /**************************************************************************/
87 /*!
88 @brief Sends the specified command to the PN532, automatically
89 creating an appropriate frame for it
90
91 @param pdbData Pointer to the byte data to send
92 @param szData Length in bytes of the data to send
93
94 @note Possible error messages are:
95
96 - PN532_ERROR_BUSY
97 - PN532_ERROR_NOACK
98 - PN532_ERROR_INVALIDACK
99 */
100 /**************************************************************************/
101 pn532_error_t pn532SendCommand(const byte_t * pbtData, const size_t szData)
102 {
103 pn532_pcb_t *pn532 = pn532GetPCB();
104
105 // Check if we're busy
106 if (pn532->state == PN532_STATE_BUSY)
107 {
108 return PN532_ERROR_BUSY;
109 }
110
111 // Flag the stack as busy
112 pn532->state = PN532_STATE_BUSY;
113
114 // Every packet must start with "00 00 ff"
115 byte_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff };
116 size_t szFrame = 0;
117
118 // Build the frame
119 pn532BuildFrame (abtFrame, &szFrame, pbtData, szData);
120
121 // Keep track of the last command that was sent
122 pn532->lastCommand = pbtData[0];
123
124 // Output the frame data for debugging if requested
125 PN532_DEBUG("Sending (%02d): ", szFrame);
126 pn532PrintHex(abtFrame, szFrame);
127
128 // Send data to the PN532
129 uartSend (abtFrame, szFrame);
130
131 // Wait for ACK
132 byte_t abtRxBuf[6];
133 uart_pcb_t *uart = uartGetPCB();
134 systickDelay(10); // FIXME: How long should we wait for ACK?
135 if (uart->rxfifo.len < 6)
136 {
137 // Unable to read ACK
138 PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE);
139 pn532->state = PN532_STATE_READY;
140 return PN532_ERROR_NOACK;
141 }
142
143 // Read ACK ... this will also remove it from the buffer
144 const byte_t abtAck[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
145 abtRxBuf[0] = uartRxBufferRead();
146 abtRxBuf[1] = uartRxBufferRead();
147 abtRxBuf[2] = uartRxBufferRead();
148 abtRxBuf[3] = uartRxBufferRead();
149 abtRxBuf[4] = uartRxBufferRead();
150 abtRxBuf[5] = uartRxBufferRead();
151
152 // Make sure the received ACK matches the prototype
153 if (0 != (memcmp (abtRxBuf, abtAck, 6)))
154 {
155 PN532_DEBUG ("Invalid ACK: ");
156 pn532PrintHex(abtRxBuf, 6);
157 PN532_DEBUG("%s", CFG_PRINTF_NEWLINE);
158 pn532->state = PN532_STATE_READY;
159 return PN532_ERROR_INVALIDACK;
160 }
161
162 pn532->state = PN532_STATE_READY;
163 return PN532_ERROR_NONE;
164 }
165
166 /**************************************************************************/
167 /*!
168 @brief Reads a response from the PN532
169
170 @note Possible error message are:
171
172 - PN532_ERROR_BUSY
173 - PN532_ERROR_RESPONSEBUFFEREMPTY
174 - PN532_ERROR_PREAMBLEMISMATCH
175 - PN532_ERROR_APPLEVELERROR
176 - PN532_ERROR_EXTENDEDFRAME
177 - PN532_ERROR_LENCHECKSUMMISMATCH
178 */
179 /**************************************************************************/
180 pn532_error_t pn532ReadResponse(byte_t * pbtResponse, size_t * pszRxLen)
181 {
182 pn532_pcb_t *pn532 = pn532GetPCB();
183
184 // Check if we're busy
185 if (pn532->state == PN532_STATE_BUSY)
186 {
187 return PN532_ERROR_BUSY;
188 }
189
190 // Flag the stack as busy
191 pn532->state = PN532_STATE_BUSY;
192
193 // Reset the app error flag
194 pn532->appError = PN532_APPERROR_NONE;
195
196 // Read response from uart
197 if (!uartRxBufferReadArray(pbtResponse, pszRxLen))
198 {
199 pn532->state = PN532_STATE_READY;
200 return PN532_ERROR_RESPONSEBUFFEREMPTY;
201 }
202
203 // Display the raw response data for debugging if requested
204 PN532_DEBUG("Received (%02d): ", *pszRxLen);
205 pn532PrintHex(pbtResponse, *pszRxLen);
206
207 // Check preamble
208 const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
209 if (0 != (memcmp (pbtResponse, pn53x_preamble, 3)))
210 {
211 PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE);
212 pn532->state = PN532_STATE_READY;
213 return PN532_ERROR_PREAMBLEMISMATCH;
214 }
215
216 // Check the frame type
217 if ((0x01 == pbtResponse[3]) && (0xff == pbtResponse[4]))
218 {
219 // Error frame
220 PN532_DEBUG("Application level error (%02d)%s", pbtResponse[5], CFG_PRINTF_NEWLINE);
221 // Set application error message ID
222 pn532->appError = pbtResponse[5];
223 pn532->state = PN532_STATE_READY;
224 return PN532_ERROR_APPLEVELERROR;
225 }
226 else if ((0xff == pbtResponse[3]) && (0xff == pbtResponse[4]))
227 {
228 // Extended frame
229 PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE);
230 pn532->state = PN532_STATE_READY;
231 return PN532_ERROR_EXTENDEDFRAME;
232 }
233 else
234 {
235 // Normal frame
236 if (256 != (pbtResponse[3] + pbtResponse[4]))
237 {
238 // TODO: Retry
239 PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE);
240 pn532->state = PN532_STATE_READY;
241 return PN532_ERROR_LENCHECKSUMMISMATCH;
242 }
243 // size_t szPayloadLen = abtRx[3] - 2;
244 }
245
246 pn532->state = PN532_STATE_READY;
247 return PN532_ERROR_NONE;
248 }
249
250 /**************************************************************************/
251 /*!
252 @brief Sends the wakeup sequence to the PN532.
253 */
254 /**************************************************************************/
255 pn532_error_t pn532Wakeup(void)
256 {
257 size_t szLen;
258 byte_t abtWakeUp[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
259
260 pn532_pcb_t *pn532 = pn532GetPCB();
261
262 PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE);
263 uartSend(abtWakeUp,sizeof(abtWakeUp));
264 systickDelay(100);
265
266 byte_t response[32];
267 pn532ReadResponse(response, &szLen);
268
269 // Todo: Check for error ... currently throws a checksum error
270 // that isn't really an error
271
272 pn532->state = PN532_STATE_READY;
273 return PN532_ERROR_NONE;
274 }
275
276 #endif // #ifdef PN532_UART
This page took 0.054906 seconds and 5 git commands to generate.