1 /**************************************************************************/
5 /**************************************************************************/
13 #include "core/systick/systick.h"
14 #include "core/gpio/gpio.h"
15 #include "core/uart/uart.h"
17 /**************************************************************************/
19 @brief Builds a standard PN532 frame using the supplied data
21 @param pbtFrame Pointer to the field that will hold the frame data
22 @param pszFrame Pointer to the field that will hold the frame length
23 @param pbtData Pointer to the data to insert in a frame
24 @param swData Length of the data to insert in bytes
26 @note Possible error messages are:
28 - PN532_ERROR_EXTENDEDFRAME
30 /**************************************************************************/
31 pn532_error_t
pn532_bus_BuildFrame(byte_t
* pbtFrame
, size_t * pszFrame
, const byte_t
* pbtData
, const size_t szData
)
33 if (szData
> PN532_NORMAL_FRAME__DATA_MAX_LEN
)
35 // Extended frames currently unsupported
36 return PN532_ERROR_EXTENDEDFRAME
;
39 // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
40 pbtFrame
[3] = szData
+ 1;
41 // LCS - Packet length checksum
42 pbtFrame
[4] = 256 - (szData
+ 1);
45 // DATA - Copy the PN53X command into the packet buffer
46 memcpy (pbtFrame
+ 6, pbtData
, szData
);
48 // DCS - Calculate data payload checksum
49 byte_t btDCS
= (256 - 0xD4);
51 for (szPos
= 0; szPos
< szData
; szPos
++)
53 btDCS
-= pbtData
[szPos
];
55 pbtFrame
[6 + szData
] = btDCS
;
57 // 0x00 - End of stream marker
58 pbtFrame
[szData
+ 7] = 0x00;
60 (*pszFrame
) = szData
+ PN532_NORMAL_FRAME__OVERHEAD
;
62 return PN532_ERROR_NONE
;
65 /**************************************************************************/
67 @brief Initialises UART and configures the PN532
69 /**************************************************************************/
70 void pn532_bus_HWInit(void)
72 #ifdef PN532_DEBUGMODE
73 PN532_DEBUG("Initialising UART (%d)%s", PN532_UART_BAUDRATE
, CFG_PRINTF_NEWLINE
);
75 uartInit(PN532_UART_BAUDRATE
);
77 // Set reset pin as output and reset device
78 gpioSetDir(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, gpioDirection_Output
);
79 #ifdef PN532_DEBUGMODE
80 PN532_DEBUG("Resetting the PN532...\r\n");
82 gpioSetValue(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, 0);
84 gpioSetValue(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, 1);
86 // Wait for the PN532 to finish booting
90 /**************************************************************************/
92 @brief Sends the specified command to the PN532, automatically
93 creating an appropriate frame for it
95 @param pdbData Pointer to the byte data to send
96 @param szData Length in bytes of the data to send
98 @note Possible error messages are:
102 - PN532_ERROR_INVALIDACK
104 /**************************************************************************/
105 pn532_error_t
pn532_bus_SendCommand(const byte_t
* pbtData
, const size_t szData
)
107 pn532_pcb_t
*pn532
= pn532GetPCB();
109 // Check if we're busy
110 if (pn532
->state
== PN532_STATE_BUSY
)
112 return PN532_ERROR_BUSY
;
115 // Flag the stack as busy
116 pn532
->state
= PN532_STATE_BUSY
;
118 // Every packet must start with "00 00 ff"
119 byte_t abtFrame
[PN532_BUFFER_LEN
] = { 0x00, 0x00, 0xff };
123 pn532_bus_BuildFrame (abtFrame
, &szFrame
, pbtData
, szData
);
125 // Keep track of the last command that was sent
126 pn532
->lastCommand
= pbtData
[0];
128 // Output the frame data for debugging if requested
129 #ifdef PN532_DEBUGMODE
130 PN532_DEBUG("Sending (%02d): ", szFrame
);
131 pn532PrintHex(abtFrame
, szFrame
);
134 // Send data to the PN532
135 uartSend (abtFrame
, szFrame
);
139 uart_pcb_t
*uart
= uartGetPCB();
140 systickDelay(10); // FIXME: How long should we wait for ACK?
141 if (uart
->rxfifo
.len
< 6)
143 // Unable to read ACK
144 #ifdef PN532_DEBUGMODE
145 PN532_DEBUG ("Unable to read ACK%s", CFG_PRINTF_NEWLINE
);
147 pn532
->state
= PN532_STATE_READY
;
148 return PN532_ERROR_NOACK
;
151 // Read ACK ... this will also remove it from the buffer
152 const byte_t abtAck
[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
153 abtRxBuf
[0] = uartRxBufferRead();
154 abtRxBuf
[1] = uartRxBufferRead();
155 abtRxBuf
[2] = uartRxBufferRead();
156 abtRxBuf
[3] = uartRxBufferRead();
157 abtRxBuf
[4] = uartRxBufferRead();
158 abtRxBuf
[5] = uartRxBufferRead();
160 // Make sure the received ACK matches the prototype
161 if (0 != (memcmp (abtRxBuf
, abtAck
, 6)))
163 #ifdef PN532_DEBUGMODE
164 PN532_DEBUG ("Invalid ACK: ");
165 pn532PrintHex(abtRxBuf
, 6);
166 PN532_DEBUG("%s", CFG_PRINTF_NEWLINE
);
168 pn532
->state
= PN532_STATE_READY
;
169 return PN532_ERROR_INVALIDACK
;
172 pn532
->state
= PN532_STATE_READY
;
173 return PN532_ERROR_NONE
;
176 /**************************************************************************/
178 @brief Reads a response from the PN532
180 @note Possible error message are:
183 - PN532_ERROR_RESPONSEBUFFEREMPTY
184 - PN532_ERROR_PREAMBLEMISMATCH
185 - PN532_ERROR_APPLEVELERROR
186 - PN532_ERROR_EXTENDEDFRAME
187 - PN532_ERROR_LENCHECKSUMMISMATCH
189 /**************************************************************************/
190 pn532_error_t
pn532_bus_ReadResponse(byte_t
* pbtResponse
, size_t * pszRxLen
)
192 pn532_pcb_t
*pn532
= pn532GetPCB();
194 // Check if we're busy
195 if (pn532
->state
== PN532_STATE_BUSY
)
197 return PN532_ERROR_BUSY
;
200 // Flag the stack as busy
201 pn532
->state
= PN532_STATE_BUSY
;
203 // Reset the app error flag
204 pn532
->appError
= PN532_APPERROR_NONE
;
206 // Read response from uart
207 if (!uartRxBufferReadArray(pbtResponse
, pszRxLen
))
209 pn532
->state
= PN532_STATE_READY
;
210 return PN532_ERROR_RESPONSEBUFFEREMPTY
;
213 // Display the raw response data for debugging if requested
214 #ifdef PN532_DEBUGMODE
215 PN532_DEBUG("Received (%02d): ", *pszRxLen
);
216 pn532PrintHex(pbtResponse
, *pszRxLen
);
220 const byte_t pn53x_preamble
[3] = { 0x00, 0x00, 0xff };
221 if (0 != (memcmp (pbtResponse
, pn53x_preamble
, 3)))
223 #ifdef PN532_DEBUGMODE
224 PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE
);
226 pn532
->state
= PN532_STATE_READY
;
227 return PN532_ERROR_PREAMBLEMISMATCH
;
230 // Check the frame type
231 if ((0x01 == pbtResponse
[3]) && (0xff == pbtResponse
[4]))
234 #ifdef PN532_DEBUGMODE
235 PN532_DEBUG("Application level error (0x%02x)%s", pbtResponse
[5], CFG_PRINTF_NEWLINE
);
237 // Set application error message ID
238 pn532
->appError
= pbtResponse
[5];
239 pn532
->state
= PN532_STATE_READY
;
240 return PN532_ERROR_APPLEVELERROR
;
242 else if ((0xff == pbtResponse
[3]) && (0xff == pbtResponse
[4]))
245 #ifdef PN532_DEBUGMODE
246 PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE
);
248 pn532
->state
= PN532_STATE_READY
;
249 return PN532_ERROR_EXTENDEDFRAME
;
254 if (256 != (pbtResponse
[3] + pbtResponse
[4]))
257 #ifdef PN532_DEBUGMODE
258 PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE
);
260 pn532
->state
= PN532_STATE_READY
;
261 return PN532_ERROR_LENCHECKSUMMISMATCH
;
263 // size_t szPayloadLen = abtRx[3] - 2;
266 pn532
->state
= PN532_STATE_READY
;
267 return PN532_ERROR_NONE
;
270 /**************************************************************************/
272 @brief Sends the wakeup sequence to the PN532.
274 /**************************************************************************/
275 pn532_error_t
pn532_bus_Wakeup(void)
278 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 };
280 pn532_pcb_t
*pn532
= pn532GetPCB();
282 #ifdef PN532_DEBUGMODE
283 PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE
);
285 uartSend(abtWakeUp
,sizeof(abtWakeUp
));
289 pn532_bus_ReadResponse(response
, &szLen
);
291 // Todo: Check for error ... currently throws a checksum error
292 // that isn't really an error
294 pn532
->state
= PN532_STATE_READY
;
295 return PN532_ERROR_NONE
;
298 #endif // #ifdef PN532_BUS_UART