2013-02-28 23:24:42 +01:00
/*-
* Public platform independent Near Field Communication ( NFC ) library
*
* Copyright ( C ) 2013 Evgeny Boger
* Copyright ( C ) 2010 Roel Verdult
* Copyright ( C ) 2011 Romain Tarti ? re
* Copyright ( C ) 2010 , 2011 , 2012 Romuald Conty
*
* This program is free software : you can redistribute it and / or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation , either version 3 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>
*/
/**
* @ file pn532_spi . c
* @ brief PN532 driver using SPI bus
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif // HAVE_CONFIG_H
# include "pn532_spi.h"
# include <stdio.h>
# include <inttypes.h>
# include <string.h>
# include <nfc/nfc.h>
# include "drivers.h"
# include "nfc-internal.h"
# include "chips/pn53x.h"
# include "chips/pn53x-internal.h"
# include "spi.h"
# define PN532_SPI_DEFAULT_SPEED 1000000 // 1 MHz
# define PN532_SPI_DRIVER_NAME "pn532_spi"
# define PN532_SPI_MODE SPI_MODE_0
# define LOG_CATEGORY "libnfc.driver.pn532_spi"
# define LOG_GROUP NFC_LOG_GROUP_DRIVER
2013-03-08 23:30:21 +01:00
# ifndef _WIN32
// Needed by sleep() under Unix
# include <unistd.h>
# include <time.h>
# define msleep(x) do { \
2013-03-10 00:29:01 +01:00
struct timespec xsleep ; \
xsleep . tv_sec = x / 1000 ; \
xsleep . tv_nsec = ( x - xsleep . tv_sec * 1000 ) * 1000 * 1000 ; \
nanosleep ( & xsleep , NULL ) ; \
} while ( 0 )
2013-03-08 23:30:21 +01:00
# else
// Needed by Sleep() under Windows
# include <winbase.h>
# define msleep Sleep
# endif
2013-02-28 23:24:42 +01:00
// Internal data structs
const struct pn53x_io pn532_spi_io ;
struct pn532_spi_data {
spi_port port ;
volatile bool abort_flag ;
} ;
static const uint8_t pn532_spi_cmd_dataread = 0x03 ;
static const uint8_t pn532_spi_cmd_datawrite = 0x01 ;
// Prototypes
int pn532_spi_ack ( nfc_device * pnd ) ;
int pn532_spi_wakeup ( nfc_device * pnd ) ;
# define DRIVER_DATA(pnd) ((struct pn532_spi_data*)(pnd->driver_data))
static size_t
pn532_spi_scan ( const nfc_context * context , nfc_connstring connstrings [ ] , const size_t connstrings_len )
{
size_t device_found = 0 ;
spi_port sp ;
char * * acPorts = spi_list_ports ( ) ;
const char * acPort ;
int iDevice = 0 ;
while ( ( acPort = acPorts [ iDevice + + ] ) ) {
sp = spi_open ( acPort ) ;
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " Trying to find PN532 device on SPI port: %s at %d Hz. " , acPort , PN532_SPI_DEFAULT_SPEED ) ;
if ( ( sp ! = INVALID_SPI_PORT ) & & ( sp ! = CLAIMED_SPI_PORT ) ) {
// We need to flush input to be sure first reply does not comes from older byte transceive
//~ spi_flush_input(sp);
// Serial port claimed but we need to check if a PN532_SPI is opened.
spi_set_speed ( sp , PN532_SPI_DEFAULT_SPEED ) ;
spi_set_mode ( sp , PN532_SPI_MODE ) ;
nfc_connstring connstring ;
snprintf ( connstring , sizeof ( nfc_connstring ) , " %s:%s:% " PRIu32 , PN532_SPI_DRIVER_NAME , acPort , PN532_SPI_DEFAULT_SPEED ) ;
nfc_device * pnd = nfc_device_new ( context , connstring ) ;
pnd - > driver = & pn532_spi_driver ;
pnd - > driver_data = malloc ( sizeof ( struct pn532_spi_data ) ) ;
DRIVER_DATA ( pnd ) - > port = sp ;
// Alloc and init chip's data
pn53x_data_new ( pnd , & pn532_spi_io ) ;
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA ( pnd ) - > type = PN532 ;
// This device starts in LowVBat power mode
CHIP_DATA ( pnd ) - > power_mode = LOWVBAT ;
DRIVER_DATA ( pnd ) - > abort_flag = false ;
// Check communication using "Diagnose" command, with "Communication test" (0x00)
int res = pn53x_check_communication ( pnd ) ;
pn53x_data_free ( pnd ) ;
nfc_device_free ( pnd ) ;
spi_close ( sp ) ;
if ( res < 0 ) {
continue ;
}
memcpy ( connstrings [ device_found ] , connstring , sizeof ( nfc_connstring ) ) ;
device_found + + ;
// Test if we reach the maximum "wanted" devices
if ( device_found > = connstrings_len )
break ;
}
}
iDevice = 0 ;
while ( ( acPort = acPorts [ iDevice + + ] ) ) {
free ( ( void * ) acPort ) ;
}
free ( acPorts ) ;
return device_found ;
}
struct pn532_spi_descriptor {
2013-03-10 00:29:01 +01:00
char * port ;
2013-02-28 23:24:42 +01:00
uint32_t speed ;
} ;
static void
pn532_spi_close ( nfc_device * pnd )
{
pn53x_idle ( pnd ) ;
// Release SPI port
spi_close ( DRIVER_DATA ( pnd ) - > port ) ;
2013-03-10 00:29:01 +01:00
free ( DRIVER_DATA ( pnd ) - > port ) ;
2013-02-28 23:24:42 +01:00
pn53x_data_free ( pnd ) ;
nfc_device_free ( pnd ) ;
}
static nfc_device *
pn532_spi_open ( const nfc_context * context , const nfc_connstring connstring )
{
struct pn532_spi_descriptor ndd ;
2013-03-10 00:29:01 +01:00
char * speed_s ;
int connstring_decode_level = connstring_decode ( connstring , PN532_SPI_DRIVER_NAME , NULL , & ndd . port , & speed_s ) ;
if ( connstring_decode_level = = 3 ) {
ndd . speed = 0 ;
if ( sscanf ( speed_s , " %10 " PRIu32 , & ndd . speed ) ! = 1 ) {
// speed_s is not a number
free ( ndd . port ) ;
free ( speed_s ) ;
return NULL ;
}
free ( speed_s ) ;
}
2013-02-28 23:24:42 +01:00
if ( connstring_decode_level < 2 ) {
return NULL ;
}
if ( connstring_decode_level < 3 ) {
ndd . speed = PN532_SPI_DEFAULT_SPEED ;
}
spi_port sp ;
nfc_device * pnd = NULL ;
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " Attempt to open: %s at %d Hz. " , ndd . port , ndd . speed ) ;
sp = spi_open ( ndd . port ) ;
if ( sp = = INVALID_SPI_PORT )
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " Invalid SPI port: %s " , ndd . port ) ;
if ( sp = = CLAIMED_SPI_PORT )
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " SPI port already claimed: %s " , ndd . port ) ;
2013-03-10 00:29:01 +01:00
if ( ( sp = = CLAIMED_SPI_PORT ) | | ( sp = = INVALID_SPI_PORT ) ) {
free ( ndd . port ) ;
2013-02-28 23:24:42 +01:00
return NULL ;
2013-03-10 00:29:01 +01:00
}
2013-02-28 23:24:42 +01:00
spi_set_speed ( sp , ndd . speed ) ;
spi_set_mode ( sp , PN532_SPI_MODE ) ;
// We have a connection
pnd = nfc_device_new ( context , connstring ) ;
snprintf ( pnd - > name , sizeof ( pnd - > name ) , " %s:%s " , PN532_SPI_DRIVER_NAME , ndd . port ) ;
pnd - > driver_data = malloc ( sizeof ( struct pn532_spi_data ) ) ;
DRIVER_DATA ( pnd ) - > port = sp ;
// Alloc and init chip's data
pn53x_data_new ( pnd , & pn532_spi_io ) ;
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA ( pnd ) - > type = PN532 ;
// This device starts in LowVBat mode
CHIP_DATA ( pnd ) - > power_mode = LOWVBAT ;
// empirical tuning
CHIP_DATA ( pnd ) - > timer_correction = 48 ;
pnd - > driver = & pn532_spi_driver ;
DRIVER_DATA ( pnd ) - > abort_flag = false ;
// Check communication using "Diagnose" command, with "Communication test" (0x00)
if ( pn53x_check_communication ( pnd ) < 0 ) {
nfc_perror ( pnd , " pn53x_check_communication " ) ;
pn532_spi_close ( pnd ) ;
return NULL ;
}
pn53x_init ( pnd ) ;
return pnd ;
}
static int
2013-03-03 16:22:18 +01:00
pn532_spi_read_spi_status ( nfc_device * pnd )
2013-02-28 23:24:42 +01:00
{
static const uint8_t pn532_spi_statread_cmd = 0x02 ;
uint8_t spi_status = 0 ;
int res = spi_send_receive ( DRIVER_DATA ( pnd ) - > port , & pn532_spi_statread_cmd , 1 , & spi_status , 1 , true ) ;
if ( res ! = NFC_SUCCESS ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " %s " , " Unable to read SPI status " ) ;
return res ;
}
return spi_status ;
}
int
pn532_spi_wakeup ( nfc_device * pnd )
{
/* SPI wakeup is basically activating chipselect for several ms.
* To do so , we are sending harmless command at very low speed */
int res ;
const uint32_t prev_port_speed = spi_get_speed ( DRIVER_DATA ( pnd ) - > port ) ;
// Try to get byte from the SPI line. If PN532 is powered down, the byte will be 0xff (MISO line is high)
uint8_t spi_byte = 0 ;
res = spi_receive ( DRIVER_DATA ( pnd ) - > port , & spi_byte , 1 , true ) ;
if ( res ! = NFC_SUCCESS ) {
2013-03-03 16:14:58 +01:00
return res ;
2013-02-28 23:24:42 +01:00
}
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " Got %x byte from SPI line before wakeup " , spi_byte ) ;
CHIP_DATA ( pnd ) - > power_mode = NORMAL ; // PN532 will be awake soon
2013-03-03 16:14:58 +01:00
if ( spi_byte = = 0xff ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " %s " , " Wakeup is needed " ) ;
spi_set_speed ( DRIVER_DATA ( pnd ) - > port , 5000 ) ; // set slow speed
2013-02-28 23:24:42 +01:00
2013-03-03 16:14:58 +01:00
res = pn532_SAMConfiguration ( pnd , PSM_NORMAL , 1000 ) ; // wakeup by sending SAMConfiguration, which works just fine
2013-02-28 23:24:42 +01:00
2013-03-03 16:14:58 +01:00
spi_set_speed ( DRIVER_DATA ( pnd ) - > port , prev_port_speed ) ;
2013-02-28 23:24:42 +01:00
}
return res ;
}
# define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
static int
pn532_spi_wait_for_data ( nfc_device * pnd , int timeout )
{
static const uint8_t pn532_spi_ready = 0x01 ;
static const int pn532_spi_poll_interval = 10 ; //ms
int timer = 0 ;
int ret ;
2013-03-03 16:22:18 +01:00
while ( ( ret = pn532_spi_read_spi_status ( pnd ) ) ! = pn532_spi_ready ) {
2013-02-28 23:24:42 +01:00
if ( ret < 0 ) {
2013-03-03 16:14:58 +01:00
return ret ;
2013-02-28 23:24:42 +01:00
}
if ( DRIVER_DATA ( pnd ) - > abort_flag ) {
2013-03-03 16:14:58 +01:00
DRIVER_DATA ( pnd ) - > abort_flag = false ;
return NFC_EOPABORTED ;
2013-02-28 23:24:42 +01:00
}
if ( timeout > 0 ) {
timer + = pn532_spi_poll_interval ;
if ( timer > timeout ) {
return NFC_ETIMEOUT ;
}
2013-03-08 23:30:21 +01:00
msleep ( pn532_spi_poll_interval ) ;
2013-02-28 23:24:42 +01:00
}
}
return NFC_SUCCESS ;
}
static int
pn532_spi_receive_next_chunk ( nfc_device * pnd , uint8_t * pbtData , const size_t szDataLen )
{
// According to datasheet, the entire read operation should be done at once
// However, it seems impossible to do since the length of the frame is stored in the frame
// itself and it's impossible to manualy set CS to low between two read operations
// It's possible to read the response frame in a series of read operations, provided
// each read operation is preceded by SPI_DATAREAD byte from the host.
// Unfortunately, the PN532 sends first byte of the second and successive response chunks
// at the same time as host sends SPI_DATAREAD byte
// Many hardware SPI implementations are half-duplex, so it's became impossible to read this
// first response byte
// The following hack is used here: we first try to recieve data from PN532 without SPI_DATAREAD
// and then begin full-featured read operation
// The PN532 do not shift the internal register on the recieve operation, which allows us to read the whole response
// The example transfer log is as follows:
// CS ..._/---\___________________________/---\________/------\_____________/-----\_________/---\____________/---...
// MOSI (host=>pn532) ... 0x03 0x00 0x00 0x00 0x00 0x00 0x03 0x00 0x00 0x03 0x00
// MISO (pn532<=host) ... 0x01 0x00 0xff 0x02 0xfe 0xd5 0xd5 0x15 0x16 0x16 0x00
// linux send/recieve s r r r r r s r r s r
// |<-- data -->| |<-data->| |<-data->| |<-data->| |<-data->|
// |<-- first chunk -->| |<-- second chunk -->| |<-- third chunk -->|
// The response frame is 0x00 0xff 0x02 0xfe 0xd5 0x15 0x16 0x00
int res = spi_receive ( DRIVER_DATA ( pnd ) - > port , pbtData , 1 , true ) ;
if ( res ! = NFC_SUCCESS ) {
return res ;
}
res = spi_send_receive ( DRIVER_DATA ( pnd ) - > port , & pn532_spi_cmd_dataread , 1 , pbtData + 1 , szDataLen - 1 , true ) ;
return res ;
}
static int
pn532_spi_receive ( nfc_device * pnd , uint8_t * pbtData , const size_t szDataLen , int timeout )
{
uint8_t abtRxBuf [ 5 ] ;
size_t len ;
pnd - > last_error = pn532_spi_wait_for_data ( pnd , timeout ) ;
if ( NFC_EOPABORTED = = pnd - > last_error ) {
return pn532_spi_ack ( pnd ) ;
}
if ( pnd - > last_error ! = NFC_SUCCESS ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to wait for SPI data. (RX) " ) ;
goto error ;
}
pnd - > last_error = spi_send_receive ( DRIVER_DATA ( pnd ) - > port , & pn532_spi_cmd_dataread , 1 , abtRxBuf , 4 , true ) ;
if ( pnd - > last_error < 0 ) {
goto error ;
}
const uint8_t pn53x_long_preamble [ 3 ] = { 0x00 , 0x00 , 0xff } ;
if ( 0 = = ( memcmp ( abtRxBuf , pn53x_long_preamble , 3 ) ) ) {
// long preamble
// omit first byte
2013-03-03 16:14:58 +01:00
for ( size_t i = 0 ; i < 3 ; + + i ) {
2013-02-28 23:24:42 +01:00
abtRxBuf [ i ] = abtRxBuf [ i + 1 ] ;
}
// need one more byte
pnd - > last_error = pn532_spi_receive_next_chunk ( pnd , abtRxBuf + 3 , 1 ) ;
if ( pnd - > last_error ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to receive one more byte for long preamble frame. (RX) " ) ;
goto error ;
}
}
const uint8_t pn53x_preamble [ 2 ] = { 0x00 , 0xff } ;
if ( 0 ! = ( memcmp ( abtRxBuf , pn53x_preamble , 2 ) ) ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " preamble+start code mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
if ( ( 0x01 = = abtRxBuf [ 2 ] ) & & ( 0xff = = abtRxBuf [ 3 ] ) ) {
// Error frame
pn532_spi_receive_next_chunk ( pnd , abtRxBuf , 3 ) ;
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Application level error detected " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
} else if ( ( 0xff = = abtRxBuf [ 2 ] ) & & ( 0xff = = abtRxBuf [ 3 ] ) ) {
// Extended frame
pnd - > last_error = pn532_spi_receive_next_chunk ( pnd , abtRxBuf , 3 ) ;
if ( pnd - > last_error ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to receive data. (RX) " ) ;
goto error ;
}
// (abtRxBuf[0] << 8) + abtRxBuf[1] (LEN) include TFI + (CC+1)
len = ( abtRxBuf [ 0 ] < < 8 ) + abtRxBuf [ 1 ] - 2 ;
if ( ( ( abtRxBuf [ 0 ] + abtRxBuf [ 1 ] + abtRxBuf [ 2 ] ) % 256 ) ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Length checksum mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
} else {
// Normal frame
if ( 256 ! = ( abtRxBuf [ 2 ] + abtRxBuf [ 3 ] ) ) {
// TODO: Retry
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Length checksum mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
// abtRxBuf[3] (LEN) include TFI + (CC+1)
len = abtRxBuf [ 2 ] - 2 ;
}
if ( len > szDataLen ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " Unable to receive data: buffer too small. (szDataLen: %zu, len: %zu) " , szDataLen , len ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
// TFI + PD0 (CC+1)
pnd - > last_error = pn532_spi_receive_next_chunk ( pnd , abtRxBuf , 2 ) ;
if ( pnd - > last_error ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to receive data. (RX) " ) ;
goto error ;
}
if ( abtRxBuf [ 0 ] ! = 0xD5 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " TFI Mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
if ( abtRxBuf [ 1 ] ! = CHIP_DATA ( pnd ) - > last_command + 1 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Command Code verification failed " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
if ( len ) {
pnd - > last_error = pn532_spi_receive_next_chunk ( pnd , pbtData , len ) ;
if ( pnd - > last_error ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to receive data. (RX) " ) ;
goto error ;
}
}
pnd - > last_error = pn532_spi_receive_next_chunk ( pnd , abtRxBuf , 2 ) ;
if ( pnd - > last_error ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to receive data. (RX) " ) ;
goto error ;
}
uint8_t btDCS = ( 256 - 0xD5 ) ;
btDCS - = CHIP_DATA ( pnd ) - > last_command + 1 ;
for ( size_t szPos = 0 ; szPos < len ; szPos + + ) {
btDCS - = pbtData [ szPos ] ;
}
if ( btDCS ! = abtRxBuf [ 0 ] ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Data checksum mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
if ( 0x00 ! = abtRxBuf [ 1 ] ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Frame postamble mismatch " ) ;
pnd - > last_error = NFC_EIO ;
goto error ;
}
// The PN53x command is done and we successfully received the reply
return len ;
error :
return pnd - > last_error ;
}
static int
pn532_spi_send ( nfc_device * pnd , const uint8_t * pbtData , const size_t szData , int timeout )
{
int res = 0 ;
// Before sending anything, we need to discard from any junk bytes
//~ spi_flush_input(DRIVER_DATA(pnd)->port);
switch ( CHIP_DATA ( pnd ) - > power_mode ) {
case LOWVBAT : {
/** PN532C106 wakeup. */
if ( ( res = pn532_spi_wakeup ( pnd ) ) < 0 ) {
return res ;
}
// According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command
if ( ( res = pn532_SAMConfiguration ( pnd , PSM_NORMAL , 1000 ) ) < 0 ) {
return res ;
}
}
break ;
case POWERDOWN : {
if ( ( res = pn532_spi_wakeup ( pnd ) ) < 0 ) {
return res ;
}
}
break ;
case NORMAL :
// Nothing to do :)
break ;
} ;
uint8_t abtFrame [ PN532_BUFFER_LEN + 1 ] = { pn532_spi_cmd_datawrite , 0x00 , 0x00 , 0xff } ; // SPI data transfer starts with DATAWRITE (0x01) byte, Every packet must start with "00 00 ff"
size_t szFrame = 0 ;
if ( ( res = pn53x_build_frame ( abtFrame + 1 , & szFrame , pbtData , szData ) ) < 0 ) {
pnd - > last_error = res ;
return pnd - > last_error ;
}
res = spi_send ( DRIVER_DATA ( pnd ) - > port , abtFrame , szFrame , true ) ;
if ( res ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to transmit data. (TX) " ) ;
pnd - > last_error = res ;
return pnd - > last_error ;
}
res = pn532_spi_wait_for_data ( pnd , timeout ) ;
if ( res ! = NFC_SUCCESS ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_ERROR , " %s " , " Unable to wait for SPI data. (RX) " ) ;
pnd - > last_error = res ;
return pnd - > last_error ;
}
uint8_t abtRxBuf [ 6 ] ;
res = spi_send_receive ( DRIVER_DATA ( pnd ) - > port , & pn532_spi_cmd_dataread , 1 , abtRxBuf , 6 , true ) ;
if ( res ! = 0 ) {
log_put ( LOG_GROUP , LOG_CATEGORY , NFC_LOG_PRIORITY_DEBUG , " %s " , " Unable to read ACK " ) ;
pnd - > last_error = res ;
return pnd - > last_error ;
}
if ( pn53x_check_ack_frame ( pnd , abtRxBuf , sizeof ( abtRxBuf ) ) = = 0 ) {
// The PN53x is running the sent command
} else {
return pnd - > last_error ;
}
return NFC_SUCCESS ;
}
int
pn532_spi_ack ( nfc_device * pnd )
{
const size_t ack_frame_len = ( sizeof ( pn53x_ack_frame ) / sizeof ( pn53x_ack_frame [ 0 ] ) ) ;
uint8_t ack_tx_buf [ 1 + ack_frame_len ] ;
ack_tx_buf [ 0 ] = pn532_spi_cmd_datawrite ;
memcpy ( ack_tx_buf + 1 , pn53x_ack_frame , ack_frame_len ) ;
int res = spi_send ( DRIVER_DATA ( pnd ) - > port , ack_tx_buf , ack_frame_len + 1 , true ) ;
return res ;
}
static int
pn532_spi_abort_command ( nfc_device * pnd )
{
if ( pnd ) {
2013-03-03 16:14:58 +01:00
DRIVER_DATA ( pnd ) - > abort_flag = true ;
2013-02-28 23:24:42 +01:00
}
return NFC_SUCCESS ;
}
const struct pn53x_io pn532_spi_io = {
. send = pn532_spi_send ,
. receive = pn532_spi_receive ,
} ;
const struct nfc_driver pn532_spi_driver = {
. name = PN532_SPI_DRIVER_NAME ,
. scan_type = INTRUSIVE ,
. scan = pn532_spi_scan ,
. open = pn532_spi_open ,
. close = pn532_spi_close ,
. strerror = pn53x_strerror ,
. initiator_init = pn53x_initiator_init ,
. initiator_init_secure_element = pn532_initiator_init_secure_element ,
. initiator_select_passive_target = pn53x_initiator_select_passive_target ,
. initiator_poll_target = pn53x_initiator_poll_target ,
. initiator_select_dep_target = pn53x_initiator_select_dep_target ,
. initiator_deselect_target = pn53x_initiator_deselect_target ,
. initiator_transceive_bytes = pn53x_initiator_transceive_bytes ,
. initiator_transceive_bits = pn53x_initiator_transceive_bits ,
. initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed ,
. initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed ,
. initiator_target_is_present = pn53x_initiator_target_is_present ,
. target_init = pn53x_target_init ,
. target_send_bytes = pn53x_target_send_bytes ,
. target_receive_bytes = pn53x_target_receive_bytes ,
. target_send_bits = pn53x_target_send_bits ,
. target_receive_bits = pn53x_target_receive_bits ,
. device_set_property_bool = pn53x_set_property_bool ,
. device_set_property_int = pn53x_set_property_int ,
. get_supported_modulation = pn53x_get_supported_modulation ,
. get_supported_baud_rate = pn53x_get_supported_baud_rate ,
. device_get_information_about = pn53x_get_information_about ,
. abort_command = pn532_spi_abort_command ,
. idle = pn53x_idle ,
. powerdown = pn53x_PowerDown ,
} ;